This commit is contained in:
deeaitch committed 2026-10-23 20:53:05 -04:00
1 parent f60faea2e7
commit f03882d3f4
86 files changed
+3539 -2688

No files matched your search

+25 -1
View File
@@ -99,7 +99,7 @@ line numbers for skipped syntax and immediate/deferred errors; warnings precedin
an error are retained, and failed parses return an empty database. Common headers
and namespace symbol lists stay quiet. Tests also check file-open errors, fresh
parse sessions, and compatibility with the legacy throwing API.
The diagnostic audit also covers 13 unsupported-statement variants, all namespace
The diagnostic audit also covers 11 unsupported-statement variants, all namespace
termination forms, CRLF and missing final newlines, relative paths with spaces,
first-error stopping, deferred diagnostic ordering, duplicate definitions/values,
selector ranges, overlaps, and preservation of supported decoding and metadata.
@@ -295,6 +295,30 @@ Attribute changes were verified with `qmake6 ../dbc.pro`, `make -j4`, and
passed. The standalone C++17 tree test also passed. The existing named
comma-decimal C locale test skipped because the locale is not installed.
## Unsupported signal value types
`unsupportedSignalValueTypes` verifies that both parser APIs reject `SIG_VALTYPE_`
declarations with `UnsupportedSignalType`, the original file path and physical
line, and an empty database. Cases include float32/float64, declarations before
signal definitions, extended IDs, tabs/CRLF, no final newline, type 0, unknown
types, and malformed declarations. Prior warnings are retained; `SIG_VALTYPE_`
symbols inside `NS_` lists remain quiet.
The pipeline suite checks the IEEE 754 bytes for float32 and float64 `1.0`.
Adding a type declaration must prevent publication of an integer definition,
so building from the error result cannot produce a valid decoded signal. The
same payloads still decode to exact integers when defined only by supported
`SG_` statements. New cases are included in the existing qmake targets.
Verified with Qt 6.8.2 in separate Release and ASan/UBSan builds with
`CONFIG+=dbc_qt`: each passed 2,420 core QtTest checks, seven model checks, and
the qmake tree test. One named-locale case skipped because its locale is
unavailable. ASan/UBSan used fatal errors and `detect_leaks=0` because of the
previously documented ptrace restriction. The separately built demo was checked
with float32 and float64 declarations (exit 2, source-located error, no decode
output), a supported integer definition (exit 0), and an unknown extension
(exit 0 with a visible warning).
## Long signal definitions
`longSignalDefinitions` reproduces the former stack overflow with a 50,000-character
+50 -4
View File
@@ -99,6 +99,8 @@ private Q_SLOTS:
void diagnostics();
void diagnosticErrors();
void diagnosticUnsupportedStatements();
void unsupportedSignalValueTypes_data();
void unsupportedSignalValueTypes();
void diagnosticNamespaceBoundaries();
void diagnosticFormatting();
void multiplexing();
@@ -427,7 +429,7 @@ void DbcParserTest::diagnostics() {
"BU_: ECU\n"
"BO_ 1 Frame: 1 ECU\n"
"SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
"SIG_VALTYPE_ 1 Value : 1;\n"
"SIG_TYPE_REF_ 1 Value : Custom;\n"
"BA_REL_ \"SignalType\" SG_ 1 Value 1;\n"
"VENDOR_EXTENSION_ data;\n");
const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
@@ -564,7 +566,6 @@ void DbcParserTest::diagnosticUnsupportedStatements() {
"BO_ 1 Frame: 1 ECU\nSG_ Value : 0|8@1+ (2,10) [10|520] \"V\" ECU\n"
"CM_ SG_ 1 Value \"Signal comment\";\nVAL_ 1 Value 1 \"On\";\n";
const std::vector<std::string> statements = {
"SIG_VALTYPE_ 1 Value : 1;", "SIG_VALTYPE_ 1 Value : 2;",
"BA_REL_ \"SignalType\" SG_ 1 Value 1;",
"BA_DEF_REL_ BU_SG_REL_ \"Relation\" INT 0 1;",
"BA_REL_ \"Relation\" BU_SG_REL_ ECU SG_ 1 Value 1;",
@@ -602,6 +603,51 @@ void DbcParserTest::diagnosticUnsupportedStatements() {
}
}
void DbcParserTest::unsupportedSignalValueTypes_data() {
QTest::addColumn<std::string>("statement");
QTest::addColumn<bool>("beforeDefinitions");
QTest::newRow("float32") << std::string("SIG_VALTYPE_ 1 Value : 1;") << false;
QTest::newRow("float64") << std::string("SIG_VALTYPE_ 1 Value : 2;") << false;
QTest::newRow("float32-before-definitions") << std::string("SIG_VALTYPE_ 1 Value : 1;") << true;
QTest::newRow("float64-before-definitions") << std::string("SIG_VALTYPE_ 1 Value : 2;") << true;
QTest::newRow("extended-frame") << std::string("SIG_VALTYPE_ 2147483649 Value : 1;") << false;
QTest::newRow("tabs-crlf") << std::string("\tSIG_VALTYPE_\t1\tValue : 2;\r") << false;
QTest::newRow("integer-declaration") << std::string("SIG_VALTYPE_ 1 Value : 0;") << false;
QTest::newRow("unknown-type") << std::string("SIG_VALTYPE_ 1 Value : 3;") << false;
QTest::newRow("malformed") << std::string("SIG_VALTYPE_") << false;
}
void DbcParserTest::unsupportedSignalValueTypes() {
QFETCH(std::string, statement);
QFETCH(bool, beforeDefinitions);
const std::string definitions = "BO_ 1 Frame: 8 ECU\n"
"SG_ Value : 0|64@1+ (1,0) [0|100] \"\" ECU\n";
Fixture fixture;
fixture.Write("VERSION \"\"\nNS_:\n\tSIG_VALTYPE_\nBS_:\nVENDOR_EXTENSION_ data;\n" +
(beforeDefinitions ? statement + "\n" + definitions : definitions + statement));
const std::size_t expectedLine = beforeDefinitions ? 6U : 8U;
const DbcParser parser;
const DbcParseResult result = parser.ParseFileWithDiagnostics(fixture.path.string());
QVERIFY(result.HasErrors());
QVERIFY(result.database.frames.empty());
QCOMPARE(result.diagnostics.size(), std::size_t(2));
QCOMPARE(result.diagnostics[0].severity, DbcDiagnosticSeverity::Warning);
QCOMPARE(result.diagnostics[0].code, DbcDiagnosticCode::UnsupportedStatement);
const DbcDiagnostic &error = result.diagnostics[1];
QCOMPARE(error.severity, DbcDiagnosticSeverity::Error);
QCOMPARE(error.code, DbcDiagnosticCode::UnsupportedSignalType);
QCOMPARE(error.lineNumber, expectedLine);
QCOMPARE(error.filePath, fixture.path.string());
QVERIFY(error.message.find("SIG_VALTYPE_") != std::string::npos);
try {
parser.ParseFile(fixture.path.string());
QFAIL("ParseFile must reject explicit signal value types");
} catch (const std::runtime_error &exception) {
QCOMPARE(std::string(exception.what()), fixture.path.string() + ":" +
std::to_string(expectedLine) + ": " + error.message);
}
}
void DbcParserTest::diagnosticNamespaceBoundaries() {
Fixture fixture;
const std::vector<std::string> endings = {
@@ -609,13 +655,13 @@ void DbcParserTest::diagnosticNamespaceBoundaries() {
"BO_ 1 Frame: 1 ECU\n", "VENDOR_EXTENSION_ data;\n"
};
for (const std::string &ending : endings) {
fixture.Write("NS_ :\n\tSG_MUL_VAL_\n\nBA_\n" + ending + "SIG_VALTYPE_\n");
fixture.Write("NS_ :\n\tSG_MUL_VAL_\n\nBA_\n" + ending + "SIG_TYPE_REF_\n");
const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
CHECK(!result.HasErrors(), ending);
const std::size_t expectedWarnings = ending.find("VENDOR_") == 0U ? 2U : 1U;
QCOMPARE(result.diagnostics.size(), expectedWarnings);
QCOMPARE(result.diagnostics.back().lineNumber, std::size_t(6U));
CHECK(result.diagnostics.back().message.find("SIG_VALTYPE_") != std::string::npos,
CHECK(result.diagnostics.back().message.find("SIG_TYPE_REF_") != std::string::npos,
"Unsupported keyword outside NS_ must produce a warning");
}
for (const std::string &definition : {std::string("BO_"), std::string("SG_")}) {
+50
View File
@@ -199,6 +199,8 @@ private Q_SLOTS:
void emptyDatabase_data();
void emptyDatabase();
void databaseReplacement();
void unsupportedSignalTypes_data();
void unsupportedSignalTypes();
};
void PipelineTest::metadataLookupDecodeAndTree() {
@@ -277,6 +279,54 @@ void PipelineTest::metadataLookupDecodeAndTree() {
QVERIFY(j1939.signals.empty());
}
void PipelineTest::unsupportedSignalTypes_data() {
QTest::addColumn<unsigned>("bits");
QTest::addColumn<unsigned>("type");
QTest::addColumn<std::vector<std::uint8_t>>("payload");
QTest::addColumn<std::uint64_t>("integerValue");
QTest::newRow("float32-one") << 32U << 1U << std::vector<std::uint8_t>{0U, 0U, 128U, 63U}
<< std::uint64_t(0x3F800000U);
QTest::newRow("float64-one") << 64U << 2U << std::vector<std::uint8_t>{0U, 0U, 0U, 0U, 0U, 0U, 240U, 63U}
<< std::uint64_t(0x3FF0000000000000ULL);
}
void PipelineTest::unsupportedSignalTypes() {
QFETCH(unsigned, bits);
QFETCH(unsigned, type);
QFETCH(std::vector<std::uint8_t>, payload);
QFETCH(std::uint64_t, integerValue);
const std::string definitions = "BO_ 1 Frame: " + std::to_string(bits / 8U) + " ECU\n"
"SG_ Value : 0|" + std::to_string(bits) + "@1+ (1,0) [0|100] \"\" ECU\n";
RawCanFrame raw;
raw.canId = 1U;
raw.data = payload;
const DbcDecodeBuilder builder;
const DbcDecoder decoder;
// Without a type override, the same bits are a supported integer signal.
const DbcParseResult integers = ParseFixture(definitions);
QVERIFY(!integers.HasErrors());
const DecodedFrameValue integerFrame = decoder.Decode(builder.Build(integers.database), raw);
QCOMPARE(integerFrame.status, FrameDecodeStatus::Valid);
QCOMPARE(integerFrame.signals.size(), std::size_t(1));
QVERIFY(integerFrame.signals[0].valid);
QCOMPARE(std::get<std::uint64_t>(integerFrame.signals[0].rawValue), integerValue);
const DbcParseResult floatingPoint = ParseFixture(definitions +
"SIG_VALTYPE_ 1 Value : " + std::to_string(type) + ";\n");
QVERIFY(floatingPoint.HasErrors());
QCOMPARE(floatingPoint.diagnostics.size(), std::size_t(1));
QCOMPARE(floatingPoint.diagnostics[0].code, DbcDiagnosticCode::UnsupportedSignalType);
QCOMPARE(floatingPoint.diagnostics[0].lineNumber, std::size_t(3));
QVERIFY(floatingPoint.database.frames.empty());
// Even if a caller overlooks the error, no integer definition is published.
const DecodedFrameValue rejected = decoder.Decode(builder.Build(floatingPoint.database), raw);
QCOMPARE(rejected.status, FrameDecodeStatus::UnknownFrame);
QVERIFY(!rejected.valid);
QVERIFY(!rejected.definition);
QVERIFY(rejected.signals.empty());
}
void PipelineTest::emptyDatabase_data() {
QTest::addColumn<QString>("text");
QTest::newRow("empty-file") << QString();