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 min_length for bytes fields (VarBytesCodec) and v4 string fields
24
25#include "dccl/binary.h"
26#include "dccl/codec.h"
27#include "test.pb.h"
28
29using namespace dccl::test;
30
31int main(int argc, char* argv[])
32{
33 bool verbose = false;
34 for (int i = 1; i < argc; ++i)
35 {
36 if (argv[i] && argv[i][0] == '-' && argv[i][1] == 'v' && argv[i][2] == '\0')
37 verbose = true;
38 }
39
40 dccl::dlog.connect(verbose ? dccl::logger::ALL : dccl::logger::WARN_PLUS, &std::cerr);
41
42 dccl::Codec codec;
43 codec.load<MinLengthMsg>();
44 codec.info<MinLengthMsg>(&dccl::dlog);
45
46 // --- Basic encode/decode round-trip ---
47 {
48 MinLengthMsg msg_in;
49 // req_bytes: min_length=4, max_length=10 — provide exactly min_length bytes
50 msg_in.set_req_bytes(dccl::hex_decode("aabbccdd"));
51 // opt_bytes: min_length=2, max_length=8 — provide more than min_length
52 msg_in.set_opt_bytes(dccl::hex_decode("112233445566"));
53 // str_field: min_length=3, max_length=10
54 msg_in.set_str_field("hello");
55
56 std::string encoded;
57 codec.encode(&encoded, msg_in);
58
59 MinLengthMsg msg_out;
60 codec.decode(encoded, &msg_out);
61
62 assert(msg_in.SerializeAsString() == msg_out.SerializeAsString());
63 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Round-trip with fields at/above min_length: passed" << std::endl;
64 }
65
66 // --- Verify bit savings: a field with min_length reduces prefix size ---
67 // req_bytes: min_length=4, max_length=10
68 // prefix_size = ceil_log2(10 - 4 + 1) = ceil_log2(7) = 3 bits
69 // Without min_length: prefix_size = ceil_log2(10 + 1) = ceil_log2(11) = 4 bits
70 // So we save 1 bit on the required field.
71 {
72 // DCCL ID = 8 bits
73 // max_size for req_bytes (required, prefix_size=3): 3 + 10*8 = 83 bits
74 // max_size for opt_bytes (optional, presence=1, prefix_size=ceil_log2(8-2+1)=3): 1+3+8*8=68 bits
75 // max_size for str_field (optional, presence=1, prefix_size=ceil_log2(10-3+1)=3): 1+3+10*8=84 bits
76 // total max_size = 8 + 83 + 68 + 84 = 235 bits = 31 bytes (rounded up)
77 assert(codec.max_size<MinLengthMsg>() == 31);
78 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "max_size check: passed (31 bytes)" << std::endl;
79 }
80
81 // --- Length less than min_length ---
82 {
83 MinLengthMsg msg_in;
84 // req_bytes: min_length=4, max_length=10 — provide less than min_length
85 msg_in.set_req_bytes(dccl::hex_decode("aabbcc"));
86
87 std::string encoded;
88 codec.encode(&encoded, msg_in);
89
90 MinLengthMsg msg_out;
91 codec.decode(encoded, &msg_out);
92
93 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "msg_in: " << msg_in.ShortDebugString() << std::endl;
94 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "msg_out: " << msg_out.ShortDebugString() << std::endl;
95
96 // expect padding to zero
97 msg_in.set_req_bytes(dccl::hex_decode("aabbcc00"));
98
99 assert(msg_in.SerializeAsString() == msg_out.SerializeAsString());
100 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Round-trip with fields below min_length: passed" << std::endl;
101 }
102
103 // --- Optional bytes absent ---
104 {
105 MinLengthMsg msg_in;
106 msg_in.set_req_bytes(dccl::hex_decode("aabbccdd"));
107 // opt_bytes not set
108 msg_in.set_str_field("abc");
109
110 std::string encoded;
111 codec.encode(&encoded, msg_in);
112
113 MinLengthMsg msg_out;
114 codec.decode(encoded, &msg_out);
115
116 assert(!msg_out.has_opt_bytes());
117 assert(msg_in.SerializeAsString() == msg_out.SerializeAsString());
118 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Optional bytes absent: passed" << std::endl;
119 }
120
121 // --- Fixed-size bytes (min_length == max_length) ---
122 {
123 codec.load<FixedLengthMsg>();
124 codec.info<FixedLengthMsg>(&dccl::dlog);
125
126 FixedLengthMsg msg_in;
127 msg_in.set_fixed_bytes(dccl::hex_decode("0102030405"));
128
129 std::string encoded;
130 codec.encode(&encoded, msg_in);
131
132 FixedLengthMsg msg_out;
133 codec.decode(encoded, &msg_out);
134
135 assert(msg_in.SerializeAsString() == msg_out.SerializeAsString());
136
137 // DCCL ID = 8 bits
138 // prefix_size = ceil_log2(5-5+1) = ceil_log2(1) = 0 bits
139 // max_size = 8 + 0 + 5*8 = 40 bits = 6 bytes
140 assert(codec.max_size<FixedLengthMsg>() == 6);
141 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Fixed-size bytes (min_length == max_length): passed" << std::endl;
142 }
143
144 // --- Invalid: min_length > max_length should throw on load ---
145 {
146 try
147 {
148 codec.load<InvalidMinLengthMsg>();
149 assert(false && "Expected exception for min_length > max_length");
150 }
151 catch (const dccl::Exception& e)
152 {
153 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Invalid min_length > max_length correctly rejected: " << e.what()
154 << std::endl;
155 }
156 }
157
158 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "All tests passed." << std::endl;
159 return 0;
160}
The Dynamic CCL enCODer/DECoder. This is the main class you will use to load, encode and decode DCCL ...
Definition codec.h:61
Exception class for DCCL.
Definition exception.h:47
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_decode(const std::string &in, std::string *out)
Decodes a (little-endian) hexadecimal string to a byte string. Index 0 and 1 (first byte) of in are w...
Definition binary.h:46