Skip to content

Commit 58669c9

Browse files
authored
Exception error cleanup (#24)
* feat(error): Adding non dbc file format error (extension based), Missing version header error added Fixed the tests so that they now make .dbc files since we are checking the extensions. * feat(error): Adding a missing bit timing error class * feat(error): Adding lines we attempted to parse and more error messaging for the Exceptions * test: Updating tests names to be more clear at what is being validated. * feat(parsing): Adding a way to push and read all of the unused lines since we don't error out on unused * fix(format): Running code format * fix: Fixing clang-tidy warnings
1 parent 9d42141 commit 58669c9

File tree

6 files changed

+164
-51
lines changed

6 files changed

+164
-51
lines changed

include/libdbc/dbc.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class DbcParser : public Parser {
3131

3232
Message::ParseSignalsStatus parse_message(uint32_t message_id, const std::vector<uint8_t>& data, std::vector<double>& out_values);
3333

34+
std::vector<std::string> unused_lines() const;
35+
3436
private:
3537
std::string version;
3638
std::vector<std::string> nodes;
@@ -44,9 +46,13 @@ class DbcParser : public Parser {
4446
std::regex value_re;
4547
std::regex signal_re;
4648

49+
std::vector<std::string> missed_lines;
50+
4751
void parse_dbc_header(std::istream& file_stream);
4852
void parse_dbc_nodes(std::istream& file_stream);
4953
void parse_dbc_messages(const std::vector<std::string>& lines);
54+
55+
static std::string get_extension(const std::string& file_name);
5056
};
5157

5258
}

include/libdbc/exceptions/error.hpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define ERROR_HPP
33

44
#include <exception>
5+
#include <string>
56

67
namespace Libdbc {
78

@@ -19,6 +20,49 @@ class ValidityError : public Exception {
1920
}
2021
};
2122

23+
class NonDbcFileFormatError : public ValidityError {
24+
public:
25+
NonDbcFileFormatError(const std::string& path, const std::string& extension) {
26+
error_msg = {"File is not of DBC format. Expected a .dbc extension. Cannot read this type of file (" + path + "). Found the extension (" + extension
27+
+ ")."};
28+
}
29+
30+
const char* what() const throw() override {
31+
return error_msg.c_str();
32+
}
33+
34+
private:
35+
std::string error_msg;
36+
};
37+
38+
class DbcFileIsMissingVersion : public ValidityError {
39+
public:
40+
DbcFileIsMissingVersion(const std::string& line) {
41+
error_msg = {"Invalid dbc file. Missing the required version header. Attempting to read line: (" + line + ")."};
42+
}
43+
44+
const char* what() const throw() override {
45+
return error_msg.c_str();
46+
}
47+
48+
private:
49+
std::string error_msg;
50+
};
51+
52+
class DbcFileIsMissingBitTiming : public ValidityError {
53+
public:
54+
DbcFileIsMissingBitTiming(const std::string& line) {
55+
error_msg = {"Invalid dbc file. Missing required bit timing in the header. Attempting to read line: (" + line + ")."};
56+
}
57+
58+
const char* what() const throw() override {
59+
return error_msg.c_str();
60+
}
61+
62+
private:
63+
std::string error_msg;
64+
};
65+
2266
} // libdbc
2367

2468
#endif // ERROR_HPP

src/dbc.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <cstdint>
2+
#include <cstdio>
23
#include <fstream>
34
#include <istream>
45
#include <libdbc/dbc.hpp>
@@ -76,8 +77,12 @@ void DbcParser::parse_file(const std::string& file) {
7677

7778
messages.clear();
7879

79-
parse_dbc_header(stream);
80+
auto extension = get_extension(file);
81+
if (extension != ".dbc") {
82+
throw NonDbcFileFormatError(file, extension);
83+
}
8084

85+
parse_dbc_header(stream);
8186
parse_dbc_nodes(stream);
8287

8388
while (!stream.eof()) {
@@ -88,6 +93,15 @@ void DbcParser::parse_file(const std::string& file) {
8893
parse_dbc_messages(lines);
8994
}
9095

96+
std::string DbcParser::get_extension(const std::string& file_name) {
97+
std::size_t dot = file_name.find_last_of(".");
98+
if (dot != std::string::npos) {
99+
return file_name.substr(dot, file_name.size() - dot);
100+
}
101+
102+
return "";
103+
}
104+
91105
std::string DbcParser::get_version() const {
92106
return version;
93107
}
@@ -116,7 +130,7 @@ void DbcParser::parse_dbc_header(std::istream& file_stream) {
116130
Utils::StreamHandler::get_line(file_stream, line);
117131

118132
if (!std::regex_search(line, match, version_re)) {
119-
throw ValidityError();
133+
throw DbcFileIsMissingVersion(line);
120134
}
121135

122136
version = match.str(2);
@@ -126,7 +140,7 @@ void DbcParser::parse_dbc_header(std::istream& file_stream) {
126140
Utils::StreamHandler::get_next_non_blank_line(file_stream, line);
127141

128142
if (!std::regex_search(line, match, bit_timing_re)) {
129-
throw ValidityError();
143+
throw DbcFileIsMissingBitTiming(line);
130144
}
131145
}
132146

@@ -136,9 +150,7 @@ void DbcParser::parse_dbc_nodes(std::istream& file_stream) {
136150

137151
Utils::StreamHandler::get_next_non_blank_line(file_stream, line);
138152

139-
if (!std::regex_search(line, match, node_re)) {
140-
throw ValidityError();
141-
}
153+
std::regex_search(line, match, node_re);
142154

143155
if (match.length() > 2) {
144156
std::string node = match.str(2);
@@ -213,6 +225,10 @@ void DbcParser::parse_dbc_messages(const std::vector<std::string>& lines) {
213225
signal_value.push_back(val);
214226
continue;
215227
}
228+
229+
if (line.length() > 0) {
230+
missed_lines.push_back(line);
231+
}
216232
}
217233

218234
for (const auto& signal : signal_value) {
@@ -225,4 +241,8 @@ void DbcParser::parse_dbc_messages(const std::vector<std::string>& lines) {
225241
}
226242
}
227243

244+
std::vector<std::string> DbcParser::unused_lines() const {
245+
return missed_lines;
246+
}
247+
228248
}

test/dbcs/MissingVersion.dbc

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,36 @@
1-
NS_ :
2-
BA_
3-
BA_DEF_
4-
BA_DEF_DEF_
5-
BA_DEF_DEF_REL_
6-
BA_DEF_REL_
7-
BA_DEF_SGTYPE_
8-
BA_REL_
9-
BA_SGTYPE_
10-
BO_TX_BU_
11-
BU_BO_REL_
12-
BU_EV_REL_
13-
BU_SG_REL_
14-
CAT_
15-
CAT_DEF_
16-
CM_
17-
ENVVAR_DATA_
18-
EV_DATA_
19-
FILTER
20-
NS_DESC_
21-
SGTYPE_
22-
SGTYPE_VAL_
23-
SG_MUL_VAL_
24-
SIGTYPE_VALTYPE_
25-
SIG_GROUP_
26-
SIG_TYPE_REF_
27-
SIG_VALTYPE_
28-
VAL_
29-
VAL_TABLE_
30-
31-
BS_:
32-
33-
BU_: DBG DRIVER IO MOTOR SENSOR
34-
35-
BO_ 500 IO_DEBUG: 4 IO
36-
SG_ IO_DEBUG_test_unsigned : 0|8@1+ (1,0) [0|0] "" DBG
1+
NS_ :
2+
BA_
3+
BA_DEF_
4+
BA_DEF_DEF_
5+
BA_DEF_DEF_REL_
6+
BA_DEF_REL_
7+
BA_DEF_SGTYPE_
8+
BA_REL_
9+
BA_SGTYPE_
10+
BO_TX_BU_
11+
BU_BO_REL_
12+
BU_EV_REL_
13+
BU_SG_REL_
14+
CAT_
15+
CAT_DEF_
16+
CM_
17+
ENVVAR_DATA_
18+
EV_DATA_
19+
FILTER
20+
NS_DESC_
21+
SGTYPE_
22+
SGTYPE_VAL_
23+
SG_MUL_VAL_
24+
SIGTYPE_VALTYPE_
25+
SIG_GROUP_
26+
SIG_TYPE_REF_
27+
SIG_VALTYPE_
28+
VAL_
29+
VAL_TABLE_
30+
31+
BS_:
32+
33+
BU_: DBG DRIVER IO MOTOR SENSOR
34+
35+
BO_ 500 IO_DEBUG: 4 IO
36+
SG_ IO_DEBUG_test_unsigned : 0|8@1+ (1,0) [0|0] "" DBG

test/test_dbc.cpp

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,35 @@
33
#include <catch2/catch_approx.hpp>
44
#include <catch2/catch_test_macros.hpp>
55
#include <catch2/matchers/catch_matchers.hpp>
6+
#include <catch2/matchers/catch_matchers_string.hpp>
67
#include <libdbc/dbc.hpp>
78
#include <libdbc/exceptions/error.hpp>
89
#include <string>
910

11+
using Catch::Matchers::ContainsSubstring;
12+
1013
TEST_CASE("Testing dbc file loading error issues", "[fileio][error]") {
1114
auto parser = std::unique_ptr<Libdbc::DbcParser>(new Libdbc::DbcParser());
1215

1316
SECTION("Loading a non dbc file should throw an error", "[error]") {
14-
REQUIRE_THROWS_AS(parser->parse_file(TEXT_FILE), Libdbc::ValidityError);
17+
REQUIRE_THROWS_AS(parser->parse_file(TEXT_FILE), Libdbc::NonDbcFileFormatError);
18+
REQUIRE_THROWS_WITH(parser->parse_file(TEXT_FILE), ContainsSubstring("TextFile.txt"));
1519
}
1620

17-
SECTION("Loading a dbc with bad headers throws an error", "[error]") {
18-
REQUIRE_THROWS_AS(parser->parse_file(MISSING_VERSION_DBC_FILE), Libdbc::ValidityError);
21+
SECTION("Loading a dbc with missing version header throws an error (VERSION)", "[error]") {
22+
REQUIRE_THROWS_AS(parser->parse_file(MISSING_VERSION_DBC_FILE), Libdbc::DbcFileIsMissingVersion);
23+
REQUIRE_THROWS_WITH(parser->parse_file(MISSING_VERSION_DBC_FILE), ContainsSubstring("line: (NS_ :)"));
1924
}
2025

2126
SECTION("Loading a dbc without the required bit timing section (BS_:)", "[error]") {
22-
REQUIRE_THROWS_AS(parser->parse_file(MISSING_BIT_TIMING_DBC_FILE), Libdbc::ValidityError);
27+
REQUIRE_THROWS_AS(parser->parse_file(MISSING_BIT_TIMING_DBC_FILE), Libdbc::DbcFileIsMissingBitTiming);
28+
REQUIRE_THROWS_WITH(parser->parse_file(MISSING_BIT_TIMING_DBC_FILE), ContainsSubstring("BU_: DBG DRIVER IO MOTOR SENSOR"));
2329
}
2430

2531
SECTION("Loading a dbc with some missing namespace section tags (NS_ :)", "[error]") {
2632
// Confusion about this type of error. it appears that the header isn't
2733
// very well standardized for now we ignore this type of error.
28-
CHECK_NOTHROW(parser->parse_file(MISSING_NEW_SYMBOLS_DBC_FILE));
34+
REQUIRE_NOTHROW(parser->parse_file(MISSING_NEW_SYMBOLS_DBC_FILE));
2935
}
3036

3137
SECTION("Verify that what() method is accessible for all exceptions", "[error]") {
@@ -240,7 +246,7 @@ VAL_ 123 State1 123 "Description 3" 0 "Description 4" ;)";
240246
REQUIRE(signal2.value_descriptions.at(1).description == "Description 4");
241247
}
242248

243-
TEST_CASE("Should parse DBC with empty BU_") {
249+
TEST_CASE("Should parse DBC with empty BU_", "[error][optional]") {
244250
std::string contents = R"(VERSION ""
245251
246252
@@ -254,15 +260,52 @@ NS_ :
254260
BO_ 293 Msg1: 2 Vector__XXX
255261
SG_ Wert7 : 0|16@1- (1,0) [0|0] "" Vector__XXX
256262
257-
BO_ 292 Msg2: 8 Vector__XXX
263+
BO_ 292 Msg2: 1 Vector__XXX
258264
SG_ Wert8 : 56|8@1- (1,0) [0|0] "" Vector__XXX
259265
)";
260266
const auto filename = create_temporary_dbc_with(contents.c_str());
261267

262268
auto parser = Libdbc::DbcParser();
263-
parser.parse_file(filename.c_str());
269+
REQUIRE_NOTHROW(parser.parse_file(filename.c_str()));
264270

265271
REQUIRE(parser.get_messages().size() == 2);
266272
REQUIRE(parser.get_messages().at(0).name() == "Msg1");
267273
REQUIRE(parser.get_messages().at(1).name() == "Msg2");
268274
}
275+
276+
TEST_CASE("Should report unused lines since we don't have tracing.", "[parsing]") {
277+
std::string contents = R"(VERSION ""
278+
279+
NS_ :
280+
281+
BS_:
282+
283+
BU_:
284+
285+
286+
BO_ 293 Msg1: 2 Vector__XXX
287+
SG_ Whitespace: | 0|16@1- (1,0) [0|0] "" Vector__XXX
288+
SG_ Wert7 : 0|16@1- (1,0) [0|0] "" Vector__XXX
289+
SG_ Wert8 : 0|16@1- (1,0) [0|0] "" Vector__XXX
290+
291+
BO_ 292 Msg2: 1 Vector__XXX
292+
SG_ Wert8 : 56|8@1- (1,0) [0|0] "" Vector__XXX
293+
SB_ not a correct line
294+
295+
BO_ have a issue here:
296+
)";
297+
298+
const auto filename = create_temporary_dbc_with(contents.c_str());
299+
300+
auto parser = Libdbc::DbcParser();
301+
REQUIRE_NOTHROW(parser.parse_file(filename.c_str()));
302+
303+
REQUIRE(parser.get_messages().size() == 2);
304+
REQUIRE(parser.get_messages()[0].size() == 2);
305+
REQUIRE(parser.get_messages()[1].size() == 1);
306+
307+
auto unused = parser.unused_lines();
308+
309+
// We could match them all here but i think just a check that the size is sufficent.
310+
REQUIRE(unused.size() == 3);
311+
}

test/testing_utils/common.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ std::string generate_unique_filename() {
2323
int random_num = dis(gen);
2424

2525
// Concatenate time and random number to create a unique filename
26-
return "temp_file_" + std::to_string(milliseconds) + "_" + std::to_string(random_num) + ".txt";
26+
return "temp_file_" + std::to_string(milliseconds) + "_" + std::to_string(random_num) + ".dbc";
2727
}
2828

2929
std::string create_temporary_dbc_with(const char* contents) {

0 commit comments

Comments
 (0)