Closes #33
This commit is contained in:
1 parent
f60faea2e7
commit
f03882d3f4
86 files changed
+3539
-2688
No files matched your search
+25
-1
@@ -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
|
||||
|
||||
@@ -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_")}) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in new issue
Block a user