DCCL v4
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 std::cout << "a: " << a << std::endl;
60 std::cout << "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 std::cout << "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 std::cout << value_bits << std::endl;
132 std::cout << 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 std::cout << "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 dccl::dlog.connect(dccl::logger::ALL, &std::cerr);
192
193 dccl::Codec codec;
194 codec.manager().add<dccl::test::CustomCodec>("custom_codec");
195 codec.manager().add<dccl::test::Int32RepeatedCodec>("int32_test_codec");
196
197 codec.set_crypto_passphrase("my_passphrase!");
198
199 CustomMsg msg_in1;
200
201 msg_in1.set_a(10);
202 msg_in1.set_b(true);
203
204 codec.info(msg_in1.GetDescriptor(), &std::cout);
205 std::cout << "Message in:\n" << msg_in1.DebugString() << std::endl;
206 codec.load(msg_in1.GetDescriptor());
207 std::cout << "Try encode..." << std::endl;
208 std::string bytes1;
209 codec.encode(&bytes1, msg_in1);
210 std::cout << "... got bytes (hex): " << dccl::hex_encode(bytes1) << std::endl;
211 std::cout << "Try decode..." << std::endl;
212 std::shared_ptr<google::protobuf::Message> msg_out1 =
213 codec.decode<std::shared_ptr<google::protobuf::Message>>(bytes1);
214 std::cout << "... got Message out:\n" << msg_out1->DebugString() << std::endl;
215 assert(msg_in1.SerializeAsString() == msg_out1->SerializeAsString());
216
217 CustomMsg2 msg_in2, msg_out2;
218
219 msg_in2.mutable_msg()->CopyFrom(msg_in1);
220 msg_in2.add_c(30);
221 msg_in2.add_c(2);
222
223 codec.info(msg_in2.GetDescriptor(), &std::cout);
224 std::cout << "Message in:\n" << msg_in2.DebugString() << std::endl;
225 codec.load(msg_in2.GetDescriptor());
226 std::cout << "Try encode..." << std::endl;
227 std::string bytes2;
228 codec.encode(&bytes2, msg_in2);
229 std::cout << "... got bytes (hex): " << dccl::hex_encode(bytes2) << std::endl;
230 std::cout << "Try decode..." << std::endl;
231 codec.decode(bytes2, &msg_out2);
232 std::cout << "... got Message out:\n" << msg_out2.DebugString() << std::endl;
233 assert(msg_in2.SerializeAsString() == msg_out2.SerializeAsString());
234
235 std::cout << "all tests passed" << std::endl;
236}
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:63
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:47
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:100
unsigned ceil_log2(dccl::uint64 v)
Definition binary.h:178