From f17ddb6aad0335784ce3c1f9b93916c61433ae23 Mon Sep 17 00:00:00 2001 From: deeaitch Date: Mon, 5 Oct 2026 21:41:19 -0400 Subject: [PATCH] Closes #11 --- README.md | 27 +- core/core.pri | 8 + core/core.pro | 6 + core/core_files.pri | 20 + dbc_database.h => core/dbc_database.h | 0 .../dbc_decode_builder.cpp | 0 .../dbc_decode_builder.h | 0 dbc_decoder.cpp => core/dbc_decoder.cpp | 0 dbc_decoder.h => core/dbc_decoder.h | 0 dbc_parser.cpp => core/dbc_parser.cpp | 0 dbc_parser.h => core/dbc_parser.h | 0 .../dbc_statement_handler.cpp | 0 .../dbc_statement_handler.h | 0 .../dbc_tree_builder.cpp | 0 dbc_tree_builder.h => core/dbc_tree_builder.h | 0 decode_database.h => core/decode_database.h | 0 frame_info.h => core/frame_info.h | 0 signal_info.h => core/signal_info.h | 0 tree_node.cpp => core/tree_node.cpp | 0 tree_node.h => core/tree_node.h | 0 typefactory.h => core/typefactory.h | 0 dbc.pro | 31 +- docs/dbcframework.tag | 48 +- docs/doxygen_warnings.log | 48 +- docs/html/dbc__database_8h.html | 2 +- docs/html/dbc__database_8h_source.html | 2 +- docs/html/dbc__decode__builder_8cpp.html | 2 +- .../dbc__decode__builder_8cpp_source.html | 2 +- docs/html/dbc__decode__builder_8h.html | 2 +- docs/html/dbc__decode__builder_8h_source.html | 2 +- docs/html/dbc__decoder_8cpp.html | 2 +- docs/html/dbc__decoder_8cpp_source.html | 2 +- docs/html/dbc__decoder_8h.html | 2 +- docs/html/dbc__decoder_8h_source.html | 2 +- docs/html/dbc__decoder__test_8cpp_source.html | 257 +++++---- docs/html/dbc__parser_8cpp.html | 2 +- docs/html/dbc__parser_8cpp_source.html | 2 +- docs/html/dbc__parser_8h.html | 2 +- docs/html/dbc__parser_8h_source.html | 2 +- docs/html/dbc__parser__test_8cpp_source.html | 541 +++++++++--------- .../dbc__statement__handler_8cpp_source.html | 2 +- .../dbc__statement__handler_8h_source.html | 2 +- docs/html/dbc__tree__builder_8cpp.html | 2 +- docs/html/dbc__tree__builder_8cpp_source.html | 2 +- docs/html/dbc__tree__builder_8h.html | 2 +- docs/html/dbc__tree__builder_8h_source.html | 2 +- docs/html/decode__database_8h.html | 2 +- docs/html/decode__database_8h_source.html | 2 +- .../dir_4270bfced15e0e73154b13468c7c9ad9.html | 158 +++++ .../dir_4270bfced15e0e73154b13468c7c9ad9.js | 20 + .../dir_59425e443f801f1f2fd8bbe4959a3ccf.html | 2 + .../dir_59425e443f801f1f2fd8bbe4959a3ccf.js | 3 +- .../dir_d28a4824dc47e487b107a5db32ef43c4.html | 113 ++++ .../dir_d28a4824dc47e487b107a5db32ef43c4.js | 4 + docs/html/examples_2main_8cpp.html | 164 ++++++ docs/html/examples_2main_8cpp_source.html | 287 ++++++++++ docs/html/files.html | 45 +- docs/html/files_dup.js | 22 +- docs/html/frame__info_8h.html | 2 +- docs/html/frame__info_8h_source.html | 2 +- docs/html/index.qhp | 33 +- docs/html/md_README.html | 14 +- docs/html/md_tests_2README.html | 40 +- docs/html/navtreedata.js | 5 +- docs/html/navtreeindex0.js | 96 ++-- docs/html/pages.html | 2 +- docs/html/search/all_11.js | 2 +- docs/html/search/all_12.js | 20 +- docs/html/search/all_13.js | 37 +- docs/html/search/all_14.js | 47 +- docs/html/search/all_15.js | 37 +- docs/html/search/all_16.js | 13 +- docs/html/search/all_17.js | 7 +- docs/html/search/all_18.js | 5 + docs/html/search/all_6.js | 7 +- docs/html/search/all_7.js | 6 +- docs/html/search/all_8.js | 5 +- docs/html/search/all_e.js | 11 +- docs/html/search/files_1.js | 2 +- docs/html/search/files_2.js | 2 +- docs/html/search/pages_1.js | 3 +- docs/html/search/pages_4.js | 3 +- docs/html/search/pages_5.js | 3 +- docs/html/search/pages_6.js | 4 + docs/html/search/searchdata.js | 6 +- docs/html/signal__info_8h.html | 2 +- docs/html/signal__info_8h_source.html | 2 +- docs/html/tests_2main_8cpp_source.html | 123 ++++ docs/html/tree__node_8cpp.html | 2 +- docs/html/tree__node_8cpp_source.html | 2 +- docs/html/tree__node_8h.html | 2 +- docs/html/tree__node_8h_source.html | 2 +- docs/html/typefactory_8h_source.html | 2 +- examples/demo.pro | 7 + main.cpp => examples/main.cpp | 0 tests/README.md | 52 +- tests/dbc_decoder_test.cpp | 115 ++-- tests/dbc_decoder_test.pro | 7 - tests/dbc_parser_test.cpp | 205 ++++--- tests/dbc_parser_test.pro | 7 - tests/decoder_tests.pri | 1 + tests/main.cpp | 12 + tests/parser_tests.pri | 1 + tests/tests.pro | 11 + 104 files changed, 1928 insertions(+), 889 deletions(-) create mode 100644 core/core.pri create mode 100644 core/core.pro create mode 100644 core/core_files.pri rename dbc_database.h => core/dbc_database.h (100%) rename dbc_decode_builder.cpp => core/dbc_decode_builder.cpp (100%) rename dbc_decode_builder.h => core/dbc_decode_builder.h (100%) rename dbc_decoder.cpp => core/dbc_decoder.cpp (100%) rename dbc_decoder.h => core/dbc_decoder.h (100%) rename dbc_parser.cpp => core/dbc_parser.cpp (100%) rename dbc_parser.h => core/dbc_parser.h (100%) rename dbc_statement_handler.cpp => core/dbc_statement_handler.cpp (100%) rename dbc_statement_handler.h => core/dbc_statement_handler.h (100%) rename dbc_tree_builder.cpp => core/dbc_tree_builder.cpp (100%) rename dbc_tree_builder.h => core/dbc_tree_builder.h (100%) rename decode_database.h => core/decode_database.h (100%) rename frame_info.h => core/frame_info.h (100%) rename signal_info.h => core/signal_info.h (100%) rename tree_node.cpp => core/tree_node.cpp (100%) rename tree_node.h => core/tree_node.h (100%) rename typefactory.h => core/typefactory.h (100%) create mode 100644 docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.html create mode 100644 docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.js create mode 100644 docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html create mode 100644 docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.js create mode 100644 docs/html/examples_2main_8cpp.html create mode 100644 docs/html/examples_2main_8cpp_source.html create mode 100644 docs/html/search/all_18.js create mode 100644 docs/html/search/pages_6.js create mode 100644 docs/html/tests_2main_8cpp_source.html create mode 100644 examples/demo.pro rename main.cpp => examples/main.cpp (100%) delete mode 100644 tests/dbc_decoder_test.pro delete mode 100644 tests/dbc_parser_test.pro create mode 100644 tests/decoder_tests.pri create mode 100644 tests/main.cpp create mode 100644 tests/parser_tests.pri create mode 100644 tests/tests.pro diff --git a/README.md b/README.md index a5db857..3c59fb1 100644 --- a/README.md +++ b/README.md @@ -924,7 +924,30 @@ It can be integrated with: - qmake - Makefile -Just add the source files to the project. +Open `dbc.pro` in Qt Creator to see two subprojects: `core` and `tests`. +`core/core.pro` builds the C++17 static library `dbc_core` without a Qt dependency. +`tests/tests.pro` builds the QtTest executable `dbc_tests` and links that library. +The root project declares `tests.depends = core` for parallel builds. + +Build out of source (Qt 6; use `qmake` for Qt 5): + +```sh +mkdir build +cd build +qmake6 ../dbc.pro +make -j +make check +``` + +`core/core_files.pri` lists the library sources and headers. +Consumers include `core/core.pri` for include paths and library linkage; the test +source lists live in `tests/parser_tests.pri` and `tests/decoder_tests.pri`. +When building a consumer separately, pass +`DBC_CORE_BUILD_DIR=/absolute/path/to/build/core` to qmake. + +The former demonstration program is preserved in `examples/main.cpp` with +`examples/demo.pro`. Build it separately after building core, using that same +`DBC_CORE_BUILD_DIR` option; run `dbc_demo `. --- @@ -962,7 +985,7 @@ This gives FrameTap a much better foundation for real use, because both browsing ## Regression tests -See [tests/README.md](tests/README.md) for compiler and qmake commands. +See [tests/README.md](tests/README.md) for QtTest build and execution commands. Tests cover frame validation and error locations, Intel and Motorola extraction, signed and unsigned 64-bit boundaries, physical conversion, numeric output, and invalid signal payloads. diff --git a/core/core.pri b/core/core.pri new file mode 100644 index 0000000..aff8568 --- /dev/null +++ b/core/core.pri @@ -0,0 +1,8 @@ +INCLUDEPATH += $$PWD +DEPENDPATH += $$PWD +# Consumers can override this when building separately from the root project. +isEmpty(DBC_CORE_BUILD_DIR): DBC_CORE_BUILD_DIR = $$clean_path($$OUT_PWD/../core) +LIBS += -L$$DBC_CORE_BUILD_DIR -ldbc_core +win32-msvc*: DBC_CORE_LIBRARY = $$DBC_CORE_BUILD_DIR/dbc_core.lib +else: DBC_CORE_LIBRARY = $$DBC_CORE_BUILD_DIR/libdbc_core.a +PRE_TARGETDEPS += $$DBC_CORE_LIBRARY diff --git a/core/core.pro b/core/core.pro new file mode 100644 index 0000000..2b15fa2 --- /dev/null +++ b/core/core.pro @@ -0,0 +1,6 @@ +TEMPLATE = lib +TARGET = dbc_core +CONFIG += staticlib c++17 +CONFIG -= qt +include(core_files.pri) +CONFIG -= debug_and_release debug_and_release_target diff --git a/core/core_files.pri b/core/core_files.pri new file mode 100644 index 0000000..8bda16c --- /dev/null +++ b/core/core_files.pri @@ -0,0 +1,20 @@ +SOURCES += \ + $$PWD/dbc_decode_builder.cpp \ + $$PWD/dbc_decoder.cpp \ + $$PWD/dbc_parser.cpp \ + $$PWD/dbc_statement_handler.cpp \ + $$PWD/dbc_tree_builder.cpp \ + $$PWD/tree_node.cpp + +HEADERS += \ + $$PWD/dbc_database.h \ + $$PWD/dbc_decode_builder.h \ + $$PWD/dbc_decoder.h \ + $$PWD/dbc_parser.h \ + $$PWD/dbc_statement_handler.h \ + $$PWD/dbc_tree_builder.h \ + $$PWD/decode_database.h \ + $$PWD/frame_info.h \ + $$PWD/signal_info.h \ + $$PWD/tree_node.h \ + $$PWD/typefactory.h diff --git a/dbc_database.h b/core/dbc_database.h similarity index 100% rename from dbc_database.h rename to core/dbc_database.h diff --git a/dbc_decode_builder.cpp b/core/dbc_decode_builder.cpp similarity index 100% rename from dbc_decode_builder.cpp rename to core/dbc_decode_builder.cpp diff --git a/dbc_decode_builder.h b/core/dbc_decode_builder.h similarity index 100% rename from dbc_decode_builder.h rename to core/dbc_decode_builder.h diff --git a/dbc_decoder.cpp b/core/dbc_decoder.cpp similarity index 100% rename from dbc_decoder.cpp rename to core/dbc_decoder.cpp diff --git a/dbc_decoder.h b/core/dbc_decoder.h similarity index 100% rename from dbc_decoder.h rename to core/dbc_decoder.h diff --git a/dbc_parser.cpp b/core/dbc_parser.cpp similarity index 100% rename from dbc_parser.cpp rename to core/dbc_parser.cpp diff --git a/dbc_parser.h b/core/dbc_parser.h similarity index 100% rename from dbc_parser.h rename to core/dbc_parser.h diff --git a/dbc_statement_handler.cpp b/core/dbc_statement_handler.cpp similarity index 100% rename from dbc_statement_handler.cpp rename to core/dbc_statement_handler.cpp diff --git a/dbc_statement_handler.h b/core/dbc_statement_handler.h similarity index 100% rename from dbc_statement_handler.h rename to core/dbc_statement_handler.h diff --git a/dbc_tree_builder.cpp b/core/dbc_tree_builder.cpp similarity index 100% rename from dbc_tree_builder.cpp rename to core/dbc_tree_builder.cpp diff --git a/dbc_tree_builder.h b/core/dbc_tree_builder.h similarity index 100% rename from dbc_tree_builder.h rename to core/dbc_tree_builder.h diff --git a/decode_database.h b/core/decode_database.h similarity index 100% rename from decode_database.h rename to core/decode_database.h diff --git a/frame_info.h b/core/frame_info.h similarity index 100% rename from frame_info.h rename to core/frame_info.h diff --git a/signal_info.h b/core/signal_info.h similarity index 100% rename from signal_info.h rename to core/signal_info.h diff --git a/tree_node.cpp b/core/tree_node.cpp similarity index 100% rename from tree_node.cpp rename to core/tree_node.cpp diff --git a/tree_node.h b/core/tree_node.h similarity index 100% rename from tree_node.h rename to core/tree_node.h diff --git a/typefactory.h b/core/typefactory.h similarity index 100% rename from typefactory.h rename to core/typefactory.h diff --git a/dbc.pro b/dbc.pro index 5699d2b..fde5fbc 100644 --- a/dbc.pro +++ b/dbc.pro @@ -1,26 +1,5 @@ -TEMPLATE = app -CONFIG += console c++17 -CONFIG -= app_bundle -CONFIG -= qt - -SOURCES += \ - dbc_decode_builder.cpp \ - dbc_decoder.cpp \ - dbc_parser.cpp \ - dbc_statement_handler.cpp \ - dbc_tree_builder.cpp \ - main.cpp \ - tree_node.cpp - -HEADERS += \ - dbc_database.h \ - dbc_decode_builder.h \ - dbc_decoder.h \ - dbc_parser.h \ - dbc_statement_handler.h \ - typefactory.h \ - dbc_tree_builder.h \ - decode_database.h \ - frame_info.h \ - signal_info.h \ - tree_node.h +TEMPLATE = subdirs +SUBDIRS += core tests +core.subdir = core +tests.subdir = tests +tests.depends = core diff --git a/docs/dbcframework.tag b/docs/dbcframework.tag index 23cb98d..6574055 100644 --- a/docs/dbcframework.tag +++ b/docs/dbcframework.tag @@ -2,20 +2,20 @@ dbc_database.h - + core/ dbc__database_8h.html frame_info.h DbcDatabase dbc_decode_builder.cpp - + core/ dbc__decode__builder_8cpp.html dbc_decode_builder.h dbc_decode_builder.h - + core/ dbc__decode__builder_8h.html dbc_database.h decode_database.h @@ -23,13 +23,13 @@ dbc_decoder.cpp - + core/ dbc__decoder_8cpp.html dbc_decoder.h dbc_decoder.h - + core/ dbc__decoder_8h.html decode_database.h RawCanFrame @@ -39,26 +39,26 @@ dbc_parser.cpp - + core/ dbc__parser_8cpp.html dbc_parser.h dbc_parser.h - + core/ dbc__parser_8h.html dbc_database.h DbcParser dbc_tree_builder.cpp - + core/ dbc__tree__builder_8cpp.html dbc_tree_builder.h dbc_tree_builder.h - + core/ dbc__tree__builder_8h.html dbc_database.h tree_node.h @@ -66,7 +66,7 @@ decode_database.h - + core/ decode__database_8h.html DecodeSignal DecodeFrame @@ -94,35 +94,26 @@ frame_info.h - + core/ frame__info_8h.html signal_info.h FrameInfo - - main.cpp - - main_8cpp.html - dbc_decode_builder.h - dbc_decoder.h - dbc_parser.h - dbc_tree_builder.h - signal_info.h - + core/ signal__info_8h.html SignalInfo tree_node.cpp - + core/ tree__node_8cpp.html tree_node.h tree_node.h - + core/ tree__node_8h.html frame_info.h signal_info.h @@ -138,6 +129,15 @@ Signal + + examples/main.cpp + examples/ + examples_2main_8cpp.html + dbc_decode_builder.h + dbc_decoder.h + dbc_parser.h + dbc_tree_builder.h + DbcCommentHandler classDbcCommentHandler.html @@ -761,7 +761,7 @@ md_tests_2README - Decoder regression tests + QtTest regression tests md_tests_2README.html diff --git a/docs/doxygen_warnings.log b/docs/doxygen_warnings.log index bdf9ccb..b9602aa 100644 --- a/docs/doxygen_warnings.log +++ b/docs/doxygen_warnings.log @@ -1,25 +1,25 @@ -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:38: warning: Compound DbcCommentHandler is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:22: warning: Compound DbcFrameHandler is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:30: warning: Compound DbcSignalHandler is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:16: warning: Compound DbcStatementHandler is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/main.cpp:101: warning: Member main(int argc, char *argv[]) (function) of file main.cpp is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:40: warning: Member Handle(const std::string &line, DbcParseContext &context) const override (function) of class DbcCommentHandler is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:24: warning: Member Handle(const std::string &line, DbcParseContext &context) const override (function) of class DbcFrameHandler is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:12: warning: Member database (variable) of struct DbcParseContext is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:13: warning: Member currentFrame (variable) of struct DbcParseContext is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:32: warning: Member Handle(const std::string &line, DbcParseContext &context) const override (function) of class DbcSignalHandler is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:52: warning: Member RegisterType(const std::string &keyword) (function) of class DbcStatementDispatcher is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/dbc_statement_handler.h:19: warning: Member Handle(const std::string &line, DbcParseContext &context) const =0 (function) of class DbcStatementHandler is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/decode_database.h:112: warning: Member frames (variable) of struct DecodeDatabase is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/decode_database.h:113: warning: Member frameIndexByKey (variable) of struct DecodeDatabase is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/decode_database.h:88: warning: Member FrameKey(std::uint32_t id, bool extended) (function) of struct FrameKey is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/decode_database.h:92: warning: Member operator==(const FrameKey &other) const (function) of struct FrameKey is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/decode_database.h:81: warning: Member canId (variable) of struct FrameKey is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/decode_database.h:82: warning: Member isExtended (variable) of struct FrameKey is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/decode_database.h:101: warning: Member operator()(const FrameKey &key) const (function) of struct FrameKeyHasher is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/tree_node.h:59: warning: Member TreeNode(TreeNode &&)=default (function) of class TreeNode is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/tree_node.h:60: warning: Member operator=(TreeNode &&)=default (function) of class TreeNode is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/typefactory.h:61: warning: Member BasePtr (typedef) of class TypeFactory is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/typefactory.h:62: warning: Member CreatorFn (typedef) of class TypeFactory is not documented. -/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/typefactory.h:110: warning: Member classes (variable) of class TypeFactory is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:38: warning: Compound DbcCommentHandler is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:22: warning: Compound DbcFrameHandler is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:30: warning: Compound DbcSignalHandler is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:16: warning: Compound DbcStatementHandler is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/examples/main.cpp:101: warning: Member main(int argc, char *argv[]) (function) of file examples/main.cpp is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:40: warning: Member Handle(const std::string &line, DbcParseContext &context) const override (function) of class DbcCommentHandler is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:24: warning: Member Handle(const std::string &line, DbcParseContext &context) const override (function) of class DbcFrameHandler is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:12: warning: Member database (variable) of struct DbcParseContext is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:13: warning: Member currentFrame (variable) of struct DbcParseContext is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:32: warning: Member Handle(const std::string &line, DbcParseContext &context) const override (function) of class DbcSignalHandler is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:52: warning: Member RegisterType(const std::string &keyword) (function) of class DbcStatementDispatcher is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/dbc_statement_handler.h:19: warning: Member Handle(const std::string &line, DbcParseContext &context) const =0 (function) of class DbcStatementHandler is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/decode_database.h:112: warning: Member frames (variable) of struct DecodeDatabase is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/decode_database.h:113: warning: Member frameIndexByKey (variable) of struct DecodeDatabase is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/decode_database.h:88: warning: Member FrameKey(std::uint32_t id, bool extended) (function) of struct FrameKey is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/decode_database.h:92: warning: Member operator==(const FrameKey &other) const (function) of struct FrameKey is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/decode_database.h:81: warning: Member canId (variable) of struct FrameKey is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/decode_database.h:82: warning: Member isExtended (variable) of struct FrameKey is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/decode_database.h:101: warning: Member operator()(const FrameKey &key) const (function) of struct FrameKeyHasher is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/tree_node.h:59: warning: Member TreeNode(TreeNode &&)=default (function) of class TreeNode is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/tree_node.h:60: warning: Member operator=(TreeNode &&)=default (function) of class TreeNode is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/typefactory.h:61: warning: Member BasePtr (typedef) of class TypeFactory is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/typefactory.h:62: warning: Member CreatorFn (typedef) of class TypeFactory is not documented. +/home/deeaitch/work/3.projects/git.himro.ca/automotive/dbc/core/typefactory.h:110: warning: Member classes (variable) of class TypeFactory is not documented. error: failed to run qhelpgenerator on index.qhp diff --git a/docs/html/dbc__database_8h.html b/docs/html/dbc__database_8h.html index 66dd493..0756b17 100644 --- a/docs/html/dbc__database_8h.html +++ b/docs/html/dbc__database_8h.html @@ -119,7 +119,7 @@ Classes diff --git a/docs/html/dbc__database_8h_source.html b/docs/html/dbc__database_8h_source.html index 8cd4456..d9baf55 100644 --- a/docs/html/dbc__database_8h_source.html +++ b/docs/html/dbc__database_8h_source.html @@ -121,7 +121,7 @@ $(document).ready(function(){initNavTree('dbc__database_8h_source.html',''); ini diff --git a/docs/html/dbc__decode__builder_8cpp.html b/docs/html/dbc__decode__builder_8cpp.html index 095bb28..6750082 100644 --- a/docs/html/dbc__decode__builder_8cpp.html +++ b/docs/html/dbc__decode__builder_8cpp.html @@ -109,7 +109,7 @@ $(document).ready(function(){initNavTree('dbc__decode__builder_8cpp.html',''); i diff --git a/docs/html/dbc__decode__builder_8cpp_source.html b/docs/html/dbc__decode__builder_8cpp_source.html index bc8e8fd..203858d 100644 --- a/docs/html/dbc__decode__builder_8cpp_source.html +++ b/docs/html/dbc__decode__builder_8cpp_source.html @@ -201,7 +201,7 @@ $(document).ready(function(){initNavTree('dbc__decode__builder_8cpp_source.html' diff --git a/docs/html/dbc__decode__builder_8h.html b/docs/html/dbc__decode__builder_8h.html index a4fd188..5cb0a9e 100644 --- a/docs/html/dbc__decode__builder_8h.html +++ b/docs/html/dbc__decode__builder_8h.html @@ -119,7 +119,7 @@ Classes diff --git a/docs/html/dbc__decode__builder_8h_source.html b/docs/html/dbc__decode__builder_8h_source.html index 1b5dba7..ec911a9 100644 --- a/docs/html/dbc__decode__builder_8h_source.html +++ b/docs/html/dbc__decode__builder_8h_source.html @@ -124,7 +124,7 @@ $(document).ready(function(){initNavTree('dbc__decode__builder_8h_source.html',' diff --git a/docs/html/dbc__decoder_8cpp.html b/docs/html/dbc__decoder_8cpp.html index 66ae3ae..d121dcf 100644 --- a/docs/html/dbc__decoder_8cpp.html +++ b/docs/html/dbc__decoder_8cpp.html @@ -109,7 +109,7 @@ $(document).ready(function(){initNavTree('dbc__decoder_8cpp.html',''); initResiz diff --git a/docs/html/dbc__decoder_8cpp_source.html b/docs/html/dbc__decoder_8cpp_source.html index d52d007..ac28131 100644 --- a/docs/html/dbc__decoder_8cpp_source.html +++ b/docs/html/dbc__decoder_8cpp_source.html @@ -280,7 +280,7 @@ $(document).ready(function(){initNavTree('dbc__decoder_8cpp_source.html',''); in diff --git a/docs/html/dbc__decoder_8h.html b/docs/html/dbc__decoder_8h.html index a331d14..3b2b071 100644 --- a/docs/html/dbc__decoder_8h.html +++ b/docs/html/dbc__decoder_8h.html @@ -130,7 +130,7 @@ Classes diff --git a/docs/html/dbc__decoder_8h_source.html b/docs/html/dbc__decoder_8h_source.html index 6dee24a..055ee10 100644 --- a/docs/html/dbc__decoder_8h_source.html +++ b/docs/html/dbc__decoder_8h_source.html @@ -196,7 +196,7 @@ $(document).ready(function(){initNavTree('dbc__decoder_8h_source.html',''); init diff --git a/docs/html/dbc__decoder__test_8cpp_source.html b/docs/html/dbc__decoder__test_8cpp_source.html index 1279b8e..eb5e815 100644 --- a/docs/html/dbc__decoder__test_8cpp_source.html +++ b/docs/html/dbc__decoder__test_8cpp_source.html @@ -100,7 +100,7 @@ $(document).ready(function(){initNavTree('dbc__decoder__test_8cpp_source.html','
1#include "dbc_decoder.h"
2
-
3#include <iostream>
+
3#include <QtTest>
4#include <limits>
5#include <sstream>
6
@@ -118,128 +118,141 @@ $(document).ready(function(){initNavTree('dbc__decoder__test_8cpp_source.html','
18 double physicalValue;
19};
20
-
21int main() {
-
22 const DecodeCase cases[] = {
-
23 {"Motorola reproduction", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0},
-
24 {"Motorola within byte", ByteOrder::Motorola, 5U, 4U, ValueType::Unsigned, {0xAC}, true, 11, 1.0, 0.0, 11.0},
-
25 {"Motorola unaligned crossing", ByteOrder::Motorola, 3U, 12U, ValueType::Unsigned, {0xAB, 0xCD}, true, 0xBCD, 1.0, 0.0, 3021.0},
-
26 {"Motorola starts at bit zero", ByteOrder::Motorola, 0U, 2U, ValueType::Unsigned, {0x01, 0x80}, true, 3, 1.0, 0.0, 3.0},
-
27 {"Motorola second byte", ByteOrder::Motorola, 15U, 16U, ValueType::Unsigned, {0xFF, 0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0},
-
28 {"Motorola signed scaled", ByteOrder::Motorola, 7U, 16U, ValueType::Signed, {0xFF, 0xFE}, true, -2, 0.5, 10.0, 9.0},
-
29 {"Motorola 64 bits", ByteOrder::Motorola, 7U, 64U, ValueType::Unsigned, {0, 0, 0, 0, 0, 0, 0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0},
-
30 {"Motorola 64 bits high bit", ByteOrder::Motorola, 7U, 64U, ValueType::Unsigned, {0x40, 0, 0, 0, 0, 0, 0, 0}, true, 0x4000000000000000LL, 1.0, 0.0, 4611686018427387904.0},
-
31 {"Motorola short payload", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12}, false, 0, 1.0, 0.0, 0.0},
-
32 {"Motorola empty payload", ByteOrder::Motorola, 7U, 8U, ValueType::Unsigned, {}, false, 0, 1.0, 0.0, 0.0},
-
33 {"Motorola large start", ByteOrder::Motorola, std::numeric_limits<std::uint32_t>::max(), 8U, ValueType::Unsigned, {0xFF}, false, 0, 1.0, 0.0, 0.0},
-
34 {"Motorola zero length", ByteOrder::Motorola, 7U, 0U, ValueType::Unsigned, {0xFF}, false, 0, 1.0, 0.0, 0.0},
-
35 {"Motorola excessive length", ByteOrder::Motorola, 7U, 65U, ValueType::Unsigned,
-
36 std::vector<std::uint8_t>(9U, 0xFF), false, 0, 1.0, 0.0, 0.0},
-
37 {"Intel regression", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12, 0x34}, true, 0x3412, 1.0, 0.0, 13330.0},
-
38 {"Intel signed regression", ByteOrder::Intel, 0U, 16U, ValueType::Signed, {0xFE, 0xFF}, true, -2, 0.5, 10.0, 9.0},
-
39 {"Intel short payload", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12}, false, 0, 1.0, 0.0, 0.0}};
-
40
-
41 int failures = 0;
-
42 for (const DecodeCase &test: cases) {
-
43 DecodeSignal signal;
-
44 signal.name = test.name;
-
45 signal.byteOrder = test.byteOrder;
-
46 signal.startBit = test.startBit;
-
47 signal.length = test.length;
-
48 signal.valueType = test.valueType;
-
49 signal.factor = test.factor;
-
50 signal.offset = test.offset;
+
21Q_DECLARE_METATYPE(DecodeCase)
+
22
+
23class DbcDecoderTest : public QObject {
+
24 Q_OBJECT
+
25private Q_SLOTS:
+
26 void decode_data();
+
27 void decode();
+
28 void boundaries();
+
29};
+
30
+
31void DbcDecoderTest::decode_data() {
+
32 QTest::addColumn<DecodeCase>("test");
+
33 const DecodeCase cases[] = {
+
34 {"Motorola reproduction", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0},
+
35 {"Motorola within byte", ByteOrder::Motorola, 5U, 4U, ValueType::Unsigned, {0xAC}, true, 11, 1.0, 0.0, 11.0},
+
36 {"Motorola unaligned crossing", ByteOrder::Motorola, 3U, 12U, ValueType::Unsigned, {0xAB, 0xCD}, true, 0xBCD, 1.0, 0.0, 3021.0},
+
37 {"Motorola starts at bit zero", ByteOrder::Motorola, 0U, 2U, ValueType::Unsigned, {0x01, 0x80}, true, 3, 1.0, 0.0, 3.0},
+
38 {"Motorola second byte", ByteOrder::Motorola, 15U, 16U, ValueType::Unsigned, {0xFF, 0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0},
+
39 {"Motorola signed scaled", ByteOrder::Motorola, 7U, 16U, ValueType::Signed, {0xFF, 0xFE}, true, -2, 0.5, 10.0, 9.0},
+
40 {"Motorola 64 bits", ByteOrder::Motorola, 7U, 64U, ValueType::Unsigned, {0, 0, 0, 0, 0, 0, 0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0},
+
41 {"Motorola 64 bits high bit", ByteOrder::Motorola, 7U, 64U, ValueType::Unsigned, {0x40, 0, 0, 0, 0, 0, 0, 0}, true, 0x4000000000000000LL, 1.0, 0.0, 4611686018427387904.0},
+
42 {"Motorola short payload", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12}, false, 0, 1.0, 0.0, 0.0},
+
43 {"Motorola empty payload", ByteOrder::Motorola, 7U, 8U, ValueType::Unsigned, {}, false, 0, 1.0, 0.0, 0.0},
+
44 {"Motorola large start", ByteOrder::Motorola, std::numeric_limits<std::uint32_t>::max(), 8U, ValueType::Unsigned, {0xFF}, false, 0, 1.0, 0.0, 0.0},
+
45 {"Motorola zero length", ByteOrder::Motorola, 7U, 0U, ValueType::Unsigned, {0xFF}, false, 0, 1.0, 0.0, 0.0},
+
46 {"Motorola excessive length", ByteOrder::Motorola, 7U, 65U, ValueType::Unsigned,
+
47 std::vector<std::uint8_t>(9U, 0xFF), false, 0, 1.0, 0.0, 0.0},
+
48 {"Intel regression", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12, 0x34}, true, 0x3412, 1.0, 0.0, 13330.0},
+
49 {"Intel signed regression", ByteOrder::Intel, 0U, 16U, ValueType::Signed, {0xFE, 0xFF}, true, -2, 0.5, 10.0, 9.0},
+
50 {"Intel short payload", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12}, false, 0, 1.0, 0.0, 0.0}};
51
-
52 DecodeFrame definition;
-
53 definition.canId = 0x123U;
-
54 definition.dlc = static_cast<std::uint8_t>(test.data.size());
-
55 definition.signals.push_back(signal);
-
56 DecodeDatabase database;
-
57 database.frames.push_back(definition);
-
58 database.frameIndexByKey.emplace(FrameKey(definition.canId, false), 0U);
-
59
-
60 RawCanFrame frame;
-
61 frame.canId = definition.canId;
-
62 frame.data = test.data;
-
63 const DecodedFrameValue result = DbcDecoder().Decode(database, frame);
-
64 const bool passed = result.valid &&
-
65 (result.definition == &database.frames[0]) &&
-
66 (result.signals.size() == 1U) &&
-
67 (result.signals[0].definition == &database.frames[0].signals[0]) &&
-
68 (result.signals[0].valid == test.valid) &&
-
69 (!test.valid || (((test.valueType == ValueType::Signed)
-
70 ? (std::get_if<std::int64_t>(&result.signals[0].rawValue) &&
-
71 std::get<std::int64_t>(result.signals[0].rawValue) == test.rawValue)
-
72 : (std::get_if<std::uint64_t>(&result.signals[0].rawValue) &&
-
73 std::get<std::uint64_t>(result.signals[0].rawValue) ==
-
74 static_cast<std::uint64_t>(test.rawValue))) &&
-
75 (result.signals[0].physicalValue == test.physicalValue)));
-
76 if (!passed) {
-
77 std::cerr << "FAIL: " << test.name << '\n';
-
78 ++failures;
-
79 }
-
80 }
-
81 std::size_t boundaryCases = 0U;
-
82 for (ByteOrder order: {ByteOrder::Intel, ByteOrder::Motorola}) {
-
83 for (ValueType type: {ValueType::Unsigned, ValueType::Signed}) {
-
84 for (std::uint64_t bits: {std::uint64_t(0U), std::uint64_t(0x7FFFFFFFFFFFFFFFULL),
-
85 std::uint64_t(0x8000000000000000ULL),
-
86 std::uint64_t(0x8000000000000001ULL),
-
87 std::uint64_t(0xFFFFFFFFFFFFFFFFULL)}) {
-
88 DecodeDatabase database;
-
89 DecodeFrame definition;
-
90 DecodeSignal signal;
-
91 signal.startBit = order == ByteOrder::Intel ? 0U : 7U;
-
92 signal.length = 64U;
-
93 signal.byteOrder = order;
-
94 signal.valueType = type;
-
95 signal.factor = 0.5;
-
96 signal.offset = 10.0;
-
97 definition.signals.push_back(signal);
-
98 database.frames.push_back(definition);
-
99 database.frameIndexByKey.emplace(FrameKey(0U, false), 0U);
-
100 RawCanFrame frame;
-
101 for (unsigned byte = 0U; byte < 8U; ++byte) {
-
102 const unsigned shift = (order == ByteOrder::Intel ? byte : 7U - byte) * 8U;
-
103 frame.data.push_back(static_cast<std::uint8_t>(bits >> shift));
-
104 }
-
105 const auto result = DbcDecoder().Decode(database, frame);
-
106 const std::int64_t signedExpected = bits <= 0x7FFFFFFFFFFFFFFFULL
-
107 ? static_cast<std::int64_t>(bits)
-
108 : std::numeric_limits<std::int64_t>::min() +
-
109 static_cast<std::int64_t>(bits - 0x8000000000000000ULL);
-
110 const auto &decoded = result.signals.at(0U);
-
111 const auto expected = type == ValueType::Unsigned
-
112 ? std::variant<std::int64_t, std::uint64_t>(bits)
-
113 : std::variant<std::int64_t, std::uint64_t>(signedExpected);
-
114 const double physical = (type == ValueType::Unsigned
-
115 ? static_cast<double>(bits)
-
116 : static_cast<double>(signedExpected)) *
-
117 0.5 +
-
118 10.0;
-
119 std::ostringstream actualText;
-
120 std::ostringstream expectedText;
-
121 if (const auto *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
-
122 actualText << *signedValue;
-
123 else
-
124 actualText << std::get<std::uint64_t>(decoded.rawValue);
-
125 if (type == ValueType::Unsigned)
-
126 expectedText << bits;
-
127 else
-
128 expectedText << signedExpected;
-
129 if (!decoded.valid || decoded.rawValue != expected ||
-
130 decoded.physicalValue != physical || actualText.str() != expectedText.str()) {
-
131 std::cerr << "FAIL: 64-bit boundary " << bits << '\n';
-
132 ++failures;
-
133 }
-
134 ++boundaryCases;
-
135 }
-
136 }
-
137 }
-
138 if (failures != 0)
-
139 return 1;
-
140 std::cout << "All " << sizeof(cases) / sizeof(cases[0]) + boundaryCases << " decoder cases passed.\n";
-
141 return 0;
-
142}
+
52 for (const auto &test: cases)
+
53 QTest::newRow(test.name) << test;
+
54}
+
55
+
56void DbcDecoderTest::decode() {
+
57 QFETCH(DecodeCase, test);
+
58 DecodeSignal signal;
+
59 signal.name = test.name;
+
60 signal.byteOrder = test.byteOrder;
+
61 signal.startBit = test.startBit;
+
62 signal.length = test.length;
+
63 signal.valueType = test.valueType;
+
64 signal.factor = test.factor;
+
65 signal.offset = test.offset;
+
66
+
67 DecodeFrame definition;
+
68 definition.canId = 0x123U;
+
69 definition.dlc = static_cast<std::uint8_t>(test.data.size());
+
70 definition.signals.push_back(signal);
+
71 DecodeDatabase database;
+
72 database.frames.push_back(definition);
+
73 database.frameIndexByKey.emplace(FrameKey(definition.canId, false), 0U);
+
74
+
75 RawCanFrame frame;
+
76 frame.canId = definition.canId;
+
77 frame.data = test.data;
+
78 const DecodedFrameValue result = DbcDecoder().Decode(database, frame);
+
79 const bool passed = result.valid &&
+
80 (result.definition == &database.frames[0]) &&
+
81 (result.signals.size() == 1U) &&
+
82 (result.signals[0].definition == &database.frames[0].signals[0]) &&
+
83 (result.signals[0].valid == test.valid) &&
+
84 (!test.valid || (((test.valueType == ValueType::Signed)
+
85 ? (std::get_if<std::int64_t>(&result.signals[0].rawValue) &&
+
86 std::get<std::int64_t>(result.signals[0].rawValue) == test.rawValue)
+
87 : (std::get_if<std::uint64_t>(&result.signals[0].rawValue) &&
+
88 std::get<std::uint64_t>(result.signals[0].rawValue) ==
+
89 static_cast<std::uint64_t>(test.rawValue))) &&
+
90 (result.signals[0].physicalValue == test.physicalValue)));
+
91 QVERIFY2(passed, test.name);
+
92}
+
93
+
94void DbcDecoderTest::boundaries() {
+
95 for (ByteOrder order: {ByteOrder::Intel, ByteOrder::Motorola}) {
+
96 for (ValueType type: {ValueType::Unsigned, ValueType::Signed}) {
+
97 for (std::uint64_t bits: {std::uint64_t(0U), std::uint64_t(0x7FFFFFFFFFFFFFFFULL),
+
98 std::uint64_t(0x8000000000000000ULL),
+
99 std::uint64_t(0x8000000000000001ULL),
+
100 std::uint64_t(0xFFFFFFFFFFFFFFFFULL)}) {
+
101 DecodeDatabase database;
+
102 DecodeFrame definition;
+
103 DecodeSignal signal;
+
104 signal.startBit = order == ByteOrder::Intel ? 0U : 7U;
+
105 signal.length = 64U;
+
106 signal.byteOrder = order;
+
107 signal.valueType = type;
+
108 signal.factor = 0.5;
+
109 signal.offset = 10.0;
+
110 definition.signals.push_back(signal);
+
111 database.frames.push_back(definition);
+
112 database.frameIndexByKey.emplace(FrameKey(0U, false), 0U);
+
113 RawCanFrame frame;
+
114 for (unsigned byte = 0U; byte < 8U; ++byte) {
+
115 const unsigned shift = (order == ByteOrder::Intel ? byte : 7U - byte) * 8U;
+
116 frame.data.push_back(static_cast<std::uint8_t>(bits >> shift));
+
117 }
+
118 const auto result = DbcDecoder().Decode(database, frame);
+
119 const std::int64_t signedExpected = bits <= 0x7FFFFFFFFFFFFFFFULL
+
120 ? static_cast<std::int64_t>(bits)
+
121 : std::numeric_limits<std::int64_t>::min() +
+
122 static_cast<std::int64_t>(bits - 0x8000000000000000ULL);
+
123 const auto &decoded = result.signals.at(0U);
+
124 const auto expected = type == ValueType::Unsigned
+
125 ? std::variant<std::int64_t, std::uint64_t>(bits)
+
126 : std::variant<std::int64_t, std::uint64_t>(signedExpected);
+
127 const double physical = (type == ValueType::Unsigned
+
128 ? static_cast<double>(bits)
+
129 : static_cast<double>(signedExpected)) *
+
130 0.5 +
+
131 10.0;
+
132 std::ostringstream actualText;
+
133 std::ostringstream expectedText;
+
134 if (const auto *signedValue = std::get_if<std::int64_t>(&decoded.rawValue))
+
135 actualText << *signedValue;
+
136 else
+
137 actualText << std::get<std::uint64_t>(decoded.rawValue);
+
138 if (type == ValueType::Unsigned)
+
139 expectedText << bits;
+
140 else
+
141 expectedText << signedExpected;
+
142 QVERIFY2(decoded.valid && decoded.rawValue == expected &&
+
143 decoded.physicalValue == physical && actualText.str() == expectedText.str(),
+
144 expectedText.str().c_str());
+
145 }
+
146 }
+
147 }
+
148}
+
149
+
150int RunDecoderTests(int argc, char **argv) {
+
151 DbcDecoderTest tests;
+
152 return QTest::qExec(&tests, argc, argv);
+
153}
+
154
+
155#include "dbc_decoder_test.moc"
Runtime CAN decoder using prebuilt decode database.
Definition dbc_decoder.h:64
DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
Decode one raw CAN frame.
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
diff --git a/docs/html/dbc__parser_8cpp.html b/docs/html/dbc__parser_8cpp.html index 7ab1e5b..9d7a507 100644 --- a/docs/html/dbc__parser_8cpp.html +++ b/docs/html/dbc__parser_8cpp.html @@ -113,7 +113,7 @@ $(document).ready(function(){initNavTree('dbc__parser_8cpp.html',''); initResiza diff --git a/docs/html/dbc__parser_8cpp_source.html b/docs/html/dbc__parser_8cpp_source.html index fa3fa3c..91ab595 100644 --- a/docs/html/dbc__parser_8cpp_source.html +++ b/docs/html/dbc__parser_8cpp_source.html @@ -166,7 +166,7 @@ $(document).ready(function(){initNavTree('dbc__parser_8cpp_source.html',''); ini diff --git a/docs/html/dbc__parser_8h.html b/docs/html/dbc__parser_8h.html index 76c3bce..524bbc7 100644 --- a/docs/html/dbc__parser_8h.html +++ b/docs/html/dbc__parser_8h.html @@ -119,7 +119,7 @@ Classes diff --git a/docs/html/dbc__parser_8h_source.html b/docs/html/dbc__parser_8h_source.html index fffb5d7..83a4ba4 100644 --- a/docs/html/dbc__parser_8h_source.html +++ b/docs/html/dbc__parser_8h_source.html @@ -126,7 +126,7 @@ $(document).ready(function(){initNavTree('dbc__parser_8h_source.html',''); initR diff --git a/docs/html/dbc__parser__test_8cpp_source.html b/docs/html/dbc__parser__test_8cpp_source.html index 5f11c75..e1afb5a 100644 --- a/docs/html/dbc__parser__test_8cpp_source.html +++ b/docs/html/dbc__parser__test_8cpp_source.html @@ -101,261 +101,292 @@ $(document).ready(function(){initNavTree('dbc__parser__test_8cpp_source.html',''
1#include "dbc_parser.h"
2#include "dbc_statement_handler.h"
3
-
4#include <chrono>
-
5#include <filesystem>
-
6#include <fstream>
-
7#include <iostream>
-
8#include <stdexcept>
-
9
-
10struct Fixture {
-
11 std::filesystem::path path = std::filesystem::temp_directory_path() /
-
12 ("dbc_parser_test_" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) + ".dbc");
-
13 ~Fixture() {
-
14 std::error_code error;
-
15 std::filesystem::remove(path, error);
-
16 }
-
17 void Write(const std::string &text) const {
-
18 std::ofstream output(path);
-
19 output << text;
-
20 if (!output)
-
21 throw std::runtime_error("Cannot write test fixture.");
-
22 }
-
23};
-
24
-
25class CountingHandler : public DbcStatementHandler {
-
26public:
-
27 inline static int instances = 0;
-
28 inline static int calls = 0;
-
29 CountingHandler() { ++instances; }
-
30 void Handle(const std::string &, DbcParseContext &context) const override {
-
31 ++calls;
-
32 context.database.frames.emplace_back();
-
33 }
-
34};
-
35
-
36std::string SignalLine(const std::string &start, const std::string &length,
-
37 const std::string &order, const std::string &factor,
-
38 const std::string &offset, const std::string &minimum,
-
39 const std::string &maximum) {
-
40 return "SG_ Value : " + start + "|" + length + "@" + order +
-
41 " (" + factor + "," + offset + ") [" + minimum + "|" + maximum + "] \"\" ECU";
-
42}
-
43
-
44struct TestContext {
-
45 int failures = 0;
-
46 std::size_t count = 0U;
-
47 void Check(bool passed, const std::string &name) {
-
48 ++count;
-
49 if (!passed) {
-
50 ++failures;
-
51 std::cerr << "FAIL: " << name << '\n';
-
52 }
-
53 }
-
54 void RejectSignal(const Fixture &fixture, const std::string &line, unsigned payload = 8U) {
-
55 fixture.Write("BO_ 1 Frame: " + std::to_string(payload) + " ECU\n\n" + line + "\n");
-
56 try {
-
57 DbcParser().ParseFile(fixture.path.string());
-
58 Check(false, "Reject " + line);
-
59 } catch (const std::runtime_error &error) {
-
60 const std::string prefix = fixture.path.string() + ":3: ";
-
61 Check(std::string(error.what()).find(prefix) == 0U &&
-
62 std::string(error.what()).size() > prefix.size(),
-
63 "Reject " + line);
-
64 }
-
65 }
-
66};
-
67
-
68int main() {
-
69 Fixture fixture;
-
70 TestContext tests;
-
71 struct ValidCase {
-
72 const char *line;
-
73 std::uint32_t id;
-
74 bool extended;
-
75 unsigned length;
-
76 };
-
77 const ValidCase valid[] = {
-
78 {"BO_ 0 Frame: 0 ECU", 0U, false, 0U},
-
79 {"BO_ 2047 Frame: 8 ECU", 2047U, false, 8U},
-
80 {"BO_ 2048 Frame: 64 ECU", 2048U, true, 64U},
-
81 {"BO_ 536870911 Frame: 255 ECU", 0x1FFFFFFFU, true, 255U},
-
82 {"BO_ 2147483649 Frame: 8 ECU", 1U, true, 8U},
-
83 {"BO_ 2684354559 Frame: 8 ECU", 0x1FFFFFFFU, true, 8U},
-
84 {" BO_\t256\tFrame :\t8\tECU \r", 256U, false, 8U}};
-
85 for (const auto &test: valid) {
-
86 fixture.Write(std::string(test.line) + '\n');
-
87 try {
-
88 const auto database = DbcParser().ParseFile(fixture.path.string());
-
89 tests.Check(database.frames.size() == 1U && database.frames[0].name == "Frame" &&
-
90 database.frames[0].canId == test.id &&
-
91 database.frames[0].isExtended == test.extended &&
-
92 database.frames[0].dlc == test.length &&
-
93 database.frames[0].transmitter == "ECU",
-
94 test.line);
-
95 } catch (const std::exception &error) { tests.Check(false, error.what()); }
-
96 }
-
97 const char *invalid[] = {
-
98 "BO_ invalid", "BO_", "BO_ 1", "BO_ 1 : 8 ECU", "BO_ 1 Frame 8 ECU",
-
99 "BO_ 1 Frame:", "BO_ 1 Frame: 8", "BO_ 1 Frame: 8 ECU extra",
-
100 "BO_ 1 Two Names: 8 ECU", "BO_ -1 Frame: 8 ECU", "BO_ +1 Frame: 8 ECU",
-
101 "BO_ 1x Frame: 8 ECU", "BO_ 0x123 Frame: 8 ECU", "BO_ 1.5 Frame: 8 ECU",
-
102 "BO_ 4294967296 Frame: 8 ECU", "BO_ 999999999999999999999 Frame: 8 ECU",
-
103 "BO_ 536870912 Frame: 8 ECU", "BO_ 1073741824 Frame: 8 ECU",
-
104 "BO_ 2684354560 Frame: 8 ECU", "BO_ 4294967295 Frame: 8 ECU",
-
105 "BO_ 1 Frame: -1 ECU", "BO_ 1 Frame: +8 ECU", "BO_ 1 Frame: 8x ECU",
-
106 "BO_ 1 Frame: 8.5 ECU", "BO_ 1 Frame: 256 ECU",
-
107 "BO_ 1 Frame: 4294967296 ECU", "BO_\tinvalid"};
-
108 for (const auto *line: invalid) {
-
109 fixture.Write(std::string("VERSION \"test\"\n\n") + line + '\n');
-
110 try {
-
111 DbcParser().ParseFile(fixture.path.string());
-
112 tests.Check(false, line);
-
113 } catch (const std::runtime_error &error) {
-
114 const std::string prefix = fixture.path.string() + ":3: ";
-
115 tests.Check(std::string(error.what()).find(prefix) == 0U &&
-
116 std::string(error.what()).size() > prefix.size(),
-
117 line);
-
118 }
-
119 }
-
120 fixture.Write(
-
121 "BO_TX_BU_ 256 : ECU;\nBO_ 256 Frame: 8 ECU\n"
-
122 " SG_ Speed : 0|16@1+ (0.5,1) [0|100] \"rpm\" ECU\n"
-
123 "CM_ BO_ 256 \"Frame comment\";\nCM_ SG_ 256 Speed \"Signal comment\";\n"
-
124 "BO_ 257 Second: 8 ECU\n");
-
125 const auto database = DbcParser().ParseFile(fixture.path.string());
-
126 tests.Check(database.frames.size() == 2U && database.frames[0].signals.size() == 1U &&
-
127 database.frames[0].comment == "Frame comment" &&
-
128 database.frames[0].signals[0].comment == "Signal comment",
-
129 "Integration");
-
130 fixture.Write("\nSG_ Speed : invalid\n");
-
131 try {
-
132 DbcParser().ParseFile(fixture.path.string());
-
133 tests.Check(false, "Signal error location");
-
134 } catch (const std::runtime_error &error) {
-
135 tests.Check(std::string(error.what()).find(fixture.path.string() + ":2: ") == 0U,
-
136 "Signal error location");
-
137 }
-
138 const DbcParser signalParser;
-
139 const std::string ordinary = SignalLine("0", "8", "1+", "1", "0", "0", "255");
-
140 for (const std::string value: {"-1", "+1", "0junk", "0x10", "1.5",
-
141 "4294967296", "999999999999999999999"}) {
-
142 tests.RejectSignal(fixture, SignalLine(value, "8", "1+", "1", "0", "0", "255"));
-
143 tests.RejectSignal(fixture, SignalLine("0", value, "1+", "1", "0", "0", "255"));
-
144 }
-
145 for (const std::string length: {"0", "65"})
-
146 tests.RejectSignal(fixture, SignalLine("0", length, "1+", "1", "0", "0", "255"));
-
147 for (const std::string order: {"2+", "9-", "1", "1x", "1++", "01+"})
-
148 tests.RejectSignal(fixture, SignalLine("0", "8", order, "1", "0", "0", "255"));
-
149 for (const std::string value: {"1junk", "nan", "NaN", "inf", "-inf", "1e999", "1e-999", "0x1p2", "", "1e", "1.2.3"}) {
-
150 tests.RejectSignal(fixture, SignalLine("0", "8", "1+", value, "0", "0", "255"));
-
151 tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", value, "0", "255"));
-
152 tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", value, "255"));
-
153 tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "0", value));
-
154 }
-
155 tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "2", "1"));
-
156 for (const std::string name: {"", "Two Names", "Value M", "Value m1", "Value m1M"}) {
-
157 std::string line = ordinary;
-
158 line.replace(4U, 5U, name);
-
159 tests.RejectSignal(fixture, line);
-
160 }
-
161 for (const std::string broken: {
-
162 "SG_", "SG_ Value", "SG_ Value : 0|8@1+ (1,0) [0|255] ECU",
-
163 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\"",
-
164 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU,",
-
165 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU extra"})
-
166 tests.RejectSignal(fixture, broken);
-
167 tests.RejectSignal(fixture, SignalLine("64", "1", "1+", "1", "0", "0", "1"));
-
168 tests.RejectSignal(fixture, SignalLine("63", "2", "1+", "1", "0", "0", "3"));
-
169 tests.RejectSignal(fixture, SignalLine("56", "2", "0+", "1", "0", "0", "3"));
-
170 tests.RejectSignal(fixture, SignalLine("4294967295", "64", "1+", "1", "0", "0", "1"));
-
171 tests.RejectSignal(fixture, ordinary, 0U);
-
172 for (const char delimiter: {'|', '@', '(', ')', '[', ']', '"'}) {
-
173 std::string line = ordinary;
-
174 line.erase(line.find(delimiter), 1U);
-
175 tests.RejectSignal(fixture, line);
-
176 }
-
177 fixture.Write("BO_ 1 Frame: 8 ECU\n" +
-
178 SignalLine("0", "8", "1+", "0", "0", "0", "0") + "\n" +
-
179 SignalLine("8", "8", "1-", "-1", "0", "-255", "0") + "\n");
-
180 const auto factors = signalParser.ParseFile(fixture.path.string());
-
181 tests.Check(factors.frames[0].signals.size() == 2U &&
-
182 factors.frames[0].signals[0].factor == 0.0 &&
-
183 factors.frames[0].signals[1].factor == -1.0,
-
184 "Zero and negative factors and equal range boundaries");
-
185
-
186 struct SignalCase {
-
187 const char *start;
-
188 const char *length;
-
189 const char *order;
-
190 unsigned payload;
-
191 };
-
192 const SignalCase validSignals[] = {
-
193 {"0", "1", "1+", 1U},
-
194 {"7", "1", "0-", 1U},
-
195 {"0", "64", "1+", 8U},
-
196 {"7", "64", "0-", 8U},
-
197 {"63", "1", "1+", 8U},
-
198 {"56", "1", "0+", 8U},
-
199 {"3", "12", "0+", 2U},
-
200 {"2039", "1", "1+", 255U}};
-
201 for (const auto &test: validSignals) {
-
202 fixture.Write("BO_ 1 Frame: " + std::to_string(test.payload) + " ECU\n" +
-
203 SignalLine(test.start, test.length, test.order, ".5e+1", "-2.5E-1", "-1.", "+2e2") + "\n");
-
204 try {
-
205 const auto parsed = signalParser.ParseFile(fixture.path.string());
-
206 const auto &signal = parsed.frames.at(0).signals.at(0);
-
207 tests.Check(signal.startBit == std::stoul(test.start) &&
-
208 signal.length == std::stoul(test.length) &&
-
209 signal.isLittleEndian == (test.order[0] == '1') &&
-
210 signal.isSigned == (test.order[1] == '-') &&
-
211 signal.factor == 5.0 && signal.offset == -0.25 &&
-
212 signal.minimum == -1.0 && signal.maximum == 200.0,
-
213 "Valid signal boundary and numeric metadata");
-
214 } catch (const std::exception &error) { tests.Check(false, error.what()); }
-
215 }
-
216 fixture.Write("BO_ 1 Frame: 8 ECU\n"
-
217 "SG_\tValue\t:\t0 | 8 @1+ ( 1 , 0 ) [ 0 | 255 ] \"rpm\" ECU1,\tECU2\n");
-
218 try {
-
219 const auto parsed = signalParser.ParseFile(fixture.path.string());
-
220 const auto &signal = parsed.frames.at(0).signals.at(0);
-
221 tests.Check(signal.name == "Value" && signal.unit == "rpm" &&
-
222 signal.receivers == std::vector<std::string>({"ECU1", "ECU2"}),
-
223 "Signal tabs, spaces, and receiver list");
-
224 } catch (const std::exception &error) { tests.Check(false, error.what()); }
-
225 DbcDatabase dispatchDatabase;
-
226 DbcParseContext context{dispatchDatabase, nullptr};
-
227 DbcStatementDispatcher dispatcher;
-
228 dispatcher.RegisterType<CountingHandler>("TEST_");
-
229 tests.Check(dispatcher.Dispatch("TEST_ first", context) &&
-
230 dispatcher.Dispatch("TEST_ second", context) &&
-
231 CountingHandler::instances == 1 && CountingHandler::calls == 2 &&
-
232 dispatchDatabase.frames.size() == 2U,
-
233 "Factory dispatch and handler reuse");
-
234 tests.Check(!dispatcher.Dispatch("TEST_OTHER data", context) &&
-
235 !dispatcher.Dispatch("BO_TX_BU_ 1 : ECU;", context) &&
-
236 !dispatcher.Dispatch("VAL_ 1 Speed 0 \"Stopped\";", context) &&
-
237 CountingHandler::calls == 2,
-
238 "Exact and unknown keyword dispatch");
-
239 const DbcParser parser;
-
240 fixture.Write("BO_ 1 First: 8 ECU\n");
-
241 tests.Check(parser.ParseFile(fixture.path.string()).frames.size() == 1U, "First parse");
-
242 fixture.Write("SG_ Speed : invalid\n");
-
243 try {
-
244 parser.ParseFile(fixture.path.string());
-
245 tests.Check(false, "Independent parse context");
-
246 } catch (const std::runtime_error &error) {
-
247 tests.Check(std::string(error.what()).find("Signal found before any frame") !=
-
248 std::string::npos,
-
249 "Independent parse context");
-
250 }
-
251 fixture.Write("BO_ 2 Second: 8 ECU\n");
-
252 const auto recovered = parser.ParseFile(fixture.path.string());
-
253 tests.Check(recovered.frames.size() == 1U && recovered.frames[0].canId == 2U,
-
254 "Fresh parse after error");
-
255 if (tests.failures != 0) return 1;
-
256 std::cout << "All " << tests.count << " parser cases passed.\n";
-
257 return 0;
-
258}
+
4#include <QtTest>
+
5#include <chrono>
+
6#include <filesystem>
+
7#include <fstream>
+
8
+
9#define CHECK(condition, name) QVERIFY2((condition), std::string(name).c_str())
+
10#include <stdexcept>
+
11
+
12struct Fixture {
+
13 std::filesystem::path path = std::filesystem::temp_directory_path() /
+
14 ("dbc_parser_test_" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()) + ".dbc");
+
15 ~Fixture() {
+
16 std::error_code error;
+
17 std::filesystem::remove(path, error);
+
18 }
+
19 void Write(const std::string &text) const {
+
20 std::ofstream output(path);
+
21 output << text;
+
22 if (!output)
+
23 throw std::runtime_error("Cannot write test fixture.");
+
24 }
+
25};
+
26
+
27class CountingHandler : public DbcStatementHandler {
+
28public:
+
29 inline static int instances = 0;
+
30 inline static int calls = 0;
+
31 CountingHandler() { ++instances; }
+
32 void Handle(const std::string &, DbcParseContext &context) const override {
+
33 ++calls;
+
34 context.database.frames.emplace_back();
+
35 }
+
36};
+
37
+
38std::string SignalLine(const std::string &start, const std::string &length,
+
39 const std::string &order, const std::string &factor,
+
40 const std::string &offset, const std::string &minimum,
+
41 const std::string &maximum) {
+
42 return "SG_ Value : " + start + "|" + length + "@" + order +
+
43 " (" + factor + "," + offset + ") [" + minimum + "|" + maximum + "] \"\" ECU";
+
44}
+
45
+
46class DbcParserTest : public QObject {
+
47 Q_OBJECT
+
48private:
+
49 void RejectSignal(const Fixture &fixture, const std::string &line, unsigned payload = 8U) {
+
50 fixture.Write("BO_ 1 Frame: " + std::to_string(payload) + " ECU\n\n" + line + "\n");
+
51 try {
+
52 DbcParser().ParseFile(fixture.path.string());
+
53 CHECK(false, "Reject " + line);
+
54 } catch (const std::runtime_error &error) {
+
55 const std::string prefix = fixture.path.string() + ":3: ";
+
56 CHECK(std::string(error.what()).find(prefix) == 0U &&
+
57 std::string(error.what()).size() > prefix.size(),
+
58 "Reject " + line);
+
59 }
+
60 }
+
61private Q_SLOTS:
+
62 void validFrames();
+
63 void invalidFrames();
+
64 void integration();
+
65 void invalidSignals();
+
66 void validSignals();
+
67 void dispatch();
+
68 void independentSessions();
+
69};
+
70
+
71void DbcParserTest::validFrames() {
+
72 Fixture fixture;
+
73 struct ValidCase {
+
74 const char *line;
+
75 std::uint32_t id;
+
76 bool extended;
+
77 unsigned length;
+
78 };
+
79 const ValidCase valid[] = {
+
80 {"BO_ 0 Frame: 0 ECU", 0U, false, 0U},
+
81 {"BO_ 2047 Frame: 8 ECU", 2047U, false, 8U},
+
82 {"BO_ 2048 Frame: 64 ECU", 2048U, true, 64U},
+
83 {"BO_ 536870911 Frame: 255 ECU", 0x1FFFFFFFU, true, 255U},
+
84 {"BO_ 2147483649 Frame: 8 ECU", 1U, true, 8U},
+
85 {"BO_ 2684354559 Frame: 8 ECU", 0x1FFFFFFFU, true, 8U},
+
86 {" BO_\t256\tFrame :\t8\tECU \r", 256U, false, 8U}};
+
87 for (const auto &test: valid) {
+
88 fixture.Write(std::string(test.line) + '\n');
+
89 try {
+
90 const auto database = DbcParser().ParseFile(fixture.path.string());
+
91 CHECK(database.frames.size() == 1U && database.frames[0].name == "Frame" &&
+
92 database.frames[0].canId == test.id &&
+
93 database.frames[0].isExtended == test.extended &&
+
94 database.frames[0].dlc == test.length &&
+
95 database.frames[0].transmitter == "ECU",
+
96 test.line);
+
97 } catch (const std::exception &error) { CHECK(false, error.what()); }
+
98 }
+
99}
+
100
+
101void DbcParserTest::invalidFrames() {
+
102 Fixture fixture;
+
103 const char *invalid[] = {
+
104 "BO_ invalid", "BO_", "BO_ 1", "BO_ 1 : 8 ECU", "BO_ 1 Frame 8 ECU",
+
105 "BO_ 1 Frame:", "BO_ 1 Frame: 8", "BO_ 1 Frame: 8 ECU extra",
+
106 "BO_ 1 Two Names: 8 ECU", "BO_ -1 Frame: 8 ECU", "BO_ +1 Frame: 8 ECU",
+
107 "BO_ 1x Frame: 8 ECU", "BO_ 0x123 Frame: 8 ECU", "BO_ 1.5 Frame: 8 ECU",
+
108 "BO_ 4294967296 Frame: 8 ECU", "BO_ 999999999999999999999 Frame: 8 ECU",
+
109 "BO_ 536870912 Frame: 8 ECU", "BO_ 1073741824 Frame: 8 ECU",
+
110 "BO_ 2684354560 Frame: 8 ECU", "BO_ 4294967295 Frame: 8 ECU",
+
111 "BO_ 1 Frame: -1 ECU", "BO_ 1 Frame: +8 ECU", "BO_ 1 Frame: 8x ECU",
+
112 "BO_ 1 Frame: 8.5 ECU", "BO_ 1 Frame: 256 ECU",
+
113 "BO_ 1 Frame: 4294967296 ECU", "BO_\tinvalid"};
+
114 for (const auto *line: invalid) {
+
115 fixture.Write(std::string("VERSION \"test\"\n\n") + line + '\n');
+
116 try {
+
117 DbcParser().ParseFile(fixture.path.string());
+
118 CHECK(false, line);
+
119 } catch (const std::runtime_error &error) {
+
120 const std::string prefix = fixture.path.string() + ":3: ";
+
121 CHECK(std::string(error.what()).find(prefix) == 0U &&
+
122 std::string(error.what()).size() > prefix.size(),
+
123 line);
+
124 }
+
125 }
+
126}
+
127
+
128void DbcParserTest::integration() {
+
129 Fixture fixture;
+
130 fixture.Write(
+
131 "BO_TX_BU_ 256 : ECU;\nBO_ 256 Frame: 8 ECU\n"
+
132 " SG_ Speed : 0|16@1+ (0.5,1) [0|100] \"rpm\" ECU\n"
+
133 "CM_ BO_ 256 \"Frame comment\";\nCM_ SG_ 256 Speed \"Signal comment\";\n"
+
134 "BO_ 257 Second: 8 ECU\n");
+
135 const auto database = DbcParser().ParseFile(fixture.path.string());
+
136 CHECK(database.frames.size() == 2U && database.frames[0].signals.size() == 1U &&
+
137 database.frames[0].comment == "Frame comment" &&
+
138 database.frames[0].signals[0].comment == "Signal comment",
+
139 "Integration");
+
140 fixture.Write("\nSG_ Speed : invalid\n");
+
141 try {
+
142 DbcParser().ParseFile(fixture.path.string());
+
143 CHECK(false, "Signal error location");
+
144 } catch (const std::runtime_error &error) {
+
145 CHECK(std::string(error.what()).find(fixture.path.string() + ":2: ") == 0U,
+
146 "Signal error location");
+
147 }
+
148}
+
149
+
150void DbcParserTest::invalidSignals() {
+
151 Fixture fixture;
+
152 const std::string ordinary = SignalLine("0", "8", "1+", "1", "0", "0", "255");
+
153 for (const std::string value: {"-1", "+1", "0junk", "0x10", "1.5",
+
154 "4294967296", "999999999999999999999"}) {
+
155 RejectSignal(fixture, SignalLine(value, "8", "1+", "1", "0", "0", "255"));
+
156 RejectSignal(fixture, SignalLine("0", value, "1+", "1", "0", "0", "255"));
+
157 }
+
158 for (const std::string length: {"0", "65"})
+
159 RejectSignal(fixture, SignalLine("0", length, "1+", "1", "0", "0", "255"));
+
160 for (const std::string order: {"2+", "9-", "1", "1x", "1++", "01+"})
+
161 RejectSignal(fixture, SignalLine("0", "8", order, "1", "0", "0", "255"));
+
162 for (const std::string value: {"1junk", "nan", "NaN", "inf", "-inf", "1e999", "1e-999", "0x1p2", "", "1e", "1.2.3"}) {
+
163 RejectSignal(fixture, SignalLine("0", "8", "1+", value, "0", "0", "255"));
+
164 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", value, "0", "255"));
+
165 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", value, "255"));
+
166 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "0", value));
+
167 }
+
168 RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "2", "1"));
+
169 for (const std::string name: {"", "Two Names", "Value M", "Value m1", "Value m1M"}) {
+
170 std::string line = ordinary;
+
171 line.replace(4U, 5U, name);
+
172 RejectSignal(fixture, line);
+
173 }
+
174 for (const std::string broken: {
+
175 "SG_", "SG_ Value", "SG_ Value : 0|8@1+ (1,0) [0|255] ECU",
+
176 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\"",
+
177 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU,",
+
178 "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU extra"})
+
179 RejectSignal(fixture, broken);
+
180 RejectSignal(fixture, SignalLine("64", "1", "1+", "1", "0", "0", "1"));
+
181 RejectSignal(fixture, SignalLine("63", "2", "1+", "1", "0", "0", "3"));
+
182 RejectSignal(fixture, SignalLine("56", "2", "0+", "1", "0", "0", "3"));
+
183 RejectSignal(fixture, SignalLine("4294967295", "64", "1+", "1", "0", "0", "1"));
+
184 RejectSignal(fixture, ordinary, 0U);
+
185 for (const char delimiter: {'|', '@', '(', ')', '[', ']', '"'}) {
+
186 std::string line = ordinary;
+
187 line.erase(line.find(delimiter), 1U);
+
188 RejectSignal(fixture, line);
+
189 }
+
190}
+
191
+
192void DbcParserTest::validSignals() {
+
193 Fixture fixture;
+
194 const DbcParser signalParser;
+
195 fixture.Write("BO_ 1 Frame: 8 ECU\n" +
+
196 SignalLine("0", "8", "1+", "0", "0", "0", "0") + "\n" +
+
197 SignalLine("8", "8", "1-", "-1", "0", "-255", "0") + "\n");
+
198 const auto factors = signalParser.ParseFile(fixture.path.string());
+
199 CHECK(factors.frames[0].signals.size() == 2U &&
+
200 factors.frames[0].signals[0].factor == 0.0 &&
+
201 factors.frames[0].signals[1].factor == -1.0,
+
202 "Zero and negative factors and equal range boundaries");
+
203
+
204 struct SignalCase {
+
205 const char *start;
+
206 const char *length;
+
207 const char *order;
+
208 unsigned payload;
+
209 };
+
210 const SignalCase validSignals[] = {
+
211 {"0", "1", "1+", 1U},
+
212 {"7", "1", "0-", 1U},
+
213 {"0", "64", "1+", 8U},
+
214 {"7", "64", "0-", 8U},
+
215 {"63", "1", "1+", 8U},
+
216 {"56", "1", "0+", 8U},
+
217 {"3", "12", "0+", 2U},
+
218 {"2039", "1", "1+", 255U}};
+
219 for (const auto &test: validSignals) {
+
220 fixture.Write("BO_ 1 Frame: " + std::to_string(test.payload) + " ECU\n" +
+
221 SignalLine(test.start, test.length, test.order, ".5e+1", "-2.5E-1", "-1.", "+2e2") + "\n");
+
222 try {
+
223 const auto parsed = signalParser.ParseFile(fixture.path.string());
+
224 const auto &signal = parsed.frames.at(0).signals.at(0);
+
225 CHECK(signal.startBit == std::stoul(test.start) &&
+
226 signal.length == std::stoul(test.length) &&
+
227 signal.isLittleEndian == (test.order[0] == '1') &&
+
228 signal.isSigned == (test.order[1] == '-') &&
+
229 signal.factor == 5.0 && signal.offset == -0.25 &&
+
230 signal.minimum == -1.0 && signal.maximum == 200.0,
+
231 "Valid signal boundary and numeric metadata");
+
232 } catch (const std::exception &error) { CHECK(false, error.what()); }
+
233 }
+
234 fixture.Write("BO_ 1 Frame: 8 ECU\n"
+
235 "SG_\tValue\t:\t0 | 8 @1+ ( 1 , 0 ) [ 0 | 255 ] \"rpm\" ECU1,\tECU2\n");
+
236 try {
+
237 const auto parsed = signalParser.ParseFile(fixture.path.string());
+
238 const auto &signal = parsed.frames.at(0).signals.at(0);
+
239 CHECK(signal.name == "Value" && signal.unit == "rpm" &&
+
240 signal.receivers == std::vector<std::string>({"ECU1", "ECU2"}),
+
241 "Signal tabs, spaces, and receiver list");
+
242 } catch (const std::exception &error) { CHECK(false, error.what()); }
+
243}
+
244
+
245void DbcParserTest::dispatch() {
+
246 CountingHandler::instances = 0;
+
247 CountingHandler::calls = 0;
+
248 DbcDatabase dispatchDatabase;
+
249 DbcParseContext context{dispatchDatabase, nullptr};
+
250 DbcStatementDispatcher dispatcher;
+
251 dispatcher.RegisterType<CountingHandler>("TEST_");
+
252 CHECK(dispatcher.Dispatch("TEST_ first", context) &&
+
253 dispatcher.Dispatch("TEST_ second", context) &&
+
254 CountingHandler::instances == 1 && CountingHandler::calls == 2 &&
+
255 dispatchDatabase.frames.size() == 2U,
+
256 "Factory dispatch and handler reuse");
+
257 CHECK(!dispatcher.Dispatch("TEST_OTHER data", context) &&
+
258 !dispatcher.Dispatch("BO_TX_BU_ 1 : ECU;", context) &&
+
259 !dispatcher.Dispatch("VAL_ 1 Speed 0 \"Stopped\";", context) &&
+
260 CountingHandler::calls == 2,
+
261 "Exact and unknown keyword dispatch");
+
262}
+
263
+
264void DbcParserTest::independentSessions() {
+
265 Fixture fixture;
+
266 const DbcParser parser;
+
267 fixture.Write("BO_ 1 First: 8 ECU\n");
+
268 CHECK(parser.ParseFile(fixture.path.string()).frames.size() == 1U, "First parse");
+
269 fixture.Write("SG_ Speed : invalid\n");
+
270 try {
+
271 parser.ParseFile(fixture.path.string());
+
272 CHECK(false, "Independent parse context");
+
273 } catch (const std::runtime_error &error) {
+
274 CHECK(std::string(error.what()).find("Signal found before any frame") !=
+
275 std::string::npos,
+
276 "Independent parse context");
+
277 }
+
278 fixture.Write("BO_ 2 Second: 8 ECU\n");
+
279 const auto recovered = parser.ParseFile(fixture.path.string());
+
280 CHECK(recovered.frames.size() == 1U && recovered.frames[0].canId == 2U,
+
281 "Fresh parse after error");
+
282}
+
283
+
284int RunParserTests(int argc, char **argv) {
+
285 DbcParserTest tests;
+
286 return QTest::qExec(&tests, argc, argv);
+
287}
+
288
+
289#include "dbc_parser_test.moc"
Minimal DBC parser.
Definition dbc_parser.h:33
DbcDatabase ParseFile(const std::string &filePath) const
Parse DBC file.
diff --git a/docs/html/dbc__statement__handler_8cpp_source.html b/docs/html/dbc__statement__handler_8cpp_source.html index 30ee562..b59fda7 100644 --- a/docs/html/dbc__statement__handler_8cpp_source.html +++ b/docs/html/dbc__statement__handler_8cpp_source.html @@ -450,7 +450,7 @@ $(document).ready(function(){initNavTree('dbc__statement__handler_8cpp_source.ht diff --git a/docs/html/dbc__statement__handler_8h_source.html b/docs/html/dbc__statement__handler_8h_source.html index a441043..52949e7 100644 --- a/docs/html/dbc__statement__handler_8h_source.html +++ b/docs/html/dbc__statement__handler_8h_source.html @@ -191,7 +191,7 @@ $(document).ready(function(){initNavTree('dbc__statement__handler_8h_source.html diff --git a/docs/html/dbc__tree__builder_8cpp.html b/docs/html/dbc__tree__builder_8cpp.html index 849ccf2..f4a1ec9 100644 --- a/docs/html/dbc__tree__builder_8cpp.html +++ b/docs/html/dbc__tree__builder_8cpp.html @@ -109,7 +109,7 @@ $(document).ready(function(){initNavTree('dbc__tree__builder_8cpp.html',''); ini diff --git a/docs/html/dbc__tree__builder_8cpp_source.html b/docs/html/dbc__tree__builder_8cpp_source.html index ae63936..a62c3d5 100644 --- a/docs/html/dbc__tree__builder_8cpp_source.html +++ b/docs/html/dbc__tree__builder_8cpp_source.html @@ -133,7 +133,7 @@ $(document).ready(function(){initNavTree('dbc__tree__builder_8cpp_source.html',' diff --git a/docs/html/dbc__tree__builder_8h.html b/docs/html/dbc__tree__builder_8h.html index c6e4f3a..ac29a67 100644 --- a/docs/html/dbc__tree__builder_8h.html +++ b/docs/html/dbc__tree__builder_8h.html @@ -120,7 +120,7 @@ Classes diff --git a/docs/html/dbc__tree__builder_8h_source.html b/docs/html/dbc__tree__builder_8h_source.html index ce1fdc1..4a45bf4 100644 --- a/docs/html/dbc__tree__builder_8h_source.html +++ b/docs/html/dbc__tree__builder_8h_source.html @@ -125,7 +125,7 @@ $(document).ready(function(){initNavTree('dbc__tree__builder_8h_source.html','') diff --git a/docs/html/decode__database_8h.html b/docs/html/decode__database_8h.html index ae4bb6d..1452324 100644 --- a/docs/html/decode__database_8h.html +++ b/docs/html/decode__database_8h.html @@ -200,7 +200,7 @@ Enumerations diff --git a/docs/html/decode__database_8h_source.html b/docs/html/decode__database_8h_source.html index d3094a2..78564d7 100644 --- a/docs/html/decode__database_8h_source.html +++ b/docs/html/decode__database_8h_source.html @@ -227,7 +227,7 @@ $(document).ready(function(){initNavTree('decode__database_8h_source.html',''); diff --git a/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.html b/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.html new file mode 100644 index 0000000..945efa8 --- /dev/null +++ b/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.html @@ -0,0 +1,158 @@ + + + + + + + +DBC Framework: core Directory Reference + + + + + + + + + + + + + +
+
+ + + + + + +
+
DBC Framework +
+
DBC parsing and CAN signal decoding framework
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
core Directory Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Files

 dbc_database.h
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 dbc_decode_builder.cpp
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 dbc_decode_builder.h
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 dbc_decoder.cpp
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 dbc_decoder.h
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 dbc_parser.cpp
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 dbc_parser.h
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 dbc_statement_handler.cpp
 
 dbc_statement_handler.h
 
 dbc_tree_builder.cpp
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 dbc_tree_builder.h
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 decode_database.h
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 frame_info.h
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 signal_info.h
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 tree_node.cpp
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 tree_node.h
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
 typefactory.h
 
+
+
+ + + + diff --git a/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.js b/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.js new file mode 100644 index 0000000..d17885c --- /dev/null +++ b/docs/html/dir_4270bfced15e0e73154b13468c7c9ad9.js @@ -0,0 +1,20 @@ +var dir_4270bfced15e0e73154b13468c7c9ad9 = +[ + [ "dbc_database.h", "dbc__database_8h.html", "dbc__database_8h" ], + [ "dbc_decode_builder.cpp", "dbc__decode__builder_8cpp.html", null ], + [ "dbc_decode_builder.h", "dbc__decode__builder_8h.html", "dbc__decode__builder_8h" ], + [ "dbc_decoder.cpp", "dbc__decoder_8cpp.html", null ], + [ "dbc_decoder.h", "dbc__decoder_8h.html", "dbc__decoder_8h" ], + [ "dbc_parser.cpp", "dbc__parser_8cpp.html", null ], + [ "dbc_parser.h", "dbc__parser_8h.html", "dbc__parser_8h" ], + [ "dbc_statement_handler.cpp", "dbc__statement__handler_8cpp_source.html", null ], + [ "dbc_statement_handler.h", "dbc__statement__handler_8h_source.html", null ], + [ "dbc_tree_builder.cpp", "dbc__tree__builder_8cpp.html", null ], + [ "dbc_tree_builder.h", "dbc__tree__builder_8h.html", "dbc__tree__builder_8h" ], + [ "decode_database.h", "decode__database_8h.html", "decode__database_8h" ], + [ "frame_info.h", "frame__info_8h.html", "frame__info_8h" ], + [ "signal_info.h", "signal__info_8h.html", "signal__info_8h" ], + [ "tree_node.cpp", "tree__node_8cpp.html", null ], + [ "tree_node.h", "tree__node_8h.html", "tree__node_8h" ], + [ "typefactory.h", "typefactory_8h_source.html", null ] +]; \ No newline at end of file diff --git a/docs/html/dir_59425e443f801f1f2fd8bbe4959a3ccf.html b/docs/html/dir_59425e443f801f1f2fd8bbe4959a3ccf.html index c2f6989..e9af6da 100644 --- a/docs/html/dir_59425e443f801f1f2fd8bbe4959a3ccf.html +++ b/docs/html/dir_59425e443f801f1f2fd8bbe4959a3ccf.html @@ -100,6 +100,8 @@ Files    dbc_parser_test.cpp   + main.cpp + 
diff --git a/docs/html/dir_59425e443f801f1f2fd8bbe4959a3ccf.js b/docs/html/dir_59425e443f801f1f2fd8bbe4959a3ccf.js index 0a82aef..9b85d05 100644 --- a/docs/html/dir_59425e443f801f1f2fd8bbe4959a3ccf.js +++ b/docs/html/dir_59425e443f801f1f2fd8bbe4959a3ccf.js @@ -1,5 +1,6 @@ var dir_59425e443f801f1f2fd8bbe4959a3ccf = [ [ "dbc_decoder_test.cpp", "dbc__decoder__test_8cpp_source.html", null ], - [ "dbc_parser_test.cpp", "dbc__parser__test_8cpp_source.html", null ] + [ "dbc_parser_test.cpp", "dbc__parser__test_8cpp_source.html", null ], + [ "tests/main.cpp", "tests_2main_8cpp_source.html", null ] ]; \ No newline at end of file diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html new file mode 100644 index 0000000..97bc21c --- /dev/null +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.html @@ -0,0 +1,113 @@ + + + + + + + +DBC Framework: examples Directory Reference + + + + + + + + + + + + + +
+
+ + + + + + +
+
DBC Framework +
+
DBC parsing and CAN signal decoding framework
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
examples Directory Reference
+
+
+ + + + + +

+Files

 main.cpp
 Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
 
+
+
+ + + + diff --git a/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.js b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.js new file mode 100644 index 0000000..be6e0e7 --- /dev/null +++ b/docs/html/dir_d28a4824dc47e487b107a5db32ef43c4.js @@ -0,0 +1,4 @@ +var dir_d28a4824dc47e487b107a5db32ef43c4 = +[ + [ "main.cpp", "examples_2main_8cpp.html", null ] +]; \ No newline at end of file diff --git a/docs/html/examples_2main_8cpp.html b/docs/html/examples_2main_8cpp.html new file mode 100644 index 0000000..51b7d53 --- /dev/null +++ b/docs/html/examples_2main_8cpp.html @@ -0,0 +1,164 @@ + + + + + + + +DBC Framework: main.cpp File Reference + + + + + + + + + + + + + +
+
+ + + + + + +
+
DBC Framework +
+
DBC parsing and CAN signal decoding framework
+
+
+ + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+ +
main.cpp File Reference
+
+
+ +

Created: 2026-03-13 Author: Deeaitch (Dim. Himro) +More...

+
#include <cstddef>
+#include <iomanip>
+#include <iostream>
+#include <memory>
+#include <vector>
+#include "dbc_decode_builder.h"
+#include "dbc_decoder.h"
+#include "dbc_parser.h"
+#include "dbc_tree_builder.h"
+
+

Go to the source code of this file.

+ + + + +

+Functions

int main (int argc, char *argv[])
 
+

Detailed Description

+

Created: 2026-03-13 Author: Deeaitch (Dim. Himro)

+

Licensed under the MIT License. See LICENSE file in the project root for full license text.

+ +

Definition in file examples/main.cpp.

+

Function Documentation

+ +

◆ main()

+ +
+
+ + + + + + + + + + + + + + + + + + +
int main (int argc,
char * argv[] 
)
+
+ +

Definition at line 101 of file examples/main.cpp.

+ +
+
+
+
+ + + + diff --git a/docs/html/examples_2main_8cpp_source.html b/docs/html/examples_2main_8cpp_source.html new file mode 100644 index 0000000..ba84d7d --- /dev/null +++ b/docs/html/examples_2main_8cpp_source.html @@ -0,0 +1,287 @@ + + + + + + + +DBC Framework: main.cpp Source File + + + + + + + + + + + + + +
+
+ + + + + + +
+
DBC Framework +
+
DBC parsing and CAN signal decoding framework
+
+
+ + + + + + + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+
+
+
+
+
Loading...
+
Searching...
+
No Matches
+
+
+
+
+ +
+
examples/main.cpp
+
+
+Go to the documentation of this file.
1
+
12#include <cstddef>
+
13#include <iomanip>
+
14#include <iostream>
+
15#include <memory>
+
16#include <vector>
+
17
+
18#include "dbc_decode_builder.h"
+
19#include "dbc_decoder.h"
+
20#include "dbc_parser.h"
+
21#include "dbc_tree_builder.h"
+
22
+
23static void PrintTree(const TreeNode *node, int indent) {
+
24 if (node == nullptr)
+
25 return;
+
26
+
27 for (int i = 0; i < indent; ++i)
+
28 std::cout << " ";
+
29
+
30 switch (node->GetType()) {
+
31 case NodeType::Root:
+
32 std::cout << "[root] " << node->GetName() << "\n";
+
33 break;
+
34
+
35 case NodeType::Frame: {
+
36 const FrameInfo *frame = node->GetFrame();
+
37 std::cout << "[frame] " << node->GetName();
+
38
+
39 if (frame != nullptr) {
+
40 std::cout << " id=0x" << std::hex << frame->canId << std::dec
+
41 << " ext=" << (frame->isExtended ? "yes" : "no")
+
42 << " dlc=" << static_cast<unsigned int>(frame->dlc);
+
43
+
44 if (frame->hasPgn)
+
45 std::cout << " pgn=" << frame->pgn;
+
46 }
+
47
+
48 std::cout << "\n";
+
49 break;
+
50 }
+
51
+
52 case NodeType::Signal: {
+
53 const SignalInfo *signal = node->GetSignal();
+
54 std::cout << "[signal] " << node->GetName();
+
55
+
56 if (signal != nullptr) {
+
57 std::cout << " start=" << signal->startBit
+
58 << " len=" << signal->length
+
59 << " unit=" << signal->unit;
+
60 }
+
61
+
62 std::cout << "\n";
+
63 break;
+
64 }
+
65
+
66 default:
+
67 std::cout << "[unknown]\n";
+
68 break;
+
69 }
+
70
+
71 for (std::size_t i = 0U; i < node->GetChildCount(); ++i)
+
72 PrintTree(node->GetChild(i), indent + 1);
+
73}
+
74
+
75static void PrintDecodedFrame(const DecodedFrameValue &decoded) {
+
76 if (!decoded.valid || (decoded.definition == nullptr)) {
+
77 std::cout << "No frame definition found.\n";
+
78 return;
+
79 }
+
80
+
81 std::cout << "Decoded frame: " << decoded.definition->name << "\n";
+
82
+
83 for (std::size_t index = 0U; index < decoded.signals.size(); ++index) {
+
84 const DecodedSignalValue &signal = decoded.signals[index];
+
85
+
86 if ((signal.definition == nullptr) || !signal.valid)
+
87 continue;
+
88
+
89 std::cout << " " << signal.definition->name
+
90 << " raw=";
+
91 if (const auto *signedValue = std::get_if<std::int64_t>(&signal.rawValue))
+
92 std::cout << *signedValue;
+
93 else
+
94 std::cout << std::get<std::uint64_t>(signal.rawValue);
+
95 std::cout << " physical=" << signal.physicalValue
+
96 << " " << signal.definition->unit
+
97 << "\n";
+
98 }
+
99}
+
100
+
101int main(int argc, char *argv[]) {
+
102 if (argc < 2) {
+
103 std::cerr << "Usage: dbc_demo <file.dbc>\n";
+
104 return 1;
+
105 }
+
106
+
107 try {
+
108 DbcParser parser;
+
109 DbcDatabase database = parser.ParseFile(argv[1]);
+
110
+
111 DbcTreeBuilder treeBuilder;
+
112 std::unique_ptr<TreeNode> root = treeBuilder.Build(database);
+
113
+
114 std::cout << "=== Parsed tree ===\n";
+
115 PrintTree(root.get(), 0);
+
116
+
117 DbcDecodeBuilder decodeBuilder;
+
118 DecodeDatabase decodeDatabase = decodeBuilder.Build(database);
+
119
+
120 /*
+
121 * Example raw frame.
+
122 * Replace with live CAN frame or trace record later.
+
123 */
+
124 RawCanFrame rawFrame;
+
125 rawFrame.canId = decodeDatabase.frames.empty() ? 0U : decodeDatabase.frames[0].canId;
+
126 rawFrame.isExtended = decodeDatabase.frames.empty() ? false : decodeDatabase.frames[0].isExtended;
+
127 rawFrame.data.resize(8U, 0U);
+
128
+
129 DbcDecoder decoder;
+
130 DecodedFrameValue decoded = decoder.Decode(decodeDatabase, rawFrame);
+
131
+
132 std::cout << "\n=== Decoded frame ===\n";
+
133 PrintDecodedFrame(decoded);
+
134 } catch (const std::exception &ex) {
+
135 std::cerr << "Error: " << ex.what() << "\n";
+
136 return 2;
+
137 }
+
138
+
139 return 0;
+
140}
+
Converts parsed DBC data into runtime decode database.
+
DecodeDatabase Build(const DbcDatabase &source) const
Build runtime decode database.
+
Runtime CAN decoder using prebuilt decode database.
Definition dbc_decoder.h:64
+
DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
Decode one raw CAN frame.
+
Minimal DBC parser.
Definition dbc_parser.h:33
+
DbcDatabase ParseFile(const std::string &filePath) const
Parse DBC file.
+
Builds a simple tree from parsed DBC database.
+
std::unique_ptr< TreeNode > Build(const DbcDatabase &database) const
Build tree representation of parsed DBC data.
+
Tree node for later use in model/view or other hierarchy consumers.
Definition tree_node.h:35
+
const SignalInfo * GetSignal() const
Get signal payload if node is signal.
Definition tree_node.cpp:61
+
const TreeNode * GetChild(std::size_t index) const
Get child by index.
Definition tree_node.cpp:35
+
const std::string & GetName() const
Get display name.
Definition tree_node.cpp:53
+
std::size_t GetChildCount() const
Get child count.
Definition tree_node.cpp:31
+
NodeType GetType() const
Get node type.
Definition tree_node.cpp:49
+
const FrameInfo * GetFrame() const
Get frame payload if node is frame.
Definition tree_node.cpp:57
+
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
+
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
+
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
+
Created: 2026-03-13 Author: Deeaitch (Dim. Himro)
+
Parsed DBC content stored in a simple internal form.
+
Runtime decode database with fast lookup by CAN ID.
+
std::string name
+
std::string unit
+
std::string name
+
Fully decoded frame.
Definition dbc_decoder.h:51
+ +
const DecodeFrame * definition
Definition dbc_decoder.h:52
+
One decoded signal value.
Definition dbc_decoder.h:37
+ +
std::variant< std::int64_t, std::uint64_t > rawValue
Definition dbc_decoder.h:39
+ +
const DecodeSignal * definition
Definition dbc_decoder.h:38
+
Describes one CAN frame from a DBC file.
Definition frame_info.h:24
+
bool isExtended
Definition frame_info.h:27
+
bool hasPgn
Definition frame_info.h:29
+
std::uint8_t dlc
Definition frame_info.h:30
+
std::uint32_t pgn
Definition frame_info.h:28
+
std::uint32_t canId
Definition frame_info.h:26
+
Raw CAN frame used for runtime or trace decoding.
Definition dbc_decoder.h:24
+
std::vector< std::uint8_t > data
Definition dbc_decoder.h:27
+
std::uint32_t canId
Definition dbc_decoder.h:25
+
bool isExtended
Definition dbc_decoder.h:26
+
Describes one signal inside a DBC frame.
Definition signal_info.h:22
+
std::uint32_t length
Definition signal_info.h:25
+
std::string unit
Definition signal_info.h:32
+
std::uint32_t startBit
Definition signal_info.h:24
+
+
+ + + + diff --git a/docs/html/files.html b/docs/html/files.html index 504e139..3036d8c 100644 --- a/docs/html/files.html +++ b/docs/html/files.html @@ -95,27 +95,30 @@ $(document).ready(function(){initNavTree('files.html',''); initResizable(); });
Here is a list of all documented files with brief descriptions:
[detail level 12]
- - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + +
 ▼ tests
 dbc_decoder_test.cpp
 dbc_parser_test.cpp
 dbc_database.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_decode_builder.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_decode_builder.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_decoder.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_decoder.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_parser.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_parser.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_statement_handler.cpp
 dbc_statement_handler.h
 dbc_tree_builder.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_tree_builder.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 decode_database.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 frame_info.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 main.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 signal_info.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 tree_node.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 tree_node.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 typefactory.h
 ▼ core
 dbc_database.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_decode_builder.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_decode_builder.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_decoder.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_decoder.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_parser.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_parser.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_statement_handler.cpp
 dbc_statement_handler.h
 dbc_tree_builder.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 dbc_tree_builder.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 decode_database.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 frame_info.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 signal_info.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 tree_node.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 tree_node.hCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 typefactory.h
 ▼ examples
 main.cppCreated: 2026-03-13 Author: Deeaitch (Dim. Himro)
 ▼ tests
 dbc_decoder_test.cpp
 dbc_parser_test.cpp
 main.cpp
diff --git a/docs/html/files_dup.js b/docs/html/files_dup.js index 928c939..431bb88 100644 --- a/docs/html/files_dup.js +++ b/docs/html/files_dup.js @@ -1,22 +1,6 @@ var files_dup = [ - [ "tests", "dir_59425e443f801f1f2fd8bbe4959a3ccf.html", "dir_59425e443f801f1f2fd8bbe4959a3ccf" ], - [ "dbc_database.h", "dbc__database_8h.html", "dbc__database_8h" ], - [ "dbc_decode_builder.cpp", "dbc__decode__builder_8cpp.html", null ], - [ "dbc_decode_builder.h", "dbc__decode__builder_8h.html", "dbc__decode__builder_8h" ], - [ "dbc_decoder.cpp", "dbc__decoder_8cpp.html", null ], - [ "dbc_decoder.h", "dbc__decoder_8h.html", "dbc__decoder_8h" ], - [ "dbc_parser.cpp", "dbc__parser_8cpp.html", null ], - [ "dbc_parser.h", "dbc__parser_8h.html", "dbc__parser_8h" ], - [ "dbc_statement_handler.cpp", "dbc__statement__handler_8cpp_source.html", null ], - [ "dbc_statement_handler.h", "dbc__statement__handler_8h_source.html", null ], - [ "dbc_tree_builder.cpp", "dbc__tree__builder_8cpp.html", null ], - [ "dbc_tree_builder.h", "dbc__tree__builder_8h.html", "dbc__tree__builder_8h" ], - [ "decode_database.h", "decode__database_8h.html", "decode__database_8h" ], - [ "frame_info.h", "frame__info_8h.html", "frame__info_8h" ], - [ "main.cpp", "main_8cpp.html", null ], - [ "signal_info.h", "signal__info_8h.html", "signal__info_8h" ], - [ "tree_node.cpp", "tree__node_8cpp.html", null ], - [ "tree_node.h", "tree__node_8h.html", "tree__node_8h" ], - [ "typefactory.h", "typefactory_8h_source.html", null ] + [ "core", "dir_4270bfced15e0e73154b13468c7c9ad9.html", "dir_4270bfced15e0e73154b13468c7c9ad9" ], + [ "examples", "dir_d28a4824dc47e487b107a5db32ef43c4.html", "dir_d28a4824dc47e487b107a5db32ef43c4" ], + [ "tests", "dir_59425e443f801f1f2fd8bbe4959a3ccf.html", "dir_59425e443f801f1f2fd8bbe4959a3ccf" ] ]; \ No newline at end of file diff --git a/docs/html/frame__info_8h.html b/docs/html/frame__info_8h.html index c84f4ba..9979bd2 100644 --- a/docs/html/frame__info_8h.html +++ b/docs/html/frame__info_8h.html @@ -121,7 +121,7 @@ Classes diff --git a/docs/html/frame__info_8h_source.html b/docs/html/frame__info_8h_source.html index ed37189..db51f9d 100644 --- a/docs/html/frame__info_8h_source.html +++ b/docs/html/frame__info_8h_source.html @@ -141,7 +141,7 @@ $(document).ready(function(){initNavTree('frame__info_8h_source.html',''); initR diff --git a/docs/html/index.qhp b/docs/html/index.qhp index ca94588..81d2a19 100644 --- a/docs/html/index.qhp +++ b/docs/html/index.qhp @@ -87,8 +87,9 @@
-
-
+
+
+
@@ -249,10 +250,7 @@
-
-
-
-
+
@@ -355,8 +353,6 @@
-
-
@@ -396,6 +392,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -429,7 +435,7 @@ - + @@ -576,10 +582,14 @@ dbc__tree__builder_8h_source.html decode__database_8h.html decode__database_8h_source.html +dir_4270bfced15e0e73154b13468c7c9ad9.html dir_59425e443f801f1f2fd8bbe4959a3ccf.html +dir_d28a4824dc47e487b107a5db32ef43c4.html doxygen.css doxygen.svg dynsections.js +examples_2main_8cpp.html +examples_2main_8cpp_source.html files.html frame__info_8h.html frame__info_8h_source.html @@ -615,8 +625,6 @@ inherit_graph_9.svg inherits.html jquery.js -main_8cpp.html -main_8cpp_source.html md_README.html md_tests_2README.html menu.js @@ -638,6 +646,7 @@ search/all_15.js search/all_16.js search/all_17.js +search/all_18.js search/all_2.js search/all_3.js search/all_4.js @@ -685,6 +694,7 @@ search/pages_3.js search/pages_4.js search/pages_5.js +search/pages_6.js search/search.css search/search.js search/searchdata.js @@ -744,6 +754,7 @@ tab_s.png tab_sd.png tabs.css +tests_2main_8cpp_source.html tree__node_8cpp.html tree__node_8cpp_source.html tree__node_8h.html diff --git a/docs/html/md_README.html b/docs/html/md_README.html index ed88b20..c258ca2 100644 --- a/docs/html/md_README.html +++ b/docs/html/md_README.html @@ -233,7 +233,7 @@ Parser Demo

File:

Used as a small integration example.


@@ -797,7 +797,15 @@ Build Integration
  • qmake
  • Makefile
  • -

    Just add the source files to the project.

    +

    Open dbc.pro in Qt Creator to see two subprojects: core and tests. core/core.pro builds the C++17 static library dbc_core without a Qt dependency. tests/tests.pro builds the QtTest executable dbc_tests and links that library. The root project declares tests.depends = core for parallel builds.

    +

    Build out of source (Qt 6; use qmake for Qt 5):

    +
    mkdir build
    +
    cd build
    +
    qmake6 ../dbc.pro
    +
    make -j
    +
    make check
    +

    core/core_files.pri lists the library sources and headers. Consumers include core/core.pri for include paths and library linkage; the test source lists live in tests/parser_tests.pri and tests/decoder_tests.pri. When building a consumer separately, pass DBC_CORE_BUILD_DIR=/absolute/path/to/build/core to qmake.

    +

    The former demonstration program is preserved in examples/main.cpp with examples/demo.pro. Build it separately after building core, using that same DBC_CORE_BUILD_DIR option; run dbc_demo <file.dbc>.


    Summary

    @@ -826,7 +834,7 @@ Runtime decode representation

    This gives FrameTap a much better foundation for real use, because both browsing and decoding are supported without forcing one representation to do the other's job.

    Regression tests

    -

    See tests/README.md for compiler and qmake commands. Tests cover frame validation and error locations, Intel and Motorola extraction, signed and unsigned 64-bit boundaries, physical conversion, numeric output, and invalid signal payloads.

    +

    See tests/README.md for QtTest build and execution commands. Tests cover frame validation and error locations, Intel and Motorola extraction, signed and unsigned 64-bit boundaries, physical conversion, numeric output, and invalid signal payloads.

    diff --git a/docs/html/md_tests_2README.html b/docs/html/md_tests_2README.html index 7f4221b..b685c0b 100644 --- a/docs/html/md_tests_2README.html +++ b/docs/html/md_tests_2README.html @@ -5,7 +5,7 @@ -DBC Framework: Decoder regression tests +DBC Framework: QtTest regression tests @@ -90,28 +90,30 @@ $(document).ready(function(){initNavTree('md_tests_2README.html',''); initResiza
    -
    Decoder regression tests
    +
    QtTest regression tests
    -

    Run from the repository root with a C++17 compiler:

    -
    g++ -std=c++17 -Wall -Wextra -Wpedantic -I. \
    -
    tests/dbc_decoder_test.cpp dbc_decoder.cpp -o /tmp/dbc_decoder_test
    -
    /tmp/dbc_decoder_test
    -

    Alternatively, build the standalone qmake project out of source:

    -
    mkdir -p /tmp/dbc_decoder_test_build
    -
    cd /tmp/dbc_decoder_test_build
    -
    qmake /absolute/path/to/dbc/tests/dbc_decoder_test.pro
    +

    Open the repository's root dbc.pro in Qt Creator. It contains core (a static C++17 library) and tests (the dbc_tests QtTest executable). Core is built first; tests link its archive rather than compiling its implementation again. Qt Core and Qt Test development packages are required for tests only.

    +

    Build from the repository root with Qt 6 (use qmake for Qt 5):

    +
    mkdir build
    +
    cd build
    +
    qmake6 ../dbc.pro
    +
    make -j
    +
    make check
    +

    Or run ./tests/dbc_tests directly. Both parser and decoder suites run, and the executable returns nonzero when either suite fails. Decoder cases appear as individual QtTest data rows; parser checks are grouped into named test slots. Checks also run in release builds.

    +

    To build tests separately against an existing core build:

    +
    mkdir /tmp/dbc-tests-build
    +
    cd /tmp/dbc-tests-build
    +
    qmake6 /absolute/path/to/dbc/tests/tests.pro \
    +
    DBC_CORE_BUILD_DIR=/absolute/path/to/build/core
    make
    -
    ./dbc_decoder_test
    -

    The executable returns a nonzero exit code if any case fails. Checks remain active in release builds and do not depend on assert or an external test framework.

    -

    Coverage includes Motorola bit numbering within and across bytes, unaligned signals, signed values, scaling, 64-bit extraction, signed/unsigned boundary values (including INT64_MIN, INT64_MAX, and UINT64_MAX), numeric output, invalid lengths, insufficient payloads, and Intel regression cases. Frame validity means the definition was found; insufficient payloads are checked through signal validity.

    +
    make check
    +

    parser_tests.pri and decoder_tests.pri include the test sources. ../core/core.pri supplies the library include path and linkage.

    -Parser regression tests

    -

    Run from the repository root:

    -
    g++ -std=c++17 -Wall -Wextra -Wpedantic -Werror -I. \
    -
    tests/dbc_parser_test.cpp dbc_parser.cpp dbc_statement_handler.cpp -o /tmp/dbc_parser_test
    -
    /tmp/dbc_parser_test
    -

    For qmake, use tests/dbc_parser_test.pro in a separate build directory, following the decoder instructions above, then run ./dbc_parser_test.

    +Decoder coverage +

    Coverage includes Motorola bit numbering within and across bytes, unaligned signals, signed values, scaling, 64-bit extraction, signed/unsigned boundary values (including INT64_MIN, INT64_MAX, and UINT64_MAX), numeric output, invalid lengths, insufficient payloads, and Intel regression cases. Frame validity means the definition was found; insufficient payloads are checked through signal validity.

    +

    +Parser coverage

    Parser tests cover standard and extended CAN IDs, whitespace, payload storage boundaries, missing fields, malformed and overflowing numbers, reserved ID bits, error paths and line numbers, and integration with signals and comments. 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. Temporary DBC fixtures are created in the system temporary directory and removed automatically.

    Dispatch tests also verify exact keyword matching, handler construction and reuse, unknown statements, and independent parsing sessions, including recovery after errors.

    diff --git a/docs/html/navtreedata.js b/docs/html/navtreedata.js index 708351d..6eee946 100644 --- a/docs/html/navtreedata.js +++ b/docs/html/navtreedata.js @@ -100,8 +100,9 @@ var NAVTREE = ] ], [ "Regression tests", "md_README.html#autotoc_md103", null ] ] ], - [ "Decoder regression tests", "md_tests_2README.html", [ - [ "Parser regression tests", "md_tests_2README.html#autotoc_md105", null ] + [ "QtTest regression tests", "md_tests_2README.html", [ + [ "Decoder coverage", "md_tests_2README.html#autotoc_md105", null ], + [ "Parser coverage", "md_tests_2README.html#autotoc_md106", null ] ] ], [ "Classes", "annotated.html", [ [ "Class List", "annotated.html", "annotated_dup" ], diff --git a/docs/html/navtreeindex0.js b/docs/html/navtreeindex0.js index d0c794a..7ffdbef 100644 --- a/docs/html/navtreeindex0.js +++ b/docs/html/navtreeindex0.js @@ -34,40 +34,44 @@ var NAVTREEINDEX0 = "classTypeFactory.html#ad6d85795285ee21193ac03e1b24762d3":[2,0,22,0], "classTypeFactory.html#ad82f537569ece3d3a4a376523fa94473":[2,0,22,1], "classes.html":[2,1], -"dbc__database_8h.html":[3,0,1], -"dbc__database_8h_source.html":[3,0,1], -"dbc__decode__builder_8cpp.html":[3,0,2], -"dbc__decode__builder_8cpp_source.html":[3,0,2], -"dbc__decode__builder_8h.html":[3,0,3], -"dbc__decode__builder_8h_source.html":[3,0,3], -"dbc__decoder_8cpp.html":[3,0,4], -"dbc__decoder_8cpp_source.html":[3,0,4], -"dbc__decoder_8h.html":[3,0,5], -"dbc__decoder_8h_source.html":[3,0,5], -"dbc__decoder__test_8cpp_source.html":[3,0,0,0], -"dbc__parser_8cpp.html":[3,0,6], -"dbc__parser_8cpp_source.html":[3,0,6], -"dbc__parser_8h.html":[3,0,7], -"dbc__parser_8h_source.html":[3,0,7], -"dbc__parser__test_8cpp_source.html":[3,0,0,1], -"dbc__statement__handler_8cpp_source.html":[3,0,8], -"dbc__statement__handler_8h_source.html":[3,0,9], -"dbc__tree__builder_8cpp.html":[3,0,10], -"dbc__tree__builder_8cpp_source.html":[3,0,10], -"dbc__tree__builder_8h.html":[3,0,11], -"dbc__tree__builder_8h_source.html":[3,0,11], -"decode__database_8h.html":[3,0,12], -"decode__database_8h.html#aaeb92d42f5a6e27b8ba19f18d69d142b":[3,0,12,5], -"decode__database_8h.html#aaeb92d42f5a6e27b8ba19f18d69d142ba2ed1afe3c9215523e4272f46e6186b31":[3,0,12,5,1], -"decode__database_8h.html#aaeb92d42f5a6e27b8ba19f18d69d142baff97a9fdede09eaf6e1c8ec9f6a61dd5":[3,0,12,5,0], -"decode__database_8h.html#ad9971b6ef33e02ba2c75d19c1d2518a1":[3,0,12,6], -"decode__database_8h.html#ad9971b6ef33e02ba2c75d19c1d2518a1a71fed0c3428bf1a2e19af257c4bac379":[3,0,12,6,1], -"decode__database_8h.html#ad9971b6ef33e02ba2c75d19c1d2518a1aa1a914735b205424ba6c40b85528d78a":[3,0,12,6,0], -"decode__database_8h_source.html":[3,0,12], -"dir_59425e443f801f1f2fd8bbe4959a3ccf.html":[3,0,0], +"dbc__database_8h.html":[3,0,0,0], +"dbc__database_8h_source.html":[3,0,0,0], +"dbc__decode__builder_8cpp.html":[3,0,0,1], +"dbc__decode__builder_8cpp_source.html":[3,0,0,1], +"dbc__decode__builder_8h.html":[3,0,0,2], +"dbc__decode__builder_8h_source.html":[3,0,0,2], +"dbc__decoder_8cpp.html":[3,0,0,3], +"dbc__decoder_8cpp_source.html":[3,0,0,3], +"dbc__decoder_8h.html":[3,0,0,4], +"dbc__decoder_8h_source.html":[3,0,0,4], +"dbc__decoder__test_8cpp_source.html":[3,0,2,0], +"dbc__parser_8cpp.html":[3,0,0,5], +"dbc__parser_8cpp_source.html":[3,0,0,5], +"dbc__parser_8h.html":[3,0,0,6], +"dbc__parser_8h_source.html":[3,0,0,6], +"dbc__parser__test_8cpp_source.html":[3,0,2,1], +"dbc__statement__handler_8cpp_source.html":[3,0,0,7], +"dbc__statement__handler_8h_source.html":[3,0,0,8], +"dbc__tree__builder_8cpp.html":[3,0,0,9], +"dbc__tree__builder_8cpp_source.html":[3,0,0,9], +"dbc__tree__builder_8h.html":[3,0,0,10], +"dbc__tree__builder_8h_source.html":[3,0,0,10], +"decode__database_8h.html":[3,0,0,11], +"decode__database_8h.html#aaeb92d42f5a6e27b8ba19f18d69d142b":[3,0,0,11,5], +"decode__database_8h.html#aaeb92d42f5a6e27b8ba19f18d69d142ba2ed1afe3c9215523e4272f46e6186b31":[3,0,0,11,5,1], +"decode__database_8h.html#aaeb92d42f5a6e27b8ba19f18d69d142baff97a9fdede09eaf6e1c8ec9f6a61dd5":[3,0,0,11,5,0], +"decode__database_8h.html#ad9971b6ef33e02ba2c75d19c1d2518a1":[3,0,0,11,6], +"decode__database_8h.html#ad9971b6ef33e02ba2c75d19c1d2518a1a71fed0c3428bf1a2e19af257c4bac379":[3,0,0,11,6,1], +"decode__database_8h.html#ad9971b6ef33e02ba2c75d19c1d2518a1aa1a914735b205424ba6c40b85528d78a":[3,0,0,11,6,0], +"decode__database_8h_source.html":[3,0,0,11], +"dir_4270bfced15e0e73154b13468c7c9ad9.html":[3,0,0], +"dir_59425e443f801f1f2fd8bbe4959a3ccf.html":[3,0,2], +"dir_d28a4824dc47e487b107a5db32ef43c4.html":[3,0,1], +"examples_2main_8cpp.html":[3,0,1,0], +"examples_2main_8cpp_source.html":[3,0,1,0], "files.html":[3,0], -"frame__info_8h.html":[3,0,13], -"frame__info_8h_source.html":[3,0,13], +"frame__info_8h.html":[3,0,0,12], +"frame__info_8h_source.html":[3,0,0,12], "functions.html":[2,3,0], "functions_func.html":[2,3,1], "functions_vars.html":[2,3,2], @@ -75,8 +79,6 @@ var NAVTREEINDEX0 = "globals_enum.html":[3,1,1], "hierarchy.html":[2,2], "index.html":[], -"main_8cpp.html":[3,0,14], -"main_8cpp_source.html":[3,0,14], "md_README.html":[0], "md_README.html#autotoc_md1":[0,0], "md_README.html#autotoc_md10":[0,3,0], @@ -145,9 +147,10 @@ var NAVTREEINDEX0 = "md_README.html#autotoc_md98":[0,43], "md_tests_2README.html":[1], "md_tests_2README.html#autotoc_md105":[1,0], +"md_tests_2README.html#autotoc_md106":[1,1], "pages.html":[], -"signal__info_8h.html":[3,0,15], -"signal__info_8h_source.html":[3,0,15], +"signal__info_8h.html":[3,0,0,13], +"signal__info_8h_source.html":[3,0,0,13], "structDbcDatabase.html":[2,0,1], "structDbcDatabase.html#a2cade5d0234ee816132127542f8c612b":[2,0,1,0], "structDbcParseContext.html":[2,0,5], @@ -213,13 +216,14 @@ var NAVTREEINDEX0 = "structSignalInfo.html#adf1c4331b9eabced0d7fdda40ff0eb52":[2,0,20,8], "structSignalInfo.html#ae4f78d99a2750aa564d7eba860171499":[2,0,20,5], "structSignalInfo.html#af363b1563fb4c7cc8973f9a80c06846c":[2,0,20,3], -"tree__node_8cpp.html":[3,0,16], -"tree__node_8cpp_source.html":[3,0,16], -"tree__node_8h.html":[3,0,17], -"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16":[3,0,17,1], -"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16a085fea7abdc5d904fe69a3081efd7398":[3,0,17,1,2], -"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16a3bb3e8c8a24891ba0f7608bcc96f8b0a":[3,0,17,1,1], -"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16afa03eb688ad8aa1db593d33dabd89bad":[3,0,17,1,0], -"tree__node_8h_source.html":[3,0,17], -"typefactory_8h_source.html":[3,0,18] +"tests_2main_8cpp_source.html":[3,0,2,2], +"tree__node_8cpp.html":[3,0,0,14], +"tree__node_8cpp_source.html":[3,0,0,14], +"tree__node_8h.html":[3,0,0,15], +"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16":[3,0,0,15,1], +"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16a085fea7abdc5d904fe69a3081efd7398":[3,0,0,15,1,2], +"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16a3bb3e8c8a24891ba0f7608bcc96f8b0a":[3,0,0,15,1,1], +"tree__node_8h.html#acac9cbaeea226ed297804c012dc12b16afa03eb688ad8aa1db593d33dabd89bad":[3,0,0,15,1,0], +"tree__node_8h_source.html":[3,0,0,15], +"typefactory_8h_source.html":[3,0,0,16] }; diff --git a/docs/html/pages.html b/docs/html/pages.html index 7ff3f5b..4d8961b 100644 --- a/docs/html/pages.html +++ b/docs/html/pages.html @@ -96,7 +96,7 @@ $(document).ready(function(){initNavTree('pages.html',''); initResizable(); });
    Here is a list of all related documentation pages:
    diff --git a/docs/html/search/all_11.js b/docs/html/search/all_11.js index d8201e6..e2bb34c 100644 --- a/docs/html/search/all_11.js +++ b/docs/html/search/all_11.js @@ -9,7 +9,7 @@ var searchData= ['parsefile_6',['ParseFile',['../classDbcParser.html#aef72826942c9095d653fafa435855e56',1,'DbcParser']]], ['parser_7',['Parser',['../md_README.html#autotoc_md14',1,'']]], ['parser_20and_20runtime_20decode_20module_20documentation_8',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], - ['parser_20regression_20tests_9',['Parser regression tests',['../md_tests_2README.html#autotoc_md105',1,'']]], + ['parser_20coverage_9',['Parser coverage',['../md_tests_2README.html#autotoc_md106',1,'']]], ['parser_20support_10',['Parser Support',['../md_README.html#autotoc_md53',1,'']]], ['path_11',['path',['../md_README.html#autotoc_md4',1,'1. Parse and UI path'],['../md_README.html#autotoc_md5',1,'2. Runtime decode path'],['../md_README.html#autotoc_md81',1,'live path'],['../md_README.html#autotoc_md82',1,'trace path']]], ['pgn_12',['pgn',['../structFrameInfo.html#aee518b33f1000bf0b7f6e4a87474c943',1,'FrameInfo::pgn'],['../structDecodeFrame.html#a1d3c54055c0cbceb73adf551f7067f23',1,'DecodeFrame::pgn']]], diff --git a/docs/html/search/all_12.js b/docs/html/search/all_12.js index 22a67d1..8b9b038 100644 --- a/docs/html/search/all_12.js +++ b/docs/html/search/all_12.js @@ -1,22 +1,4 @@ var searchData= [ - ['raw_20frame_0',['Decode a raw frame',['../md_README.html#autotoc_md78',1,'']]], - ['raw_20value_20representation_20and_20precision_1',['Raw value representation and precision',['../md_README.html#autotoc_md47',1,'']]], - ['rawcanframe_2',['RawCanFrame',['../structRawCanFrame.html',1,'']]], - ['rawcanframe_20tt_3',['<tt>RawCanFrame</tt>',['../md_README.html#autotoc_md43',1,'']]], - ['rawvalue_4',['rawValue',['../structDecodedSignalValue.html#a95db4f7f93b5f311e8f272833e45055e',1,'DecodedSignalValue']]], - ['receivers_5',['receivers',['../structDecodeSignal.html#abdbae62a64d2df716bf60c6b67b30eaa',1,'DecodeSignal::receivers'],['../structSignalInfo.html#a2c95562fd0b29327a7fd7b1e6feee7f3',1,'SignalInfo::receivers']]], - ['recommended_20next_20steps_6',['Recommended Next Steps',['../md_README.html#autotoc_md92',1,'']]], - ['registertype_7',['registerType',['../classTypeFactory.html#ad6d85795285ee21193ac03e1b24762d3',1,'TypeFactory']]], - ['regression_20tests_8',['regression tests',['../md_tests_2README.html',1,'Decoder regression tests'],['../md_tests_2README.html#autotoc_md105',1,'Parser regression tests'],['../md_README.html#autotoc_md103',1,'Regression tests']]], - ['representation_9',['representation',['../md_README.html#autotoc_md101',1,'Parsed representation'],['../md_README.html#autotoc_md102',1,'Runtime decode representation']]], - ['representation_20and_20precision_10',['Raw value representation and precision',['../md_README.html#autotoc_md47',1,'']]], - ['runtime_20decode_20database_11',['Build runtime decode database',['../md_README.html#autotoc_md77',1,'']]], - ['runtime_20decode_20layer_12',['Runtime Decode Layer',['../md_README.html#autotoc_md27',1,'']]], - ['runtime_20decode_20layer_20exists_13',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md7',1,'']]], - ['runtime_20decode_20module_20documentation_14',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], - ['runtime_20decode_20path_15',['2. Runtime decode path',['../md_README.html#autotoc_md5',1,'']]], - ['runtime_20decode_20representation_16',['Runtime decode representation',['../md_README.html#autotoc_md102',1,'']]], - ['runtime_20decode_20structures_17',['Runtime decode structures',['../md_README.html#autotoc_md12',1,'']]], - ['runtime_20decoder_18',['Runtime decoder',['../md_README.html#autotoc_md13',1,'']]] + ['qttest_20regression_20tests_0',['QtTest regression tests',['../md_tests_2README.html',1,'']]] ]; diff --git a/docs/html/search/all_13.js b/docs/html/search/all_13.js index 586734f..9cf117e 100644 --- a/docs/html/search/all_13.js +++ b/docs/html/search/all_13.js @@ -1,21 +1,22 @@ var searchData= [ - ['signal_20definition_0',['Signal definition',['../md_README.html#autotoc_md60',1,'']]], - ['signal_20validation_20and_20parse_20errors_1',['Signal validation and parse errors',['../md_README.html#autotoc_md62',1,'']]], - ['signal_5finfo_2eh_2',['signal_info.h',['../signal__info_8h.html',1,'']]], - ['signalinfo_3',['SignalInfo',['../structSignalInfo.html',1,'']]], - ['signalinfo_20tt_4',['<tt>SignalInfo</tt>',['../md_README.html#autotoc_md18',1,'']]], - ['stage_201_20already_20implemented_5',['Stage 1 - already implemented',['../md_README.html#autotoc_md93',1,'']]], - ['stage_202_6',['Stage 2',['../md_README.html#autotoc_md94',1,'']]], - ['stage_203_7',['Stage 3',['../md_README.html#autotoc_md95',1,'']]], - ['stage_204_8',['Stage 4',['../md_README.html#autotoc_md96',1,'']]], - ['startbit_9',['startbit',['../structSignalInfo.html#ace290724f9801521609aedaa946d61f1',1,'SignalInfo::startBit'],['../structDecodeSignal.html#aaf5d7527ddf65b6355c2b4f3626df22d',1,'DecodeSignal::startBit']]], - ['statement_20handler_20factory_10',['Statement Handler Factory',['../md_README.html#autotoc_md88',1,'']]], - ['steps_11',['Recommended Next Steps',['../md_README.html#autotoc_md92',1,'']]], - ['strategy_12',['Unified Decode Strategy',['../md_README.html#autotoc_md80',1,'']]], - ['structures_13',['structures',['../md_README.html#autotoc_md17',1,'Parsed Data Structures'],['../md_README.html#autotoc_md10',1,'Parsed DBC structures'],['../md_README.html#autotoc_md12',1,'Runtime decode structures'],['../md_README.html#autotoc_md11',1,'UI tree structures']]], - ['summary_14',['Summary',['../md_README.html#autotoc_md100',1,'']]], - ['support_15',['Parser Support',['../md_README.html#autotoc_md53',1,'']]], - ['supported_20dbc_20syntax_16',['Supported DBC Syntax',['../md_README.html#autotoc_md55',1,'']]], - ['syntax_17',['Supported DBC Syntax',['../md_README.html#autotoc_md55',1,'']]] + ['raw_20frame_0',['Decode a raw frame',['../md_README.html#autotoc_md78',1,'']]], + ['raw_20value_20representation_20and_20precision_1',['Raw value representation and precision',['../md_README.html#autotoc_md47',1,'']]], + ['rawcanframe_2',['RawCanFrame',['../structRawCanFrame.html',1,'']]], + ['rawcanframe_20tt_3',['<tt>RawCanFrame</tt>',['../md_README.html#autotoc_md43',1,'']]], + ['rawvalue_4',['rawValue',['../structDecodedSignalValue.html#a95db4f7f93b5f311e8f272833e45055e',1,'DecodedSignalValue']]], + ['receivers_5',['receivers',['../structDecodeSignal.html#abdbae62a64d2df716bf60c6b67b30eaa',1,'DecodeSignal::receivers'],['../structSignalInfo.html#a2c95562fd0b29327a7fd7b1e6feee7f3',1,'SignalInfo::receivers']]], + ['recommended_20next_20steps_6',['Recommended Next Steps',['../md_README.html#autotoc_md92',1,'']]], + ['registertype_7',['registerType',['../classTypeFactory.html#ad6d85795285ee21193ac03e1b24762d3',1,'TypeFactory']]], + ['regression_20tests_8',['regression tests',['../md_tests_2README.html',1,'QtTest regression tests'],['../md_README.html#autotoc_md103',1,'Regression tests']]], + ['representation_9',['representation',['../md_README.html#autotoc_md101',1,'Parsed representation'],['../md_README.html#autotoc_md102',1,'Runtime decode representation']]], + ['representation_20and_20precision_10',['Raw value representation and precision',['../md_README.html#autotoc_md47',1,'']]], + ['runtime_20decode_20database_11',['Build runtime decode database',['../md_README.html#autotoc_md77',1,'']]], + ['runtime_20decode_20layer_12',['Runtime Decode Layer',['../md_README.html#autotoc_md27',1,'']]], + ['runtime_20decode_20layer_20exists_13',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md7',1,'']]], + ['runtime_20decode_20module_20documentation_14',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], + ['runtime_20decode_20path_15',['2. Runtime decode path',['../md_README.html#autotoc_md5',1,'']]], + ['runtime_20decode_20representation_16',['Runtime decode representation',['../md_README.html#autotoc_md102',1,'']]], + ['runtime_20decode_20structures_17',['Runtime decode structures',['../md_README.html#autotoc_md12',1,'']]], + ['runtime_20decoder_18',['Runtime decoder',['../md_README.html#autotoc_md13',1,'']]] ]; diff --git a/docs/html/search/all_14.js b/docs/html/search/all_14.js index 6705832..586734f 100644 --- a/docs/html/search/all_14.js +++ b/docs/html/search/all_14.js @@ -1,32 +1,21 @@ var searchData= [ - ['tests_0',['tests',['../md_tests_2README.html',1,'Decoder regression tests'],['../md_tests_2README.html#autotoc_md105',1,'Parser regression tests'],['../md_README.html#autotoc_md103',1,'Regression tests']]], - ['the_20runtime_20decode_20layer_20exists_1',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md7',1,'']]], - ['the_20tree_20is_20not_20enough_2',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md86',1,'']]], - ['trace_20path_3',['trace path',['../md_README.html#autotoc_md82',1,'']]], - ['transmitter_4',['transmitter',['../structFrameInfo.html#a92749ec3798d4211a505860fb389a9e8',1,'FrameInfo::transmitter'],['../structDecodeFrame.html#ad78241dc40c793aabb8495b6989b81a9',1,'DecodeFrame::transmitter']]], - ['tree_5',['Build UI tree',['../md_README.html#autotoc_md76',1,'']]], - ['tree_20is_20not_20enough_6',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md86',1,'']]], - ['tree_20layer_7',['UI Tree Layer',['../md_README.html#autotoc_md24',1,'']]], - ['tree_20structures_8',['UI tree structures',['../md_README.html#autotoc_md11',1,'']]], - ['tree_5fnode_2ecpp_9',['tree_node.cpp',['../tree__node_8cpp.html',1,'']]], - ['tree_5fnode_2eh_10',['tree_node.h',['../tree__node_8h.html',1,'']]], - ['treenode_11',['treenode',['../classTreeNode.html#a984a98d5ccf7ef1f5a18094c6821f35d',1,'TreeNode::TreeNode()'],['../classTreeNode.html#a8e38dd591d8801d7ee3a7dbad90c67fc',1,'TreeNode::TreeNode(const FrameInfo &frame)'],['../classTreeNode.html#ab9f00f5253d56461bb2d420fd639c5ae',1,'TreeNode::TreeNode(const SignalInfo &signal)'],['../classTreeNode.html',1,'TreeNode']]], - ['treenode_20tt_12',['<tt>TreeNode</tt>',['../md_README.html#autotoc_md25',1,'']]], - ['tt_20byteorder_20tt_13',['<tt>ByteOrder</tt>',['../md_README.html#autotoc_md30',1,'']]], - ['tt_20dbcdatabase_20tt_14',['<tt>DbcDatabase</tt>',['../md_README.html#autotoc_md22',1,'']]], - ['tt_20dbcdecoder_20tt_15',['<tt>DbcDecoder</tt>',['../md_README.html#autotoc_md51',1,'']]], - ['tt_20decodedatabase_20tt_16',['<tt>DecodeDatabase</tt>',['../md_README.html#autotoc_md40',1,'']]], - ['tt_20decodedframevalue_20tt_17',['<tt>DecodedFrameValue</tt>',['../md_README.html#autotoc_md49',1,'']]], - ['tt_20decodedsignalvalue_20tt_18',['<tt>DecodedSignalValue</tt>',['../md_README.html#autotoc_md45',1,'']]], - ['tt_20decodeframe_20tt_19',['<tt>DecodeFrame</tt>',['../md_README.html#autotoc_md36',1,'']]], - ['tt_20decodesignal_20tt_20',['<tt>DecodeSignal</tt>',['../md_README.html#autotoc_md34',1,'']]], - ['tt_20frameinfo_20tt_21',['<tt>FrameInfo</tt>',['../md_README.html#autotoc_md20',1,'']]], - ['tt_20framekey_20tt_22',['<tt>FrameKey</tt>',['../md_README.html#autotoc_md38',1,'']]], - ['tt_20rawcanframe_20tt_23',['<tt>RawCanFrame</tt>',['../md_README.html#autotoc_md43',1,'']]], - ['tt_20signalinfo_20tt_24',['<tt>SignalInfo</tt>',['../md_README.html#autotoc_md18',1,'']]], - ['tt_20treenode_20tt_25',['<tt>TreeNode</tt>',['../md_README.html#autotoc_md25',1,'']]], - ['tt_20valuetype_20tt_26',['<tt>ValueType</tt>',['../md_README.html#autotoc_md32',1,'']]], - ['typefactory_27',['TypeFactory',['../classTypeFactory.html',1,'']]], - ['typefactory_3c_20std_3a_3astring_2c_20dbcstatementhandler_20_3e_28',['TypeFactory< std::string, DbcStatementHandler >',['../classTypeFactory.html',1,'']]] + ['signal_20definition_0',['Signal definition',['../md_README.html#autotoc_md60',1,'']]], + ['signal_20validation_20and_20parse_20errors_1',['Signal validation and parse errors',['../md_README.html#autotoc_md62',1,'']]], + ['signal_5finfo_2eh_2',['signal_info.h',['../signal__info_8h.html',1,'']]], + ['signalinfo_3',['SignalInfo',['../structSignalInfo.html',1,'']]], + ['signalinfo_20tt_4',['<tt>SignalInfo</tt>',['../md_README.html#autotoc_md18',1,'']]], + ['stage_201_20already_20implemented_5',['Stage 1 - already implemented',['../md_README.html#autotoc_md93',1,'']]], + ['stage_202_6',['Stage 2',['../md_README.html#autotoc_md94',1,'']]], + ['stage_203_7',['Stage 3',['../md_README.html#autotoc_md95',1,'']]], + ['stage_204_8',['Stage 4',['../md_README.html#autotoc_md96',1,'']]], + ['startbit_9',['startbit',['../structSignalInfo.html#ace290724f9801521609aedaa946d61f1',1,'SignalInfo::startBit'],['../structDecodeSignal.html#aaf5d7527ddf65b6355c2b4f3626df22d',1,'DecodeSignal::startBit']]], + ['statement_20handler_20factory_10',['Statement Handler Factory',['../md_README.html#autotoc_md88',1,'']]], + ['steps_11',['Recommended Next Steps',['../md_README.html#autotoc_md92',1,'']]], + ['strategy_12',['Unified Decode Strategy',['../md_README.html#autotoc_md80',1,'']]], + ['structures_13',['structures',['../md_README.html#autotoc_md17',1,'Parsed Data Structures'],['../md_README.html#autotoc_md10',1,'Parsed DBC structures'],['../md_README.html#autotoc_md12',1,'Runtime decode structures'],['../md_README.html#autotoc_md11',1,'UI tree structures']]], + ['summary_14',['Summary',['../md_README.html#autotoc_md100',1,'']]], + ['support_15',['Parser Support',['../md_README.html#autotoc_md53',1,'']]], + ['supported_20dbc_20syntax_16',['Supported DBC Syntax',['../md_README.html#autotoc_md55',1,'']]], + ['syntax_17',['Supported DBC Syntax',['../md_README.html#autotoc_md55',1,'']]] ]; diff --git a/docs/html/search/all_15.js b/docs/html/search/all_15.js index ae1a27c..722a0b2 100644 --- a/docs/html/search/all_15.js +++ b/docs/html/search/all_15.js @@ -1,11 +1,32 @@ var searchData= [ - ['ui_20path_0',['1. Parse and UI path',['../md_README.html#autotoc_md4',1,'']]], - ['ui_20tree_1',['Build UI tree',['../md_README.html#autotoc_md76',1,'']]], - ['ui_20tree_20layer_2',['UI Tree Layer',['../md_README.html#autotoc_md24',1,'']]], - ['ui_20tree_20structures_3',['UI tree structures',['../md_README.html#autotoc_md11',1,'']]], - ['unified_20decode_20strategy_4',['Unified Decode Strategy',['../md_README.html#autotoc_md80',1,'']]], - ['unit_5',['unit',['../structDecodeSignal.html#a38eed9ca7581423fd8bfbedcffc12092',1,'DecodeSignal::unit'],['../structSignalInfo.html#a1f214f03e94ef5794de2d3367bfcbd01',1,'SignalInfo::unit']]], - ['usage_6',['Example Usage',['../md_README.html#autotoc_md74',1,'']]], - ['use_20in_20frametap_7',['Intended Use in FrameTap',['../md_README.html#autotoc_md84',1,'']]] + ['tests_0',['tests',['../md_tests_2README.html',1,'QtTest regression tests'],['../md_README.html#autotoc_md103',1,'Regression tests']]], + ['the_20runtime_20decode_20layer_20exists_1',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md7',1,'']]], + ['the_20tree_20is_20not_20enough_2',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md86',1,'']]], + ['trace_20path_3',['trace path',['../md_README.html#autotoc_md82',1,'']]], + ['transmitter_4',['transmitter',['../structFrameInfo.html#a92749ec3798d4211a505860fb389a9e8',1,'FrameInfo::transmitter'],['../structDecodeFrame.html#ad78241dc40c793aabb8495b6989b81a9',1,'DecodeFrame::transmitter']]], + ['tree_5',['Build UI tree',['../md_README.html#autotoc_md76',1,'']]], + ['tree_20is_20not_20enough_6',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md86',1,'']]], + ['tree_20layer_7',['UI Tree Layer',['../md_README.html#autotoc_md24',1,'']]], + ['tree_20structures_8',['UI tree structures',['../md_README.html#autotoc_md11',1,'']]], + ['tree_5fnode_2ecpp_9',['tree_node.cpp',['../tree__node_8cpp.html',1,'']]], + ['tree_5fnode_2eh_10',['tree_node.h',['../tree__node_8h.html',1,'']]], + ['treenode_11',['treenode',['../classTreeNode.html#a984a98d5ccf7ef1f5a18094c6821f35d',1,'TreeNode::TreeNode()'],['../classTreeNode.html#a8e38dd591d8801d7ee3a7dbad90c67fc',1,'TreeNode::TreeNode(const FrameInfo &frame)'],['../classTreeNode.html#ab9f00f5253d56461bb2d420fd639c5ae',1,'TreeNode::TreeNode(const SignalInfo &signal)'],['../classTreeNode.html',1,'TreeNode']]], + ['treenode_20tt_12',['<tt>TreeNode</tt>',['../md_README.html#autotoc_md25',1,'']]], + ['tt_20byteorder_20tt_13',['<tt>ByteOrder</tt>',['../md_README.html#autotoc_md30',1,'']]], + ['tt_20dbcdatabase_20tt_14',['<tt>DbcDatabase</tt>',['../md_README.html#autotoc_md22',1,'']]], + ['tt_20dbcdecoder_20tt_15',['<tt>DbcDecoder</tt>',['../md_README.html#autotoc_md51',1,'']]], + ['tt_20decodedatabase_20tt_16',['<tt>DecodeDatabase</tt>',['../md_README.html#autotoc_md40',1,'']]], + ['tt_20decodedframevalue_20tt_17',['<tt>DecodedFrameValue</tt>',['../md_README.html#autotoc_md49',1,'']]], + ['tt_20decodedsignalvalue_20tt_18',['<tt>DecodedSignalValue</tt>',['../md_README.html#autotoc_md45',1,'']]], + ['tt_20decodeframe_20tt_19',['<tt>DecodeFrame</tt>',['../md_README.html#autotoc_md36',1,'']]], + ['tt_20decodesignal_20tt_20',['<tt>DecodeSignal</tt>',['../md_README.html#autotoc_md34',1,'']]], + ['tt_20frameinfo_20tt_21',['<tt>FrameInfo</tt>',['../md_README.html#autotoc_md20',1,'']]], + ['tt_20framekey_20tt_22',['<tt>FrameKey</tt>',['../md_README.html#autotoc_md38',1,'']]], + ['tt_20rawcanframe_20tt_23',['<tt>RawCanFrame</tt>',['../md_README.html#autotoc_md43',1,'']]], + ['tt_20signalinfo_20tt_24',['<tt>SignalInfo</tt>',['../md_README.html#autotoc_md18',1,'']]], + ['tt_20treenode_20tt_25',['<tt>TreeNode</tt>',['../md_README.html#autotoc_md25',1,'']]], + ['tt_20valuetype_20tt_26',['<tt>ValueType</tt>',['../md_README.html#autotoc_md32',1,'']]], + ['typefactory_27',['TypeFactory',['../classTypeFactory.html',1,'']]], + ['typefactory_3c_20std_3a_3astring_2c_20dbcstatementhandler_20_3e_28',['TypeFactory< std::string, DbcStatementHandler >',['../classTypeFactory.html',1,'']]] ]; diff --git a/docs/html/search/all_16.js b/docs/html/search/all_16.js index 3f0906c..ae1a27c 100644 --- a/docs/html/search/all_16.js +++ b/docs/html/search/all_16.js @@ -1,8 +1,11 @@ var searchData= [ - ['valid_0',['valid',['../structDecodedSignalValue.html#aac0ed361af545cde48d0e6f41a859686',1,'DecodedSignalValue::valid'],['../structDecodedFrameValue.html#a4f51c31110dba1f73a763c596372beb0',1,'DecodedFrameValue::valid']]], - ['validation_20and_20parse_20errors_1',['validation and parse errors',['../md_README.html#autotoc_md58',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md62',1,'Signal validation and parse errors']]], - ['value_20representation_20and_20precision_2',['Raw value representation and precision',['../md_README.html#autotoc_md47',1,'']]], - ['valuetype_3',['valuetype',['../structDecodeSignal.html#a9d37638129263b8902ba5be59baf39a8',1,'DecodeSignal::valueType'],['../decode__database_8h.html#ad9971b6ef33e02ba2c75d19c1d2518a1',1,'ValueType: decode_database.h']]], - ['valuetype_20tt_4',['<tt>ValueType</tt>',['../md_README.html#autotoc_md32',1,'']]] + ['ui_20path_0',['1. Parse and UI path',['../md_README.html#autotoc_md4',1,'']]], + ['ui_20tree_1',['Build UI tree',['../md_README.html#autotoc_md76',1,'']]], + ['ui_20tree_20layer_2',['UI Tree Layer',['../md_README.html#autotoc_md24',1,'']]], + ['ui_20tree_20structures_3',['UI tree structures',['../md_README.html#autotoc_md11',1,'']]], + ['unified_20decode_20strategy_4',['Unified Decode Strategy',['../md_README.html#autotoc_md80',1,'']]], + ['unit_5',['unit',['../structDecodeSignal.html#a38eed9ca7581423fd8bfbedcffc12092',1,'DecodeSignal::unit'],['../structSignalInfo.html#a1f214f03e94ef5794de2d3367bfcbd01',1,'SignalInfo::unit']]], + ['usage_6',['Example Usage',['../md_README.html#autotoc_md74',1,'']]], + ['use_20in_20frametap_7',['Intended Use in FrameTap',['../md_README.html#autotoc_md84',1,'']]] ]; diff --git a/docs/html/search/all_17.js b/docs/html/search/all_17.js index de2f9a0..3f0906c 100644 --- a/docs/html/search/all_17.js +++ b/docs/html/search/all_17.js @@ -1,5 +1,8 @@ var searchData= [ - ['why_20the_20runtime_20decode_20layer_20exists_0',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md7',1,'']]], - ['why_20the_20tree_20is_20not_20enough_1',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md86',1,'']]] + ['valid_0',['valid',['../structDecodedSignalValue.html#aac0ed361af545cde48d0e6f41a859686',1,'DecodedSignalValue::valid'],['../structDecodedFrameValue.html#a4f51c31110dba1f73a763c596372beb0',1,'DecodedFrameValue::valid']]], + ['validation_20and_20parse_20errors_1',['validation and parse errors',['../md_README.html#autotoc_md58',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md62',1,'Signal validation and parse errors']]], + ['value_20representation_20and_20precision_2',['Raw value representation and precision',['../md_README.html#autotoc_md47',1,'']]], + ['valuetype_3',['valuetype',['../structDecodeSignal.html#a9d37638129263b8902ba5be59baf39a8',1,'DecodeSignal::valueType'],['../decode__database_8h.html#ad9971b6ef33e02ba2c75d19c1d2518a1',1,'ValueType: decode_database.h']]], + ['valuetype_20tt_4',['<tt>ValueType</tt>',['../md_README.html#autotoc_md32',1,'']]] ]; diff --git a/docs/html/search/all_18.js b/docs/html/search/all_18.js new file mode 100644 index 0000000..de2f9a0 --- /dev/null +++ b/docs/html/search/all_18.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['why_20the_20runtime_20decode_20layer_20exists_0',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md7',1,'']]], + ['why_20the_20tree_20is_20not_20enough_1',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md86',1,'']]] +]; diff --git a/docs/html/search/all_6.js b/docs/html/search/all_6.js index 10d9f9e..1af75ab 100644 --- a/docs/html/search/all_6.js +++ b/docs/html/search/all_6.js @@ -5,7 +5,8 @@ var searchData= ['comment_2',['comment',['../structDecodeSignal.html#ae28c905d4a2bc86419c2a8361bfea473',1,'DecodeSignal::comment'],['../structDecodeFrame.html#a25819ef907a32391af5c9f7cae9cdb22',1,'DecodeFrame::comment'],['../structFrameInfo.html#ace75121294f9d89b762080ab5643293c',1,'FrameInfo::comment'],['../structSignalInfo.html#ac99ba7563a5dad01e39c4257216953f5',1,'SignalInfo::comment']]], ['comments_3',['Comments',['../md_README.html#autotoc_md64',1,'']]], ['contains_4',['contains',['../classTypeFactory.html#a1a119ad2956abe146213c6ca124d8dd4',1,'TypeFactory']]], - ['create_5',['create',['../classTypeFactory.html#a3f43b03d6e3a0fd503fdec01ecf62e9f',1,'TypeFactory']]], - ['creator_6',['creator',['../classTypeFactory.html#ad82f537569ece3d3a4a376523fa94473',1,'TypeFactory']]], - ['current_20limitations_7',['Current Limitations',['../md_README.html#autotoc_md90',1,'']]] + ['coverage_5',['coverage',['../md_tests_2README.html#autotoc_md105',1,'Decoder coverage'],['../md_tests_2README.html#autotoc_md106',1,'Parser coverage']]], + ['create_6',['create',['../classTypeFactory.html#a3f43b03d6e3a0fd503fdec01ecf62e9f',1,'TypeFactory']]], + ['creator_7',['creator',['../classTypeFactory.html#ad82f537569ece3d3a4a376523fa94473',1,'TypeFactory']]], + ['current_20limitations_8',['Current Limitations',['../md_README.html#autotoc_md90',1,'']]] ]; diff --git a/docs/html/search/all_7.js b/docs/html/search/all_7.js index 72ad136..23b0f56 100644 --- a/docs/html/search/all_7.js +++ b/docs/html/search/all_7.js @@ -50,13 +50,13 @@ var searchData= ['decodeframe_47',['DecodeFrame',['../structDecodeFrame.html',1,'']]], ['decodeframe_20tt_48',['<tt>DecodeFrame</tt>',['../md_README.html#autotoc_md36',1,'']]], ['decoder_49',['Runtime decoder',['../md_README.html#autotoc_md13',1,'']]], - ['decoder_20layer_50',['Decoder Layer',['../md_README.html#autotoc_md42',1,'']]], - ['decoder_20regression_20tests_51',['Decoder regression tests',['../md_tests_2README.html',1,'']]], + ['decoder_20coverage_50',['Decoder coverage',['../md_tests_2README.html#autotoc_md105',1,'']]], + ['decoder_20layer_51',['Decoder Layer',['../md_README.html#autotoc_md42',1,'']]], ['decodesignal_52',['DecodeSignal',['../structDecodeSignal.html',1,'']]], ['decodesignal_20tt_53',['<tt>DecodeSignal</tt>',['../md_README.html#autotoc_md34',1,'']]], ['definition_54',['definition',['../structDecodedFrameValue.html#a60dda1cc352d2c8087f0bdbc81dd266c',1,'DecodedFrameValue::definition'],['../structDecodedSignalValue.html#acadc3b3bb21dd6b0412d342c7e6b20d7',1,'DecodedSignalValue::definition'],['../md_README.html#autotoc_md56',1,'Frame definition'],['../md_README.html#autotoc_md60',1,'Signal definition']]], ['demo_55',['Demo',['../md_README.html#autotoc_md15',1,'']]], ['dispatch_56',['Dispatch',['../classDbcStatementDispatcher.html#a495c2d5c7ebb8103b1987cdd87c142ed',1,'DbcStatementDispatcher']]], - ['dlc_57',['dlc',['../structDecodeFrame.html#a51111ac13988be372d5673d12cf3e060',1,'DecodeFrame::dlc'],['../structFrameInfo.html#aa2b198ea0f55e560c123d35e7b3ecab9',1,'FrameInfo::dlc']]], + ['dlc_57',['dlc',['../structFrameInfo.html#aa2b198ea0f55e560c123d35e7b3ecab9',1,'FrameInfo::dlc'],['../structDecodeFrame.html#a51111ac13988be372d5673d12cf3e060',1,'DecodeFrame::dlc']]], ['documentation_58',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]] ]; diff --git a/docs/html/search/all_8.js b/docs/html/search/all_8.js index 46fc52c..760e9a7 100644 --- a/docs/html/search/all_8.js +++ b/docs/html/search/all_8.js @@ -3,6 +3,7 @@ var searchData= ['enough_0',['Why the Tree Is Not Enough',['../md_README.html#autotoc_md86',1,'']]], ['errors_1',['errors',['../md_README.html#autotoc_md58',1,'Frame validation and parse errors'],['../md_README.html#autotoc_md62',1,'Signal validation and parse errors']]], ['example_20usage_2',['Example Usage',['../md_README.html#autotoc_md74',1,'']]], - ['exists_3',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md7',1,'']]], - ['extraction_4',['extraction',['../md_README.html#autotoc_md72',1,'Intel and Motorola Extraction'],['../md_README.html#autotoc_md68',1,'PGN Extraction']]] + ['examples_2fmain_2ecpp_3',['main.cpp',['../examples_2main_8cpp.html',1,'']]], + ['exists_4',['Why the Runtime Decode Layer Exists',['../md_README.html#autotoc_md7',1,'']]], + ['extraction_5',['extraction',['../md_README.html#autotoc_md72',1,'Intel and Motorola Extraction'],['../md_README.html#autotoc_md68',1,'PGN Extraction']]] ]; diff --git a/docs/html/search/all_e.js b/docs/html/search/all_e.js index f36e4a8..0c87f60 100644 --- a/docs/html/search/all_e.js +++ b/docs/html/search/all_e.js @@ -1,9 +1,8 @@ var searchData= [ - ['main_2ecpp_0',['main.cpp',['../main_8cpp.html',1,'']]], - ['maximum_1',['maximum',['../structDecodeSignal.html#a4a6ba87142a9badbf0ca830e9e709cb7',1,'DecodeSignal::maximum'],['../structSignalInfo.html#adf1c4331b9eabced0d7fdda40ff0eb52',1,'SignalInfo::maximum']]], - ['minimum_2',['minimum',['../structDecodeSignal.html#a0fb84e19a0ab3bd50b6f65c1075ebc25',1,'DecodeSignal::minimum'],['../structSignalInfo.html#ada7bf94fbeaa26bd08c73982b5af255b',1,'SignalInfo::minimum']]], - ['module_20documentation_3',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], - ['module_20layout_4',['Module Layout',['../md_README.html#autotoc_md9',1,'']]], - ['motorola_20extraction_5',['Intel and Motorola Extraction',['../md_README.html#autotoc_md72',1,'']]] + ['maximum_0',['maximum',['../structDecodeSignal.html#a4a6ba87142a9badbf0ca830e9e709cb7',1,'DecodeSignal::maximum'],['../structSignalInfo.html#adf1c4331b9eabced0d7fdda40ff0eb52',1,'SignalInfo::maximum']]], + ['minimum_1',['minimum',['../structDecodeSignal.html#a0fb84e19a0ab3bd50b6f65c1075ebc25',1,'DecodeSignal::minimum'],['../structSignalInfo.html#ada7bf94fbeaa26bd08c73982b5af255b',1,'SignalInfo::minimum']]], + ['module_20documentation_2',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], + ['module_20layout_3',['Module Layout',['../md_README.html#autotoc_md9',1,'']]], + ['motorola_20extraction_4',['Intel and Motorola Extraction',['../md_README.html#autotoc_md72',1,'']]] ]; diff --git a/docs/html/search/files_1.js b/docs/html/search/files_1.js index 7cebf32..92ce7f2 100644 --- a/docs/html/search/files_1.js +++ b/docs/html/search/files_1.js @@ -1,4 +1,4 @@ var searchData= [ - ['frame_5finfo_2eh_0',['frame_info.h',['../frame__info_8h.html',1,'']]] + ['examples_2fmain_2ecpp_0',['main.cpp',['../examples_2main_8cpp.html',1,'']]] ]; diff --git a/docs/html/search/files_2.js b/docs/html/search/files_2.js index 695b4fd..7cebf32 100644 --- a/docs/html/search/files_2.js +++ b/docs/html/search/files_2.js @@ -1,4 +1,4 @@ var searchData= [ - ['main_2ecpp_0',['main.cpp',['../main_8cpp.html',1,'']]] + ['frame_5finfo_2eh_0',['frame_info.h',['../frame__info_8h.html',1,'']]] ]; diff --git a/docs/html/search/pages_1.js b/docs/html/search/pages_1.js index 7edc4cb..79cbdab 100644 --- a/docs/html/search/pages_1.js +++ b/docs/html/search/pages_1.js @@ -2,6 +2,5 @@ var searchData= [ ['dbc_20parser_20and_20runtime_20decode_20module_20documentation_0',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], ['decode_20module_20documentation_1',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]], - ['decoder_20regression_20tests_2',['Decoder regression tests',['../md_tests_2README.html',1,'']]], - ['documentation_3',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]] + ['documentation_2',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]] ]; diff --git a/docs/html/search/pages_4.js b/docs/html/search/pages_4.js index 4a26e47..8b9b038 100644 --- a/docs/html/search/pages_4.js +++ b/docs/html/search/pages_4.js @@ -1,5 +1,4 @@ var searchData= [ - ['regression_20tests_0',['Decoder regression tests',['../md_tests_2README.html',1,'']]], - ['runtime_20decode_20module_20documentation_1',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]] + ['qttest_20regression_20tests_0',['QtTest regression tests',['../md_tests_2README.html',1,'']]] ]; diff --git a/docs/html/search/pages_5.js b/docs/html/search/pages_5.js index 28f8db6..25f5fce 100644 --- a/docs/html/search/pages_5.js +++ b/docs/html/search/pages_5.js @@ -1,4 +1,5 @@ var searchData= [ - ['tests_0',['Decoder regression tests',['../md_tests_2README.html',1,'']]] + ['regression_20tests_0',['QtTest regression tests',['../md_tests_2README.html',1,'']]], + ['runtime_20decode_20module_20documentation_1',['DBC Parser and Runtime Decode Module Documentation',['../md_README.html',1,'']]] ]; diff --git a/docs/html/search/pages_6.js b/docs/html/search/pages_6.js new file mode 100644 index 0000000..7f0360c --- /dev/null +++ b/docs/html/search/pages_6.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['tests_0',['QtTest regression tests',['../md_tests_2README.html',1,'']]] +]; diff --git a/docs/html/search/searchdata.js b/docs/html/search/searchdata.js index 732d968..6f7bbcc 100644 --- a/docs/html/search/searchdata.js +++ b/docs/html/search/searchdata.js @@ -1,12 +1,12 @@ var indexSectionsWithContent = { - 0: "1234abcdefghilmnoprstuvw", + 0: "1234abcdefghilmnopqrstuvw", 1: "dfrst", - 2: "dfmst", + 2: "defst", 3: "abcdfgprt", 4: "bcdfhilmnoprstuv", 5: "bnv", - 6: "admprt" + 6: "admpqrt" }; var indexSectionNames = diff --git a/docs/html/signal__info_8h.html b/docs/html/signal__info_8h.html index 0abc693..dc673e0 100644 --- a/docs/html/signal__info_8h.html +++ b/docs/html/signal__info_8h.html @@ -120,7 +120,7 @@ Classes diff --git a/docs/html/signal__info_8h_source.html b/docs/html/signal__info_8h_source.html index e99be67..af6ed12 100644 --- a/docs/html/signal__info_8h_source.html +++ b/docs/html/signal__info_8h_source.html @@ -145,7 +145,7 @@ $(document).ready(function(){initNavTree('signal__info_8h_source.html',''); init diff --git a/docs/html/tests_2main_8cpp_source.html b/docs/html/tests_2main_8cpp_source.html new file mode 100644 index 0000000..d2d90f0 --- /dev/null +++ b/docs/html/tests_2main_8cpp_source.html @@ -0,0 +1,123 @@ + + + + + + + +DBC Framework: main.cpp Source File + + + + + + + + + + + + + +
    +
    + + + + + + +
    +
    DBC Framework +
    +
    DBC parsing and CAN signal decoding framework
    +
    +
    + + + + + + + + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    Loading...
    +
    Searching...
    +
    No Matches
    +
    +
    +
    +
    + +
    +
    tests/main.cpp
    +
    +
    +
    1#include <QCoreApplication>
    +
    2#include <QtTest>
    +
    3
    +
    4int RunParserTests(int argc, char **argv);
    +
    5int RunDecoderTests(int argc, char **argv);
    +
    6
    +
    7int main(int argc, char **argv) {
    +
    8 QCoreApplication application(argc, argv);
    +
    9 const int parserResult = RunParserTests(argc, argv);
    +
    10 const int decoderResult = RunDecoderTests(argc, argv);
    +
    11 return parserResult | decoderResult;
    +
    12}
    +
    +
    + + + + diff --git a/docs/html/tree__node_8cpp.html b/docs/html/tree__node_8cpp.html index 9fd7c20..3c9924c 100644 --- a/docs/html/tree__node_8cpp.html +++ b/docs/html/tree__node_8cpp.html @@ -109,7 +109,7 @@ $(document).ready(function(){initNavTree('tree__node_8cpp.html',''); initResizab diff --git a/docs/html/tree__node_8cpp_source.html b/docs/html/tree__node_8cpp_source.html index daeaa85..dffa12e 100644 --- a/docs/html/tree__node_8cpp_source.html +++ b/docs/html/tree__node_8cpp_source.html @@ -191,7 +191,7 @@ $(document).ready(function(){initNavTree('tree__node_8cpp_source.html',''); init diff --git a/docs/html/tree__node_8h.html b/docs/html/tree__node_8h.html index d3073be..6b7e3ca 100644 --- a/docs/html/tree__node_8h.html +++ b/docs/html/tree__node_8h.html @@ -160,7 +160,7 @@ Enumerations diff --git a/docs/html/tree__node_8h_source.html b/docs/html/tree__node_8h_source.html index 8d01a78..f28e3b6 100644 --- a/docs/html/tree__node_8h_source.html +++ b/docs/html/tree__node_8h_source.html @@ -180,7 +180,7 @@ $(document).ready(function(){initNavTree('tree__node_8h_source.html',''); initRe diff --git a/docs/html/typefactory_8h_source.html b/docs/html/typefactory_8h_source.html index 1b29784..5d8b258 100644 --- a/docs/html/typefactory_8h_source.html +++ b/docs/html/typefactory_8h_source.html @@ -170,7 +170,7 @@ $(document).ready(function(){initNavTree('typefactory_8h_source.html',''); initR diff --git a/examples/demo.pro b/examples/demo.pro new file mode 100644 index 0000000..6625e58 --- /dev/null +++ b/examples/demo.pro @@ -0,0 +1,7 @@ +TEMPLATE = app +TARGET = dbc_demo +CONFIG += console c++17 +CONFIG -= qt app_bundle +include(../core/core.pri) +SOURCES += main.cpp +CONFIG -= debug_and_release debug_and_release_target diff --git a/main.cpp b/examples/main.cpp similarity index 100% rename from main.cpp rename to examples/main.cpp diff --git a/tests/README.md b/tests/README.md index 8cb7c75..41a6d34 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,25 +1,40 @@ -# Decoder regression tests +# QtTest regression tests -Run from the repository root with a C++17 compiler: +Open the repository's root `dbc.pro` in Qt Creator. It contains `core` (a static +C++17 library) and `tests` (the `dbc_tests` QtTest executable). Core is built first; +tests link its archive rather than compiling its implementation again. +Qt Core and Qt Test development packages are required for tests only. + +Build from the repository root with Qt 6 (use `qmake` for Qt 5): ```sh -g++ -std=c++17 -Wall -Wextra -Wpedantic -I. \ - tests/dbc_decoder_test.cpp dbc_decoder.cpp -o /tmp/dbc_decoder_test -/tmp/dbc_decoder_test +mkdir build +cd build +qmake6 ../dbc.pro +make -j +make check ``` -Alternatively, build the standalone qmake project out of source: +Or run `./tests/dbc_tests` directly. Both parser and decoder suites run, and the +executable returns nonzero when either suite fails. Decoder cases appear as +individual QtTest data rows; parser checks are grouped into named test slots. +Checks also run in release builds. + +To build tests separately against an existing core build: ```sh -mkdir -p /tmp/dbc_decoder_test_build -cd /tmp/dbc_decoder_test_build -qmake /absolute/path/to/dbc/tests/dbc_decoder_test.pro +mkdir /tmp/dbc-tests-build +cd /tmp/dbc-tests-build +qmake6 /absolute/path/to/dbc/tests/tests.pro \ + DBC_CORE_BUILD_DIR=/absolute/path/to/build/core make -./dbc_decoder_test +make check ``` -The executable returns a nonzero exit code if any case fails. Checks remain -active in release builds and do not depend on `assert` or an external test framework. +`parser_tests.pri` and `decoder_tests.pri` include the test sources. +`../core/core.pri` supplies the library include path and linkage. + +## Decoder coverage Coverage includes Motorola bit numbering within and across bytes, unaligned signals, signed values, scaling, 64-bit extraction, signed/unsigned boundary values @@ -27,18 +42,7 @@ signals, signed values, scaling, 64-bit extraction, signed/unsigned boundary val payloads, and Intel regression cases. Frame validity means the definition was found; insufficient payloads are checked through signal validity. -## Parser regression tests - -Run from the repository root: - -```sh -g++ -std=c++17 -Wall -Wextra -Wpedantic -Werror -I. \ - tests/dbc_parser_test.cpp dbc_parser.cpp dbc_statement_handler.cpp -o /tmp/dbc_parser_test -/tmp/dbc_parser_test -``` - -For qmake, use `tests/dbc_parser_test.pro` in a separate build directory, -following the decoder instructions above, then run `./dbc_parser_test`. +## Parser coverage Parser tests cover standard and extended CAN IDs, whitespace, payload storage boundaries, missing fields, malformed and overflowing numbers, reserved ID bits, diff --git a/tests/dbc_decoder_test.cpp b/tests/dbc_decoder_test.cpp index cd3bdd6..ff08c1d 100644 --- a/tests/dbc_decoder_test.cpp +++ b/tests/dbc_decoder_test.cpp @@ -1,6 +1,6 @@ #include "dbc_decoder.h" -#include +#include #include #include @@ -18,7 +18,18 @@ struct DecodeCase { double physicalValue; }; -int main() { +Q_DECLARE_METATYPE(DecodeCase) + +class DbcDecoderTest : public QObject { + Q_OBJECT +private Q_SLOTS: + void decode_data(); + void decode(); + void boundaries(); +}; + +void DbcDecoderTest::decode_data() { + QTest::addColumn("test"); const DecodeCase cases[] = { {"Motorola reproduction", ByteOrder::Motorola, 7U, 16U, ValueType::Unsigned, {0x12, 0x34}, true, 0x1234, 1.0, 0.0, 4660.0}, {"Motorola within byte", ByteOrder::Motorola, 5U, 4U, ValueType::Unsigned, {0xAC}, true, 11, 1.0, 0.0, 11.0}, @@ -38,47 +49,49 @@ int main() { {"Intel signed regression", ByteOrder::Intel, 0U, 16U, ValueType::Signed, {0xFE, 0xFF}, true, -2, 0.5, 10.0, 9.0}, {"Intel short payload", ByteOrder::Intel, 0U, 16U, ValueType::Unsigned, {0x12}, false, 0, 1.0, 0.0, 0.0}}; - int failures = 0; - for (const DecodeCase &test: cases) { - DecodeSignal signal; - signal.name = test.name; - signal.byteOrder = test.byteOrder; - signal.startBit = test.startBit; - signal.length = test.length; - signal.valueType = test.valueType; - signal.factor = test.factor; - signal.offset = test.offset; + for (const auto &test: cases) + QTest::newRow(test.name) << test; +} - DecodeFrame definition; - definition.canId = 0x123U; - definition.dlc = static_cast(test.data.size()); - definition.signals.push_back(signal); - DecodeDatabase database; - database.frames.push_back(definition); - database.frameIndexByKey.emplace(FrameKey(definition.canId, false), 0U); +void DbcDecoderTest::decode() { + QFETCH(DecodeCase, test); + DecodeSignal signal; + signal.name = test.name; + signal.byteOrder = test.byteOrder; + signal.startBit = test.startBit; + signal.length = test.length; + signal.valueType = test.valueType; + signal.factor = test.factor; + signal.offset = test.offset; - RawCanFrame frame; - frame.canId = definition.canId; - frame.data = test.data; - const DecodedFrameValue result = DbcDecoder().Decode(database, frame); - const bool passed = result.valid && - (result.definition == &database.frames[0]) && - (result.signals.size() == 1U) && - (result.signals[0].definition == &database.frames[0].signals[0]) && - (result.signals[0].valid == test.valid) && - (!test.valid || (((test.valueType == ValueType::Signed) - ? (std::get_if(&result.signals[0].rawValue) && - std::get(result.signals[0].rawValue) == test.rawValue) - : (std::get_if(&result.signals[0].rawValue) && - std::get(result.signals[0].rawValue) == - static_cast(test.rawValue))) && - (result.signals[0].physicalValue == test.physicalValue))); - if (!passed) { - std::cerr << "FAIL: " << test.name << '\n'; - ++failures; - } - } - std::size_t boundaryCases = 0U; + DecodeFrame definition; + definition.canId = 0x123U; + definition.dlc = static_cast(test.data.size()); + definition.signals.push_back(signal); + DecodeDatabase database; + database.frames.push_back(definition); + database.frameIndexByKey.emplace(FrameKey(definition.canId, false), 0U); + + RawCanFrame frame; + frame.canId = definition.canId; + frame.data = test.data; + const DecodedFrameValue result = DbcDecoder().Decode(database, frame); + const bool passed = result.valid && + (result.definition == &database.frames[0]) && + (result.signals.size() == 1U) && + (result.signals[0].definition == &database.frames[0].signals[0]) && + (result.signals[0].valid == test.valid) && + (!test.valid || (((test.valueType == ValueType::Signed) + ? (std::get_if(&result.signals[0].rawValue) && + std::get(result.signals[0].rawValue) == test.rawValue) + : (std::get_if(&result.signals[0].rawValue) && + std::get(result.signals[0].rawValue) == + static_cast(test.rawValue))) && + (result.signals[0].physicalValue == test.physicalValue))); + QVERIFY2(passed, test.name); +} + +void DbcDecoderTest::boundaries() { for (ByteOrder order: {ByteOrder::Intel, ByteOrder::Motorola}) { for (ValueType type: {ValueType::Unsigned, ValueType::Signed}) { for (std::uint64_t bits: {std::uint64_t(0U), std::uint64_t(0x7FFFFFFFFFFFFFFFULL), @@ -126,17 +139,17 @@ int main() { expectedText << bits; else expectedText << signedExpected; - if (!decoded.valid || decoded.rawValue != expected || - decoded.physicalValue != physical || actualText.str() != expectedText.str()) { - std::cerr << "FAIL: 64-bit boundary " << bits << '\n'; - ++failures; - } - ++boundaryCases; + QVERIFY2(decoded.valid && decoded.rawValue == expected && + decoded.physicalValue == physical && actualText.str() == expectedText.str(), + expectedText.str().c_str()); } } } - if (failures != 0) - return 1; - std::cout << "All " << sizeof(cases) / sizeof(cases[0]) + boundaryCases << " decoder cases passed.\n"; - return 0; } + +int RunDecoderTests(int argc, char **argv) { + DbcDecoderTest tests; + return QTest::qExec(&tests, argc, argv); +} + +#include "dbc_decoder_test.moc" diff --git a/tests/dbc_decoder_test.pro b/tests/dbc_decoder_test.pro deleted file mode 100644 index b5e22b4..0000000 --- a/tests/dbc_decoder_test.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = dbc_decoder_test -CONFIG += console c++17 -CONFIG -= app_bundle qt -INCLUDEPATH += .. -SOURCES += dbc_decoder_test.cpp ../dbc_decoder.cpp -HEADERS += ../dbc_decoder.h ../decode_database.h diff --git a/tests/dbc_parser_test.cpp b/tests/dbc_parser_test.cpp index 9fe0450..d276ba1 100644 --- a/tests/dbc_parser_test.cpp +++ b/tests/dbc_parser_test.cpp @@ -1,10 +1,12 @@ #include "dbc_parser.h" #include "dbc_statement_handler.h" +#include #include #include #include -#include + +#define CHECK(condition, name) QVERIFY2((condition), std::string(name).c_str()) #include struct Fixture { @@ -41,33 +43,33 @@ std::string SignalLine(const std::string &start, const std::string &length, " (" + factor + "," + offset + ") [" + minimum + "|" + maximum + "] \"\" ECU"; } -struct TestContext { - int failures = 0; - std::size_t count = 0U; - void Check(bool passed, const std::string &name) { - ++count; - if (!passed) { - ++failures; - std::cerr << "FAIL: " << name << '\n'; - } - } +class DbcParserTest : public QObject { + Q_OBJECT +private: 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 { DbcParser().ParseFile(fixture.path.string()); - Check(false, "Reject " + line); + CHECK(false, "Reject " + line); } catch (const std::runtime_error &error) { const std::string prefix = fixture.path.string() + ":3: "; - Check(std::string(error.what()).find(prefix) == 0U && + CHECK(std::string(error.what()).find(prefix) == 0U && std::string(error.what()).size() > prefix.size(), "Reject " + line); } } +private Q_SLOTS: + void validFrames(); + void invalidFrames(); + void integration(); + void invalidSignals(); + void validSignals(); + void dispatch(); + void independentSessions(); }; -int main() { +void DbcParserTest::validFrames() { Fixture fixture; - TestContext tests; struct ValidCase { const char *line; std::uint32_t id; @@ -86,14 +88,18 @@ int main() { fixture.Write(std::string(test.line) + '\n'); try { const auto database = DbcParser().ParseFile(fixture.path.string()); - tests.Check(database.frames.size() == 1U && database.frames[0].name == "Frame" && - database.frames[0].canId == test.id && - database.frames[0].isExtended == test.extended && - database.frames[0].dlc == test.length && - database.frames[0].transmitter == "ECU", - test.line); - } catch (const std::exception &error) { tests.Check(false, error.what()); } + CHECK(database.frames.size() == 1U && database.frames[0].name == "Frame" && + database.frames[0].canId == test.id && + database.frames[0].isExtended == test.extended && + database.frames[0].dlc == test.length && + database.frames[0].transmitter == "ECU", + test.line); + } catch (const std::exception &error) { CHECK(false, error.what()); } } +} + +void DbcParserTest::invalidFrames() { + Fixture fixture; const char *invalid[] = { "BO_ invalid", "BO_", "BO_ 1", "BO_ 1 : 8 ECU", "BO_ 1 Frame 8 ECU", "BO_ 1 Frame:", "BO_ 1 Frame: 8", "BO_ 1 Frame: 8 ECU extra", @@ -109,79 +115,91 @@ int main() { fixture.Write(std::string("VERSION \"test\"\n\n") + line + '\n'); try { DbcParser().ParseFile(fixture.path.string()); - tests.Check(false, line); + CHECK(false, line); } catch (const std::runtime_error &error) { const std::string prefix = fixture.path.string() + ":3: "; - tests.Check(std::string(error.what()).find(prefix) == 0U && - std::string(error.what()).size() > prefix.size(), - line); + CHECK(std::string(error.what()).find(prefix) == 0U && + std::string(error.what()).size() > prefix.size(), + line); } } +} + +void DbcParserTest::integration() { + Fixture fixture; fixture.Write( "BO_TX_BU_ 256 : ECU;\nBO_ 256 Frame: 8 ECU\n" " SG_ Speed : 0|16@1+ (0.5,1) [0|100] \"rpm\" ECU\n" "CM_ BO_ 256 \"Frame comment\";\nCM_ SG_ 256 Speed \"Signal comment\";\n" "BO_ 257 Second: 8 ECU\n"); const auto database = DbcParser().ParseFile(fixture.path.string()); - tests.Check(database.frames.size() == 2U && database.frames[0].signals.size() == 1U && - database.frames[0].comment == "Frame comment" && - database.frames[0].signals[0].comment == "Signal comment", - "Integration"); + CHECK(database.frames.size() == 2U && database.frames[0].signals.size() == 1U && + database.frames[0].comment == "Frame comment" && + database.frames[0].signals[0].comment == "Signal comment", + "Integration"); fixture.Write("\nSG_ Speed : invalid\n"); try { DbcParser().ParseFile(fixture.path.string()); - tests.Check(false, "Signal error location"); + CHECK(false, "Signal error location"); } catch (const std::runtime_error &error) { - tests.Check(std::string(error.what()).find(fixture.path.string() + ":2: ") == 0U, - "Signal error location"); + CHECK(std::string(error.what()).find(fixture.path.string() + ":2: ") == 0U, + "Signal error location"); } - const DbcParser signalParser; +} + +void DbcParserTest::invalidSignals() { + Fixture fixture; const std::string ordinary = SignalLine("0", "8", "1+", "1", "0", "0", "255"); for (const std::string value: {"-1", "+1", "0junk", "0x10", "1.5", "4294967296", "999999999999999999999"}) { - tests.RejectSignal(fixture, SignalLine(value, "8", "1+", "1", "0", "0", "255")); - tests.RejectSignal(fixture, SignalLine("0", value, "1+", "1", "0", "0", "255")); + RejectSignal(fixture, SignalLine(value, "8", "1+", "1", "0", "0", "255")); + RejectSignal(fixture, SignalLine("0", value, "1+", "1", "0", "0", "255")); } for (const std::string length: {"0", "65"}) - tests.RejectSignal(fixture, SignalLine("0", length, "1+", "1", "0", "0", "255")); + RejectSignal(fixture, SignalLine("0", length, "1+", "1", "0", "0", "255")); for (const std::string order: {"2+", "9-", "1", "1x", "1++", "01+"}) - tests.RejectSignal(fixture, SignalLine("0", "8", order, "1", "0", "0", "255")); + RejectSignal(fixture, SignalLine("0", "8", order, "1", "0", "0", "255")); for (const std::string value: {"1junk", "nan", "NaN", "inf", "-inf", "1e999", "1e-999", "0x1p2", "", "1e", "1.2.3"}) { - tests.RejectSignal(fixture, SignalLine("0", "8", "1+", value, "0", "0", "255")); - tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", value, "0", "255")); - tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", value, "255")); - tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "0", value)); + 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)); } - tests.RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "2", "1")); + RejectSignal(fixture, SignalLine("0", "8", "1+", "1", "0", "2", "1")); for (const std::string name: {"", "Two Names", "Value M", "Value m1", "Value m1M"}) { std::string line = ordinary; line.replace(4U, 5U, name); - tests.RejectSignal(fixture, line); + RejectSignal(fixture, line); } for (const std::string broken: { "SG_", "SG_ Value", "SG_ Value : 0|8@1+ (1,0) [0|255] ECU", "SG_ Value : 0|8@1+ (1,0) [0|255] \"\"", "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU,", "SG_ Value : 0|8@1+ (1,0) [0|255] \"\" ECU extra"}) - tests.RejectSignal(fixture, broken); - tests.RejectSignal(fixture, SignalLine("64", "1", "1+", "1", "0", "0", "1")); - tests.RejectSignal(fixture, SignalLine("63", "2", "1+", "1", "0", "0", "3")); - tests.RejectSignal(fixture, SignalLine("56", "2", "0+", "1", "0", "0", "3")); - tests.RejectSignal(fixture, SignalLine("4294967295", "64", "1+", "1", "0", "0", "1")); - tests.RejectSignal(fixture, ordinary, 0U); + RejectSignal(fixture, broken); + RejectSignal(fixture, SignalLine("64", "1", "1+", "1", "0", "0", "1")); + RejectSignal(fixture, SignalLine("63", "2", "1+", "1", "0", "0", "3")); + RejectSignal(fixture, SignalLine("56", "2", "0+", "1", "0", "0", "3")); + RejectSignal(fixture, SignalLine("4294967295", "64", "1+", "1", "0", "0", "1")); + RejectSignal(fixture, ordinary, 0U); for (const char delimiter: {'|', '@', '(', ')', '[', ']', '"'}) { std::string line = ordinary; line.erase(line.find(delimiter), 1U); - tests.RejectSignal(fixture, line); + RejectSignal(fixture, line); } +} + +void DbcParserTest::validSignals() { + Fixture fixture; + const DbcParser signalParser; fixture.Write("BO_ 1 Frame: 8 ECU\n" + SignalLine("0", "8", "1+", "0", "0", "0", "0") + "\n" + SignalLine("8", "8", "1-", "-1", "0", "-255", "0") + "\n"); const auto factors = signalParser.ParseFile(fixture.path.string()); - tests.Check(factors.frames[0].signals.size() == 2U && - factors.frames[0].signals[0].factor == 0.0 && - factors.frames[0].signals[1].factor == -1.0, - "Zero and negative factors and equal range boundaries"); + CHECK(factors.frames[0].signals.size() == 2U && + factors.frames[0].signals[0].factor == 0.0 && + factors.frames[0].signals[1].factor == -1.0, + "Zero and negative factors and equal range boundaries"); struct SignalCase { const char *start; @@ -204,55 +222,68 @@ int main() { try { const auto parsed = signalParser.ParseFile(fixture.path.string()); const auto &signal = parsed.frames.at(0).signals.at(0); - tests.Check(signal.startBit == std::stoul(test.start) && - signal.length == std::stoul(test.length) && - signal.isLittleEndian == (test.order[0] == '1') && - signal.isSigned == (test.order[1] == '-') && - signal.factor == 5.0 && signal.offset == -0.25 && - signal.minimum == -1.0 && signal.maximum == 200.0, - "Valid signal boundary and numeric metadata"); - } catch (const std::exception &error) { tests.Check(false, error.what()); } + CHECK(signal.startBit == std::stoul(test.start) && + signal.length == std::stoul(test.length) && + signal.isLittleEndian == (test.order[0] == '1') && + signal.isSigned == (test.order[1] == '-') && + signal.factor == 5.0 && signal.offset == -0.25 && + signal.minimum == -1.0 && signal.maximum == 200.0, + "Valid signal boundary and numeric metadata"); + } catch (const std::exception &error) { CHECK(false, error.what()); } } fixture.Write("BO_ 1 Frame: 8 ECU\n" "SG_\tValue\t:\t0 | 8 @1+ ( 1 , 0 ) [ 0 | 255 ] \"rpm\" ECU1,\tECU2\n"); try { const auto parsed = signalParser.ParseFile(fixture.path.string()); const auto &signal = parsed.frames.at(0).signals.at(0); - tests.Check(signal.name == "Value" && signal.unit == "rpm" && - signal.receivers == std::vector({"ECU1", "ECU2"}), - "Signal tabs, spaces, and receiver list"); - } catch (const std::exception &error) { tests.Check(false, error.what()); } + CHECK(signal.name == "Value" && signal.unit == "rpm" && + signal.receivers == std::vector({"ECU1", "ECU2"}), + "Signal tabs, spaces, and receiver list"); + } catch (const std::exception &error) { CHECK(false, error.what()); } +} + +void DbcParserTest::dispatch() { + CountingHandler::instances = 0; + CountingHandler::calls = 0; DbcDatabase dispatchDatabase; DbcParseContext context{dispatchDatabase, nullptr}; DbcStatementDispatcher dispatcher; dispatcher.RegisterType("TEST_"); - tests.Check(dispatcher.Dispatch("TEST_ first", context) && - dispatcher.Dispatch("TEST_ second", context) && - CountingHandler::instances == 1 && CountingHandler::calls == 2 && - dispatchDatabase.frames.size() == 2U, - "Factory dispatch and handler reuse"); - tests.Check(!dispatcher.Dispatch("TEST_OTHER data", context) && - !dispatcher.Dispatch("BO_TX_BU_ 1 : ECU;", context) && - !dispatcher.Dispatch("VAL_ 1 Speed 0 \"Stopped\";", context) && - CountingHandler::calls == 2, - "Exact and unknown keyword dispatch"); + CHECK(dispatcher.Dispatch("TEST_ first", context) && + dispatcher.Dispatch("TEST_ second", context) && + CountingHandler::instances == 1 && CountingHandler::calls == 2 && + dispatchDatabase.frames.size() == 2U, + "Factory dispatch and handler reuse"); + CHECK(!dispatcher.Dispatch("TEST_OTHER data", context) && + !dispatcher.Dispatch("BO_TX_BU_ 1 : ECU;", context) && + !dispatcher.Dispatch("VAL_ 1 Speed 0 \"Stopped\";", context) && + CountingHandler::calls == 2, + "Exact and unknown keyword dispatch"); +} + +void DbcParserTest::independentSessions() { + Fixture fixture; const DbcParser parser; fixture.Write("BO_ 1 First: 8 ECU\n"); - tests.Check(parser.ParseFile(fixture.path.string()).frames.size() == 1U, "First parse"); + CHECK(parser.ParseFile(fixture.path.string()).frames.size() == 1U, "First parse"); fixture.Write("SG_ Speed : invalid\n"); try { parser.ParseFile(fixture.path.string()); - tests.Check(false, "Independent parse context"); + CHECK(false, "Independent parse context"); } catch (const std::runtime_error &error) { - tests.Check(std::string(error.what()).find("Signal found before any frame") != - std::string::npos, - "Independent parse context"); + CHECK(std::string(error.what()).find("Signal found before any frame") != + std::string::npos, + "Independent parse context"); } fixture.Write("BO_ 2 Second: 8 ECU\n"); const auto recovered = parser.ParseFile(fixture.path.string()); - tests.Check(recovered.frames.size() == 1U && recovered.frames[0].canId == 2U, - "Fresh parse after error"); - if (tests.failures != 0) return 1; - std::cout << "All " << tests.count << " parser cases passed.\n"; - return 0; + CHECK(recovered.frames.size() == 1U && recovered.frames[0].canId == 2U, + "Fresh parse after error"); } + +int RunParserTests(int argc, char **argv) { + DbcParserTest tests; + return QTest::qExec(&tests, argc, argv); +} + +#include "dbc_parser_test.moc" diff --git a/tests/dbc_parser_test.pro b/tests/dbc_parser_test.pro deleted file mode 100644 index d6341b3..0000000 --- a/tests/dbc_parser_test.pro +++ /dev/null @@ -1,7 +0,0 @@ -TEMPLATE = app -TARGET = dbc_parser_test -CONFIG += console c++17 -CONFIG -= app_bundle qt -INCLUDEPATH += .. -SOURCES += dbc_parser_test.cpp ../dbc_parser.cpp ../dbc_statement_handler.cpp -HEADERS += ../dbc_statement_handler.h ../typefactory.h ../dbc_parser.h ../dbc_database.h ../frame_info.h ../signal_info.h diff --git a/tests/decoder_tests.pri b/tests/decoder_tests.pri new file mode 100644 index 0000000..5b51f18 --- /dev/null +++ b/tests/decoder_tests.pri @@ -0,0 +1 @@ +SOURCES += $$PWD/dbc_decoder_test.cpp diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..b5a388a --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,12 @@ +#include +#include + +int RunParserTests(int argc, char **argv); +int RunDecoderTests(int argc, char **argv); + +int main(int argc, char **argv) { + QCoreApplication application(argc, argv); + const int parserResult = RunParserTests(argc, argv); + const int decoderResult = RunDecoderTests(argc, argv); + return parserResult | decoderResult; +} diff --git a/tests/parser_tests.pri b/tests/parser_tests.pri new file mode 100644 index 0000000..f46d193 --- /dev/null +++ b/tests/parser_tests.pri @@ -0,0 +1 @@ +SOURCES += $$PWD/dbc_parser_test.cpp diff --git a/tests/tests.pro b/tests/tests.pro new file mode 100644 index 0000000..f5d428d --- /dev/null +++ b/tests/tests.pro @@ -0,0 +1,11 @@ +TEMPLATE = app +TARGET = dbc_tests +QT += core testlib +QT -= gui +CONFIG += console testcase c++17 no_keywords +CONFIG -= app_bundle +include(../core/core.pri) +include(parser_tests.pri) +include(decoder_tests.pri) +SOURCES += main.cpp +CONFIG -= debug_and_release debug_and_release_target