DCCL v5
Loading...
Searching...
No Matches
test.cpp
1// Copyright 2024:
2// GobySoft, LLC (2013-)
3// Community contributors (see AUTHORS file)
4// File authors:
5// Toby Schneider <toby@gobysoft.org>
6//
7//
8// This file is part of the Dynamic Compact Control Language Library
9// ("DCCL").
10//
11// DCCL is free software: you can redistribute it and/or modify
12// it under the terms of the GNU Lesser General Public License as published by
13// the Free Software Foundation, either version 2.1 of the License, or
14// (at your option) any later version.
15//
16// DCCL is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU Lesser General Public License for more details.
20//
21// You should have received a copy of the GNU Lesser General Public License
22// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
23// tests CRC field codecs (dccl.crc16 and dccl.crc32)
24
25#include <cassert>
26#include <iostream>
27#include <stdexcept>
28
29#include "../../binary.h"
30#include "../../codec.h"
31#include "test.pb.h"
32
33using namespace dccl::test;
34
35int main(int argc, char* argv[])
36{
37 bool verbose = false;
38 for (int i = 1; i < argc; ++i)
39 {
40 if (argv[i] && argv[i][0] == '-' && argv[i][1] == 'v' && argv[i][2] == '\0')
41 verbose = true;
42 }
43
44 dccl::dlog.connect(verbose ? dccl::logger::ALL : dccl::logger::WARN_PLUS, &std::cerr);
45
46 dccl::Codec codec;
47
48 //
49 // Test CRC-16
50 //
51 {
52 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "=== Testing CRC-16 ===" << std::endl;
53 codec.load<TestCRC16>();
54 if (dccl::dlog.is(dccl::logger::INFO))
55 {
56 codec.info<TestCRC16>(&dccl::dlog);
57 }
58
59 TestCRC16 msg_in, msg_out;
60 msg_in.set_x(1234);
61 msg_in.set_y(-5678);
62 msg_in.set_crc(0); // dummy value - overwritten by dccl.crc16 codec
63
64 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Message in:\n" << msg_in.DebugString() << std::endl;
65 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Encoding..." << std::endl;
66 std::string bytes;
67 codec.encode(&bytes, msg_in);
68 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Encoded (hex): " << dccl::hex_encode(bytes) << std::endl;
69
70 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Decoding..." << std::endl;
71 try
72 {
73 codec.decode(bytes, &msg_out);
74 }
75 catch (const std::exception& e)
76 {
77 std::cerr << "UNEXPECTED exception during decode: " << e.what() << std::endl;
78 assert(false);
79 }
80 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Message out:\n" << msg_out.DebugString() << std::endl;
81
82 assert(msg_out.x() == msg_in.x());
83 assert(msg_out.y() == msg_in.y());
84 assert(msg_out.crc() != 0); // CRC should be set
85
86 // Verify that the CRC in the decoded message matches what was encoded
87 assert(msg_out.crc() == msg_out.crc());
88
89 // Test that a corrupt message throws an exception
90 std::string corrupt_bytes = bytes;
91 corrupt_bytes[corrupt_bytes.size() - 1] ^= 0xFF; // flip bits in last byte
92 try
93 {
94 TestCRC16 corrupt_out;
95 codec.decode(corrupt_bytes, &corrupt_out);
96 std::cerr << "ERROR: Corrupt message did not throw exception!" << std::endl;
97 assert(false);
98 }
99 catch (const std::exception& e)
100 {
101 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Caught expected exception for corrupt CRC-16: " << e.what() << std::endl;
102 }
103
104 codec.unload<TestCRC16>();
105 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "CRC-16 tests passed!" << std::endl;
106 }
107
108 //
109 // Test CRC-32
110 //
111 {
112 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "\n=== Testing CRC-32 ===" << std::endl;
113 codec.load<TestCRC32>();
114 if (dccl::dlog.is(dccl::logger::INFO))
115 {
116 codec.info<TestCRC32>(&dccl::dlog);
117 }
118
119 TestCRC32 msg_in, msg_out;
120 msg_in.set_x(9999);
121 msg_in.set_y(-9999);
122 msg_in.set_crc(0); // dummy value - overwritten by dccl.crc32 codec
123
124 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Message in:\n" << msg_in.DebugString() << std::endl;
125 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Encoding..." << std::endl;
126 std::string bytes;
127 codec.encode(&bytes, msg_in);
128 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Encoded (hex): " << dccl::hex_encode(bytes) << std::endl;
129
130 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Decoding..." << std::endl;
131 codec.decode(bytes, &msg_out);
132 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Message out:\n" << msg_out.DebugString() << std::endl;
133
134 assert(msg_out.x() == msg_in.x());
135 assert(msg_out.y() == msg_in.y());
136 assert(msg_out.crc() != 0); // CRC should be set
137
138 // Test that a corrupt message throws an exception
139 std::string corrupt_bytes = bytes;
140 corrupt_bytes[corrupt_bytes.size() - 1] ^= 0xFF; // flip bits in last byte
141 try
142 {
143 TestCRC32 corrupt_out;
144 codec.decode(corrupt_bytes, &corrupt_out);
145 std::cerr << "ERROR: Corrupt message did not throw exception!" << std::endl;
146 assert(false);
147 }
148 catch (const std::exception& e)
149 {
150 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Caught expected exception for corrupt CRC-32: " << e.what() << std::endl;
151 }
152
153 codec.unload<TestCRC32>();
154 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "CRC-32 tests passed!" << std::endl;
155 }
156
157 //
158 // Test encoding twice gives same result (CRC is deterministic)
159 //
160 {
161 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "\n=== Testing CRC-16 determinism ===" << std::endl;
162 codec.load<TestCRC16>();
163
164 TestCRC16 msg;
165 msg.set_x(42);
166 msg.set_y(100);
167 msg.set_crc(0);
168
169 std::string bytes1, bytes2;
170 codec.encode(&bytes1, msg);
171 codec.encode(&bytes2, msg);
172 assert(bytes1 == bytes2);
173 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "CRC is deterministic." << std::endl;
174
175 // Test different field values give different CRC
176 TestCRC16 msg2;
177 msg2.set_x(43); // different x
178 msg2.set_y(100);
179 msg2.set_crc(0);
180 std::string bytes3;
181 codec.encode(&bytes3, msg2);
182 assert(bytes3 != bytes1);
183 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "CRC differs for different data." << std::endl;
184
185 codec.unload<TestCRC16>();
186 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Determinism tests passed!" << std::endl;
187 }
188
189 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "\nAll CRC tests passed!" << std::endl;
190 return 0;
191}
The Dynamic CCL enCODer/DECoder. This is the main class you will use to load, encode and decode DCCL ...
Definition codec.h:61
bool is(logger::Verbosity verbosity, logger::Group group=logger::GENERAL)
Indicates the verbosity of the Logger until the next std::flush or std::endl. The boolean return is u...
Definition logger.h:191
void connect(int verbosity_mask, Slot slot)
Connect the output of one or more given verbosities to a slot (function pointer or similar)
Definition logger.h:213
Unit test namespace.
Definition test.cpp:45
Dynamic Compact Control Language namespace.
Definition any.h:28
void hex_encode(CharIterator begin, CharIterator end, std::string *out, bool upper_case=false)
Encodes a (little-endian) hexadecimal string from a byte string. Index 0 of begin is written to index...
Definition binary.h:95