This commit is contained in:
deeaitch committed 2026-10-06 17:04:13 -04:00
1 parent 65142fdfe3
commit e5d818d9b2
14 files changed
+393 -39

No files matched your search

+126 -1
View File
@@ -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);