Fixed SIGSEGV
This commit is contained in:
1 parent
f03882d3f4
commit
5b0019d50d
50 files changed
+1565
-821
No files matched your search
@@ -0,0 +1,194 @@
|
||||
#include "dbc_decode_builder.h"
|
||||
#include "dbc_decoder.h"
|
||||
#include "dbc_parser.h"
|
||||
#include <QTemporaryFile>
|
||||
#include <QtTest>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace {
|
||||
std::string WriteFixture(QTemporaryFile &file, const std::string &text) {
|
||||
if (!file.open() || file.write(text.data(), static_cast<qint64>(text.size())) != static_cast<qint64>(text.size()) || !file.flush())
|
||||
throw std::runtime_error("Cannot write statement fixture");
|
||||
return file.fileName().toStdString();
|
||||
}
|
||||
|
||||
std::string Quote(const std::string &text) {
|
||||
std::ostringstream stream;
|
||||
stream << std::quoted(text);
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string RepeatedRanges() {
|
||||
std::string ranges = "1-1";
|
||||
for (unsigned index = 1U; index < 10000U; ++index)
|
||||
ranges += ",1-1";
|
||||
return ranges;
|
||||
}
|
||||
|
||||
const std::string definitions =
|
||||
"BO_ 1 Frame: 2 ECU\n"
|
||||
"SG_ Mode M : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
|
||||
"SG_ Value m1 : 8|8@1+ (1,0) [0|255] \"\" ECU\n";
|
||||
}// namespace
|
||||
|
||||
class StatementParserTest : public QObject {
|
||||
Q_OBJECT
|
||||
private Q_SLOTS:
|
||||
void longValueDescriptions_data();
|
||||
void longValueDescriptions();
|
||||
void longMultiplexRanges_data();
|
||||
void longMultiplexRanges();
|
||||
void invalidLongStatements_data();
|
||||
void invalidLongStatements();
|
||||
};
|
||||
|
||||
void StatementParserTest::longValueDescriptions_data() {
|
||||
QTest::addColumn<std::string>("description");
|
||||
QTest::addColumn<unsigned>("count");
|
||||
QTest::addColumn<bool>("beforeDefinitions");
|
||||
QTest::newRow("50000-character-description") << std::string(50000U, 'x') << 1U << false;
|
||||
std::string escaped;
|
||||
for (unsigned index = 0U; index < 12500U; ++index)
|
||||
escaped += "\"\\; ";
|
||||
QTest::newRow("50000-escaped-characters") << escaped << 1U << true;
|
||||
QTest::newRow("10000-pairs") << std::string("Description") << 10000U << true;
|
||||
QTest::newRow("50000-spaces") << std::string(50000U, ' ') << 1U << false;
|
||||
}
|
||||
|
||||
void StatementParserTest::longValueDescriptions() {
|
||||
QFETCH(std::string, description);
|
||||
QFETCH(unsigned, count);
|
||||
QFETCH(bool, beforeDefinitions);
|
||||
std::string statement = "VAL_ 1 Value";
|
||||
for (unsigned index = 0U; index < count; ++index)
|
||||
statement += " " + std::to_string(index) + " " + Quote(description);
|
||||
statement += ";\n";
|
||||
const std::string frame = "BO_ 1 Frame: 4 ECU\nSG_ Value : 0|32@1+ (1,0) [0|1e10] \"\" ECU\n";
|
||||
QTemporaryFile file;
|
||||
const std::string path = WriteFixture(file, beforeDefinitions ? statement + frame : frame + statement);
|
||||
const DbcParser parser;
|
||||
const DbcParseResult result = parser.ParseFileWithDiagnostics(path);
|
||||
QVERIFY(!result.HasErrors());
|
||||
QVERIFY(result.diagnostics.empty());
|
||||
const std::vector<DbcDatabase> databases = {result.database, parser.ParseFile(path)};
|
||||
for (const DbcDatabase &database: databases) {
|
||||
const ValueDescriptions &values = database.frames.at(0).signals.at(0).valueDescriptions;
|
||||
QCOMPARE(values.size(), static_cast<std::size_t>(count));
|
||||
for (unsigned index = 0U; index < count; ++index)
|
||||
QCOMPARE(values.at(std::uint64_t(index)), description);
|
||||
const DecodeDatabase runtime = DbcDecodeBuilder().Build(database);
|
||||
RawCanFrame raw;
|
||||
raw.canId = 1U;
|
||||
const unsigned last = count - 1U;
|
||||
raw.data = {static_cast<std::uint8_t>(last), static_cast<std::uint8_t>(last >> 8U), 0U, 0U};
|
||||
const DecodedFrameValue decoded = DbcDecoder().Decode(runtime, raw);
|
||||
QCOMPARE(decoded.status, FrameDecodeStatus::Valid);
|
||||
const std::string *label = decoded.signals.at(0).GetValueDescription();
|
||||
QVERIFY(label);
|
||||
QCOMPARE(*label, description);
|
||||
}
|
||||
}
|
||||
|
||||
void StatementParserTest::longMultiplexRanges_data() {
|
||||
QTest::addColumn<std::string>("ranges");
|
||||
QTest::addColumn<unsigned>("count");
|
||||
QTest::addColumn<bool>("beforeDefinitions");
|
||||
QTest::newRow("10000-ranges") << RepeatedRanges() << 10000U << false;
|
||||
const std::string paddedOne = std::string(50000U, '0') + "1";
|
||||
QTest::newRow("long-bounds") << paddedOne + "-" + paddedOne << 1U << true;
|
||||
QTest::newRow("long-whitespace") << std::string(50000U, ' ') + "1\t-\t1" + std::string(50000U, ' ') << 1U << false;
|
||||
}
|
||||
|
||||
void StatementParserTest::longMultiplexRanges() {
|
||||
QFETCH(std::string, ranges);
|
||||
QFETCH(unsigned, count);
|
||||
QFETCH(bool, beforeDefinitions);
|
||||
const std::string statement = "SG_MUL_VAL_ 1 Value Mode " + ranges + ";\n";
|
||||
QTemporaryFile file;
|
||||
const std::string path = WriteFixture(file, beforeDefinitions ? statement + definitions : definitions + statement);
|
||||
const DbcParser parser;
|
||||
const DbcParseResult result = parser.ParseFileWithDiagnostics(path);
|
||||
QVERIFY(!result.HasErrors());
|
||||
QVERIFY(result.diagnostics.empty());
|
||||
const std::vector<DbcDatabase> databases = {result.database, parser.ParseFile(path)};
|
||||
for (const DbcDatabase &database: databases) {
|
||||
const Multiplexing &mux = database.frames.at(0).signals.at(1).multiplexing;
|
||||
QCOMPARE(mux.selector, std::string("Mode"));
|
||||
QCOMPARE(mux.ranges.size(), static_cast<std::size_t>(count));
|
||||
for (const MultiplexRange &range: mux.ranges) {
|
||||
QCOMPARE(range.minimum, std::uint64_t(1));
|
||||
QCOMPARE(range.maximum, std::uint64_t(1));
|
||||
}
|
||||
const DecodeDatabase runtime = DbcDecodeBuilder().Build(database);
|
||||
RawCanFrame raw;
|
||||
raw.canId = 1U;
|
||||
raw.data = {1U, 42U};
|
||||
const DecodedFrameValue active = DbcDecoder().Decode(runtime, raw);
|
||||
QCOMPARE(active.status, FrameDecodeStatus::Valid);
|
||||
QVERIFY(active.signals.at(1).valid);
|
||||
QCOMPARE(std::get<std::uint64_t>(active.signals[1].rawValue), std::uint64_t(42));
|
||||
raw.data[0] = 2U;
|
||||
const DecodedFrameValue inactive = DbcDecoder().Decode(runtime, raw);
|
||||
QCOMPARE(inactive.signals.at(1).status, SignalDecodeStatus::Inactive);
|
||||
}
|
||||
}
|
||||
|
||||
void StatementParserTest::invalidLongStatements_data() {
|
||||
QTest::addColumn<std::string>("statement");
|
||||
QTest::addColumn<DbcDiagnosticCode>("code");
|
||||
const std::string text(50000U, 'x');
|
||||
const std::string value = "VAL_ 1 Value 0 \"" + text;
|
||||
QTest::newRow("val-missing-quote") << value + ";" << DbcDiagnosticCode::InvalidValueDescription;
|
||||
QTest::newRow("val-dangling-escape") << value + "\\" << DbcDiagnosticCode::InvalidValueDescription;
|
||||
QTest::newRow("val-invalid-escape") << value + "\\q\";" << DbcDiagnosticCode::InvalidValueDescription;
|
||||
QTest::newRow("val-missing-semicolon") << value + "\"" << DbcDiagnosticCode::InvalidValueDescription;
|
||||
QTest::newRow("val-trailing-text") << value + "\"; junk" << DbcDiagnosticCode::InvalidValueDescription;
|
||||
QTest::newRow("val-missing-pair-separator") << value + "\"1 \"On\";" << DbcDiagnosticCode::InvalidValueDescription;
|
||||
QTest::newRow("val-missing-number-separator") << "VAL_ 1 Value 0\"" + text + "\";" << DbcDiagnosticCode::InvalidValueDescription;
|
||||
QTest::newRow("val-duplicate") << value + "\" 00 \"Duplicate\";" << DbcDiagnosticCode::InvalidValueDescription;
|
||||
QTest::newRow("val-overflow") << "VAL_ 1 Value " + std::string(50000U, '9') + " \"Bad\";" << DbcDiagnosticCode::InvalidValueDescription;
|
||||
QTest::newRow("val-long-missing-reference") << "VAL_ 1 " + text + " 0 \"Bad\";" << DbcDiagnosticCode::InvalidValueDescription;
|
||||
const std::string mux = "SG_MUL_VAL_ 1 Value Mode " + RepeatedRanges();
|
||||
QTest::newRow("mux-missing-semicolon") << mux << DbcDiagnosticCode::InvalidMultiplexing;
|
||||
QTest::newRow("mux-trailing-comma") << mux + ",;" << DbcDiagnosticCode::InvalidMultiplexing;
|
||||
QTest::newRow("mux-empty-range") << mux + ",,1-1;" << DbcDiagnosticCode::InvalidMultiplexing;
|
||||
QTest::newRow("mux-reversed-range") << mux + ",2-1;" << DbcDiagnosticCode::InvalidMultiplexing;
|
||||
QTest::newRow("mux-signed-bound") << mux + ",+1-1;" << DbcDiagnosticCode::InvalidMultiplexing;
|
||||
QTest::newRow("mux-suffix") << mux + "x;" << DbcDiagnosticCode::InvalidMultiplexing;
|
||||
QTest::newRow("mux-overflow") << mux + ",0-18446744073709551616;" << DbcDiagnosticCode::InvalidMultiplexing;
|
||||
QTest::newRow("mux-long-overflow") << "SG_MUL_VAL_ 1 Value Mode 0-" + std::string(50000U, '9') + ";" << DbcDiagnosticCode::InvalidMultiplexing;
|
||||
QTest::newRow("mux-trailing-text") << mux + "; junk" << DbcDiagnosticCode::InvalidMultiplexing;
|
||||
QTest::newRow("mux-long-missing-reference") << "SG_MUL_VAL_ 1 " + text + " Mode 1-1;" << DbcDiagnosticCode::InvalidMultiplexing;
|
||||
}
|
||||
|
||||
void StatementParserTest::invalidLongStatements() {
|
||||
QFETCH(std::string, statement);
|
||||
QFETCH(DbcDiagnosticCode, code);
|
||||
QTemporaryFile file;
|
||||
const std::string path = WriteFixture(file, "\n" + statement + "\n" + definitions);
|
||||
const DbcParser parser;
|
||||
const DbcParseResult result = parser.ParseFileWithDiagnostics(path);
|
||||
QVERIFY(result.HasErrors());
|
||||
QVERIFY(result.database.frames.empty());
|
||||
QCOMPARE(result.diagnostics.size(), std::size_t(1));
|
||||
const DbcDiagnostic &error = result.diagnostics[0];
|
||||
QCOMPARE(error.severity, DbcDiagnosticSeverity::Error);
|
||||
QCOMPARE(error.code, code);
|
||||
QCOMPARE(error.filePath, path);
|
||||
QCOMPARE(error.lineNumber, std::size_t(2));
|
||||
try {
|
||||
parser.ParseFile(path);
|
||||
QFAIL("Malformed statements must throw through ParseFile");
|
||||
} catch (const std::runtime_error &exception) {
|
||||
QCOMPARE(std::string(exception.what()), path + ":2: " + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
int RunStatementParserTests(int argc, char **argv) {
|
||||
StatementParserTest tests;
|
||||
return QTest::qExec(&tests, argc, argv);
|
||||
}
|
||||
|
||||
#include "dbc_statement_test.moc"
|
||||
Reference in new issue
Block a user