1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_protobuf/decoder.h"
16
17 #include <cstring>
18
19 #include "pw_preprocessor/util.h"
20 #include "pw_unit_test/framework.h"
21
22 namespace pw::protobuf {
23 namespace {
24
25 class TestDecodeHandler : public DecodeHandler {
26 public:
ProcessField(CallbackDecoder & decoder,uint32_t field_number)27 Status ProcessField(CallbackDecoder& decoder,
28 uint32_t field_number) override {
29 std::string_view str;
30
31 switch (field_number) {
32 case 1:
33 EXPECT_EQ(OkStatus(), decoder.ReadInt32(&test_int32));
34 break;
35 case 2:
36 EXPECT_EQ(OkStatus(), decoder.ReadSint32(&test_sint32));
37 break;
38 case 3:
39 EXPECT_EQ(OkStatus(), decoder.ReadBool(&test_bool));
40 break;
41 case 4:
42 EXPECT_EQ(OkStatus(), decoder.ReadDouble(&test_double));
43 break;
44 case 5:
45 EXPECT_EQ(OkStatus(), decoder.ReadFixed32(&test_fixed32));
46 break;
47 case 6:
48 EXPECT_EQ(OkStatus(), decoder.ReadString(&str));
49 std::memcpy(test_string, str.data(), str.size());
50 test_string[str.size()] = '\0';
51 break;
52 }
53
54 called = true;
55 return OkStatus();
56 }
57
58 bool called = false;
59 int32_t test_int32 = 0;
60 int32_t test_sint32 = 0;
61 bool test_bool = true;
62 double test_double = 0;
63 uint32_t test_fixed32 = 0;
64 char test_string[16];
65 };
66
TEST(Decoder,Decode)67 TEST(Decoder, Decode) {
68 // clang-format off
69 uint8_t encoded_proto[] = {
70 // type=int32, k=1, v=42
71 0x08, 0x2a,
72 // type=sint32, k=2, v=-13
73 0x10, 0x19,
74 // type=bool, k=3, v=false
75 0x18, 0x00,
76 // type=double, k=4, v=3.14159
77 0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
78 // type=fixed32, k=5, v=0xdeadbeef
79 0x2d, 0xef, 0xbe, 0xad, 0xde,
80 // type=string, k=6, v="Hello world"
81 0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
82 };
83 // clang-format on
84
85 Decoder decoder(as_bytes(span(encoded_proto)));
86
87 int32_t v1 = 0;
88 EXPECT_EQ(decoder.Next(), OkStatus());
89 ASSERT_EQ(decoder.FieldNumber(), 1u);
90 EXPECT_EQ(decoder.ReadInt32(&v1), OkStatus());
91 EXPECT_EQ(v1, 42);
92
93 int32_t v2 = 0;
94 EXPECT_EQ(decoder.Next(), OkStatus());
95 ASSERT_EQ(decoder.FieldNumber(), 2u);
96 EXPECT_EQ(decoder.ReadSint32(&v2), OkStatus());
97 EXPECT_EQ(v2, -13);
98
99 bool v3 = true;
100 EXPECT_EQ(decoder.Next(), OkStatus());
101 ASSERT_EQ(decoder.FieldNumber(), 3u);
102 EXPECT_EQ(decoder.ReadBool(&v3), OkStatus());
103 EXPECT_FALSE(v3);
104
105 double v4 = 0;
106 EXPECT_EQ(decoder.Next(), OkStatus());
107 ASSERT_EQ(decoder.FieldNumber(), 4u);
108 EXPECT_EQ(decoder.ReadDouble(&v4), OkStatus());
109 EXPECT_EQ(v4, 3.14159);
110
111 uint32_t v5 = 0;
112 EXPECT_EQ(decoder.Next(), OkStatus());
113 ASSERT_EQ(decoder.FieldNumber(), 5u);
114 EXPECT_EQ(decoder.ReadFixed32(&v5), OkStatus());
115 EXPECT_EQ(v5, 0xdeadbeef);
116
117 std::string_view v6;
118 char buffer[16];
119 EXPECT_EQ(decoder.Next(), OkStatus());
120 ASSERT_EQ(decoder.FieldNumber(), 6u);
121 EXPECT_EQ(decoder.ReadString(&v6), OkStatus());
122 std::memcpy(buffer, v6.data(), v6.size());
123 buffer[v6.size()] = '\0';
124 EXPECT_STREQ(buffer, "Hello world");
125
126 EXPECT_EQ(decoder.Next(), Status::OutOfRange());
127 }
128
TEST(Decoder,Decode_SkipsUnusedFields)129 TEST(Decoder, Decode_SkipsUnusedFields) {
130 // clang-format off
131 uint8_t encoded_proto[] = {
132 // type=int32, k=1, v=42
133 0x08, 0x2a,
134 // type=sint32, k=2, v=-13
135 0x10, 0x19,
136 // type=bool, k=3, v=false
137 0x18, 0x00,
138 // type=double, k=4, v=3.14159
139 0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
140 // type=fixed32, k=5, v=0xdeadbeef
141 0x2d, 0xef, 0xbe, 0xad, 0xde,
142 // type=string, k=6, v="Hello world"
143 0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
144 };
145 // clang-format on
146
147 Decoder decoder(as_bytes(span(encoded_proto)));
148
149 // Don't process any fields except for the fourth. Next should still iterate
150 // correctly despite field values not being consumed.
151 EXPECT_EQ(decoder.Next(), OkStatus());
152 EXPECT_EQ(decoder.Next(), OkStatus());
153 EXPECT_EQ(decoder.Next(), OkStatus());
154 EXPECT_EQ(decoder.Next(), OkStatus());
155 ASSERT_EQ(decoder.FieldNumber(), 4u);
156 EXPECT_EQ(decoder.Next(), OkStatus());
157 EXPECT_EQ(decoder.Next(), OkStatus());
158 EXPECT_EQ(decoder.Next(), Status::OutOfRange());
159 }
160
TEST(Decoder,Decode_BadFieldNumber)161 TEST(Decoder, Decode_BadFieldNumber) {
162 // clang-format off
163 constexpr uint8_t encoded_proto[] = {
164 // type=int32, k=1, v=42
165 0x08, 0x2a,
166 // type=int32, k=19001, v=42 (invalid field number)
167 0xc8, 0xa3, 0x09, 0x2a,
168 // type=bool, k=3, v=false
169 0x18, 0x00,
170 };
171 // clang-format on
172
173 Decoder decoder(as_bytes(span(encoded_proto)));
174 int32_t value;
175
176 EXPECT_EQ(decoder.Next(), OkStatus());
177 EXPECT_EQ(decoder.FieldNumber(), 1u);
178 ASSERT_EQ(decoder.ReadInt32(&value), OkStatus());
179 EXPECT_EQ(value, 42);
180
181 // Bad field.
182 EXPECT_EQ(decoder.Next(), Status::DataLoss());
183 EXPECT_EQ(decoder.FieldNumber(), 0u);
184 EXPECT_EQ(decoder.ReadInt32(&value), Status::DataLoss());
185 }
186
TEST(CallbackDecoder,Decode)187 TEST(CallbackDecoder, Decode) {
188 CallbackDecoder decoder;
189 TestDecodeHandler handler;
190
191 // clang-format off
192 uint8_t encoded_proto[] = {
193 // type=int32, k=1, v=42
194 0x08, 0x2a,
195 // type=sint32, k=2, v=-13
196 0x10, 0x19,
197 // type=bool, k=3, v=false
198 0x18, 0x00,
199 // type=double, k=4, v=3.14159
200 0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
201 // type=fixed32, k=5, v=0xdeadbeef
202 0x2d, 0xef, 0xbe, 0xad, 0xde,
203 // type=string, k=6, v="Hello world"
204 0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
205 };
206 // clang-format on
207
208 decoder.set_handler(&handler);
209 EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), OkStatus());
210 EXPECT_TRUE(handler.called);
211 EXPECT_EQ(handler.test_int32, 42);
212 EXPECT_EQ(handler.test_sint32, -13);
213 EXPECT_FALSE(handler.test_bool);
214 EXPECT_EQ(handler.test_double, 3.14159);
215 EXPECT_EQ(handler.test_fixed32, 0xdeadbeef);
216 EXPECT_STREQ(handler.test_string, "Hello world");
217 }
218
TEST(CallbackDecoder,Decode_OverridesDuplicateFields)219 TEST(CallbackDecoder, Decode_OverridesDuplicateFields) {
220 CallbackDecoder decoder;
221 TestDecodeHandler handler;
222
223 // clang-format off
224 uint8_t encoded_proto[] = {
225 // type=int32, k=1, v=42
226 0x08, 0x2a,
227 // type=int32, k=1, v=43
228 0x08, 0x2b,
229 // type=int32, k=1, v=44
230 0x08, 0x2c,
231 };
232 // clang-format on
233
234 decoder.set_handler(&handler);
235 EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), OkStatus());
236 EXPECT_TRUE(handler.called);
237 EXPECT_EQ(handler.test_int32, 44);
238 }
239
TEST(CallbackDecoder,Decode_Empty)240 TEST(CallbackDecoder, Decode_Empty) {
241 CallbackDecoder decoder;
242 TestDecodeHandler handler;
243
244 decoder.set_handler(&handler);
245 EXPECT_EQ(decoder.Decode(span<std::byte>()), OkStatus());
246 EXPECT_FALSE(handler.called);
247 EXPECT_EQ(handler.test_int32, 0);
248 EXPECT_EQ(handler.test_sint32, 0);
249 }
250
TEST(CallbackDecoder,Decode_BadData)251 TEST(CallbackDecoder, Decode_BadData) {
252 CallbackDecoder decoder;
253 TestDecodeHandler handler;
254
255 // Field key without a value.
256 uint8_t encoded_proto[] = {0x08};
257
258 decoder.set_handler(&handler);
259 EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), Status::DataLoss());
260 }
261
262 // Only processes fields numbered 1 or 3.
263 class OneThreeDecodeHandler : public DecodeHandler {
264 public:
ProcessField(CallbackDecoder & decoder,uint32_t field_number)265 Status ProcessField(CallbackDecoder& decoder,
266 uint32_t field_number) override {
267 switch (field_number) {
268 case 1:
269 EXPECT_EQ(decoder.ReadInt32(&field_one), OkStatus());
270 break;
271 case 3:
272 EXPECT_EQ(decoder.ReadInt32(&field_three), OkStatus());
273 break;
274 default:
275 // Do nothing.
276 break;
277 }
278
279 called = true;
280 return OkStatus();
281 }
282
283 bool called = false;
284 int32_t field_one = 0;
285 int32_t field_three = 0;
286 };
287
TEST(CallbackDecoder,Decode_SkipsUnprocessedFields)288 TEST(CallbackDecoder, Decode_SkipsUnprocessedFields) {
289 CallbackDecoder decoder;
290 OneThreeDecodeHandler handler;
291
292 // clang-format off
293 uint8_t encoded_proto[] = {
294 // type=int32, k=1, v=42
295 // Should be read.
296 0x08, 0x2a,
297 // type=sint32, k=2, v=-13
298 // Should be ignored.
299 0x10, 0x19,
300 // type=int32, k=2, v=3
301 // Should be ignored.
302 0x10, 0x03,
303 // type=int32, k=3, v=99
304 // Should be read.
305 0x18, 0x63,
306 // type=int32, k=4, v=16
307 // Should be ignored.
308 0x20, 0x10,
309 };
310 // clang-format on
311
312 decoder.set_handler(&handler);
313 EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), OkStatus());
314 EXPECT_TRUE(handler.called);
315 EXPECT_EQ(handler.field_one, 42);
316 EXPECT_EQ(handler.field_three, 99);
317 }
318
319 // Only processes fields numbered 1 or 3, and stops the decode after hitting 1.
320 class ExitOnOneDecoder : public DecodeHandler {
321 public:
ProcessField(CallbackDecoder & decoder,uint32_t field_number)322 Status ProcessField(CallbackDecoder& decoder,
323 uint32_t field_number) override {
324 switch (field_number) {
325 case 1:
326 EXPECT_EQ(decoder.ReadInt32(&field_one), OkStatus());
327 return Status::Cancelled();
328 case 3:
329 EXPECT_EQ(decoder.ReadInt32(&field_three), OkStatus());
330 break;
331 default:
332 // Do nothing.
333 break;
334 }
335
336 return OkStatus();
337 }
338
339 int32_t field_one = 0;
340 int32_t field_three = 1111;
341 };
342
TEST(CallbackDecoder,Decode_StopsOnNonOkStatus)343 TEST(CallbackDecoder, Decode_StopsOnNonOkStatus) {
344 CallbackDecoder decoder;
345 ExitOnOneDecoder handler;
346
347 // clang-format off
348 uint8_t encoded_proto[] = {
349 // type=int32, k=1, v=42
350 // Should be read.
351 0x08, 0x2a,
352 // type=int32, k=3, v=99
353 // Should be skipped.
354 0x18, 0x63,
355 // type=int32, k=2, v=16
356 // Should be skipped.
357 0x08, 0x10,
358 };
359 // clang-format on
360
361 decoder.set_handler(&handler);
362 EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), Status::Cancelled());
363 EXPECT_EQ(handler.field_one, 42);
364 EXPECT_EQ(handler.field_three, 1111);
365 }
366
367 } // namespace
368 } // namespace pw::protobuf
369