blob: 303c4d329fc0f09fa8274f240baa2e9b2df8f96c [file] [log] [blame]
Brian Silverman41709732019-02-09 20:53:08 -08001#include "y2019/jevois/cobs.h"
2
Austin Schuhb72be802022-01-02 12:26:28 -08003#include "absl/types/span.h"
Brian Silverman41709732019-02-09 20:53:08 -08004#include "gtest/gtest.h"
Brian Silverman41709732019-02-09 20:53:08 -08005
Philipp Schrader790cb542023-07-05 21:06:52 -07006#include "aos/testing/test_logging.h"
7
Brian Silverman41709732019-02-09 20:53:08 -08008namespace frc971 {
9namespace jevois {
10
11// Tests the size conversions for some known, simple values.
12TEST(CobsMaxEncodedSizeTest, Simple) {
13 EXPECT_EQ(0u, CobsMaxEncodedSize(0));
14 EXPECT_EQ(2u, CobsMaxEncodedSize(1));
15 EXPECT_EQ(3u, CobsMaxEncodedSize(2));
16
17 EXPECT_EQ(254u, CobsMaxEncodedSize(253));
18 EXPECT_EQ(255u, CobsMaxEncodedSize(254));
19 EXPECT_EQ(257u, CobsMaxEncodedSize(255));
20}
21
22class CobsTest : public ::testing::Test {
23 public:
24 CobsTest() { aos::testing::EnableTestLogging(); }
25
26 template <size_t min_buffer_size = 0, size_t number_elements>
27 void EncodeAndDecode(const char (&input_data)[number_elements]) {
28 static constexpr size_t input_size =
29 (min_buffer_size > number_elements) ? min_buffer_size : number_elements;
Austin Schuhb72be802022-01-02 12:26:28 -080030 EncodeAndDecode<input_size>(absl::Span<const char>(input_data));
Brian Silverman41709732019-02-09 20:53:08 -080031 }
32
33 template <size_t max_decoded_size>
Austin Schuhb72be802022-01-02 12:26:28 -080034 void EncodeAndDecode(const absl::Span<const char> decoded_input) {
Brian Silverman41709732019-02-09 20:53:08 -080035 std::array<char, CobsMaxEncodedSize(max_decoded_size)> encoded_buffer;
Tyler Chatowd0a49742022-02-25 22:06:19 -080036 const auto encoded = CobsEncode<max_decoded_size>(
37 decoded_input, absl::Span<char>(encoded_buffer));
Brian Silverman41709732019-02-09 20:53:08 -080038 ASSERT_LE(encoded.size(), encoded_buffer.size());
39 ASSERT_EQ(encoded.data(), &encoded_buffer.front());
40
41 std::array<char, max_decoded_size> decoded_buffer;
42 const auto decoded = CobsDecode<max_decoded_size>(encoded, &decoded_buffer);
43 ASSERT_LE(decoded.size(), decoded_buffer.size());
44 ASSERT_EQ(decoded.data(), &decoded_buffer.front());
45 ASSERT_EQ(decoded.size(), decoded_input.size());
Austin Schuhb72be802022-01-02 12:26:28 -080046 for (size_t i = 0; i < decoded.size(); ++i) {
Brian Silverman41709732019-02-09 20:53:08 -080047 EXPECT_EQ(decoded[i], decoded_input[i]);
48 }
49 }
50};
51
52// Tests various small buffers.
53TEST_F(CobsTest, Small) {
54 EncodeAndDecode<1>(std::array<char, 0>{});
55 EncodeAndDecode<5>(std::array<char, 0>{});
56 {
57 const char data[] = {0};
58 EncodeAndDecode(data);
59 }
60 {
61 const char data[] = {1};
62 EncodeAndDecode(data);
63 }
64 {
65 const char data[] = {static_cast<char>(254)};
66 EncodeAndDecode(data);
67 }
68 {
69 const char data[] = {static_cast<char>(255)};
70 EncodeAndDecode(data);
71 }
72 {
73 const char data[] = {0, 1};
74 EncodeAndDecode(data);
75 }
76 {
77 const char data[] = {0, static_cast<char>(254)};
78 EncodeAndDecode(data);
79 }
80 {
81 const char data[] = {0, static_cast<char>(255)};
82 EncodeAndDecode(data);
83 }
84 {
85 const char data[] = {0, 1, static_cast<char>(254)};
86 EncodeAndDecode(data);
87 }
88 {
89 const char data[] = {0, 1, static_cast<char>(255)};
90 EncodeAndDecode(data);
91 }
92 {
93 const char data[] = {static_cast<char>(254), 1};
94 EncodeAndDecode(data);
95 }
96 {
97 const char data[] = {static_cast<char>(255), 1};
98 EncodeAndDecode(data);
99 }
100 {
101 const char data[] = {static_cast<char>(254), 0};
102 EncodeAndDecode(data);
103 }
104 {
105 const char data[] = {static_cast<char>(255), 0};
106 EncodeAndDecode(data);
107 }
108}
109
110// Tests encoding arrays with approximately one full chunk. This exposes some
111// corner cases in the binary format.
112TEST_F(CobsTest, AroundOneChunk) {
113 char data[256];
114 for (size_t i = 0; i < sizeof(data); ++i) {
115 data[i] = (i * 7) & 0xFF;
116 }
Austin Schuhb72be802022-01-02 12:26:28 -0800117 const absl::Span<char> data_span(data);
Brian Silverman41709732019-02-09 20:53:08 -0800118 for (int i = 253; i <= 256; ++i) {
119 EncodeAndDecode<256>(data_span.subspan(0, i));
120 }
121 for (int i = 253; i <= 255; ++i) {
122 EncodeAndDecode<255>(data_span.subspan(0, i));
123 }
124 for (int i = 253; i <= 254; ++i) {
125 EncodeAndDecode<254>(data_span.subspan(0, i));
126 }
127 EncodeAndDecode<253>(data_span.subspan(0, 253));
128}
129
Brian Silvermanc64372e2019-02-17 18:07:40 -0800130// Tests parsing a few packets, one byte at a time.
131TEST(CobsPacketizerTest, BasicSingleByte) {
132 CobsPacketizer<5> packetizer;
133
134 ASSERT_TRUE(packetizer.received_packet().empty());
135 packetizer.ParseData(std::array<char, 1>{{1}});
136 ASSERT_TRUE(packetizer.received_packet().empty());
137 packetizer.ParseData(std::array<char, 1>{{2}});
138 ASSERT_TRUE(packetizer.received_packet().empty());
139 packetizer.ParseData(std::array<char, 1>{{3}});
140 ASSERT_TRUE(packetizer.received_packet().empty());
141 packetizer.ParseData(std::array<char, 1>{{0}});
142 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800143 EXPECT_EQ(absl::Span<const char>(std::array<char, 3>{{1, 2, 3}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800144 packetizer.received_packet());
145 packetizer.clear_received_packet();
146 ASSERT_TRUE(packetizer.received_packet().empty());
147
148 ASSERT_TRUE(packetizer.received_packet().empty());
149 packetizer.ParseData(std::array<char, 1>{{5}});
150 ASSERT_TRUE(packetizer.received_packet().empty());
151 packetizer.ParseData(std::array<char, 1>{{0}});
152 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800153 EXPECT_EQ(absl::Span<const char>(std::array<char, 1>{{5}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800154 packetizer.received_packet());
155
156 ASSERT_FALSE(packetizer.received_packet().empty());
157 packetizer.ParseData(std::array<char, 1>{{9}});
158 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800159 EXPECT_EQ(absl::Span<const char>(std::array<char, 1>{{5}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800160 packetizer.received_packet());
161 packetizer.ParseData(std::array<char, 1>{{7}});
162 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800163 EXPECT_EQ(absl::Span<const char>(std::array<char, 1>{{5}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800164 packetizer.received_packet());
165 packetizer.ParseData(std::array<char, 1>{{0}});
166 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800167 EXPECT_EQ(absl::Span<const char>(std::array<char, 2>{{9, 7}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800168 packetizer.received_packet());
169}
170
171// Tests parsing a few packets, one span per packet.
172TEST(CobsPacketizerTest, BasicSinglePacket) {
173 CobsPacketizer<5> packetizer;
174
175 ASSERT_TRUE(packetizer.received_packet().empty());
176 packetizer.ParseData(std::array<char, 3>{{1, 2, 3}});
177 ASSERT_TRUE(packetizer.received_packet().empty());
178 packetizer.ParseData(std::array<char, 1>{{0}});
179 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800180 EXPECT_EQ(absl::Span<const char>(std::array<char, 3>{{1, 2, 3}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800181 packetizer.received_packet());
182 packetizer.clear_received_packet();
183 ASSERT_TRUE(packetizer.received_packet().empty());
184
185 ASSERT_TRUE(packetizer.received_packet().empty());
186 packetizer.ParseData(std::array<char, 1>{{5}});
187 ASSERT_TRUE(packetizer.received_packet().empty());
188 packetizer.ParseData(std::array<char, 1>{{0}});
189 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800190 EXPECT_EQ(absl::Span<const char>(std::array<char, 1>{{5}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800191 packetizer.received_packet());
192
193 ASSERT_FALSE(packetizer.received_packet().empty());
194 packetizer.ParseData(std::array<char, 2>{{9, 7}});
195 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800196 EXPECT_EQ(absl::Span<const char>(std::array<char, 1>{{5}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800197 packetizer.received_packet());
198 packetizer.ParseData(std::array<char, 1>{{0}});
199 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800200 EXPECT_EQ(absl::Span<const char>(std::array<char, 2>{{9, 7}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800201 packetizer.received_packet());
202}
203
204// Tests parsing a few packets, one span per packet including its terminator.
205TEST(CobsPacketizerTest, BasicSinglePacketWithTerminator) {
206 CobsPacketizer<5> packetizer;
207
208 ASSERT_TRUE(packetizer.received_packet().empty());
209 packetizer.ParseData(std::array<char, 4>{{1, 2, 3, 0}});
210 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800211 EXPECT_EQ(absl::Span<const char>(std::array<char, 3>{{1, 2, 3}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800212 packetizer.received_packet());
213 packetizer.clear_received_packet();
214 ASSERT_TRUE(packetizer.received_packet().empty());
215
216 ASSERT_TRUE(packetizer.received_packet().empty());
217 packetizer.ParseData(std::array<char, 2>{{5, 0}});
218 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800219 EXPECT_EQ(absl::Span<const char>(std::array<char, 1>{{5}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800220 packetizer.received_packet());
221
222 ASSERT_FALSE(packetizer.received_packet().empty());
223 packetizer.ParseData(std::array<char, 3>{{9, 7, 0}});
224 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800225 EXPECT_EQ(absl::Span<const char>(std::array<char, 2>{{9, 7}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800226 packetizer.received_packet());
227}
228
229// Tests parsing a packet in the same span as the previous terminator.
230TEST(CobsPacketizerTest, OverlappingEnd) {
231 CobsPacketizer<5> packetizer;
232
233 ASSERT_TRUE(packetizer.received_packet().empty());
234 packetizer.ParseData(std::array<char, 3>{{1, 2, 3}});
235 ASSERT_TRUE(packetizer.received_packet().empty());
236
237 ASSERT_TRUE(packetizer.received_packet().empty());
238 packetizer.ParseData(std::array<char, 2>{{0, 5}});
239 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800240 EXPECT_EQ(absl::Span<const char>(std::array<char, 3>{{1, 2, 3}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800241 packetizer.received_packet());
242 packetizer.clear_received_packet();
243 ASSERT_TRUE(packetizer.received_packet().empty());
244 packetizer.ParseData(std::array<char, 1>{{0}});
245 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800246 EXPECT_EQ(absl::Span<const char>(std::array<char, 1>{{5}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800247 packetizer.received_packet());
248}
249
250// Tests parsing a packet in the same span as the previous terminator, including
251// its terminator (so we skip the first packet).
252TEST(CobsPacketizerTest, OverlappingTwoEnds) {
253 CobsPacketizer<5> packetizer;
254
255 ASSERT_TRUE(packetizer.received_packet().empty());
256 packetizer.ParseData(std::array<char, 3>{{1, 2, 3}});
257 ASSERT_TRUE(packetizer.received_packet().empty());
258
259 ASSERT_TRUE(packetizer.received_packet().empty());
260 packetizer.ParseData(std::array<char, 3>{{0, 5, 0}});
261 ASSERT_FALSE(packetizer.received_packet().empty());
262 // We skip the {{1, 2, 3}} packet (arbitrarily; either that packet or this one
263 // has to be skipped).
Austin Schuhb72be802022-01-02 12:26:28 -0800264 EXPECT_EQ(absl::Span<const char>(std::array<char, 1>{{5}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800265 packetizer.received_packet());
266}
267
268// Tests parsing a packet in the same span as the previous terminator, including
269// its terminator (so we skip the first packet), and then starting another new
270// packet.
271TEST(CobsPacketizerTest, OverlappingTwoEndsAndPartial) {
272 CobsPacketizer<5> packetizer;
273
274 ASSERT_TRUE(packetizer.received_packet().empty());
275 packetizer.ParseData(std::array<char, 3>{{1, 2, 3}});
276 ASSERT_TRUE(packetizer.received_packet().empty());
277
278 ASSERT_TRUE(packetizer.received_packet().empty());
279 packetizer.ParseData(std::array<char, 4>{{0, 5, 0, 8}});
280 ASSERT_FALSE(packetizer.received_packet().empty());
281 // We skip the {{5}} packet (arbitrarily; either that packet or this one has
282 // to be skipped).
Austin Schuhb72be802022-01-02 12:26:28 -0800283 EXPECT_EQ(absl::Span<const char>(std::array<char, 3>{{1, 2, 3}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800284 packetizer.received_packet());
285
286 packetizer.ParseData(std::array<char, 1>{{0}});
287 ASSERT_FALSE(packetizer.received_packet().empty());
Austin Schuhb72be802022-01-02 12:26:28 -0800288 EXPECT_EQ(absl::Span<const char>(std::array<char, 1>{{8}}),
Brian Silvermanc64372e2019-02-17 18:07:40 -0800289 packetizer.received_packet());
290}
291
Brian Silverman41709732019-02-09 20:53:08 -0800292} // namespace jevois
293} // namespace frc971