Closes
This commit is contained in:
1 parent
65142fdfe3
commit
e5d818d9b2
14 files changed
+393
-39
No files matched your search
@@ -50,6 +50,10 @@ error paths and line numbers, and integration with signals and comments.
|
||||
Signal tests cover complete syntax and numeric validation, scientific notation,
|
||||
finite physical parameters and ordered ranges, spaces and tabs, receiver lists,
|
||||
unsupported multiplexing, and Intel/Motorola declared-payload boundaries.
|
||||
Value-description tests cover full `VAL_` syntax, whitespace, escaped quotes,
|
||||
empty text, exact integer boundaries, duplicate keys within and across statements,
|
||||
deferred and normalized frame references, missing targets, error locations,
|
||||
raw lookup with scaling, unknown/invalid values, and both database builders.
|
||||
Temporary DBC fixtures are created in the system temporary directory and removed
|
||||
automatically.
|
||||
|
||||
|
||||
+126
-1
@@ -1,5 +1,9 @@
|
||||
#include "dbc_decode_builder.h"
|
||||
#include "dbc_decoder.h"
|
||||
#include "dbc_parser.h"
|
||||
#include "dbc_statement_handler.h"
|
||||
#include "dbc_tree_builder.h"
|
||||
#include <limits>
|
||||
|
||||
#include <QtTest>
|
||||
#include <chrono>
|
||||
@@ -66,6 +70,8 @@ private Q_SLOTS:
|
||||
void validSignals();
|
||||
void dispatch();
|
||||
void independentSessions();
|
||||
void valueDescriptions();
|
||||
void invalidValueDescriptions();
|
||||
};
|
||||
|
||||
void DbcParserTest::validFrames() {
|
||||
@@ -256,7 +262,7 @@ void DbcParserTest::dispatch() {
|
||||
"Factory dispatch and handler reuse");
|
||||
CHECK(!dispatcher.Dispatch("TEST_OTHER data", context) &&
|
||||
!dispatcher.Dispatch("BO_TX_BU_ 1 : ECU;", context) &&
|
||||
!dispatcher.Dispatch("VAL_ 1 Speed 0 \"Stopped\";", context) &&
|
||||
!dispatcher.Dispatch("VAL_TABLE_ States 0 \"Stopped\";", context) &&
|
||||
CountingHandler::calls == 2,
|
||||
"Exact and unknown keyword dispatch");
|
||||
}
|
||||
@@ -281,6 +287,125 @@ void DbcParserTest::independentSessions() {
|
||||
"Fresh parse after error");
|
||||
}
|
||||
|
||||
|
||||
void DbcParserTest::valueDescriptions() {
|
||||
Fixture fixture;
|
||||
fixture.Write(
|
||||
"VAL_\t256\tState\t0\t\"Off\"\t1 \"On\" 2 \"Error with spaces; and \\\"quotes\\\"\";\n"
|
||||
"BO_ 256 Status: 8 ECU\n"
|
||||
"SG_ State : 0|8@1+ (2,10) [0|520] \"\" ECU\n"
|
||||
"VAL_ 256 State 3 \"\";\n"
|
||||
"VAL_ 2147483904 State -9223372036854775808 \"Minimum\" -1 \"Negative\" 9223372036854775807 \"Maximum\";\n"
|
||||
"BO_ 2147483904 Extended: 8 ECU\n"
|
||||
"SG_ State : 0|64@1- (1,0) [-1e20|1e20] \"\" ECU\n"
|
||||
"BO_ 2048 Unsigned: 8 ECU\n"
|
||||
"SG_ State : 0|64@1+ (1,0) [0|2e20] \"\" ECU\n"
|
||||
"VAL_ 2147485696 State 9223372036854775808 \"High\" 18446744073709551615 \"Full\";\n");
|
||||
const auto parsed = DbcParser().ParseFile(fixture.path.string());
|
||||
const auto runtime = DbcDecodeBuilder().Build(parsed);
|
||||
const auto tree = DbcTreeBuilder().Build(parsed);
|
||||
CHECK(tree->GetChild(0)->GetSignal() == nullptr, "Frame node");
|
||||
for (std::size_t index = 0; index < parsed.frames.size(); ++index) {
|
||||
CHECK(tree->GetChild(index)->GetChild(0)->GetSignal()->valueDescriptions ==
|
||||
parsed.frames[index].signals[0].valueDescriptions &&
|
||||
runtime.frames[index].signals[0].valueDescriptions ==
|
||||
parsed.frames[index].signals[0].valueDescriptions,
|
||||
"All mappings survive both builders");
|
||||
}
|
||||
CHECK(tree->GetChild(0)->GetChild(0)->GetSignal()->valueDescriptions ==
|
||||
runtime.frames[0].signals[0].valueDescriptions,
|
||||
"Both builders preserve descriptions");
|
||||
RawCanFrame frame;
|
||||
frame.canId = 256;
|
||||
frame.data.resize(8);
|
||||
const std::string expected[] = {"Off", "On", "Error with spaces; and \"quotes\"", ""};
|
||||
for (unsigned value = 0; value < 5; ++value) {
|
||||
frame.data[0] = value;
|
||||
const auto decoded = DbcDecoder().Decode(runtime, frame).signals[0];
|
||||
CHECK(decoded.valid && decoded.physicalValue == value * 2 + 10, "Numeric scaling unchanged");
|
||||
const auto description = decoded.GetValueDescription();
|
||||
CHECK(value < 4 ? description && *description == expected[value] : !description,
|
||||
"Raw lookup and unknown value");
|
||||
}
|
||||
frame.isExtended = true;
|
||||
struct Boundary {
|
||||
std::uint64_t bits;
|
||||
const char *description;
|
||||
};
|
||||
for (const auto &test: {Boundary{0x8000000000000000ULL, "Minimum"},
|
||||
Boundary{0xFFFFFFFFFFFFFFFFULL, "Negative"},
|
||||
Boundary{0x7FFFFFFFFFFFFFFFULL, "Maximum"}}) {
|
||||
for (unsigned byte = 0; byte < 8; ++byte)
|
||||
frame.data[byte] = static_cast<std::uint8_t>(test.bits >> (byte * 8));
|
||||
const auto decoded = DbcDecoder().Decode(runtime, frame).signals[0];
|
||||
CHECK(decoded.GetValueDescription() && *decoded.GetValueDescription() == test.description,
|
||||
"Signed boundaries and distinct extended frame");
|
||||
}
|
||||
frame.canId = 2048;
|
||||
for (const auto &test: {Boundary{0x8000000000000000ULL, "High"},
|
||||
Boundary{0xFFFFFFFFFFFFFFFFULL, "Full"}}) {
|
||||
for (unsigned byte = 0; byte < 8; ++byte)
|
||||
frame.data[byte] = static_cast<std::uint8_t>(test.bits >> (byte * 8));
|
||||
const auto decoded = DbcDecoder().Decode(runtime, frame).signals[0];
|
||||
CHECK(decoded.GetValueDescription() && *decoded.GetValueDescription() == test.description,
|
||||
"Unsigned boundaries");
|
||||
}
|
||||
CHECK(FindValueDescription(runtime.frames[0].signals[0].valueDescriptions, std::int64_t(1)) != nullptr,
|
||||
"Nonnegative signed lookup matches unsigned key");
|
||||
frame.data.clear();
|
||||
CHECK(!DbcDecoder().Decode(runtime, frame).signals[0].GetValueDescription(), "Invalid decode has no description");
|
||||
}
|
||||
|
||||
void DbcParserTest::invalidValueDescriptions() {
|
||||
Fixture fixture;
|
||||
const std::string definitions = "BO_ 1 Frame: 8 ECU\nSG_ State : 0|64@1+ (1,0) [0|2e20] \"\" ECU\n";
|
||||
for (const std::string statement: {
|
||||
"VAL_", "VAL_ 1 State;", "VAL_ 1 State ;", "VAL_ 1 State 0 \"Off\"",
|
||||
"VAL_ 1 State 0 \"Off\"; junk", "VAL_ 1 State 0 Off;",
|
||||
"VAL_ 1 State 0 \"Unclosed;", "VAL_ 1 State 0 \"Off\"1 \"On\";",
|
||||
"VAL_ 1 State 0 \"Off\" 00 \"Duplicate\";",
|
||||
"VAL_ 1 State 0 \"Off\" -0 \"Duplicate\";",
|
||||
"VAL_ 1 State 0 \"Off\";\nVAL_ 1 State 0 \"Duplicate\";",
|
||||
"VAL_ 2 State 0 \"Missing frame\";", "VAL_ 1 Missing 0 \"Missing signal\";",
|
||||
"VAL_ -1 State 0 \"Bad ID\";", "VAL_ 536870912 State 0 \"Bad ID\";",
|
||||
"VAL_ 4294967296 State 0 \"Bad ID\";", "VAL_ Environment 0 \"Unsupported\";",
|
||||
"VAL_ 1 State 0 \"Bad\\q escape\";"}) {
|
||||
fixture.Write(definitions + statement + '\n');
|
||||
const auto line = statement.find('\n') == std::string::npos ? 3 : 4;
|
||||
try {
|
||||
DbcParser().ParseFile(fixture.path.string());
|
||||
CHECK(false, statement);
|
||||
} catch (const std::runtime_error &error) {
|
||||
CHECK(std::string(error.what()).find(fixture.path.string() + ":" + std::to_string(line) + ": ") == 0,
|
||||
statement + " " + error.what());
|
||||
}
|
||||
}
|
||||
for (const std::string suffix: {
|
||||
"BO_ 1 Other: 8 ECU\n", // Ambiguous normalized frame reference.
|
||||
"SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n",// Ambiguous signal reference.
|
||||
""}) {
|
||||
fixture.Write("VAL_ 1 " + std::string(suffix.empty() ? "Missing" : "State") +
|
||||
" 0 \"Description\";\n" + definitions + suffix);
|
||||
try {
|
||||
DbcParser().ParseFile(fixture.path.string());
|
||||
CHECK(false, "Deferred missing or ambiguous reference");
|
||||
} catch (const std::runtime_error &error) {
|
||||
CHECK(std::string(error.what()).find(fixture.path.string() + ":1: ") == 0,
|
||||
"Deferred reference retains source location");
|
||||
}
|
||||
}
|
||||
for (const std::string number: {"+1", "1x", "0x10", "1.5", "1e2", "--1",
|
||||
"-9223372036854775809", "18446744073709551616"}) {
|
||||
fixture.Write("VAL_ 1 State " + number + " \"Bad\";\n" + definitions);
|
||||
try {
|
||||
DbcParser().ParseFile(fixture.path.string());
|
||||
CHECK(false, number);
|
||||
} catch (const std::runtime_error &error) {
|
||||
CHECK(std::string(error.what()).find(fixture.path.string() + ":1: ") == 0, number);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RunParserTests(int argc, char **argv) {
|
||||
DbcParserTest tests;
|
||||
return QTest::qExec(&tests, argc, argv);
|
||||
|
||||
Reference in new issue
Block a user