Closes #10
This commit is contained in:
1 parent
a533d9aa00
commit
a0938cb29c
14 files changed
+375
-13
No files matched your search
@@ -72,3 +72,9 @@ Enable `CONFIG+=dbc_qt` in the root qmake invocation to build `dbc_qt` and
|
||||
QAbstractItemModelTester, verify navigation across columns, invalid/foreign
|
||||
indexes, metadata and exact VAL_ integers, and persistent-index invalidation
|
||||
when reloading or clearing the tree. No GUI/display server is needed.
|
||||
|
||||
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_.
|
||||
+124
-1
@@ -63,6 +63,8 @@ private:
|
||||
}
|
||||
}
|
||||
private Q_SLOTS:
|
||||
void multiplexing();
|
||||
void multiplexingBoundaries();
|
||||
void validFrames();
|
||||
void invalidFrames();
|
||||
void integration();
|
||||
@@ -153,6 +155,127 @@ void DbcParserTest::integration() {
|
||||
}
|
||||
}
|
||||
|
||||
void DbcParserTest::multiplexing() {
|
||||
Fixture fixture;
|
||||
const std::string selector = "SG_ Mode M : 0|8@1+ (10,3) [0|255] \"\" ECU\n";
|
||||
const std::string first = "SG_ First m1 : 8|8@1- (2,0) [-128|127] \"V\" ECU\n";
|
||||
const std::string second = "SG_ Second m2 : 15|8@0+ (1,0) [0|255] \"\" ECU\n";
|
||||
const std::string common = "SG_ Common : 16|8@1+ (1,0) [0|255] \"\" ECU\n";
|
||||
fixture.Write("BO_ 1 Frame: 3 ECU\n" + first + second + common + selector +
|
||||
"VAL_ 1 First -1 \"Negative\";\n");
|
||||
const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
|
||||
const DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
|
||||
CHECK(parsed.frames[0].signals[3].multiplexing.role == MultiplexRole::Selector,
|
||||
"Selector declared after branches");
|
||||
const std::unique_ptr<TreeNode> tree = DbcTreeBuilder().Build(parsed);
|
||||
CHECK(tree->GetChild(0U)->GetChild(0U)->GetSignal()->multiplexing.value == 1U,
|
||||
"Tree preserves multiplexing");
|
||||
RawCanFrame raw;
|
||||
raw.canId = 1U;
|
||||
raw.data = {1U, 255U, 7U};
|
||||
DecodedFrameValue result = DbcDecoder().Decode(runtime, raw);
|
||||
CHECK(result.signals[0].valid && std::get<std::int64_t>(result.signals[0].rawValue) == -1 &&
|
||||
result.signals[0].physicalValue == -2 && *result.signals[0].GetValueDescription() == "Negative",
|
||||
"Active signed branch and VAL_ use exact raw selector");
|
||||
CHECK(!result.signals[1].valid && result.signals[1].status == SignalDecodeStatus::Inactive &&
|
||||
result.signals[1].GetValueDescription() == nullptr && result.signals[2].valid,
|
||||
"Inactive branch and unconditional signal");
|
||||
raw.data[0] = 2U;
|
||||
result = DbcDecoder().Decode(runtime, raw);
|
||||
CHECK(result.signals[0].status == SignalDecodeStatus::Inactive && result.signals[1].valid &&
|
||||
std::get<std::uint64_t>(result.signals[1].rawValue) == 255U,
|
||||
"Motorola branch becomes active");
|
||||
raw.data = {3U};
|
||||
result = DbcDecoder().Decode(runtime, raw);
|
||||
CHECK(result.signals[0].status == SignalDecodeStatus::Inactive &&
|
||||
result.signals[1].status == SignalDecodeStatus::Inactive &&
|
||||
result.signals[2].status == SignalDecodeStatus::InsufficientPayload,
|
||||
"Unmapped selector leaves branches inactive even with missing bytes");
|
||||
raw.data = {1U};
|
||||
result = DbcDecoder().Decode(runtime, raw);
|
||||
CHECK(result.signals[0].status == SignalDecodeStatus::InsufficientPayload,
|
||||
"Active branch requires payload");
|
||||
raw.data.clear();
|
||||
result = DbcDecoder().Decode(runtime, raw);
|
||||
CHECK(result.signals[0].status == SignalDecodeStatus::SelectorUnavailable &&
|
||||
result.signals[3].status == SignalDecodeStatus::InsufficientPayload,
|
||||
"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"
|
||||
};
|
||||
for (const std::string &signals : invalid) {
|
||||
fixture.Write("BO_ 1 Frame: 3 ECU\n" + signals);
|
||||
bool rejected = false;
|
||||
try {
|
||||
DbcParser().ParseFile(fixture.path.string());
|
||||
} catch (const std::runtime_error &error) {
|
||||
rejected = std::string(error.what()).find(fixture.path.string() + ":") == 0U;
|
||||
}
|
||||
CHECK(rejected, "Invalid multiplexing rejected with location");
|
||||
}
|
||||
for (const std::string marker : {"m", "m-1", "m+1", "m1M", "m18446744073709551616", "M m1"})
|
||||
RejectSignal(fixture, "SG_ Bad " + marker + " : 8|8@1+ (1,0) [0|255] \"\" ECU");
|
||||
}
|
||||
|
||||
void DbcParserTest::multiplexingBoundaries() {
|
||||
Fixture fixture;
|
||||
fixture.Write("BO_ 1 Frame: 9 ECU\n"
|
||||
"SG_ Branch m18446744073709551615 : 64|8@1+ (1,0) [0|255] \"\" ECU\n"
|
||||
"SG_ Mode M : 7|64@0+ (0,5) [0|1] \"\" ECU\n");
|
||||
const DbcDatabase parsed = DbcParser().ParseFile(fixture.path.string());
|
||||
DecodeDatabase runtime = DbcDecodeBuilder().Build(parsed);
|
||||
CHECK(runtime.frames[0].signals[0].multiplexing.value == std::numeric_limits<std::uint64_t>::max(),
|
||||
"Exact uint64 branch metadata");
|
||||
RawCanFrame raw;
|
||||
raw.canId = 1U;
|
||||
raw.data = std::vector<std::uint8_t>(9U, 255U);
|
||||
DecodedFrameValue result = DbcDecoder().Decode(runtime, raw);
|
||||
CHECK(result.signals[0].valid && result.signals[1].valid &&
|
||||
std::get<std::uint64_t>(result.signals[1].rawValue) == std::numeric_limits<std::uint64_t>::max(),
|
||||
"Motorola uint64 selector compares raw value before zero scaling");
|
||||
raw.data[7] = 254U;
|
||||
result = DbcDecoder().Decode(runtime, raw);
|
||||
CHECK(result.signals[0].status == SignalDecodeStatus::Inactive,
|
||||
"Adjacent large integers remain distinct");
|
||||
runtime.frames[0].signals[1].length = 0U;
|
||||
result = DbcDecoder().Decode(runtime, raw);
|
||||
CHECK(result.signals[0].status == SignalDecodeStatus::InvalidDefinition &&
|
||||
result.signals[1].status == SignalDecodeStatus::InvalidDefinition,
|
||||
"Malformed runtime selector distinguished from payload errors");
|
||||
runtime.frames[0].signals.pop_back();
|
||||
result = DbcDecoder().Decode(runtime, raw);
|
||||
CHECK(result.signals[0].status == SignalDecodeStatus::InvalidDefinition,
|
||||
"Missing runtime selector");
|
||||
fixture.Write("BO_ 1 Frame: 2 ECU\n\n"
|
||||
"SG_ Branch m2 : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
|
||||
"SG_ Mode M : 0|1@1+ (1,0) [0|1] \"\" ECU\n");
|
||||
bool rejected = false;
|
||||
try {
|
||||
DbcParser().ParseFile(fixture.path.string());
|
||||
} catch (const std::runtime_error &error) {
|
||||
rejected = std::string(error.what()).find(fixture.path.string() + ":3: ") == 0U;
|
||||
}
|
||||
CHECK(rejected, "Deferred validation reports branch source line");
|
||||
fixture.Write("BO_ 1 Frame: 2 ECU\n"
|
||||
"SG_ A : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
|
||||
"SG_ B : 15|8@0+ (1,0) [0|255] \"\" ECU\n");
|
||||
rejected = false;
|
||||
try {
|
||||
DbcParser().ParseFile(fixture.path.string());
|
||||
} catch (const std::runtime_error &) {
|
||||
rejected = true;
|
||||
}
|
||||
CHECK(rejected, "Ordinary overlapping signals rejected");
|
||||
}
|
||||
|
||||
void DbcParserTest::invalidSignals() {
|
||||
Fixture fixture;
|
||||
const std::string ordinary = SignalLine("0", "8", "1+", "1", "0", "0", "255");
|
||||
@@ -172,7 +295,7 @@ void DbcParserTest::invalidSignals() {
|
||||
RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "0", value));
|
||||
}
|
||||
RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "2", "1"));
|
||||
for (const std::string name: {"", "Two Names", "Value M", "Value m1", "Value m1M"}) {
|
||||
for (const std::string name: {"", "Two Names", "Value m1M"}) {
|
||||
std::string line = ordinary;
|
||||
line.replace(4U, 5U, name);
|
||||
RejectSignal(fixture, line);
|
||||
|
||||
Reference in new issue
Block a user