This commit is contained in:
deeaitch committed 2026-10-14 10:41:17 -04:00
1 parent d87c100398
commit 4ae4e527b8
5 files changed
+138 -10

No files matched your search

+16
View File
@@ -86,6 +86,22 @@ extended frames may share a numeric ID, and separate frames may reuse signal nam
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.
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
numbers, comma/grouped numbers, overflow/underflow, and reversed ranges. Locale
changes are restored after each test. The named C locale case skips if none of
the supported locale names are installed; the custom C++ locale case always runs.
On Linux with locale sources and `localedef`, run both cases without installing a
system locale:
```sh
mkdir -p /tmp/dbc-test-locales
localedef --no-archive -i de_DE -f UTF-8 /tmp/dbc-test-locales/de_DE.UTF-8
LOCPATH=/tmp/dbc-test-locales make check
```
Run `make check` from the build directory as usual.
Value-description tests cover full `VAL_` syntax, whitespace, escaped quotes,
empty text, exact integer boundaries, duplicate keys within and across statements,
deferred and normalized frame references, missing targets, error locations,
+95
View File
@@ -3,7 +3,9 @@
#include "dbc_parser.h"
#include "dbc_statement_handler.h"
#include "dbc_tree_builder.h"
#include <clocale>
#include <limits>
#include <locale>
#include <QtTest>
#include <chrono>
@@ -28,6 +30,27 @@ struct Fixture {
}
};
class CommaDecimalPunctuation : public std::numpunct<char> {
protected:
char do_decimal_point() const override { return ','; }
char do_thousands_sep() const override { return '.'; }
std::string do_grouping() const override { return "\3"; }
};
class ApplicationLocaleGuard {
public:
ApplicationLocaleGuard()
: previousCppLocale(std::locale()), previousCLocale(std::setlocale(LC_ALL, nullptr)) {}
~ApplicationLocaleGuard() {
std::locale::global(previousCppLocale);
std::setlocale(LC_ALL, previousCLocale.c_str());
}
private:
std::locale previousCppLocale;
std::string previousCLocale;
};
class CountingHandler : public DbcStatementHandler {
public:
inline static int instances = 0;
@@ -50,6 +73,7 @@ std::string SignalLine(const std::string &start, const std::string &length,
class DbcParserTest : public QObject {
Q_OBJECT
private:
void CheckPhysicalNumbers();
void RejectSignal(const Fixture &fixture, const std::string &line, unsigned payload = 8U) {
fixture.Write("BO_ 1 Frame: " + std::to_string(payload) + " ECU\n\n" + line + "\n");
try {
@@ -81,6 +105,8 @@ private Q_SLOTS:
void integration();
void invalidSignals();
void validSignals();
void physicalNumbersCppLocale();
void physicalNumbersCLocale();
void dispatch();
void independentSessions();
void valueDescriptions();
@@ -824,6 +850,75 @@ void DbcParserTest::validSignals() {
} catch (const std::exception &error) { CHECK(false, error.what()); }
}
void DbcParserTest::CheckPhysicalNumbers() {
Fixture fixture;
struct PhysicalCase {
const char *factor;
const char *offset;
const char *minimum;
const char *maximum;
double expectedFactor;
double expectedOffset;
double expectedMinimum;
double expectedMaximum;
};
const PhysicalCase valid[] = {
{"+1.25", "-0.5", "-2.75", "255.5", 1.25, -0.5, -2.75, 255.5},
{"+.5e+1", "-2.5E-1", "-1.", "+2e2", 5.0, -0.25, -1.0, 200.0},
{"0e-999", "+0.", "-.0", ".0e+999", 0.0, 0.0, 0.0, 0.0},
{"1.7976931348623157e308", "2.2250738585072014e-308", "-1e308", "+1e308",
std::numeric_limits<double>::max(), std::numeric_limits<double>::min(), -1e308, 1e308}};
for (const PhysicalCase &test: valid) {
fixture.Write("BO_ 1 Frame: 1 ECU\n" +
SignalLine("0", "8", "1+", test.factor, test.offset, test.minimum, test.maximum) + "\n");
const DbcParseResult result = DbcParser().ParseFileWithDiagnostics(fixture.path.string());
QVERIFY(!result.HasErrors());
QVERIFY(result.diagnostics.empty());
QCOMPARE(result.database.frames.size(), std::size_t(1));
const SignalInfo &signal = result.database.frames[0].signals[0];
QCOMPARE(signal.factor, test.expectedFactor);
QCOMPARE(signal.offset, test.expectedOffset);
QCOMPARE(signal.minimum, test.expectedMinimum);
QCOMPARE(signal.maximum, test.expectedMaximum);
}
const char *invalid[] = {"1,5", "1.234,5", "1,234.5", "1junk", "nan", "inf", "-inf",
"1e999", "1e-999", "1e-320", "-1e-320", "0x1p2", "1e", "1.2.3"};
for (const char *value: invalid) {
RejectSignal(fixture, SignalLine("0", "8", "1+", value, "0", "0", "255"));
RejectSignal(fixture, SignalLine("0", "8", "1+", "1", value, "0", "255"));
RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", value, "255"));
RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "0", value));
}
RejectSignal(fixture, SignalLine("0", "8", "1+", "1.25", "0", "2.5", "1.5"));
}
void DbcParserTest::physicalNumbersCppLocale() {
const ApplicationLocaleGuard guard;
std::locale::global(std::locale(std::locale::classic(), new CommaDecimalPunctuation));
QCOMPARE(std::use_facet<std::numpunct<char>>(std::locale()).decimal_point(), ',');
CheckPhysicalNumbers();
QCOMPARE(std::use_facet<std::numpunct<char>>(std::locale()).decimal_point(), ',');
}
void DbcParserTest::physicalNumbersCLocale() {
const ApplicationLocaleGuard guard;
bool found = false;
const char *names[] = {"de_DE.UTF-8", "de_DE.utf8", "fr_FR.UTF-8", "fr_FR.utf8",
"German_Germany.1252", "French_France.1252"};
for (const char *name: names) {
if (std::setlocale(LC_NUMERIC, name) && std::string(std::localeconv()->decimal_point) == ",") {
found = true;
break;
}
}
if (!found)
QSKIP("No named comma-decimal C locale is installed; generate de_DE.UTF-8 and set LOCPATH.");
QCOMPARE(std::string(std::localeconv()->decimal_point), std::string(","));
CheckPhysicalNumbers();
QCOMPARE(std::string(std::localeconv()->decimal_point), std::string(","));
}
void DbcParserTest::dispatch() {
CountingHandler::instances = 0;
CountingHandler::calls = 0;