This commit is contained in:
deeaitch committed 2026-10-20 13:38:21 -04:00
1 parent 849ce31e2f
commit a55d1c58ed
272 files changed
+41866 -261

No files matched your search

+31
View File
@@ -237,3 +237,34 @@ Attribute changes were verified with `qmake6 ../dbc.pro`, `make -j4`, and
`make check` in `build/`: all six QtTest suites and the qmake tree target
passed. The standalone C++17 tree test also passed. The existing named
comma-decimal C locale test skipped because the locale is not installed.
## Extended validation
`attributeNumbers` checks signed 64-bit limits, leading plus signs, decimal HEX
values, FLOAT fractions/exponents, and default overrides under a comma-decimal
C++ locale. Node/environment defaults remain on definitions without becoming
database attributes. `invalidAttributeNumbers` supplies 39 data rows, each checked
in both definition bounds, a default, and an explicit assignment. The throwing
and diagnostic APIs must reject malformed signs, trailing text, hexadecimal
notation, non-finite values, overflow, and underflow with the correct error line.
Additional malformed-attribute cases cover token separators, scope/type names,
reversed FLOAT bounds, value types/ranges, and invalid CAN references.
Run AddressSanitizer and UndefinedBehaviorSanitizer in a separate directory:
```sh
mkdir -p build-sanitize
cd build-sanitize
qmake6 ../dbc.pro CONFIG+=dbc_qt CONFIG+=debug CONFIG-=release \
'QMAKE_CXXFLAGS+=-fsanitize=address,undefined -fno-omit-frame-pointer' \
'QMAKE_LFLAGS+=-fsanitize=address,undefined'
make -j4
ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=halt_on_error=1 \
QT_FATAL_WARNINGS=1 LOCPATH=/tmp/dbc-test-locales make check
```
Generate the optional German locale as described above before setting LOCPATH.
LeakSanitizer cannot run under this environment's tracer: `detect_leaks=1`
completes the core QtTest suites but fails during leak checking with the message
that LeakSanitizer does not work under ptrace. Disabling leak checking retains
AddressSanitizer and UndefinedBehaviorSanitizer checks; it does not verify leaks.
+87
View File
@@ -90,6 +90,9 @@ private:
private Q_SLOTS:
void attributes();
void invalidAttributes();
void attributeNumbers();
void invalidAttributeNumbers_data();
void invalidAttributeNumbers();
void attributeWarnings();
void diagnostics();
void diagnosticErrors();
@@ -186,6 +189,18 @@ void DbcParserTest::attributes() {
void DbcParserTest::invalidAttributes() {
Fixture fixture;
const std::vector<std::string> invalid = {
"BA_DEF_ BO_ \"A\"STRING;",
"BA_DEF_ BO_\"A\" STRING;",
"BA_DEF_ BO_ \"A\" \"STRING\";",
"BA_DEF_ BO_ A STRING;",
"BA_DEF_ ZZ_ \"A\" STRING;",
"BA_DEF_ BO_ \"A\" BLOB;",
"BA_DEF_ BO_ \"A\" FLOAT 2 1;",
"BA_DEF_ BO_ \"A\" STRING;\nBA_ \"A\" BO_ 1 0;",
"BA_DEF_ BO_ \"A\" FLOAT 0 1;\nBA_ \"A\" BO_ 1 2;",
"BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ -1 0;",
"BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 4294967296 0;",
"BA_DEF_ BO_ \"A\" INT 0 1;\nBA_ \"A\" BO_ 536870912 0;",
"BA_DEF_ BO_ \"A\" INT 2 1;",
"BA_DEF_ BO_ \"A\" FLOAT nan 1;",
"BA_DEF_ BO_ \"A\" FLOAT 0 inf;",
@@ -222,6 +237,78 @@ void DbcParserTest::invalidAttributes() {
}
}
void DbcParserTest::attributeNumbers() {
ApplicationLocaleGuard guard;
std::locale::global(std::locale(std::locale::classic(), new CommaDecimalPunctuation));
Fixture fixture;
fixture.Write("BA_DEF_ \"I\" INT -9223372036854775808 +9223372036854775807;\n"
"BA_DEF_DEF_ \"I\" -9223372036854775808;\n"
"BA_ \"I\" +9223372036854775807;\n"
"BA_DEF_ \"H\" HEX -10 +10;\n"
"BA_DEF_DEF_ \"H\" +0;\n"
"BA_ \"H\" -10;\n"
"BA_DEF_ \"F\" FLOAT -1.25e+2 +2.5E2;\n"
"BA_DEF_DEF_ \"F\" +.5;\n"
"BA_ \"F\" -1.25e+2;\n"
"BA_DEF_ BU_ \"NodeDefault\" INT 0 10;\n"
"BA_DEF_DEF_ \"NodeDefault\" 5;\n"
"BA_DEF_ EV_ \"EnvironmentDefault\" STRING;\n"
"BA_DEF_DEF_ \"EnvironmentDefault\" \"default\";\n");
const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
QVERIFY(!result.HasErrors());
QVERIFY(result.diagnostics.empty());
QCOMPARE(std::get<std::int64_t>(*result.database.attributeDefinitions.at("I").defaultValue), std::numeric_limits<std::int64_t>::min());
QCOMPARE(std::get<std::int64_t>(result.database.attributes.at("I")), std::numeric_limits<std::int64_t>::max());
QCOMPARE(std::get<std::int64_t>(*result.database.attributeDefinitions.at("H").defaultValue), std::int64_t(0));
QCOMPARE(std::get<std::int64_t>(result.database.attributes.at("H")), std::int64_t(-10));
QCOMPARE(std::get<double>(*result.database.attributeDefinitions.at("F").defaultValue), 0.5);
QCOMPARE(std::get<double>(result.database.attributes.at("F")), -125.0);
QCOMPARE(result.database.attributes.size(), std::size_t(3));
QCOMPARE(std::get<std::int64_t>(*result.database.attributeDefinitions.at("NodeDefault").defaultValue), std::int64_t(5));
QCOMPARE(std::get<std::string>(*result.database.attributeDefinitions.at("EnvironmentDefault").defaultValue), std::string("default"));
}
void DbcParserTest::invalidAttributeNumbers_data() {
QTest::addColumn<QString>("type");
QTest::addColumn<QString>("number");
const char *types[] = {"INT", "HEX", "FLOAT"};
const char *invalid[] = {"+", "-", "++1", "+-1", "--1", "1x", "0x10",
"nan", "inf", "-inf", "1e9999", "1e-9999"};
for (const char *type: types) {
for (const char *number: invalid) {
const std::string name = std::string(type) + '-' + number;
QTest::newRow(name.c_str()) << QString(type) << QString(number);
}
}
QTest::newRow("integer-overflow") << QString("INT") << QString("9223372036854775808");
QTest::newRow("integer-underflow") << QString("INT") << QString("-9223372036854775809");
QTest::newRow("integer-fraction") << QString("INT") << QString("1.5");
}
void DbcParserTest::invalidAttributeNumbers() {
QFETCH(QString, type);
QFETCH(QString, number);
const std::string kind = type.toStdString();
const std::string text = number.toStdString();
const std::string definition = "BA_DEF_ \"A\" " + kind + " -10 10;\n";
const std::string statements[] = {
"BA_DEF_ \"A\" " + kind + ' ' + text + " 10;\n",
"BA_DEF_ \"A\" " + kind + " -10 " + text + ";\n",
definition + "BA_DEF_DEF_ \"A\" " + text + ";\n",
definition + "BA_ \"A\" " + text + ";\n"};
Fixture fixture;
for (const std::string &statement: statements) {
fixture.Write(statement);
const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
QVERIFY2(result.HasErrors(), statement.c_str());
QVERIFY(result.database.attributeDefinitions.empty());
QCOMPARE(result.diagnostics.back().code, DbcDiagnosticCode::InvalidAttribute);
QCOMPARE(result.diagnostics.back().lineNumber,
static_cast<std::size_t>(std::count(statement.begin(), statement.end(), '\n')));
QVERIFY_THROWS_EXCEPTION(std::runtime_error, DbcParser().ParseFile(fixture.path.string()));
}
}
void DbcParserTest::attributeWarnings() {
Fixture fixture;
fixture.Write("BA_DEF_ BO_ \"VFrameFormat\" ENUM \"StandardCAN\",\"ExtendedCAN\",\"J1939PG\",\"StandardCAN_FD\";\n"