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
virtual std::string info()
Write field specific information (in addition to general information such as sizes that are automatic...
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.
virtual void validate()
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
dccl::DCCLFieldOptions dccl_field_options() const
Get the DCCL field option extension value for the current field.
std::enable_if< std::is_base_of< google::protobuf::Message, typenameCodec::wire_type >::value &&!std::is_same< google::protobuf::Message, typenameCodec::wire_type >::value, void >::type add(const std::string &name)
Add a new field codec (used for codecs operating on statically generated Protobuf messages,...
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