Skip to content

Commit 80df25a

Browse files
committed
Add examples directory and enable builds in CI
Created a directory of . In there I have a simple function to add these source files. It creates and executable and links to the library. Building of the examples was enabled in CI and then execute them to compare to the example output for verification they work.
1 parent 2c8acdb commit 80df25a

File tree

9 files changed

+192
-6
lines changed

9 files changed

+192
-6
lines changed

.github/workflows/pipeline.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,14 @@ jobs:
229229
- name: Run build
230230
run: cmake --build build
231231

232+
test-examples:
233+
runs-on: ubuntu-latest
234+
235+
steps:
236+
- uses: actions/checkout@v4
237+
238+
- name: Make build directory
239+
run: cmake -Bbuild -DDBC_BUILD_EXAMPLES=ON -H$GITHUB_WORKSPACE
240+
241+
- name: Run example tests
242+
run: cmake --build build --target test-examples

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ option(DBC_ENABLE_TESTS "Enable Unittests" ON)
88
option(DBC_TEST_LOCALE_INDEPENDENCE "Used to deterime if the libary is locale agnostic when it comes to converting floats. You need `de_DE.UTF-8` locale installed for this testing." OFF)
99
option(DBC_GENERATE_DOCS "Use doxygen if installed to generated documentation files" OFF)
1010
option(DBC_GENERATE_SINGLE_HEADER "This will run the generator for the single header file version. Default is OFF since we make a static build. Requires cargo installed." OFF)
11+
option(DBC_BUILD_EXAMPLES "Build all the examples in the examples folder." OFF)
1112
# ---------------------- #
1213

1314
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
@@ -123,3 +124,5 @@ add_custom_target(clang-tidy-fix
123124
clang-tidy -fix-notes -p ${CMAKE_BINARY_DIR}/compile_commands.json ${SOURCE_FILES} ${HEADER_FILES}
124125
DEPENDS ${SOURCE_FILES} ${HEADER_FILES}
125126
)
127+
128+
add_subdirectory(examples)

examples/CMakeLists.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
project(examples)
2+
3+
set(EXECUTABLE_EXAMPLES "")
4+
5+
function(add_example_executable SOURCE_NAME SOURCE_FILE)
6+
add_executable(${SOURCE_NAME} ${SOURCE_FILE})
7+
target_link_libraries(${SOURCE_NAME} PRIVATE dbc)
8+
target_compile_definitions(${SOURCE_NAME} PRIVATE DBC_FILE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/dbcs")
9+
10+
set(EXECUTABLE_EXAMPLES "${SOURCE_NAME} ${EXECUTABLE_EXAMPLES} " PARENT_SCOPE)
11+
endfunction()
12+
13+
if(DBC_BUILD_EXAMPLES)
14+
add_example_executable(read_simple_dbc src/example_read_simple_dbc.cpp EXECUTABLE_EXAMPLES)
15+
16+
string(STRIP ${EXECUTABLE_EXAMPLES} EXECUTABLE_EXAMPLES)
17+
18+
add_custom_target(test_examples ALL
19+
DEPENDS "${EXECUTABLE_EXAMPLES}"
20+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
21+
COMMAND ${PROJECT_SOURCE_DIR}/validate_examples.py
22+
)
23+
endif()

examples/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Examples
2+
3+
You will find all the examples in the `src/` directory.
4+
Each example shall be prefixed with `example_` and then named
5+
with the use case then end with `.cpp`.
6+
7+
There are tests to build and validate that all examples are working.
8+
You can validate output as well. You need to enclose the expected output
9+
with `=== +++ ===`. The python script will parse out the text between
10+
and compare the stdout to the text. You are not required to have test
11+
output.
12+
13+
## Build and Run Examples
14+
15+
They are turned off by default and enabled via the `DBC_BUILD_EXAMPLES`
16+
option.
17+
18+
A quick getting started is:
19+
20+
```shell
21+
cmake --build build -DDBC_BUILD_EXAMPLES=ON -H.
22+
cmake --build build --target read_simple_dbc
23+
./build/examples/read_simple_dbc
24+
```
25+
26+
## Testing Examples
27+
28+
There is a cmake target to build the examples and run the tests.
29+
30+
You can do so with:
31+
32+
```shell
33+
cmake --build build -DDBC_BUILD_EXAMPLES=ON -H.
34+
cmake --build build --target test-examples
35+
```

examples/dbcs/HelloWorld.dbc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
VERSION "1.0.0"
2+
3+
NS_ :
4+
BA_
5+
BA_DEF_
6+
BA_DEF_DEF_
7+
BA_DEF_DEF_REL_
8+
BA_DEF_REL_
9+
BA_DEF_SGTYPE_
10+
BA_REL_
11+
BA_SGTYPE_
12+
BO_TX_BU_
13+
BU_BO_REL_
14+
BU_EV_REL_
15+
BU_SG_REL_
16+
CAT_
17+
CAT_DEF_
18+
CM_
19+
ENVVAR_DATA_
20+
EV_DATA_
21+
FILTER
22+
NS_DESC_
23+
SGTYPE_
24+
SGTYPE_VAL_
25+
SG_MUL_VAL_
26+
SIGTYPE_VALTYPE_
27+
SIG_GROUP_
28+
SIG_TYPE_REF_
29+
SIG_VALTYPE_
30+
VAL_
31+
VAL_TABLE_
32+
33+
BS_:
34+
35+
BU_: DBG DRIVER IO MOTOR SENSOR
36+
37+
BO_ 500 IO_DEBUG: 4 IO
38+
SG_ IO_DEBUG_test_unsigned : 0|8@1+ (1,0) [0|0] "m/s" DBG
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
This is the the very basic use case of the library.
3+
Here we are just reading a very basic dbc with one message and signal.
4+
5+
All we do below is read the basic information of the dbc files
6+
such as the nodes, messages, and signals. This library supports
7+
the << operator to print out the messages and signals.
8+
9+
EXAMPLE OUT:
10+
11+
=== +++ ===
12+
Version: 1.0.0
13+
Node: DBG
14+
Node: DRIVER
15+
Node: IO
16+
Node: MOTOR
17+
Node: SENSOR
18+
Message: {id: 500, name: IO_DEBUG, size: 4, node: IO}
19+
Signal: {name: IO_DEBUG_test_unsigned, Multiplexed: False, Start bit: 0, Size: 8, Endianness: Little endian, Value Type: Unsigned, Min: 0.000000, Max: 0.000000, Unit: (m/s), receivers: DBG}
20+
=== +++ ===
21+
*/
22+
23+
#include <libdbc/dbc.hpp>
24+
#include <string>
25+
26+
// `DBC_FILE_PATH` is defined in the build system as an absolute path
27+
static const std::string dbc_file_path = std::string(DBC_FILE_PATH) + "/HelloWorld.dbc";
28+
29+
int main() {
30+
Libdbc::DbcParser parser = Libdbc::DbcParser();
31+
parser.parse_file(dbc_file_path);
32+
33+
std::cout << "Version: " << parser.get_version() << std::endl;
34+
35+
for(auto const& node: parser.get_nodes()) {
36+
std::cout << "Node: " << node << std::endl;
37+
}
38+
39+
for(auto const& message: parser.get_messages()) {
40+
std::cout << message << std::endl;
41+
for(auto const& signal: message.get_signals()) {
42+
std::cout << signal << std::endl;
43+
}
44+
}
45+
}

examples/validate_examples.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env python3
2+
3+
import pathlib
4+
import subprocess
5+
import os
6+
import unittest
7+
8+
class TestExamples(unittest.TestCase):
9+
def setUp(self):
10+
filenames = next(os.walk("./src/"), (None, None, []))[2]
11+
self.examples = [file for file in filenames if ".cpp" in file]
12+
self.assertGreaterEqual(len(self.examples), 1)
13+
self.maxDiff = None # Enable big diffs of text
14+
15+
def tearDown(self):
16+
pass
17+
18+
def test_hello_world(self):
19+
for example in self.examples:
20+
contents = pathlib.Path("src/" + example).read_text()
21+
example_binary_name = example.split("example_")[1].split(".cpp")[0]
22+
test_output = contents.split("=== +++ ===")[1].lstrip()
23+
24+
result = subprocess.run("../build/examples/" + example_binary_name, capture_output=True, text=True)
25+
with self.subTest(msg='Check example run'):
26+
self.assertEqual(result.returncode, 0)
27+
self.assertEqual(result.stdout, test_output)
28+
self.assertEqual(result.stderr, "")
29+
30+
if __name__ == '__main__':
31+
unittest.main()

src/message.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ const std::string& Message::name() const {
111111
void Message::add_value_description(const std::string& signal_name, const std::vector<Signal::ValueDescription>& value_descriptor) {
112112
for (auto& signal : m_signals) {
113113
if (signal.name == signal_name) {
114-
signal.value_descriptions = value_descriptor;
114+
signal.value_descriptions = value_descriptor;
115115
return;
116116
}
117117
}
@@ -120,7 +120,7 @@ void Message::add_value_description(const std::string& signal_name, const std::v
120120
std::ostream& operator<<(std::ostream& out, const Message& msg) {
121121
out << "Message: {id: " << msg.id() << ", ";
122122
out << "name: " << msg.m_name << ", ";
123-
out << "size: " << msg.m_size << ", ";
123+
out << "size: " << std::to_string(msg.m_size) << ", ";
124124
out << "node: " << msg.m_node << "}";
125125
return out;
126126
}

src/signal.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ bool Signal::operator<(const Signal& rhs) const {
4242
}
4343

4444
std::ostream& operator<<(std::ostream& out, const Signal& sig) {
45-
out << "Signal {name: " << sig.name << ", ";
45+
out << "Signal: {name: " << sig.name << ", ";
4646
out << "Multiplexed: " << (sig.is_multiplexed ? "True" : "False") << ", ";
47-
out << "Start bit: " << sig.start_bit << ", ";
48-
out << "Size: " << sig.size << ", ";
47+
out << "Start bit: " << std::to_string(sig.start_bit) << ", ";
48+
out << "Size: " << std::to_string(sig.size) << ", ";
4949
out << "Endianness: " << (sig.is_bigendian ? "Big endian" : "Little endian") << ", ";
5050
out << "Value Type: " << (sig.is_signed ? "Signed" : "Unsigned") << ", ";
51-
out << "Min: " << sig.min << ", Max: " << sig.max << ", ";
51+
out << "Min: " << std::to_string(sig.min) << ", Max: " << std::to_string(sig.max) << ", ";
5252
out << "Unit: (" << sig.unit << "), ";
5353
out << "receivers: ";
5454
for (const auto& reciever : sig.receivers) {

0 commit comments

Comments
 (0)