This commit is contained in:
deeaitch committed 2026-10-23 20:28:55 -04:00
1 parent a702cffd93
commit 8d06165979
18 files changed
+611 -215

No files matched your search

+15 -3
View File
@@ -118,7 +118,7 @@ extended ID encodings and repeated signal names within a frame. Standard and
extended frames may share a numeric ID, and separate frames may reuse signal names.
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.
invalid multiplexing, and Intel/Motorola declared-payload boundaries.
Physical-number tests apply a custom comma-decimal C++ locale and an available
named comma-decimal C numeric locale. They check all four physical fields,
leading signs, fractions, scientific notation, finite boundaries, zero, malformed
@@ -172,7 +172,19 @@ Basic multiplexing coverage includes selector declarations after branches,
Intel/Motorola branch overlap, signed active values and VAL_ lookup, unconditional
signals, inactive branches, missing selector/branch payloads, exact UINT64_MAX
selector matching, malformed runtime selectors, source locations, and rejection
of invalid markers, selector references/ranges, overlaps, and SG_MUL_VAL_.
of invalid markers, selector references/ranges, and overlaps.
Extended and nested multiplexing coverage includes deferred `SG_MUL_VAL_`
references, inclusive and separated ranges, repeated range statements, explicit
range precedence over markers, `mNM` fallback, independent selectors, nested
siblings sharing Intel/Motorola payload bits, raw selection with scaling, and
64-bit boundaries. Tests verify metadata through tree/runtime builders, selective
decoding with ancestor dependencies, inactive paths with missing bytes, missing
selectors versus leaf payload, malformed ranges, unknown targets, cycles,
conflicting parents, and invalid manually constructed runtime graphs.
The extended multiplexing change was verified with the root qmake build,
`make -j4`, `make check` (2,398 passed, no failures, one existing named C-locale
check skipped because the locale is unavailable), and the standalone tree test.
## Additional regression coverage
@@ -245,7 +257,7 @@ frame and signal lookups.
`dbc_pipeline_test.cpp` parses temporary DBC files and checks independent expected
metadata against the parser, runtime builder, and tree builder. It exercises
standard and extended frames with the same numeric ID and signal name, Intel
and signed Motorola decoding, scaling, raw value descriptions, basic multiplexing,
and signed Motorola decoding, scaling, raw value descriptions, basic and extended multiplexing,
PGN metadata, receivers, units, ranges, and frame/signal comments. Tree checks
include node types, payloads, parents, rows, names, and child counts.
+5 -5
View File
@@ -813,10 +813,10 @@ void CoverageTest::multiplexingErrorLocations_data() {
const QString selector = "SG_ Mode M : 0|1@1+ (1,0) [0|1] \"\" ECU\n";
const QString branch = "SG_ A m1 : 8|8@1+ (1,0) [0|255] \"\" ECU\n";
QTest::newRow("missing-selector") << header + branch << 3U << QString::fromUtf8("Multiplexed branch has no selector.");
QTest::newRow("second-selector") << header + selector + "\nSG_ Other M : 16|1@1+ (1,0) [0|1] \"\" ECU\n"
<< 5U << QString::fromUtf8("Multiplexing requires one unsigned selector per frame.");
QTest::newRow("second-selector") << header + selector + "\nSG_ Other M : 16|1@1- (1,0) [-1|0] \"\" ECU\n"
<< 5U << QString::fromUtf8("Multiplex selectors must be unsigned.");
QTest::newRow("signed-selector") << header + "SG_ Mode M : 0|1@1- (1,0) [-1|0] \"\" ECU\n"
<< 3U << QString::fromUtf8("Multiplexing requires one unsigned selector per frame.");
<< 3U << QString::fromUtf8("Multiplex selectors must be unsigned.");
QTest::newRow("branch-range") << header + "SG_ A m2 : 8|8@1+ (1,0) [0|255] \"\" ECU\n" + selector << 3U << QString::fromUtf8("Branch value exceeds selector raw range.");
QTest::newRow("same-branch-overlap") << header + selector + branch + "SG_ B m1 : 15|8@0+ (1,0) [0|255] \"\" ECU\n"
<< 5U << QString::fromUtf8("Signals overlap without mutually exclusive multiplexing conditions.");
@@ -827,9 +827,9 @@ void CoverageTest::multiplexingErrorLocations_data() {
QTest::newRow("ordinary-overlap") << header + "SG_ A : 8|8@1+ (1,0) [0|255] \"\" ECU\nSG_ B : 15|8@0+ (1,0) [0|255] \"\" ECU\n"
<< 4U << QString::fromUtf8("Signals overlap without mutually exclusive multiplexing conditions.");
QTest::newRow("extended-multiplexing") << header + "SG_MUL_VAL_ 1 A Mode 1-2;\n"
<< 3U << QString::fromUtf8("Extended and nested multiplexing are unsupported.");
<< 3U << QString::fromUtf8("Unresolved SG_MUL_VAL_ signal reference: A");
QTest::newRow("nested-marker") << header + "SG_ A m1M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
<< 3U << QString::fromUtf8("Invalid or unsupported multiplexing marker.");
<< 3U << QString::fromUtf8("Multiplexed branch has no selector.");
}
void CoverageTest::multiplexingErrorLocations() {
+237 -44
View File
@@ -103,6 +103,8 @@ private Q_SLOTS:
void diagnosticFormatting();
void multiplexing();
void multiplexingBoundaries();
void extendedMultiplexing();
void extendedMultiplexingErrors();
void validFrames();
void invalidFrames();
void duplicateFrames();
@@ -458,41 +460,40 @@ void DbcParserTest::diagnosticErrors() {
std::size_t line;
};
const ErrorCase cases[] = {
{"UNKNOWN_ data;\n\nBO_ invalid Frame: 1 ECU\n",
DbcDiagnosticCode::InvalidStatement, 3U},
{"BO_ 1 Frame: 1 ECU\nSG_MUL_VAL_ 1 Value Mode 1-2;\n",
DbcDiagnosticCode::UnsupportedStatement, 2U},
{"BO_ 1 Frame: 1 ECU\nVAL_ 1 Missing 0 \"Off\";\n",
DbcDiagnosticCode::InvalidValueDescription, 2U},
{"BO_ 1 Frame: 1 ECU\nSG_ Value m1 : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidMultiplexing, 2U},
{"BO_ 1 Frame: 1 ECU\nSG_ Mode M : 0|8@1- (1,0) [-128|127] \"\" ECU\n",
DbcDiagnosticCode::InvalidMultiplexing, 2U},
{"VAL_ broken\n", DbcDiagnosticCode::InvalidValueDescription, 1U},
{"SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidStatement, 1U},
{"BO_ 1 Frame: 1 ECU\nBO_ 1 Duplicate: 1 ECU\n",
DbcDiagnosticCode::InvalidStatement, 2U},
{"BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidStatement, 3U},
{"BO_ 1 Frame: 1 ECU\nSG_ Value : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidStatement, 2U},
{"BO_ 1 Frame: 1 ECU\nVAL_ 2 Missing 0 \"Off\";\n",
DbcDiagnosticCode::InvalidValueDescription, 2U},
{"BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"VAL_ 1 Value 0 \"Off\";\nVAL_ 1 Value 0 \"Duplicate\";\n",
DbcDiagnosticCode::InvalidValueDescription, 4U},
{"BO_ 1 Frame: 2 ECU\nSG_ Mode M : 0|1@1+ (1,0) [0|1] \"\" ECU\n"
"SG_ Value m2 : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidMultiplexing, 3U},
{"BO_ 1 Frame: 2 ECU\nSG_ Mode M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Other M : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidMultiplexing, 3U},
{"BO_ 1 Frame: 1 ECU\nSG_ First : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Second : 7|8@0+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidMultiplexing, 3U}
};
{"UNKNOWN_ data;\n\nBO_ invalid Frame: 1 ECU\n",
DbcDiagnosticCode::InvalidStatement, 3U},
{"BO_ 1 Frame: 1 ECU\nSG_MUL_VAL_ 1 Value Mode 1-2;\n",
DbcDiagnosticCode::InvalidMultiplexing, 2U},
{"BO_ 1 Frame: 1 ECU\nVAL_ 1 Missing 0 \"Off\";\n",
DbcDiagnosticCode::InvalidValueDescription, 2U},
{"BO_ 1 Frame: 1 ECU\nSG_ Value m1 : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidMultiplexing, 2U},
{"BO_ 1 Frame: 1 ECU\nSG_ Mode M : 0|8@1- (1,0) [-128|127] \"\" ECU\n",
DbcDiagnosticCode::InvalidMultiplexing, 2U},
{"VAL_ broken\n", DbcDiagnosticCode::InvalidValueDescription, 1U},
{"SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidStatement, 1U},
{"BO_ 1 Frame: 1 ECU\nBO_ 1 Duplicate: 1 ECU\n",
DbcDiagnosticCode::InvalidStatement, 2U},
{"BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidStatement, 3U},
{"BO_ 1 Frame: 1 ECU\nSG_ Value : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidStatement, 2U},
{"BO_ 1 Frame: 1 ECU\nVAL_ 2 Missing 0 \"Off\";\n",
DbcDiagnosticCode::InvalidValueDescription, 2U},
{"BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"VAL_ 1 Value 0 \"Off\";\nVAL_ 1 Value 0 \"Duplicate\";\n",
DbcDiagnosticCode::InvalidValueDescription, 4U},
{"BO_ 1 Frame: 2 ECU\nSG_ Mode M : 0|1@1+ (1,0) [0|1] \"\" ECU\n"
"SG_ Value m2 : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidMultiplexing, 3U},
{"BO_ 1 Frame: 2 ECU\nSG_ Mode M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Other M : 8|8@1- (1,0) [-128|127] \"\" ECU\n",
DbcDiagnosticCode::InvalidMultiplexing, 3U},
{"BO_ 1 Frame: 1 ECU\nSG_ First : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Second : 7|8@0+ (1,0) [0|255] \"\" ECU\n",
DbcDiagnosticCode::InvalidMultiplexing, 3U}};
for (const ErrorCase &test : cases) {
fixture.Write(test.text);
const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
@@ -980,15 +981,14 @@ void DbcParserTest::multiplexing() {
"Unavailable selector does not imply inactive branch");
const std::vector<std::string> invalid = {
first,
selector + "SG_ Other M : 16|8@1+ (1,0) [0|255] \"\" ECU\n",
"SG_ Mode M : 0|8@1- (1,0) [-128|127] \"\" ECU\n",
selector + "SG_ TooLarge m256 : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
selector + first + "SG_ Same m1 : 15|8@0+ (1,0) [0|255] \"\" ECU\n",
selector + "SG_ Collision m1 : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
selector + first + "SG_ Always : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
"SG_MUL_VAL_ 1 First Mode 1-2;\n"
};
first,
selector + "SG_ Other M : 16|8@1- (1,0) [-128|127] \"\" ECU\n",
"SG_ Mode M : 0|8@1- (1,0) [-128|127] \"\" ECU\n",
selector + "SG_ TooLarge m256 : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
selector + first + "SG_ Same m1 : 15|8@0+ (1,0) [0|255] \"\" ECU\n",
selector + "SG_ Collision m1 : 0|8@1+ (1,0) [0|255] \"\" ECU\n",
selector + first + "SG_ Always : 8|8@1+ (1,0) [0|255] \"\" ECU\n",
"SG_MUL_VAL_ 1 First Mode 1-2;\n"};
for (const std::string &signals : invalid) {
fixture.Write("BO_ 1 Frame: 3 ECU\n" + signals);
bool rejected = false;
@@ -1374,6 +1374,199 @@ void DbcParserTest::invalidValueDescriptions() {
}
}
void DbcParserTest::extendedMultiplexing() {
Fixture fixture;
// Forward references, multiple ranges, repeated range statements, and nested siblings.
fixture.Write(
"SG_MUL_VAL_ 1 Child Root 1-2, 4-4;\n"
"SG_MUL_VAL_ 1 Leaf Child 3-5;\n"
"SG_MUL_VAL_ 1 Leaf Child 7-7;\n"
"SG_MUL_VAL_ 1 Sibling Root 6-6;\n"
"SG_MUL_VAL_ 1 Other Sibling 3-5;\n"
"BO_ 1 Frame: 4 ECU\n"
"SG_ Leaf m99 : 16|8@1- (2,1) [-128|127] \"\" ECU\n"
"SG_ Other m0 : 23|8@0+ (1,0) [0|255] \"\" ECU\n"
"SG_ Child m1M : 8|8@1+ (10,3) [0|255] \"\" ECU\n"
"SG_ Sibling m6M : 15|8@0+ (1,0) [0|255] \"\" ECU\n"
"SG_ Root M : 0|8@1+ (10,3) [0|255] \"\" ECU\n"
"SG_ Common : 24|8@1+ (1,0) [0|255] \"\" ECU\n");
const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
const DecodeDatabase database = DbcDecodeBuilder().Build(parsed);
const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(parsed);
const Multiplexing &metadata = tree->GetChild(0U)->GetChild(0U)->GetSignal()->multiplexing;
CHECK(metadata.selector == "Child" && metadata.ranges.size() == 2U &&
metadata.ranges[1].minimum == 7U,
"Tree preserves ranges and selector name");
CHECK(database.GetFrames()[0].signals[2].multiplexing.role == MultiplexRole::BranchSelector,
"Runtime preserves nested selector role");
RawCanFrame raw;
raw.canId = 1U;
raw.data = {2U, 4U, 255U, 8U};
DecodedFrameValue result = DbcDecoder().Decode(database, raw);
CHECK(result.signals[0].valid && result.signals[0].physicalValue == -1.0 &&
result.signals[1].status == SignalDecodeStatus::Inactive && result.signals[2].valid &&
result.signals[3].status == SignalDecodeStatus::Inactive && result.signals[5].valid,
"Nested raw conditions select one path and preserve definition order");
const std::vector<SignalKey> selection = {SignalKey(FrameKey(1U, false), "Leaf")};
result = DbcDecoder().Decode(database, raw, selection);
CHECK(result.signals.size() == 1U && result.signals[0].valid,
"Selection reads all ancestors internally");
for (std::uint8_t root: {1U, 2U, 4U}) {
for (std::uint8_t child: {3U, 5U, 7U}) {
raw.data = {root, child, 9U, 8U};
CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].valid,
"Inclusive endpoints and separated ranges");
}
}
raw.data = {6U, 4U, 9U, 8U};
result = DbcDecoder().Decode(database, raw);
CHECK(result.signals[0].status == SignalDecodeStatus::Inactive && result.signals[1].valid &&
result.signals[3].valid,
"Overlapping sibling selector path becomes active");
raw.data = {0U};
CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].status == SignalDecodeStatus::Inactive,
"Inactive root does not require child selector bytes");
raw.data = {1U};
CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].status == SignalDecodeStatus::SelectorUnavailable,
"Active root with missing child selector");
raw.data = {1U, 3U};
CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].status == SignalDecodeStatus::InsufficientPayload,
"Active nested leaf needs its bytes");
raw.data = {1U, 6U};
CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].status == SignalDecodeStatus::Inactive,
"Gap between explicit ranges does not fall back to mN");
raw.data.clear();
CHECK(DbcDecoder().Decode(database, raw, selection).signals[0].status == SignalDecodeStatus::SelectorUnavailable,
"Missing root selector");
fixture.Write("BO_ 1 Frame: 9 ECU\n"
"SG_ Root M : 0|64@1+ (1,0) [0|1] \"\" ECU\n"
"SG_ Leaf m0 : 64|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_MUL_VAL_ 1 Leaf Root 18446744073709551614-18446744073709551615;\n");
raw.data.assign(9U, 255U);
CHECK(DbcDecoder().Decode(DbcDecodeBuilder().Build(DbcParser().ParseFile(fixture.path.string())), raw).signals[1].valid,
"64-bit ranges retain exact UINT64_MAX without expansion");
fixture.Write("BO_ 1 Frame: 4 ECU\n"
"SG_ Root M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Second M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ A m0 : 16|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ B m0 : 24|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_MUL_VAL_ 1 A Root 1-1;\nSG_MUL_VAL_ 1 B Second 2-2;\n");
raw.data = {1U, 2U, 9U, 10U};
result = DbcDecoder().Decode(DbcDecodeBuilder().Build(DbcParser().ParseFile(fixture.path.string())), raw);
CHECK(result.signals[2].valid && result.signals[3].valid, "Independent explicit selectors");
fixture.Write("BO_ 1 Deep: 5 ECU\n"
"SG_ Root M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Child m1M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Grandchild m2M : 16|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Leaf : 24|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_MUL_VAL_ 1 Grandchild Child 2-2;\n"
"SG_MUL_VAL_ 1 Leaf Grandchild 3-3;\n");
const DecodeDatabase deep = DbcDecodeBuilder().Build(DbcParser().ParseFile(fixture.path.string()));
raw.data = {1U, 2U, 3U, 9U, 0U};
CHECK(DbcDecoder().Decode(deep, raw).signals[3].valid, "Three selector levels and an unmarked extended branch");
raw.data = {1U, 0U};
CHECK(DbcDecoder().Decode(deep, raw).signals[3].status == SignalDecodeStatus::Inactive,
"Inactive middle ancestor skips missing descendant bytes");
// Marker fallback also works on a nested selector without its own SG_MUL_VAL_.
fixture.Write("BO_ 1 Frame: 3 ECU\n"
"SG_ Root M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Child m1M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Leaf m2 : 16|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_MUL_VAL_ 1 Leaf Child 2-2;\n");
raw.data = {1U, 2U, 9U};
CHECK(DbcDecoder().Decode(DbcDecodeBuilder().Build(DbcParser().ParseFile(fixture.path.string())), raw).signals[2].valid,
"mNM retains implicit root fallback");
}
void DbcParserTest::extendedMultiplexingErrors() {
Fixture fixture;
const std::string definitions =
"BO_ 1 Frame: 3 ECU\n"
"SG_ Root M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Child m1M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Leaf m2 : 16|8@1+ (1,0) [0|255] \"\" ECU\n";
for (const std::string statement: {
"SG_MUL_VAL_ 1 Leaf Root 3-2;", "SG_MUL_VAL_ 1 Leaf Root -1-2;",
"SG_MUL_VAL_ 1 Leaf Root 1-256;", "SG_MUL_VAL_ 1 Leaf Root 1-2,;",
"SG_MUL_VAL_ 1 Leaf Root 1-2 trailing;", "SG_MUL_VAL_ 1 Leaf Root 1-2",
"SG_MUL_VAL_ 1 Leaf Root 0-18446744073709551616;",
"SG_MUL_VAL_ 1 Leaf Missing 1-2;", "SG_MUL_VAL_ 1 Missing Root 1-2;",
"SG_MUL_VAL_ 2 Leaf Root 1-2;", "SG_MUL_VAL_ 1 Leaf Leaf 1-2;"}) {
fixture.Write(statement + "\n" + definitions);
const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
CHECK(result.HasErrors() && result.database.frames.empty(), statement);
CHECK(result.diagnostics.back().code == DbcDiagnosticCode::InvalidMultiplexing &&
result.diagnostics.back().lineNumber == 1U,
"Extended error retains source statement location");
}
for (const std::string statements: {
"SG_MUL_VAL_ 1 Root Child 1-1;\nSG_MUL_VAL_ 1 Child Root 1-1;\n",
"SG_MUL_VAL_ 1 Child Child 1-1;\n",
"SG_MUL_VAL_ 1 Leaf Root 1-1;\nSG_MUL_VAL_ 1 Leaf Child 1-1;\n"}) {
fixture.Write(definitions + statements);
CHECK(DbcParser().ParseFileWithDiagnostics(fixture.path.string()).HasErrors(), "Cyclic or conflicting parents rejected");
}
// Range intersection and inherited root conditions must both protect overlaps.
const std::string overlapping =
"BO_ 1 Frame: 4 ECU\n"
"SG_ Root M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ Child m1M : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ A m0 : 16|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_ B m0 : 23|8@0+ (1,0) [0|255] \"\" ECU\n"
"SG_MUL_VAL_ 1 A Child 2-4;\n"
"SG_MUL_VAL_ 1 Child Root 1-1;\n";
for (const std::string condition: {"SG_MUL_VAL_ 1 B Child 4-6;\n",
"SG_MUL_VAL_ 1 B Root 1-1;\n"}) {
fixture.Write(overlapping + condition);
CHECK(DbcParser().ParseFileWithDiagnostics(fixture.path.string()).HasErrors(),
"Overlapping ranges or compatible ancestors cannot share bits");
}
fixture.Write(overlapping + "SG_MUL_VAL_ 1 B Child 5-6;\n");
CHECK(!DbcParser().ParseFileWithDiagnostics(fixture.path.string()).HasErrors(),
"Disjoint adjacent ranges may share bits");
fixture.Write(overlapping + "SG_ Second M : 24|8@1+ (1,0) [0|255] \"\" ECU\n"
"SG_MUL_VAL_ 1 B Second 2-4;\n");
const DbcParseResult independent = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
CHECK(independent.HasErrors() && independent.diagnostics.back().message ==
"Signals overlap without mutually exclusive multiplexing conditions.",
"Independent selector conditions do not imply exclusion");
// Validate manually constructed runtime graphs with the same rules.
fixture.Write(definitions + "SG_MUL_VAL_ 1 Leaf Child 2-3;\n");
const DecodeDatabase valid = DbcDecodeBuilder().Build(DbcParser().ParseFile(fixture.path.string()));
for (unsigned kind = 0U; kind < 6U; ++kind) {
std::vector<DecodeFrame> frames = valid.GetFrames();
Multiplexing &leaf = frames[0].signals[2].multiplexing;
switch (kind) {
case 0:
leaf.selector = "Missing";
break;
case 1:
leaf.ranges[0] = {4U, 3U};
break;
case 2:
leaf.ranges[0] = {0U, 256U};
break;
case 3:
leaf.ranges.clear();
break;
case 4:
frames[0].signals[0].multiplexing.selector = "Child";
frames[0].signals[0].multiplexing.ranges = {{1U, 1U}};
break;
case 5:
frames[0].signals[1].valueType = ValueType::Signed;
break;
}
QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (void) DecodeDatabase(frames));
}
}
int RunParserTests(int argc, char **argv) {
DbcParserTest tests;
return QTest::qExec(&tests, argc, argv);
+1
View File
@@ -165,6 +165,7 @@ void DbcValidationTest::invalidMetadata() {
case 19:
signal.multiplexing.role = MultiplexRole::Selector;
other.multiplexing.role = MultiplexRole::Selector;
other.valueType = ValueType::Signed;
other.startBit = 8U;
frame.signals.push_back(other);
break;