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