7#include <QTemporaryFile>
11#include <unordered_map>
14static_assert(std::is_same_v<decltype(std::declval<const DecodeDatabase &>().GetFrames()),
15 const std::vector<DecodeFrame> &>);
23 file.write(text.data(),
static_cast<qint64
>(text.size())) !=
static_cast<qint64
>(text.size()) ||
25 throw std::runtime_error(
"Cannot write reload fixture");
29 const std::string firstDbc =
30 "BO_ 17 OldFrame: 2 ECU\n"
31 "SG_ State : 0|8@1+ (2,1) [1|511] \"old\" ECU\n"
32 "SG_ Removed : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
33 "VAL_ 17 State 1 \"Old label\";\n"
34 "BO_ 18 Deleted: 1 ECU\n"
35 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n";
36 const std::string secondDbc =
37 "BO_ 2147483665 Extended: 1 ECU\n"
38 "SG_ State : 0|8@1+ (1,0) [0|255] \"\" ECU\n"
39 "BO_ 17 NewFrame: 2 ECU\n"
40 "SG_ Renamed : 8|8@1+ (1,0) [0|255] \"\" ECU\n"
41 "SG_ State : 0|8@1+ (4,0) [0|1020] \"new\" ECU\n"
42 "VAL_ 17 State 1 \"New label\";\n";
45class DbcLifetimeTest :
public QObject {
49 void independentSignalLifetime();
50 void lookupLifetime();
54 void invalidResults();
55 void retainedMultiplexStatuses();
58void DbcLifetimeTest::reload() {
66 std::weak_ptr<const DecodeFrame> oldDefinition = moved.
definition;
67 database = BuildText(secondDbc);
71 QVERIFY(current.
key == moved.
key);
72 QVERIFY(current.signals[1].
key == moved.signals[0].
key);
73 QCOMPARE(moved.
definition->name, std::string(
"OldFrame"));
75 QCOMPARE(moved.signals[0].physicalValue, 3.0);
76 QCOMPARE(current.signals[1].physicalValue, 4.0);
77 QCOMPARE(moved.signals[0].
definition->unit, std::string(
"old"));
78 QCOMPARE(current.signals[1].
definition->unit, std::string(
"new"));
79 QCOMPARE(*moved.signals[0].GetValueDescription(), std::string(
"Old label"));
80 QCOMPARE(*current.signals[1].GetValueDescription(), std::string(
"New label"));
81 QCOMPARE(moved.signals[1].
definition->name, std::string(
"Removed"));
84 QVERIFY(!oldDefinition.expired());
85 QCOMPARE(current.
definition->name, std::string(
"NewFrame"));
86 QCOMPARE(*current.signals[1].GetValueDescription(), std::string(
"New label"));
89void DbcLifetimeTest::independentSignalLifetime() {
91 std::weak_ptr<const DecodeSignal> definition;
92 const std::string *label =
nullptr;
99 saved = result.signals[0];
103 database = BuildText(secondDbc);
105 QVERIFY(!definition.expired());
106 QVERIFY(label !=
nullptr);
107 QCOMPARE(*label, std::string(
"Old label"));
114 QVERIFY(!definition.expired());
116 QVERIFY(definition.expired());
119void DbcLifetimeTest::lookupLifetime() {
120 std::shared_ptr<const DecodeFrame> frame;
121 std::shared_ptr<const DecodeSignal> signal;
122 std::weak_ptr<const DecodeFrame> released;
128 QVERIFY(frame && signal);
129 QCOMPARE(frame.get(), ©.
GetFrames()[0]);
130 QCOMPARE(signal.get(), &frame->signals[0]);
132 database = BuildText(secondDbc);
138 QCOMPARE(frame->name, std::string(
"OldFrame"));
140 QVERIFY(!released.expired());
141 QCOMPARE(signal->name, std::string(
"State"));
143 QVERIFY(released.expired());
146void DbcLifetimeTest::keys() {
159 std::unordered_map<FrameKey, int, FrameKeyHasher> frames;
160 frames.emplace(frame, 1);
161 frames.emplace(
FrameKey(17U,
true), 2);
162 QCOMPARE(frames.size(), std::size_t(2U));
163 std::unordered_map<SignalKey, int, SignalKeyHasher> signals;
164 signals.emplace(state, 1);
166 signals.emplace(
SignalKey(frame,
"Renamed"), 3);
169 QCOMPARE(signals.size(), std::size_t(4U));
172void DbcLifetimeTest::duplicateKeys() {
175 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (
void)
DecodeDatabase({frame, frame}));
177 signal.
name =
"State";
180 frame.signals = {signal, signal};
181 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (
void)
DecodeDatabase({frame}));
185 parsed.
frames = {source, source};
186 QVERIFY_THROWS_EXCEPTION(std::invalid_argument, (
void)
DbcDecodeBuilder().Build(parsed));
189void DbcLifetimeTest::failedReload() {
191 const std::shared_ptr<const DecodeFrame> original = database.
FindFrame(
FrameKey(17U,
false));
192 QVERIFY_THROWS_EXCEPTION(std::runtime_error, database = BuildText(
"BO_ invalid\n"));
194 database = BuildText(
"");
197 QCOMPARE(original->name, std::string(
"OldFrame"));
200void DbcLifetimeTest::invalidResults() {
204 QVERIFY(result.
valid);
205 QVERIFY(!result.signals[0].
valid);
206 QCOMPARE(result.signals[0].
status, SignalDecodeStatus::InsufficientPayload);
207 QVERIFY(!result.signals[0].GetValueDescription());
208 QCOMPARE(result.signals[0].
definition->name, std::string(
"State"));
210 QVERIFY(!result.
valid && !result.
definition && result.signals.empty());
216void DbcLifetimeTest::retainedMultiplexStatuses() {
217 const std::string text =
218 "BO_ 17 Frame: 2 ECU\n"
219 "SG_ Mode M : 0|1@1+ (1,0) [0|1] \"\" ECU\n"
220 "SG_ State m1 : 8|8@1+ (1,0) [0|255] \"\" ECU\n";
221 const std::vector<std::vector<std::uint8_t>> payloads = {{0U}, {}, {1U}};
223 SignalDecodeStatus::SelectorUnavailable,
224 SignalDecodeStatus::InsufficientPayload};
225 for (std::size_t index = 0U; index < payloads.size(); ++index) {
229 raw.
data = payloads[index];
231 database = BuildText(secondDbc);
232 QCOMPARE(saved.
status, statuses[index]);
234 QCOMPARE(saved.
definition->multiplexing.role, MultiplexRole::Branch);
239int RunLifetimeTests(
int argc,
char **argv) {
240 DbcLifetimeTest test;
241 return QTest::qExec(&test, argc, argv);
244#include "dbc_lifetime_test.moc"
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.
DecodedFrameValue Decode(const DecodeDatabase &database, const RawCanFrame &frame) const
Decode one raw CAN frame.
std::shared_ptr< const DecodeFrame > FindFrame(const DecodeDatabase &database, std::uint32_t canId, bool isExtended) const
Find exact CAN ID first, then unique PGN among explicitly J1939 definitions.
Immutable runtime snapshot. Copies share storage; reload replaces a snapshot. Owning lookup handles a...
std::shared_ptr< const DecodeSignal > FindSignal(const SignalKey &key) const
Return an owning signal handle, or an empty handle for a missing key.
std::shared_ptr< const DecodeFrame > FindFrame(const FrameKey &key) const
const std::vector< DecodeFrame > & GetFrames() const
Runtime decode database builder.
CAN frame decoding API and result types.
SignalDecodeStatus
Outcome of signal extraction and physical conversion.
DBC file parser and interpretation options.
Parsed DBC content stored in a simple internal form.
std::vector< FrameInfo > frames
Runtime-ready frame definition.
Runtime-ready signal definition.
std::shared_ptr< const DecodeFrame > definition
One decoded signal value.
std::shared_ptr< const DecodeSignal > definition
SignalDecodeStatus status
const std::string * GetValueDescription() const
Describes one CAN frame from a DBC file.
Stable frame identifier: normalized CAN ID and frame type.
Raw CAN frame used for runtime or trace decoding.
std::vector< std::uint8_t > data