xref: /aosp_15_r20/external/pigweed/pw_protobuf/codegen_decoder_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 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 #include <array>
15 #include <string_view>
16 
17 #include "pw_bytes/span.h"
18 #include "pw_containers/vector.h"
19 #include "pw_protobuf/find.h"
20 #include "pw_span/span.h"
21 #include "pw_status/status.h"
22 #include "pw_status/status_with_size.h"
23 #include "pw_stream/memory_stream.h"
24 #include "pw_unit_test/framework.h"
25 
26 // These header files contain the code generated by the pw_protobuf plugin.
27 // They are re-generated every time the tests are built and are used by the
28 // tests to ensure that the interface remains consistent.
29 //
30 // The purpose of the tests in this file is primarily to verify that the
31 // generated C++ interface is valid rather than the correctness of the
32 // low-level encoder.
33 #include "pw_protobuf_test_protos/full_test.pwpb.h"
34 #include "pw_protobuf_test_protos/importer.pwpb.h"
35 #include "pw_protobuf_test_protos/non_pw_package.pwpb.h"
36 #include "pw_protobuf_test_protos/proto2.pwpb.h"
37 #include "pw_protobuf_test_protos/repeated.pwpb.h"
38 
39 namespace pw::protobuf {
40 namespace {
41 
42 using test::pwpb::Bool;
43 using test::pwpb::Enum;
44 
45 namespace DeviceInfo = test::pwpb::DeviceInfo;
46 namespace KeyValuePair = test::pwpb::KeyValuePair;
47 namespace Pigweed = test::pwpb::Pigweed;
48 namespace Proto = test::pwpb::Proto;
49 namespace RepeatedTest = test::pwpb::RepeatedTest;
50 namespace TestResult = test::pwpb::TestResult;
51 
52 namespace imported {
53 using ::pw::protobuf::test::imported::pwpb::IsValidStatus;
54 using ::pw::protobuf::test::imported::pwpb::Status;
55 }  // namespace imported
56 
TEST(Codegen,StreamDecoder)57 TEST(Codegen, StreamDecoder) {
58   // clang-format off
59   constexpr uint8_t proto_data[] = {
60     // pigweed.magic_number
61     0x08, 0x49,
62     // pigweed.ziggy
63     0x10, 0xdd, 0x01,
64     // pigweed.error_message
65     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
66     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
67     // pigweed.bin
68     0x40, 0x01,
69     // pigweed.pigweed
70     0x3a, 0x02,
71     // pigweed.pigweed.status
72     0x08, 0x02,
73     // pigweed.proto
74     0x4a, 0x56,
75     // pigweed.proto.bin
76     0x10, 0x00,
77     // pigweed.proto.pigweed_pigweed_bin
78     0x18, 0x00,
79     // pigweed.proto.pigweed_protobuf_bin
80     0x20, 0x01,
81     // pigweed.proto.meta
82     0x2a, 0x0f,
83     // pigweed.proto.meta.file_name
84     0x0a, 0x0b, '/', 'e', 't', 'c', '/', 'p', 'a', 's', 's', 'w', 'd',
85     // pigweed.proto.meta.status
86     0x10, 0x02,
87     // pigweed.proto.nested_pigweed
88     0x0a, 0x3d,
89     // pigweed.proto.nested_pigweed.error_message
90     0x2a, 0x10, 'h', 'e', 'r', 'e', ' ', 'w', 'e', ' ',
91     'g', 'o', ' ', 'a', 'g', 'a', 'i', 'n',
92     // pigweed.proto.nested_pigweed.magic_number
93     0x08, 0xe8, 0x04,
94     // pigweed.proto.nested_pigweed.device_info
95     0x32, 0x26,
96     // pigweed.proto.nested_pigweed.device_info.attributes[0]
97     0x22, 0x10,
98     // pigweed.proto.nested_pigweed.device_info.attributes[0].key
99     0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
100     // pigweed.proto.nested_pigweed.device_info.attributes[0].value
101     0x12, 0x05, '5', '.', '3', '.', '1',
102     // pigweed.proto.nested_pigweed.device_info.attributes[1]
103     0x22, 0x10,
104     // pigweed.proto.nested_pigweed.device_info.attributes[1].key
105     0x0a, 0x04, 'c', 'h', 'i', 'p',
106     // pigweed.proto.nested_pigweed.device_info.attributes[1].value
107     0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
108     // pigweed.proto.nested_pigweed.device_info.status
109     0x18, 0x03,
110     // pigweed.id[0]
111     0x52, 0x02,
112     // pigweed.id[0].id
113     0x08, 0x31,
114     // pigweed.id[1]
115     0x52, 0x02,
116     // pigweed.id[1].id
117     0x08, 0x39,
118     // pigweed.id[2]
119     0x52, 0x02,
120     // pigweed.id[2].id
121     0x08, 0x4b,
122     // pigweed.id[3]
123     0x52, 0x02,
124     // pigweed.id[3].id
125     0x08, 0x67,
126     // pigweed.id[4]
127     0x52, 0x03,
128     // pigweed.id[4].id
129     0x08, 0x8d, 0x01
130 
131   };
132   // clang-format on
133 
134   stream::MemoryReader reader(as_bytes(span(proto_data)));
135   Pigweed::StreamDecoder pigweed(reader);
136 
137   EXPECT_EQ(pigweed.Next(), OkStatus());
138   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kMagicNumber);
139   Result<uint32_t> magic_number = pigweed.ReadMagicNumber();
140   EXPECT_EQ(magic_number.status(), OkStatus());
141   EXPECT_EQ(magic_number.value(), 0x49u);
142 
143   EXPECT_EQ(pigweed.Next(), OkStatus());
144   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kZiggy);
145   Result<int32_t> ziggy = pigweed.ReadZiggy();
146   EXPECT_EQ(ziggy.status(), OkStatus());
147   EXPECT_EQ(ziggy.value(), -111);
148 
149   constexpr std::string_view kExpectedErrorMessage{"not a typewriter"};
150 
151   EXPECT_EQ(pigweed.Next(), OkStatus());
152   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kErrorMessage);
153   std::array<char, 32> error_message{};
154   StatusWithSize error_message_status = pigweed.ReadErrorMessage(error_message);
155   EXPECT_EQ(error_message_status.status(), OkStatus());
156   EXPECT_EQ(error_message_status.size(), kExpectedErrorMessage.size());
157   EXPECT_EQ(std::memcmp(error_message.data(),
158                         kExpectedErrorMessage.data(),
159                         kExpectedErrorMessage.size()),
160             0);
161 
162   EXPECT_EQ(pigweed.Next(), OkStatus());
163   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kBin);
164   Result<Pigweed::Protobuf::Binary> bin = pigweed.ReadBin();
165   EXPECT_EQ(bin.status(), OkStatus());
166   EXPECT_EQ(bin.value(), Pigweed::Protobuf::Binary::ZERO);
167 
168   EXPECT_EQ(pigweed.Next(), OkStatus());
169   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kPigweed);
170   {
171     Pigweed::Pigweed::StreamDecoder pigweed_pigweed =
172         pigweed.GetPigweedDecoder();
173 
174     EXPECT_EQ(pigweed_pigweed.Next(), OkStatus());
175     EXPECT_EQ(pigweed_pigweed.Field().value(),
176               Pigweed::Pigweed::Fields::kStatus);
177     Result<Bool> pigweed_status = pigweed_pigweed.ReadStatus();
178     EXPECT_EQ(pigweed_status.status(), OkStatus());
179     EXPECT_EQ(pigweed_status.value(), Bool::FILE_NOT_FOUND);
180 
181     EXPECT_EQ(pigweed_pigweed.Next(), Status::OutOfRange());
182   }
183 
184   EXPECT_EQ(pigweed.Next(), OkStatus());
185   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kProto);
186   {
187     Proto::StreamDecoder proto = pigweed.GetProtoDecoder();
188 
189     EXPECT_EQ(proto.Next(), OkStatus());
190     EXPECT_EQ(proto.Field().value(), Proto::Fields::kBin);
191     Result<Proto::Binary> proto_bin = proto.ReadBin();
192     EXPECT_EQ(proto_bin.status(), OkStatus());
193     EXPECT_EQ(proto_bin.value(), Proto::Binary::OFF);
194 
195     EXPECT_EQ(proto.Next(), OkStatus());
196     EXPECT_EQ(proto.Field().value(), Proto::Fields::kPigweedPigweedBin);
197     Result<Pigweed::Pigweed::Binary> proto_pigweed_bin =
198         proto.ReadPigweedPigweedBin();
199     EXPECT_EQ(proto_pigweed_bin.status(), OkStatus());
200     EXPECT_EQ(proto_pigweed_bin.value(), Pigweed::Pigweed::Binary::ZERO);
201 
202     EXPECT_EQ(proto.Next(), OkStatus());
203     EXPECT_EQ(proto.Field().value(), Proto::Fields::kPigweedProtobufBin);
204     Result<Pigweed::Protobuf::Binary> proto_protobuf_bin =
205         proto.ReadPigweedProtobufBin();
206     EXPECT_EQ(proto_protobuf_bin.status(), OkStatus());
207     EXPECT_EQ(proto_protobuf_bin.value(), Pigweed::Protobuf::Binary::ZERO);
208 
209     EXPECT_EQ(proto.Next(), OkStatus());
210     EXPECT_EQ(proto.Field().value(), Proto::Fields::kMeta);
211     {
212       Pigweed::Protobuf::Compiler::StreamDecoder meta = proto.GetMetaDecoder();
213 
214       constexpr std::string_view kExpectedFileName{"/etc/passwd"};
215 
216       EXPECT_EQ(meta.Next(), OkStatus());
217       EXPECT_EQ(meta.Field().value(),
218                 Pigweed::Protobuf::Compiler::Fields::kFileName);
219       std::array<char, 32> meta_file_name{};
220       StatusWithSize meta_file_name_status = meta.ReadFileName(meta_file_name);
221       EXPECT_EQ(meta_file_name_status.status(), OkStatus());
222       EXPECT_EQ(meta_file_name_status.size(), kExpectedFileName.size());
223       EXPECT_EQ(std::memcmp(meta_file_name.data(),
224                             kExpectedFileName.data(),
225                             kExpectedFileName.size()),
226                 0);
227 
228       EXPECT_EQ(meta.Next(), OkStatus());
229       EXPECT_EQ(meta.Field().value(),
230                 Pigweed::Protobuf::Compiler::Fields::kStatus);
231       Result<Pigweed::Protobuf::Compiler::Status> meta_status =
232           meta.ReadStatus();
233       EXPECT_EQ(meta_status.status(), OkStatus());
234       EXPECT_EQ(meta_status.value(),
235                 Pigweed::Protobuf::Compiler::Status::FUBAR);
236 
237       EXPECT_EQ(meta.Next(), Status::OutOfRange());
238     }
239 
240     EXPECT_EQ(proto.Next(), OkStatus());
241     EXPECT_EQ(proto.Field().value(), Proto::Fields::kPigweed);
242     {
243       Pigweed::StreamDecoder proto_pigweed = proto.GetPigweedDecoder();
244 
245       constexpr std::string_view kExpectedProtoErrorMessage{"here we go again"};
246 
247       EXPECT_EQ(proto_pigweed.Next(), OkStatus());
248       EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::kErrorMessage);
249       std::array<char, 32> proto_pigweed_error_message{};
250       StatusWithSize proto_pigweed_error_message_status =
251           proto_pigweed.ReadErrorMessage(proto_pigweed_error_message);
252       EXPECT_EQ(proto_pigweed_error_message_status.status(), OkStatus());
253       EXPECT_EQ(proto_pigweed_error_message_status.size(),
254                 kExpectedProtoErrorMessage.size());
255       EXPECT_EQ(std::memcmp(proto_pigweed_error_message.data(),
256                             kExpectedProtoErrorMessage.data(),
257                             kExpectedProtoErrorMessage.size()),
258                 0);
259 
260       EXPECT_EQ(proto_pigweed.Next(), OkStatus());
261       EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::kMagicNumber);
262       Result<uint32_t> proto_pigweed_magic_number =
263           proto_pigweed.ReadMagicNumber();
264       EXPECT_EQ(proto_pigweed_magic_number.status(), OkStatus());
265       EXPECT_EQ(proto_pigweed_magic_number.value(), 616u);
266 
267       EXPECT_EQ(proto_pigweed.Next(), OkStatus());
268       EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::kDeviceInfo);
269       {
270         DeviceInfo::StreamDecoder device_info =
271             proto_pigweed.GetDeviceInfoDecoder();
272 
273         EXPECT_EQ(device_info.Next(), OkStatus());
274         EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::kAttributes);
275         {
276           KeyValuePair::StreamDecoder key_value_pair =
277               device_info.GetAttributesDecoder();
278 
279           constexpr std::string_view kExpectedKey{"version"};
280           constexpr std::string_view kExpectedValue{"5.3.1"};
281 
282           EXPECT_EQ(key_value_pair.Next(), OkStatus());
283           EXPECT_EQ(key_value_pair.Field().value(), KeyValuePair::Fields::kKey);
284           std::array<char, 32> key{};
285           StatusWithSize key_status = key_value_pair.ReadKey(key);
286           EXPECT_EQ(key_status.status(), OkStatus());
287           EXPECT_EQ(key_status.size(), kExpectedKey.size());
288           EXPECT_EQ(
289               std::memcmp(key.data(), kExpectedKey.data(), kExpectedKey.size()),
290               0);
291 
292           EXPECT_EQ(key_value_pair.Next(), OkStatus());
293           EXPECT_EQ(key_value_pair.Field().value(),
294                     KeyValuePair::Fields::kValue);
295           std::array<char, 32> value{};
296           StatusWithSize value_status = key_value_pair.ReadValue(value);
297           EXPECT_EQ(value_status.status(), OkStatus());
298           EXPECT_EQ(value_status.size(), kExpectedValue.size());
299           EXPECT_EQ(
300               std::memcmp(
301                   value.data(), kExpectedValue.data(), kExpectedValue.size()),
302               0);
303 
304           EXPECT_EQ(key_value_pair.Next(), Status::OutOfRange());
305         }
306 
307         EXPECT_EQ(device_info.Next(), OkStatus());
308         EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::kAttributes);
309         {
310           KeyValuePair::StreamDecoder key_value_pair =
311               device_info.GetAttributesDecoder();
312 
313           constexpr std::string_view kExpectedKey{"chip"};
314           constexpr std::string_view kExpectedValue{"left-soc"};
315 
316           EXPECT_EQ(key_value_pair.Next(), OkStatus());
317           EXPECT_EQ(key_value_pair.Field().value(), KeyValuePair::Fields::kKey);
318           std::array<char, 32> key{};
319           StatusWithSize key_status = key_value_pair.ReadKey(key);
320           EXPECT_EQ(key_status.status(), OkStatus());
321           EXPECT_EQ(key_status.size(), kExpectedKey.size());
322           EXPECT_EQ(
323               std::memcmp(key.data(), kExpectedKey.data(), kExpectedKey.size()),
324               0);
325 
326           EXPECT_EQ(key_value_pair.Next(), OkStatus());
327           EXPECT_EQ(key_value_pair.Field().value(),
328                     KeyValuePair::Fields::kValue);
329           std::array<char, 32> value{};
330           StatusWithSize value_status = key_value_pair.ReadValue(value);
331           EXPECT_EQ(value_status.status(), OkStatus());
332           EXPECT_EQ(value_status.size(), kExpectedValue.size());
333           EXPECT_EQ(
334               std::memcmp(
335                   value.data(), kExpectedValue.data(), kExpectedValue.size()),
336               0);
337 
338           EXPECT_EQ(key_value_pair.Next(), Status::OutOfRange());
339         }
340 
341         EXPECT_EQ(device_info.Next(), OkStatus());
342         EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::kStatus);
343         Result<DeviceInfo::DeviceStatus> device_info_status =
344             device_info.ReadStatus();
345         EXPECT_EQ(device_info_status.status(), OkStatus());
346         EXPECT_EQ(device_info_status.value(), DeviceInfo::DeviceStatus::PANIC);
347 
348         EXPECT_EQ(device_info.Next(), Status::OutOfRange());
349       }
350 
351       EXPECT_EQ(proto_pigweed.Next(), Status::OutOfRange());
352     }
353 
354     EXPECT_EQ(proto.Next(), Status::OutOfRange());
355   }
356 
357   for (unsigned i = 0; i < 5; ++i) {
358     EXPECT_EQ(pigweed.Next(), OkStatus());
359     EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kId);
360 
361     Proto::ID::StreamDecoder id = pigweed.GetIdDecoder();
362 
363     EXPECT_EQ(id.Next(), OkStatus());
364     EXPECT_EQ(id.Field().value(), Proto::ID::Fields::kId);
365     Result<uint32_t> id_id = id.ReadId();
366     EXPECT_EQ(id_id.status(), OkStatus());
367     EXPECT_EQ(id_id.value(), 5u * i * i + 3 * i + 49);
368 
369     EXPECT_EQ(id.Next(), Status::OutOfRange());
370   }
371 
372   EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
373 }
374 
TEST(Codegen,ResourceExhausted)375 TEST(Codegen, ResourceExhausted) {
376   // clang-format off
377   constexpr uint8_t proto_data[] = {
378     // pigweed.error_message
379     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
380     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
381   };
382   // clang-format on
383 
384   stream::MemoryReader reader(as_bytes(span(proto_data)));
385   Pigweed::StreamDecoder pigweed(reader);
386 
387   EXPECT_EQ(pigweed.Next(), OkStatus());
388   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kErrorMessage);
389   std::array<char, 8> error_message{};
390   StatusWithSize error_message_status = pigweed.ReadErrorMessage(error_message);
391   EXPECT_EQ(error_message_status.status(), Status::ResourceExhausted());
392   EXPECT_EQ(error_message_status.size(), 0u);
393 
394   EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
395 }
396 
TEST(Codegen,BytesReader)397 TEST(Codegen, BytesReader) {
398   // clang-format off
399   constexpr uint8_t proto_data[] = {
400     // pigweed.error_message
401     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
402     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
403   };
404   // clang-format on
405 
406   stream::MemoryReader reader(as_bytes(span(proto_data)));
407   Pigweed::StreamDecoder pigweed(reader);
408 
409   constexpr std::string_view kExpectedErrorMessage{"not a typewriter"};
410 
411   EXPECT_EQ(pigweed.Next(), OkStatus());
412   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kErrorMessage);
413   {
414     StreamDecoder::BytesReader bytes_reader = pigweed.GetErrorMessageReader();
415     EXPECT_EQ(bytes_reader.field_size(), kExpectedErrorMessage.size());
416 
417     std::array<std::byte, 32> error_message{};
418     Result<ByteSpan> result = bytes_reader.Read(error_message);
419     EXPECT_EQ(result.status(), OkStatus());
420     EXPECT_EQ(result.value().size(), kExpectedErrorMessage.size());
421     EXPECT_EQ(std::memcmp(result.value().data(),
422                           kExpectedErrorMessage.data(),
423                           kExpectedErrorMessage.size()),
424               0);
425 
426     result = bytes_reader.Read(error_message);
427     EXPECT_EQ(result.status(), Status::OutOfRange());
428   }
429 
430   EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
431 }
432 
TEST(Codegen,Enum)433 TEST(Codegen, Enum) {
434   // clang-format off
435   constexpr uint8_t proto_data[] = {
436     // pigweed.bin (valid value)
437     0x40, 0x01,
438     // pigweed.bin (unknown value)
439     0x40, 0x7f,
440     // pigweed.bin (invalid value)
441     0x40, 0xff,
442   };
443   // clang-format on
444 
445   stream::MemoryReader reader(as_bytes(span(proto_data)));
446   Pigweed::StreamDecoder pigweed(reader);
447 
448   EXPECT_EQ(pigweed.Next(), OkStatus());
449   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kBin);
450   Result<Pigweed::Protobuf::Binary> bin = pigweed.ReadBin();
451   EXPECT_EQ(bin.status(), OkStatus());
452   EXPECT_TRUE(Pigweed::Protobuf::IsValidBinary(bin.value()));
453   EXPECT_EQ(bin.value(), Pigweed::Protobuf::Binary::ZERO);
454 
455   EXPECT_EQ(pigweed.Next(), OkStatus());
456   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kBin);
457   bin = pigweed.ReadBin();
458   EXPECT_EQ(bin.status(), OkStatus());
459   EXPECT_FALSE(Pigweed::Protobuf::IsValidBinary(bin.value()));
460   EXPECT_EQ(static_cast<uint32_t>(bin.value()), 0x7fu);
461 
462   EXPECT_EQ(pigweed.Next(), OkStatus());
463   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::kBin);
464   bin = pigweed.ReadBin();
465   EXPECT_EQ(bin.status(), Status::DataLoss());
466 }
467 
TEST(Codegen,ImportedEnum)468 TEST(Codegen, ImportedEnum) {
469   // clang-format off
470   constexpr uint8_t proto_data[] = {
471     // result.status (valid value)
472     0x08, 0x01,
473     // result.status (unknown value)
474     0x08, 0x7f,
475     // result.status (invalid value)
476     0x08, 0xff,
477   };
478   // clang-format on
479 
480   stream::MemoryReader reader(as_bytes(span(proto_data)));
481   TestResult::StreamDecoder test_result(reader);
482 
483   EXPECT_EQ(test_result.Next(), OkStatus());
484   EXPECT_EQ(test_result.Field().value(), TestResult::Fields::kStatus);
485   Result<imported::Status> status = test_result.ReadStatus();
486   EXPECT_EQ(status.status(), OkStatus());
487   EXPECT_TRUE(imported::IsValidStatus(status.value()));
488   EXPECT_EQ(status.value(), imported::Status::NOT_OK);
489 
490   EXPECT_EQ(test_result.Next(), OkStatus());
491   EXPECT_EQ(test_result.Field().value(), TestResult::Fields::kStatus);
492   status = test_result.ReadStatus();
493   EXPECT_EQ(status.status(), OkStatus());
494   EXPECT_FALSE(imported::IsValidStatus(status.value()));
495   EXPECT_EQ(static_cast<uint32_t>(status.value()), 0x7fu);
496 
497   EXPECT_EQ(test_result.Next(), OkStatus());
498   EXPECT_EQ(test_result.Field().value(), TestResult::Fields::kStatus);
499   status = test_result.ReadStatus();
500   EXPECT_EQ(status.status(), Status::DataLoss());
501 }
502 
TEST(CodegenRepeated,NonPackedScalar)503 TEST(CodegenRepeated, NonPackedScalar) {
504   // clang-format off
505   constexpr uint8_t proto_data[] = {
506     // uint32s[], v={0, 16, 32, 48}
507     0x08, 0x00,
508     0x08, 0x10,
509     0x08, 0x20,
510     0x08, 0x30,
511     // fixed32s[]. v={0, 16, 32, 48}
512     0x35, 0x00, 0x00, 0x00, 0x00,
513     0x35, 0x10, 0x00, 0x00, 0x00,
514     0x35, 0x20, 0x00, 0x00, 0x00,
515     0x35, 0x30, 0x00, 0x00, 0x00,
516   };
517   // clang-format on
518 
519   stream::MemoryReader reader(as_bytes(span(proto_data)));
520   RepeatedTest::StreamDecoder repeated_test(reader);
521 
522   for (uint32_t i = 0; i < 4; ++i) {
523     EXPECT_EQ(repeated_test.Next(), OkStatus());
524     EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
525 
526     Result<uint32_t> result = repeated_test.ReadUint32s();
527     EXPECT_EQ(result.status(), OkStatus());
528     EXPECT_EQ(result.value(), i * 16u);
529   }
530 
531   for (unsigned i = 0; i < 4; ++i) {
532     EXPECT_EQ(repeated_test.Next(), OkStatus());
533     EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
534 
535     Result<uint32_t> result = repeated_test.ReadFixed32s();
536     EXPECT_EQ(result.status(), OkStatus());
537     EXPECT_EQ(result.value(), i * 16u);
538   }
539 
540   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
541 }
542 
TEST(CodegenRepeated,NonPackedScalarVector)543 TEST(CodegenRepeated, NonPackedScalarVector) {
544   // clang-format off
545   constexpr uint8_t proto_data[] = {
546     // uint32s[], v={0, 16, 32, 48}
547     0x08, 0x00,
548     0x08, 0x10,
549     0x08, 0x20,
550     0x08, 0x30,
551     // fixed32s[]. v={0, 16, 32, 48}
552     0x35, 0x00, 0x00, 0x00, 0x00,
553     0x35, 0x10, 0x00, 0x00, 0x00,
554     0x35, 0x20, 0x00, 0x00, 0x00,
555     0x35, 0x30, 0x00, 0x00, 0x00,
556   };
557   // clang-format on
558 
559   stream::MemoryReader reader(as_bytes(span(proto_data)));
560   RepeatedTest::StreamDecoder repeated_test(reader);
561 
562   pw::Vector<uint32_t, 8> uint32s{};
563 
564   for (unsigned i = 0; i < 4; ++i) {
565     EXPECT_EQ(repeated_test.Next(), OkStatus());
566     EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
567 
568     Status status = repeated_test.ReadUint32s(uint32s);
569     EXPECT_EQ(status, OkStatus());
570     EXPECT_EQ(uint32s.size(), i + 1u);
571   }
572 
573   for (unsigned short i = 0; i < 4; ++i) {
574     EXPECT_EQ(uint32s[i], i * 16u);
575   }
576 
577   pw::Vector<uint32_t, 8> fixed32s{};
578 
579   for (unsigned i = 0; i < 4; ++i) {
580     EXPECT_EQ(repeated_test.Next(), OkStatus());
581     EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
582 
583     Status status = repeated_test.ReadFixed32s(fixed32s);
584     EXPECT_EQ(status, OkStatus());
585     EXPECT_EQ(fixed32s.size(), i + 1u);
586   }
587 
588   for (unsigned short i = 0; i < 4; ++i) {
589     EXPECT_EQ(fixed32s[i], i * 16u);
590   }
591 
592   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
593 }
594 
TEST(CodegenRepeated,NonPackedVarintScalarVectorFull)595 TEST(CodegenRepeated, NonPackedVarintScalarVectorFull) {
596   // clang-format off
597   constexpr uint8_t proto_data[] = {
598     // uint32s[], v={0, 16, 32, 48}
599     0x08, 0x00,
600     0x08, 0x10,
601     0x08, 0x20,
602     0x08, 0x30,
603   };
604   // clang-format on
605 
606   stream::MemoryReader reader(as_bytes(span(proto_data)));
607   RepeatedTest::StreamDecoder repeated_test(reader);
608 
609   pw::Vector<uint32_t, 2> uint32s{};
610 
611   EXPECT_EQ(repeated_test.Next(), OkStatus());
612   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
613   Status status = repeated_test.ReadUint32s(uint32s);
614   EXPECT_EQ(status, OkStatus());
615   EXPECT_EQ(uint32s.size(), 1u);
616 
617   EXPECT_EQ(repeated_test.Next(), OkStatus());
618   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
619   status = repeated_test.ReadUint32s(uint32s);
620   EXPECT_EQ(status, OkStatus());
621   EXPECT_EQ(uint32s.size(), 2u);
622 
623   EXPECT_EQ(repeated_test.Next(), OkStatus());
624   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
625   status = repeated_test.ReadUint32s(uint32s);
626   EXPECT_EQ(status, Status::ResourceExhausted());
627   EXPECT_EQ(uint32s.size(), 2u);
628 
629   for (unsigned short i = 0; i < 2; ++i) {
630     EXPECT_EQ(uint32s[i], i * 16u);
631   }
632 }
633 
TEST(CodegenRepeated,NonPackedFixedScalarVectorFull)634 TEST(CodegenRepeated, NonPackedFixedScalarVectorFull) {
635   // clang-format off
636   constexpr uint8_t proto_data[] = {
637     // fixed32s[]. v={0, 16, 32, 48}
638     0x35, 0x00, 0x00, 0x00, 0x00,
639     0x35, 0x10, 0x00, 0x00, 0x00,
640     0x35, 0x20, 0x00, 0x00, 0x00,
641     0x35, 0x30, 0x00, 0x00, 0x00,
642   };
643   // clang-format on
644 
645   stream::MemoryReader reader(as_bytes(span(proto_data)));
646   RepeatedTest::StreamDecoder repeated_test(reader);
647 
648   pw::Vector<uint32_t, 2> fixed32s{};
649 
650   EXPECT_EQ(repeated_test.Next(), OkStatus());
651   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
652   Status status = repeated_test.ReadFixed32s(fixed32s);
653   EXPECT_EQ(status, OkStatus());
654   EXPECT_EQ(fixed32s.size(), 1u);
655 
656   EXPECT_EQ(repeated_test.Next(), OkStatus());
657   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
658   status = repeated_test.ReadFixed32s(fixed32s);
659   EXPECT_EQ(status, OkStatus());
660   EXPECT_EQ(fixed32s.size(), 2u);
661 
662   EXPECT_EQ(repeated_test.Next(), OkStatus());
663   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
664   status = repeated_test.ReadFixed32s(fixed32s);
665   EXPECT_EQ(status, Status::ResourceExhausted());
666   EXPECT_EQ(fixed32s.size(), 2u);
667 
668   for (unsigned short i = 0; i < 2; ++i) {
669     EXPECT_EQ(fixed32s[i], i * 16u);
670   }
671 }
672 
TEST(CodegenRepeated,PackedScalar)673 TEST(CodegenRepeated, PackedScalar) {
674   // clang-format off
675   constexpr uint8_t proto_data[] = {
676     // uint32s[], v={0, 16, 32, 48}
677     0x0a, 0x04,
678     0x00,
679     0x10,
680     0x20,
681     0x30,
682     // fixed32s[]. v={0, 16, 32, 48}
683     0x32, 0x10,
684     0x00, 0x00, 0x00, 0x00,
685     0x10, 0x00, 0x00, 0x00,
686     0x20, 0x00, 0x00, 0x00,
687     0x30, 0x00, 0x00, 0x00,
688   };
689   // clang-format on
690 
691   stream::MemoryReader reader(as_bytes(span(proto_data)));
692   RepeatedTest::StreamDecoder repeated_test(reader);
693 
694   EXPECT_EQ(repeated_test.Next(), OkStatus());
695   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
696   std::array<uint32_t, 8> uint32s{};
697   StatusWithSize sws = repeated_test.ReadUint32s(uint32s);
698   EXPECT_EQ(sws.status(), OkStatus());
699   EXPECT_EQ(sws.size(), 4u);
700 
701   for (unsigned short i = 0; i < 4; ++i) {
702     EXPECT_EQ(uint32s[i], i * 16u);
703   }
704 
705   EXPECT_EQ(repeated_test.Next(), OkStatus());
706   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
707   std::array<uint32_t, 8> fixed32s{};
708   sws = repeated_test.ReadFixed32s(fixed32s);
709   EXPECT_EQ(sws.status(), OkStatus());
710   EXPECT_EQ(sws.size(), 4u);
711 
712   for (unsigned short i = 0; i < 4; ++i) {
713     EXPECT_EQ(fixed32s[i], i * 16u);
714   }
715 
716   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
717 }
718 
TEST(CodegenRepeated,PackedVarintScalarExhausted)719 TEST(CodegenRepeated, PackedVarintScalarExhausted) {
720   // clang-format off
721   constexpr uint8_t proto_data[] = {
722     // uint32s[], v={0, 16, 32, 48}
723     0x0a, 0x04,
724     0x00,
725     0x10,
726     0x20,
727     0x30,
728   };
729   // clang-format on
730 
731   stream::MemoryReader reader(as_bytes(span(proto_data)));
732   RepeatedTest::StreamDecoder repeated_test(reader);
733 
734   EXPECT_EQ(repeated_test.Next(), OkStatus());
735   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
736   std::array<uint32_t, 2> uint32s{};
737   StatusWithSize sws = repeated_test.ReadUint32s(uint32s);
738   EXPECT_EQ(sws.status(), Status::ResourceExhausted());
739   EXPECT_EQ(sws.size(), 2u);
740 
741   for (unsigned short i = 0; i < 2; ++i) {
742     EXPECT_EQ(uint32s[i], i * 16u);
743   }
744 }
745 
TEST(CodegenRepeated,PackedFixedScalarExhausted)746 TEST(CodegenRepeated, PackedFixedScalarExhausted) {
747   // clang-format off
748   constexpr uint8_t proto_data[] = {
749     // fixed32s[]. v={0, 16, 32, 48}
750     0x32, 0x10,
751     0x00, 0x00, 0x00, 0x00,
752     0x10, 0x00, 0x00, 0x00,
753     0x20, 0x00, 0x00, 0x00,
754     0x30, 0x00, 0x00, 0x00,
755   };
756   // clang-format on
757 
758   stream::MemoryReader reader(as_bytes(span(proto_data)));
759   RepeatedTest::StreamDecoder repeated_test(reader);
760 
761   EXPECT_EQ(repeated_test.Next(), OkStatus());
762   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
763   std::array<uint32_t, 2> fixed32s{};
764   StatusWithSize sws = repeated_test.ReadFixed32s(fixed32s);
765   EXPECT_EQ(sws.status(), Status::ResourceExhausted());
766   EXPECT_EQ(sws.size(), 0u);
767 }
768 
TEST(CodegenRepeated,PackedScalarVector)769 TEST(CodegenRepeated, PackedScalarVector) {
770   // clang-format off
771   constexpr uint8_t proto_data[] = {
772     // uint32s[], v={0, 16, 32, 48}
773     0x0a, 0x04,
774     0x00,
775     0x10,
776     0x20,
777     0x30,
778     // fixed32s[]. v={0, 16, 32, 48}
779     0x32, 0x10,
780     0x00, 0x00, 0x00, 0x00,
781     0x10, 0x00, 0x00, 0x00,
782     0x20, 0x00, 0x00, 0x00,
783     0x30, 0x00, 0x00, 0x00,
784   };
785   // clang-format on
786 
787   stream::MemoryReader reader(as_bytes(span(proto_data)));
788   RepeatedTest::StreamDecoder repeated_test(reader);
789 
790   EXPECT_EQ(repeated_test.Next(), OkStatus());
791   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
792   pw::Vector<uint32_t, 8> uint32s{};
793   Status status = repeated_test.ReadUint32s(uint32s);
794   EXPECT_EQ(status, OkStatus());
795   EXPECT_EQ(uint32s.size(), 4u);
796 
797   for (unsigned short i = 0; i < 4; ++i) {
798     EXPECT_EQ(uint32s[i], i * 16u);
799   }
800 
801   EXPECT_EQ(repeated_test.Next(), OkStatus());
802   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
803   pw::Vector<uint32_t, 8> fixed32s{};
804   status = repeated_test.ReadFixed32s(fixed32s);
805   EXPECT_EQ(status, OkStatus());
806   EXPECT_EQ(fixed32s.size(), 4u);
807 
808   for (unsigned short i = 0; i < 4; ++i) {
809     EXPECT_EQ(fixed32s[i], i * 16u);
810   }
811 
812   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
813 }
814 
TEST(CodegenRepeated,PackedVarintScalarVectorFull)815 TEST(CodegenRepeated, PackedVarintScalarVectorFull) {
816   // clang-format off
817   constexpr uint8_t proto_data[] = {
818     // uint32s[], v={0, 16, 32, 48}
819     0x0a, 0x04,
820     0x00,
821     0x10,
822     0x20,
823     0x30,
824   };
825   // clang-format on
826 
827   stream::MemoryReader reader(as_bytes(span(proto_data)));
828   RepeatedTest::StreamDecoder repeated_test(reader);
829 
830   EXPECT_EQ(repeated_test.Next(), OkStatus());
831   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
832   pw::Vector<uint32_t, 2> uint32s{};
833   Status status = repeated_test.ReadUint32s(uint32s);
834   EXPECT_EQ(status, Status::ResourceExhausted());
835   EXPECT_EQ(uint32s.size(), 2u);
836 
837   for (unsigned short i = 0; i < 2; ++i) {
838     EXPECT_EQ(uint32s[i], i * 16u);
839   }
840 }
841 
TEST(CodegenRepeated,PackedFixedScalarVectorFull)842 TEST(CodegenRepeated, PackedFixedScalarVectorFull) {
843   // clang-format off
844   constexpr uint8_t proto_data[] = {
845     // fixed32s[]. v={0, 16, 32, 48}
846     0x32, 0x10,
847     0x00, 0x00, 0x00, 0x00,
848     0x10, 0x00, 0x00, 0x00,
849     0x20, 0x00, 0x00, 0x00,
850     0x30, 0x00, 0x00, 0x00,
851   };
852   // clang-format on
853 
854   stream::MemoryReader reader(as_bytes(span(proto_data)));
855   RepeatedTest::StreamDecoder repeated_test(reader);
856 
857   EXPECT_EQ(repeated_test.Next(), OkStatus());
858   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
859   pw::Vector<uint32_t, 2> fixed32s{};
860   Status status = repeated_test.ReadFixed32s(fixed32s);
861   EXPECT_EQ(status, Status::ResourceExhausted());
862   EXPECT_EQ(fixed32s.size(), 0u);
863 }
864 
TEST(CodegenRepeated,PackedScalarVectorRepeated)865 TEST(CodegenRepeated, PackedScalarVectorRepeated) {
866   // clang-format off
867   constexpr uint8_t proto_data[] = {
868     // uint32s[], v={0, 16, 32, 48}
869     0x0a, 0x04,
870     0x00,
871     0x10,
872     0x20,
873     0x30,
874     // uint32s[], v={64, 80, 96, 112}
875     0x0a, 0x04,
876     0x40,
877     0x50,
878     0x60,
879     0x70,
880     // fixed32s[]. v={0, 16, 32, 48}
881     0x32, 0x10,
882     0x00, 0x00, 0x00, 0x00,
883     0x10, 0x00, 0x00, 0x00,
884     0x20, 0x00, 0x00, 0x00,
885     0x30, 0x00, 0x00, 0x00,
886     // fixed32s[]. v={64, 80, 96, 112}
887     0x32, 0x10,
888     0x40, 0x00, 0x00, 0x00,
889     0x50, 0x00, 0x00, 0x00,
890     0x60, 0x00, 0x00, 0x00,
891     0x70, 0x00, 0x00, 0x00,
892   };
893   // clang-format on
894 
895   stream::MemoryReader reader(as_bytes(span(proto_data)));
896   RepeatedTest::StreamDecoder repeated_test(reader);
897 
898   EXPECT_EQ(repeated_test.Next(), OkStatus());
899   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
900   pw::Vector<uint32_t, 8> uint32s{};
901   Status status = repeated_test.ReadUint32s(uint32s);
902   EXPECT_EQ(status, OkStatus());
903   EXPECT_EQ(uint32s.size(), 4u);
904 
905   EXPECT_EQ(repeated_test.Next(), OkStatus());
906   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kUint32s);
907   status = repeated_test.ReadUint32s(uint32s);
908   EXPECT_EQ(status, OkStatus());
909   EXPECT_EQ(uint32s.size(), 8u);
910 
911   for (unsigned short i = 0; i < 8; ++i) {
912     EXPECT_EQ(uint32s[i], i * 16u);
913   }
914 
915   EXPECT_EQ(repeated_test.Next(), OkStatus());
916   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
917   pw::Vector<uint32_t, 8> fixed32s{};
918   status = repeated_test.ReadFixed32s(fixed32s);
919   EXPECT_EQ(status, OkStatus());
920   EXPECT_EQ(fixed32s.size(), 4u);
921 
922   EXPECT_EQ(repeated_test.Next(), OkStatus());
923   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kFixed32s);
924   status = repeated_test.ReadFixed32s(fixed32s);
925   EXPECT_EQ(status, OkStatus());
926   EXPECT_EQ(fixed32s.size(), 8u);
927 
928   for (unsigned short i = 0; i < 8; ++i) {
929     EXPECT_EQ(fixed32s[i], i * 16u);
930   }
931 
932   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
933 }
934 
TEST(CodegenRepeated,NonScalar)935 TEST(CodegenRepeated, NonScalar) {
936   // clang-format off
937   constexpr uint8_t proto_data[] = {
938     // strings[], v={"the", "quick", "brown", "fox"}
939     0x1a, 0x03, 't', 'h', 'e',
940     0x1a, 0x5, 'q',  'u', 'i', 'c', 'k',
941     0x1a, 0x5,  'b', 'r', 'o', 'w',  'n',
942     0x1a, 0x3, 'f', 'o', 'x'
943   };
944   // clang-format on
945 
946   stream::MemoryReader reader(as_bytes(span(proto_data)));
947   RepeatedTest::StreamDecoder repeated_test(reader);
948 
949   constexpr std::array<std::string_view, 4> kExpectedString{
950       {{"the"}, {"quick"}, {"brown"}, {"fox"}}};
951 
952   for (unsigned short i = 0; i < 4; ++i) {
953     EXPECT_EQ(repeated_test.Next(), OkStatus());
954     EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kStrings);
955     std::array<char, 32> string{};
956     StatusWithSize sws = repeated_test.ReadStrings(string);
957     EXPECT_EQ(sws.status(), OkStatus());
958     EXPECT_EQ(sws.size(), kExpectedString[i].size());
959     EXPECT_EQ(std::memcmp(string.data(),
960                           kExpectedString[i].data(),
961                           kExpectedString[i].size()),
962               0);
963   }
964 
965   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
966 }
967 
TEST(CodegenRepeated,PackedEnum)968 TEST(CodegenRepeated, PackedEnum) {
969   // clang-format off
970   constexpr uint8_t proto_data[] = {
971     // enums[], v={RED, GREEN, AMBER, RED}
972     0x4a, 0x04, 0x00, 0x02, 0x01, 0x00,
973   };
974   // clang-format on
975 
976   stream::MemoryReader reader(as_bytes(span(proto_data)));
977   RepeatedTest::StreamDecoder repeated_test(reader);
978 
979   EXPECT_EQ(repeated_test.Next(), OkStatus());
980   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kEnums);
981   std::array<Enum, 4> enums{};
982   StatusWithSize sws = repeated_test.ReadEnums(enums);
983   EXPECT_EQ(sws.status(), OkStatus());
984   ASSERT_EQ(sws.size(), 4u);
985 
986   for (unsigned short i = 0; i < 4; ++i) {
987     EXPECT_TRUE(IsValidEnum(enums[i]));
988   }
989 
990   EXPECT_EQ(enums[0], Enum::RED);
991   EXPECT_EQ(enums[1], Enum::GREEN);
992   EXPECT_EQ(enums[2], Enum::AMBER);
993   EXPECT_EQ(enums[3], Enum::RED);
994 
995   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
996 }
997 
TEST(CodegenRepeated,PackedEnumVector)998 TEST(CodegenRepeated, PackedEnumVector) {
999   // clang-format off
1000   constexpr uint8_t proto_data[] = {
1001     // enums[], v={RED, GREEN, AMBER, RED}
1002     0x4a, 0x04, 0x00, 0x02, 0x01, 0x00,
1003   };
1004   // clang-format on
1005 
1006   stream::MemoryReader reader(as_bytes(span(proto_data)));
1007   RepeatedTest::StreamDecoder repeated_test(reader);
1008 
1009   EXPECT_EQ(repeated_test.Next(), OkStatus());
1010   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::kEnums);
1011   pw::Vector<Enum, 4> enums{};
1012   Status status = repeated_test.ReadEnums(enums);
1013   EXPECT_EQ(status, OkStatus());
1014   ASSERT_EQ(enums.size(), 4u);
1015 
1016   for (unsigned short i = 0; i < 4; ++i) {
1017     EXPECT_TRUE(IsValidEnum(enums[i]));
1018   }
1019 
1020   EXPECT_EQ(enums[0], Enum::RED);
1021   EXPECT_EQ(enums[1], Enum::GREEN);
1022   EXPECT_EQ(enums[2], Enum::AMBER);
1023   EXPECT_EQ(enums[3], Enum::RED);
1024 
1025   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
1026 }
1027 
TEST(Codegen,FindBuffer)1028 TEST(Codegen, FindBuffer) {
1029   // clang-format off
1030   constexpr uint8_t proto_data[] = {
1031     // pigweed.magic_number
1032     0x08, 0x49,
1033     // pigweed.ziggy
1034     0x10, 0xdd, 0x01,
1035     // pigweed.cycles
1036     0x19, 0xde, 0xad, 0xca, 0xfe, 0x10, 0x20, 0x30, 0x40,
1037     // pigweed.ratio
1038     0x25, 0x8f, 0xc2, 0xb5, 0xbf,
1039     // pigweed.error_message
1040     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
1041     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
1042     // pigweed.bin
1043     0x40, 0x01,
1044     // pigweed.pigweed
1045     0x3a, 0x02,
1046     // pigweed.pigweed.status
1047     0x08, 0x02,
1048     // pigweed.proto
1049     0x4a, 0x56,
1050     // pigweed.proto.bin
1051     0x10, 0x00,
1052     // pigweed.proto.pigweed_pigweed_bin
1053     0x18, 0x00,
1054     // pigweed.proto.pigweed_protobuf_bin
1055     0x20, 0x01,
1056     // pigweed.proto.meta
1057     0x2a, 0x0f,
1058     // pigweed.proto.meta.file_name
1059     0x0a, 0x0b, '/', 'e', 't', 'c', '/', 'p', 'a', 's', 's', 'w', 'd',
1060     // pigweed.proto.meta.status
1061     0x10, 0x02,
1062     // pigweed.proto.nested_pigweed
1063     0x0a, 0x3d,
1064     // pigweed.proto.nested_pigweed.error_message
1065     0x2a, 0x10, 'h', 'e', 'r', 'e', ' ', 'w', 'e', ' ',
1066     'g', 'o', ' ', 'a', 'g', 'a', 'i', 'n',
1067     // pigweed.proto.nested_pigweed.magic_number
1068     0x08, 0xe8, 0x04,
1069     // pigweed.proto.nested_pigweed.device_info
1070     0x32, 0x26,
1071     // pigweed.proto.nested_pigweed.device_info.attributes[0]
1072     0x22, 0x10,
1073     // pigweed.proto.nested_pigweed.device_info.attributes[0].key
1074     0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
1075     // pigweed.proto.nested_pigweed.device_info.attributes[0].value
1076     0x12, 0x05, '5', '.', '3', '.', '1',
1077     // pigweed.proto.nested_pigweed.device_info.attributes[1]
1078     0x22, 0x10,
1079     // pigweed.proto.nested_pigweed.device_info.attributes[1].key
1080     0x0a, 0x04, 'c', 'h', 'i', 'p',
1081     // pigweed.proto.nested_pigweed.device_info.attributes[1].value
1082     0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
1083     // pigweed.proto.nested_pigweed.device_info.status
1084     0x18, 0x03,
1085     // pigweed.id[0]
1086     0x52, 0x02,
1087     // pigweed.id[0].id
1088     0x08, 0x31,
1089     // pigweed.id[1]
1090     0x52, 0x02,
1091     // pigweed.id[1].id
1092     0x08, 0x39,
1093     // pigweed.id[2]
1094     0x52, 0x02,
1095     // pigweed.id[2].id
1096     0x08, 0x4b,
1097     // pigweed.id[3]
1098     0x52, 0x02,
1099     // pigweed.id[3].id
1100     0x08, 0x67,
1101     // pigweed.id[4]
1102     0x52, 0x03,
1103     // pigweed.id[4].id
1104     0x08, 0x8d, 0x01
1105 
1106   };
1107   // clang-format on
1108 
1109   EXPECT_EQ(Pigweed::FindMagicNumber(as_bytes(span(proto_data))).value(),
1110             0x49u);
1111   EXPECT_EQ(Pigweed::FindZiggy(as_bytes(span(proto_data))).value(), -111);
1112   EXPECT_EQ(Pigweed::FindCycles(as_bytes(span(proto_data))).value(),
1113             0x40302010fecaaddeu);
1114   EXPECT_EQ(Pigweed::FindRatio(as_bytes(span(proto_data))).value(), -1.42f);
1115 
1116   auto result = Pigweed::FindErrorMessage(as_bytes(span(proto_data)));
1117   EXPECT_EQ(result.status(), OkStatus());
1118   InlineString<32> str(*result);
1119   EXPECT_STREQ(str.c_str(), "not a typewriter");
1120 
1121   EXPECT_EQ(Pigweed::FindBin(as_bytes(span(proto_data))).value(),
1122             Pigweed::Protobuf::Binary::ZERO);
1123 
1124   Result<ConstByteSpan> pigweed =
1125       Pigweed::FindPigweed(as_bytes(span(proto_data)));
1126   EXPECT_EQ(result.status(), OkStatus());
1127   EXPECT_EQ(pigweed->size(), 2u);
1128 
1129   EXPECT_EQ(Pigweed::Pigweed::FindStatus(*pigweed).value(),
1130             Bool::FILE_NOT_FOUND);
1131 
1132   // Nonexisting fields.
1133   EXPECT_EQ(Pigweed::FindData(as_bytes(span(proto_data))).status(),
1134             Status::NotFound());
1135   EXPECT_EQ(Pigweed::FindDescription(as_bytes(span(proto_data))).status(),
1136             Status::NotFound());
1137   EXPECT_EQ(Pigweed::FindSpecialProperty(as_bytes(span(proto_data))).status(),
1138             Status::NotFound());
1139   EXPECT_EQ(Pigweed::FindBungle(as_bytes(span(proto_data))).status(),
1140             Status::NotFound());
1141 }
1142 
TEST(Codegen,FindStream)1143 TEST(Codegen, FindStream) {
1144   stream::MemoryReader reader({});
1145   // clang-format off
1146   constexpr uint8_t proto_data[] = {
1147     // pigweed.magic_number
1148     0x08, 0x49,
1149     // pigweed.ziggy
1150     0x10, 0xdd, 0x01,
1151     // pigweed.cycles
1152     0x19, 0xde, 0xad, 0xca, 0xfe, 0x10, 0x20, 0x30, 0x40,
1153     // pigweed.ratio
1154     0x25, 0x8f, 0xc2, 0xb5, 0xbf,
1155     // pigweed.error_message
1156     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
1157     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
1158     // pigweed.bin
1159     0x40, 0x01,
1160     // pigweed.pigweed
1161     0x3a, 0x02,
1162     // pigweed.pigweed.status
1163     0x08, 0x02,
1164     // pigweed.proto
1165     0x4a, 0x56,
1166     // pigweed.proto.bin
1167     0x10, 0x00,
1168     // pigweed.proto.pigweed_pigweed_bin
1169     0x18, 0x00,
1170     // pigweed.proto.pigweed_protobuf_bin
1171     0x20, 0x01,
1172     // pigweed.proto.meta
1173     0x2a, 0x0f,
1174     // pigweed.proto.meta.file_name
1175     0x0a, 0x0b, '/', 'e', 't', 'c', '/', 'p', 'a', 's', 's', 'w', 'd',
1176     // pigweed.proto.meta.status
1177     0x10, 0x02,
1178     // pigweed.proto.nested_pigweed
1179     0x0a, 0x3d,
1180     // pigweed.proto.nested_pigweed.error_message
1181     0x2a, 0x10, 'h', 'e', 'r', 'e', ' ', 'w', 'e', ' ',
1182     'g', 'o', ' ', 'a', 'g', 'a', 'i', 'n',
1183     // pigweed.proto.nested_pigweed.magic_number
1184     0x08, 0xe8, 0x04,
1185     // pigweed.proto.nested_pigweed.device_info
1186     0x32, 0x26,
1187     // pigweed.proto.nested_pigweed.device_info.attributes[0]
1188     0x22, 0x10,
1189     // pigweed.proto.nested_pigweed.device_info.attributes[0].key
1190     0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
1191     // pigweed.proto.nested_pigweed.device_info.attributes[0].value
1192     0x12, 0x05, '5', '.', '3', '.', '1',
1193     // pigweed.proto.nested_pigweed.device_info.attributes[1]
1194     0x22, 0x10,
1195     // pigweed.proto.nested_pigweed.device_info.attributes[1].key
1196     0x0a, 0x04, 'c', 'h', 'i', 'p',
1197     // pigweed.proto.nested_pigweed.device_info.attributes[1].value
1198     0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
1199     // pigweed.proto.nested_pigweed.device_info.status
1200     0x18, 0x03,
1201     // pigweed.id[0]
1202     0x52, 0x02,
1203     // pigweed.id[0].id
1204     0x08, 0x31,
1205     // pigweed.id[1]
1206     0x52, 0x02,
1207     // pigweed.id[1].id
1208     0x08, 0x39,
1209     // pigweed.id[2]
1210     0x52, 0x02,
1211     // pigweed.id[2].id
1212     0x08, 0x4b,
1213     // pigweed.id[3]
1214     0x52, 0x02,
1215     // pigweed.id[3].id
1216     0x08, 0x67,
1217     // pigweed.id[4]
1218     0x52, 0x03,
1219     // pigweed.id[4].id
1220     0x08, 0x8d, 0x01
1221 
1222   };
1223   // clang-format on
1224 
1225   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1226   EXPECT_EQ(Pigweed::FindMagicNumber(reader).value(), 0x49u);
1227 
1228   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1229   EXPECT_EQ(Pigweed::FindZiggy(reader).value(), -111);
1230 
1231   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1232   EXPECT_EQ(Pigweed::FindCycles(reader).value(), 0x40302010fecaaddeu);
1233 
1234   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1235   EXPECT_EQ(Pigweed::FindRatio(reader).value(), -1.42f);
1236 
1237   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1238   char str[32] = {'\0'};
1239   auto result = Pigweed::FindErrorMessage(reader, str);
1240   EXPECT_EQ(result.status(), OkStatus());
1241   EXPECT_EQ(result.size(), 16u);
1242   EXPECT_STREQ(str, "not a typewriter");
1243 
1244   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1245   InlineString<32> error_message;
1246   result = Pigweed::FindErrorMessage(reader, error_message);
1247   EXPECT_EQ(result.status(), OkStatus());
1248   EXPECT_EQ(result.size(), 16u);
1249   EXPECT_STREQ(error_message.c_str(), "not a typewriter");
1250 
1251   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1252   EXPECT_EQ(Pigweed::FindBin(reader).value(), Pigweed::Protobuf::Binary::ZERO);
1253 
1254   // Nonexisting fields.
1255   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1256   std::byte buf[32];
1257   EXPECT_EQ(Pigweed::FindData(reader, buf).status(), Status::NotFound());
1258 
1259   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1260   EXPECT_EQ(Pigweed::FindDescription(reader, str).status(), Status::NotFound());
1261 
1262   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1263   EXPECT_EQ(Pigweed::FindSpecialProperty(reader).status(), Status::NotFound());
1264 
1265   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1266   EXPECT_EQ(Pigweed::FindBungle(reader).status(), Status::NotFound());
1267 
1268   // Advance the stream past `magic_number`, then attempt to find it.
1269   reader = stream::MemoryReader(as_bytes(span(proto_data)));
1270   EXPECT_EQ(Pigweed::FindZiggy(reader).status(), OkStatus());
1271   EXPECT_EQ(Pigweed::FindMagicNumber(reader).status(), Status::NotFound());
1272 }
1273 
TEST(CodegenRepeated,Find)1274 TEST(CodegenRepeated, Find) {
1275   // clang-format off
1276   constexpr uint8_t proto_data[] = {
1277     // uint32s[], v={0, 16, 32, 48}
1278     0x08, 0x00,
1279     0x08, 0x10,
1280     0x08, 0x20,
1281     0x08, 0x30,
1282     // fixed32s[]. v={0, 16, 32, 48}
1283     0x35, 0x00, 0x00, 0x00, 0x00,
1284     0x35, 0x10, 0x00, 0x00, 0x00,
1285     0x35, 0x20, 0x00, 0x00, 0x00,
1286     0x35, 0x30, 0x00, 0x00, 0x00,
1287   };
1288   // clang-format on
1289 
1290   Uint32Finder uint32s_finder =
1291       RepeatedTest::FindUint32s(as_bytes(span(proto_data)));
1292 
1293   for (uint32_t i = 0; i < 4; ++i) {
1294     Result<uint32_t> result = uint32s_finder.Next();
1295     EXPECT_EQ(result.status(), OkStatus());
1296     EXPECT_EQ(result.value(), i * 16u);
1297   }
1298   EXPECT_EQ(uint32s_finder.Next().status(), Status::NotFound());
1299 
1300   Fixed32Finder fixed32s_finder =
1301       RepeatedTest::FindFixed32s(as_bytes(span(proto_data)));
1302 
1303   for (unsigned i = 0; i < 4; ++i) {
1304     Result<uint32_t> result = fixed32s_finder.Next();
1305     EXPECT_EQ(result.status(), OkStatus());
1306     EXPECT_EQ(result.value(), i * 16u);
1307   }
1308   EXPECT_EQ(fixed32s_finder.Next().status(), Status::NotFound());
1309 }
1310 
TEST(CodegenRepeated,FindStream)1311 TEST(CodegenRepeated, FindStream) {
1312   // clang-format off
1313   constexpr uint8_t proto_data[] = {
1314     // uint32s[], v={0, 16, 32, 48}
1315     0x08, 0x00,
1316     0x08, 0x10,
1317     0x08, 0x20,
1318     0x08, 0x30,
1319     // fixed32s[]. v={0, 16, 32, 48}
1320     0x35, 0x00, 0x00, 0x00, 0x00,
1321     0x35, 0x10, 0x00, 0x00, 0x00,
1322     0x35, 0x20, 0x00, 0x00, 0x00,
1323     0x35, 0x30, 0x00, 0x00, 0x00,
1324   };
1325   // clang-format on
1326 
1327   stream::MemoryReader reader(as_bytes(span(proto_data)));
1328   Uint32StreamFinder uint32s_finder = RepeatedTest::FindUint32s(reader);
1329 
1330   for (uint32_t i = 0; i < 4; ++i) {
1331     Result<uint32_t> result = uint32s_finder.Next();
1332     EXPECT_EQ(result.status(), OkStatus());
1333     EXPECT_EQ(result.value(), i * 16u);
1334   }
1335   EXPECT_EQ(uint32s_finder.Next().status(), Status::NotFound());
1336 
1337   ASSERT_EQ(reader.Seek(0), OkStatus());
1338 
1339   Fixed32StreamFinder fixed32s_finder = RepeatedTest::FindFixed32s(reader);
1340 
1341   for (unsigned i = 0; i < 4; ++i) {
1342     Result<uint32_t> result = fixed32s_finder.Next();
1343     EXPECT_EQ(result.status(), OkStatus());
1344     EXPECT_EQ(result.value(), i * 16u);
1345   }
1346   EXPECT_EQ(fixed32s_finder.Next().status(), Status::NotFound());
1347 }
1348 
1349 }  // namespace
1350 }  // namespace pw::protobuf
1351