DCCL v5
Loading...
Searching...
No Matches
test.cpp
1// Copyright 2011-2023:
2// GobySoft, LLC (2013-)
3// Massachusetts Institute of Technology (2007-2014)
4// Community contributors (see AUTHORS file)
5// File authors:
6// Toby Schneider <toby@gobysoft.org>
7// Chris Murphy <cmurphy@aphysci.com>
8//
9//
10// This file is part of the Dynamic Compact Control Language Library
11// ("DCCL").
12//
13// DCCL is free software: you can redistribute it and/or modify
14// it under the terms of the GNU Lesser General Public License as published by
15// the Free Software Foundation, either version 2.1 of the License, or
16// (at your option) any later version.
17//
18// DCCL is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public License
24// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
25// tests custom message codec
26// tests cryptography
27
28#include "../../codec.h"
29#include "test.pb.h"
30
31#include "../../binary.h"
32using namespace dccl::test;
33
34using dccl::operator<<;
35using dccl::Bitset;
36
37namespace dccl
38{
40namespace test
41{
42class CustomCodec : public dccl::TypedFixedFieldCodec<CustomMsg>
43{
44 private:
45 unsigned size() override { return (part() == dccl::HEAD) ? 0 : A_SIZE + B_SIZE; }
46 Bitset encode() override { return Bitset(size()); }
47
48 Bitset encode(const CustomMsg& msg) override
49 {
50 if (part() == dccl::HEAD)
51 {
52 return encode();
53 }
54 else
55 {
56 Bitset a(A_SIZE, static_cast<unsigned long>(msg.a()));
57 Bitset b(B_SIZE, static_cast<unsigned long>(msg.b()));
58
59 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "a: " << a << std::endl;
60 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "b: " << b << std::endl;
61
62 a.append(b);
63 return a;
64 }
65 }
66
67 CustomMsg decode(Bitset* bits) override
68 {
69 if (part() == dccl::HEAD)
70 {
72 }
73 else
74 {
75 Bitset a = *bits;
76 a.resize(A_SIZE);
77 Bitset b = *bits;
78 b >>= A_SIZE;
79 b.resize(B_SIZE);
80
81 CustomMsg msg;
82 msg.set_a(a.to_ulong());
83 msg.set_b(b.to_ulong());
84 return msg;
85 }
86 }
87
88 void validate() override {}
89
90 enum
91 {
92 A_SIZE = 32
93 };
94 enum
95 {
96 B_SIZE = 1
97 };
98};
99
101{
102 private:
103 enum
104 {
105 REPEAT_STORAGE_BITS = 4
106 };
107 enum
108 {
109 MAX_REPEAT_SIZE = 1 << REPEAT_STORAGE_BITS
110 }; // 2^4
111
112 dccl::int32 max() { return FieldCodecBase::dccl_field_options().max(); }
113 dccl::int32 min() { return FieldCodecBase::dccl_field_options().min(); }
114 dccl::int32 max_repeat() { return FieldCodecBase::dccl_field_options().max_repeat(); }
115
116 Bitset encode_repeated(const std::vector<dccl::int32>& wire_values) override
117 {
118 Bitset value_bits;
119 int repeat_size =
120 static_cast<int>(wire_values.size()) > max_repeat() ? max_repeat() : wire_values.size();
121
122 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "repeat size is " << repeat_size << std::endl;
123
124 for (int i = 0, n = repeat_size; i < n; ++i)
125 {
126 dccl::int32 wire_value = wire_values[i];
127 wire_value -= min();
128 value_bits.append(Bitset(singular_size(), static_cast<unsigned long>(wire_value)));
129 }
130
131 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << value_bits << std::endl;
132 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << Bitset(REPEAT_STORAGE_BITS, repeat_size) << std::endl;
133 Bitset out(REPEAT_STORAGE_BITS, repeat_size);
134 out.append(value_bits);
135 return out;
136 }
137
138 std::vector<dccl::int32> decode_repeated(Bitset* bits) override
139 {
140 int repeat_size = bits->to_ulong();
141 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "repeat size is " << repeat_size << std::endl;
142 // grabs more bits to add to the MSBs of `bits`
143 bits->get_more_bits(repeat_size * singular_size());
144
145 Bitset value_bits = *bits;
146 value_bits >>= REPEAT_STORAGE_BITS;
147
148 std::vector<dccl::int32> out;
149 for (int i = 0; i < repeat_size; ++i)
150 {
151 dccl::int32 value = value_bits.to_ulong() & ((1 << singular_size()) - 1);
152 value += min();
153 out.push_back(value);
154 value_bits >>= singular_size();
155 }
156 return out;
157 }
158
159 unsigned size_repeated(const std::vector<dccl::int32>& field_values) override
160 {
161 return REPEAT_STORAGE_BITS + field_values.size() * singular_size();
162 }
163
164 unsigned singular_size() { return dccl::ceil_log2((max() - min()) + 1); }
165
166 unsigned max_size_repeated() override
167 {
168 return REPEAT_STORAGE_BITS + max_repeat() * singular_size();
169 }
170
171 unsigned min_size_repeated() override { return REPEAT_STORAGE_BITS; }
172
173 void validate() override
174 {
176 "missing (dccl.field).min");
178 "missing (dccl.field).max");
180 FieldCodecBase::dccl_field_options().max_repeat() < MAX_REPEAT_SIZE,
181 "(dccl.field).max_repeat must be less than " +
182 std::to_string(static_cast<int>(MAX_REPEAT_SIZE)));
183 }
184};
185
186} // namespace test
187} // namespace dccl
188
189int main(int argc, char* argv[])
190{
191 bool verbose = false;
192 for (int i = 1; i < argc; ++i)
193 {
194 if (argv[i] && argv[i][0] == '-' && argv[i][1] == 'v' && argv[i][2] == '\0')
195 verbose = true;
196 }
197
198 dccl::dlog.connect(verbose ? dccl::logger::ALL : dccl::logger::WARN_PLUS, &std::cerr);
199
200 dccl::Codec codec;
201 codec.manager().add<dccl::test::CustomCodec>("custom_codec");
202 codec.manager().add<dccl::test::Int32RepeatedCodec>("int32_test_codec");
203
204 codec.set_crypto_passphrase("my_passphrase!");
205
206 CustomMsg msg_in1;
207
208 msg_in1.set_a(10);
209 msg_in1.set_b(true);
210
211 if (dccl::dlog.is(dccl::logger::INFO))
212 codec.info(msg_in1.GetDescriptor(), &dccl::dlog);
213
214
215 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Message in:\n" << msg_in1.DebugString() << std::endl;
216 codec.load(msg_in1.GetDescriptor());
217 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Try encode..." << std::endl;
218 std::string bytes1;
219 codec.encode(&bytes1, msg_in1);
220 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "... got bytes (hex): " << dccl::hex_encode(bytes1) << std::endl;
221 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Try decode..." << std::endl;
222 std::shared_ptr<google::protobuf::Message> msg_out1 =
223 codec.decode<std::shared_ptr<google::protobuf::Message>>(bytes1);
224 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "... got Message out:\n" << msg_out1->DebugString() << std::endl;
225 assert(msg_in1.SerializeAsString() == msg_out1->SerializeAsString());
226
227 CustomMsg2 msg_in2, msg_out2;
228
229 msg_in2.mutable_msg()->CopyFrom(msg_in1);
230 msg_in2.add_c(30);
231 msg_in2.add_c(2);
232
233 if (dccl::dlog.is(dccl::logger::INFO))
234 {
235 codec.info(msg_in2.GetDescriptor(), &dccl::dlog);
236 }
237 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Message in:\n" << msg_in2.DebugString() << std::endl;
238 codec.load(msg_in2.GetDescriptor());
239 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Try encode..." << std::endl;
240 std::string bytes2;
241 codec.encode(&bytes2, msg_in2);
242 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "... got bytes (hex): " << dccl::hex_encode(bytes2) << std::endl;
243 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "Try decode..." << std::endl;
244 codec.decode(bytes2, &msg_out2);
245 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "... got Message out:\n" << msg_out2.DebugString() << std::endl;
246 assert(msg_in2.SerializeAsString() == msg_out2.SerializeAsString());
247
248 dccl::dlog.is(dccl::logger::INFO) && dccl::dlog << "all tests passed" << std::endl;
249}
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition bitset.h:43
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition bitset.h:420
Bitset & append(const Bitset &bits)
Adds the bitset to the big end.
Definition bitset.h:361
unsigned long to_ulong() const
Returns the value of the Bitset as an unsigned long integer. Equivalent to to<unsigned long>().
Definition bitset.h:275
The Dynamic CCL enCODer/DECoder. This is the main class you will use to load, encode and decode DCCL ...
Definition codec.h:61
MessagePart part()
the part of the message currently being encoded (head or body)
void require(bool b, const std::string &description)
Essentially an assertion to be used in the validate() virtual method.
dccl::DCCLFieldOptions dccl_field_options() const
Get the DCCL field option extension value for the current field.
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
Exception used to signal null (non-existent) value within field codecs during decode.
Definition exception.h:62
Base class for "repeated" (multiple value) static-typed (no dccl::any) field encoders/decoders....
Base class for static-typed field encoders/decoders that use a fixed number of bits on the wire regar...
Unit test namespace.
Definition test.cpp:45
Dynamic Compact Control Language namespace.
Definition any.h:28
google::protobuf::int32 int32
a signed 32 bit integer
Definition common.h:58
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
unsigned ceil_log2(dccl::uint64 v)
Definition binary.h:163