• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <span>
16 #include <stdexcept>
17 #include <string_view>
18 
19 #include "gtest/gtest.h"
20 #include "pw_bytes/span.h"
21 #include "pw_containers/vector.h"
22 #include "pw_status/status.h"
23 #include "pw_status/status_with_size.h"
24 #include "pw_stream/memory_stream.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 namespace pw::protobuf::test;
43 
TEST(Codegen,StreamDecoder)44 TEST(Codegen, StreamDecoder) {
45   // clang-format off
46   constexpr uint8_t proto_data[] = {
47     // pigweed.magic_number
48     0x08, 0x49,
49     // pigweed.ziggy
50     0x10, 0xdd, 0x01,
51     // pigweed.error_message
52     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
53     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
54     // pigweed.bin
55     0x40, 0x01,
56     // pigweed.pigweed
57     0x3a, 0x02,
58     // pigweed.pigweed.status
59     0x08, 0x02,
60     // pigweed.proto
61     0x4a, 0x56,
62     // pigweed.proto.bin
63     0x10, 0x00,
64     // pigweed.proto.pigweed_pigweed_bin
65     0x18, 0x00,
66     // pigweed.proto.pigweed_protobuf_bin
67     0x20, 0x01,
68     // pigweed.proto.meta
69     0x2a, 0x0f,
70     // pigweed.proto.meta.file_name
71     0x0a, 0x0b, '/', 'e', 't', 'c', '/', 'p', 'a', 's', 's', 'w', 'd',
72     // pigweed.proto.meta.status
73     0x10, 0x02,
74     // pigweed.proto.nested_pigweed
75     0x0a, 0x3d,
76     // pigweed.proto.nested_pigweed.error_message
77     0x2a, 0x10, 'h', 'e', 'r', 'e', ' ', 'w', 'e', ' ',
78     'g', 'o', ' ', 'a', 'g', 'a', 'i', 'n',
79     // pigweed.proto.nested_pigweed.magic_number
80     0x08, 0xe8, 0x04,
81     // pigweed.proto.nested_pigweed.device_info
82     0x32, 0x26,
83     // pigweed.proto.nested_pigweed.device_info.attributes[0]
84     0x22, 0x10,
85     // pigweed.proto.nested_pigweed.device_info.attributes[0].key
86     0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
87     // pigweed.proto.nested_pigweed.device_info.attributes[0].value
88     0x12, 0x05, '5', '.', '3', '.', '1',
89     // pigweed.proto.nested_pigweed.device_info.attributes[1]
90     0x22, 0x10,
91     // pigweed.proto.nested_pigweed.device_info.attributes[1].key
92     0x0a, 0x04, 'c', 'h', 'i', 'p',
93     // pigweed.proto.nested_pigweed.device_info.attributes[1].value
94     0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
95     // pigweed.proto.nested_pigweed.device_info.status
96     0x18, 0x03,
97     // pigweed.id[0]
98     0x52, 0x02,
99     // pigweed.id[0].id
100     0x08, 0x31,
101     // pigweed.id[1]
102     0x52, 0x02,
103     // pigweed.id[1].id
104     0x08, 0x39,
105     // pigweed.id[2]
106     0x52, 0x02,
107     // pigweed.id[2].id
108     0x08, 0x4b,
109     // pigweed.id[3]
110     0x52, 0x02,
111     // pigweed.id[3].id
112     0x08, 0x67,
113     // pigweed.id[4]
114     0x52, 0x03,
115     // pigweed.id[4].id
116     0x08, 0x8d, 0x01
117 
118   };
119   // clang-format on
120 
121   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
122   Pigweed::StreamDecoder pigweed(reader);
123 
124   EXPECT_EQ(pigweed.Next(), OkStatus());
125   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::MAGIC_NUMBER);
126   Result<uint32_t> magic_number = pigweed.ReadMagicNumber();
127   EXPECT_EQ(magic_number.status(), OkStatus());
128   EXPECT_EQ(magic_number.value(), 0x49u);
129 
130   EXPECT_EQ(pigweed.Next(), OkStatus());
131   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ZIGGY);
132   Result<int32_t> ziggy = pigweed.ReadZiggy();
133   EXPECT_EQ(ziggy.status(), OkStatus());
134   EXPECT_EQ(ziggy.value(), -111);
135 
136   constexpr std::string_view kExpectedErrorMessage{"not a typewriter"};
137 
138   EXPECT_EQ(pigweed.Next(), OkStatus());
139   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
140   std::array<char, 32> error_message{};
141   StatusWithSize error_message_status = pigweed.ReadErrorMessage(error_message);
142   EXPECT_EQ(error_message_status.status(), OkStatus());
143   EXPECT_EQ(error_message_status.size(), kExpectedErrorMessage.size());
144   EXPECT_EQ(std::memcmp(error_message.data(),
145                         kExpectedErrorMessage.data(),
146                         kExpectedErrorMessage.size()),
147             0);
148 
149   EXPECT_EQ(pigweed.Next(), OkStatus());
150   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::BIN);
151   Result<Pigweed::Protobuf::Binary> bin = pigweed.ReadBin();
152   EXPECT_EQ(bin.status(), OkStatus());
153   EXPECT_EQ(bin.value(), Pigweed::Protobuf::Binary::ZERO);
154 
155   EXPECT_EQ(pigweed.Next(), OkStatus());
156   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::PIGWEED);
157   {
158     Pigweed::Pigweed::StreamDecoder pigweed_pigweed =
159         pigweed.GetPigweedDecoder();
160 
161     EXPECT_EQ(pigweed_pigweed.Next(), OkStatus());
162     EXPECT_EQ(pigweed_pigweed.Field().value(),
163               Pigweed::Pigweed::Fields::STATUS);
164     Result<Bool> pigweed_status = pigweed_pigweed.ReadStatus();
165     EXPECT_EQ(pigweed_status.status(), OkStatus());
166     EXPECT_EQ(pigweed_status.value(), Bool::FILE_NOT_FOUND);
167 
168     EXPECT_EQ(pigweed_pigweed.Next(), Status::OutOfRange());
169   }
170 
171   EXPECT_EQ(pigweed.Next(), OkStatus());
172   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::PROTO);
173   {
174     Proto::StreamDecoder proto = pigweed.GetProtoDecoder();
175 
176     EXPECT_EQ(proto.Next(), OkStatus());
177     EXPECT_EQ(proto.Field().value(), Proto::Fields::BIN);
178     Result<Proto::Binary> proto_bin = proto.ReadBin();
179     EXPECT_EQ(proto_bin.status(), OkStatus());
180     EXPECT_EQ(proto_bin.value(), Proto::Binary::OFF);
181 
182     EXPECT_EQ(proto.Next(), OkStatus());
183     EXPECT_EQ(proto.Field().value(), Proto::Fields::PIGWEED_PIGWEED_BIN);
184     Result<Pigweed::Pigweed::Binary> proto_pigweed_bin =
185         proto.ReadPigweedPigweedBin();
186     EXPECT_EQ(proto_pigweed_bin.status(), OkStatus());
187     EXPECT_EQ(proto_pigweed_bin.value(), Pigweed::Pigweed::Binary::ZERO);
188 
189     EXPECT_EQ(proto.Next(), OkStatus());
190     EXPECT_EQ(proto.Field().value(), Proto::Fields::PIGWEED_PROTOBUF_BIN);
191     Result<Pigweed::Protobuf::Binary> proto_protobuf_bin =
192         proto.ReadPigweedProtobufBin();
193     EXPECT_EQ(proto_protobuf_bin.status(), OkStatus());
194     EXPECT_EQ(proto_protobuf_bin.value(), Pigweed::Protobuf::Binary::ZERO);
195 
196     EXPECT_EQ(proto.Next(), OkStatus());
197     EXPECT_EQ(proto.Field().value(), Proto::Fields::META);
198     {
199       Pigweed::Protobuf::Compiler::StreamDecoder meta = proto.GetMetaDecoder();
200 
201       constexpr std::string_view kExpectedFileName{"/etc/passwd"};
202 
203       EXPECT_EQ(meta.Next(), OkStatus());
204       EXPECT_EQ(meta.Field().value(),
205                 Pigweed::Protobuf::Compiler::Fields::FILE_NAME);
206       std::array<char, 32> meta_file_name{};
207       StatusWithSize meta_file_name_status = meta.ReadFileName(meta_file_name);
208       EXPECT_EQ(meta_file_name_status.status(), OkStatus());
209       EXPECT_EQ(meta_file_name_status.size(), kExpectedFileName.size());
210       EXPECT_EQ(std::memcmp(meta_file_name.data(),
211                             kExpectedFileName.data(),
212                             kExpectedFileName.size()),
213                 0);
214 
215       EXPECT_EQ(meta.Next(), OkStatus());
216       EXPECT_EQ(meta.Field().value(),
217                 Pigweed::Protobuf::Compiler::Fields::STATUS);
218       Result<Pigweed::Protobuf::Compiler::Status> meta_status =
219           meta.ReadStatus();
220       EXPECT_EQ(meta_status.status(), OkStatus());
221       EXPECT_EQ(meta_status.value(),
222                 Pigweed::Protobuf::Compiler::Status::FUBAR);
223 
224       EXPECT_EQ(meta.Next(), Status::OutOfRange());
225     }
226 
227     EXPECT_EQ(proto.Next(), OkStatus());
228     EXPECT_EQ(proto.Field().value(), Proto::Fields::PIGWEED);
229     {
230       Pigweed::StreamDecoder proto_pigweed = proto.GetPigweedDecoder();
231 
232       constexpr std::string_view kExpectedProtoErrorMessage{"here we go again"};
233 
234       EXPECT_EQ(proto_pigweed.Next(), OkStatus());
235       EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
236       std::array<char, 32> proto_pigweed_error_message{};
237       StatusWithSize proto_pigweed_error_message_status =
238           proto_pigweed.ReadErrorMessage(proto_pigweed_error_message);
239       EXPECT_EQ(proto_pigweed_error_message_status.status(), OkStatus());
240       EXPECT_EQ(proto_pigweed_error_message_status.size(),
241                 kExpectedProtoErrorMessage.size());
242       EXPECT_EQ(std::memcmp(proto_pigweed_error_message.data(),
243                             kExpectedProtoErrorMessage.data(),
244                             kExpectedProtoErrorMessage.size()),
245                 0);
246 
247       EXPECT_EQ(proto_pigweed.Next(), OkStatus());
248       EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::MAGIC_NUMBER);
249       Result<uint32_t> proto_pigweed_magic_number =
250           proto_pigweed.ReadMagicNumber();
251       EXPECT_EQ(proto_pigweed_magic_number.status(), OkStatus());
252       EXPECT_EQ(proto_pigweed_magic_number.value(), 616u);
253 
254       EXPECT_EQ(proto_pigweed.Next(), OkStatus());
255       EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::DEVICE_INFO);
256       {
257         DeviceInfo::StreamDecoder device_info =
258             proto_pigweed.GetDeviceInfoDecoder();
259 
260         EXPECT_EQ(device_info.Next(), OkStatus());
261         EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::ATTRIBUTES);
262         {
263           KeyValuePair::StreamDecoder key_value_pair =
264               device_info.GetAttributesDecoder();
265 
266           constexpr std::string_view kExpectedKey{"version"};
267           constexpr std::string_view kExpectedValue{"5.3.1"};
268 
269           EXPECT_EQ(key_value_pair.Next(), OkStatus());
270           EXPECT_EQ(key_value_pair.Field().value(), KeyValuePair::Fields::KEY);
271           std::array<char, 32> key{};
272           StatusWithSize key_status = key_value_pair.ReadKey(key);
273           EXPECT_EQ(key_status.status(), OkStatus());
274           EXPECT_EQ(key_status.size(), kExpectedKey.size());
275           EXPECT_EQ(
276               std::memcmp(key.data(), kExpectedKey.data(), kExpectedKey.size()),
277               0);
278 
279           EXPECT_EQ(key_value_pair.Next(), OkStatus());
280           EXPECT_EQ(key_value_pair.Field().value(),
281                     KeyValuePair::Fields::VALUE);
282           std::array<char, 32> value{};
283           StatusWithSize value_status = key_value_pair.ReadValue(value);
284           EXPECT_EQ(value_status.status(), OkStatus());
285           EXPECT_EQ(value_status.size(), kExpectedValue.size());
286           EXPECT_EQ(
287               std::memcmp(
288                   value.data(), kExpectedValue.data(), kExpectedValue.size()),
289               0);
290 
291           EXPECT_EQ(key_value_pair.Next(), Status::OutOfRange());
292         }
293 
294         EXPECT_EQ(device_info.Next(), OkStatus());
295         EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::ATTRIBUTES);
296         {
297           KeyValuePair::StreamDecoder key_value_pair =
298               device_info.GetAttributesDecoder();
299 
300           constexpr std::string_view kExpectedKey{"chip"};
301           constexpr std::string_view kExpectedValue{"left-soc"};
302 
303           EXPECT_EQ(key_value_pair.Next(), OkStatus());
304           EXPECT_EQ(key_value_pair.Field().value(), KeyValuePair::Fields::KEY);
305           std::array<char, 32> key{};
306           StatusWithSize key_status = key_value_pair.ReadKey(key);
307           EXPECT_EQ(key_status.status(), OkStatus());
308           EXPECT_EQ(key_status.size(), kExpectedKey.size());
309           EXPECT_EQ(
310               std::memcmp(key.data(), kExpectedKey.data(), kExpectedKey.size()),
311               0);
312 
313           EXPECT_EQ(key_value_pair.Next(), OkStatus());
314           EXPECT_EQ(key_value_pair.Field().value(),
315                     KeyValuePair::Fields::VALUE);
316           std::array<char, 32> value{};
317           StatusWithSize value_status = key_value_pair.ReadValue(value);
318           EXPECT_EQ(value_status.status(), OkStatus());
319           EXPECT_EQ(value_status.size(), kExpectedValue.size());
320           EXPECT_EQ(
321               std::memcmp(
322                   value.data(), kExpectedValue.data(), kExpectedValue.size()),
323               0);
324 
325           EXPECT_EQ(key_value_pair.Next(), Status::OutOfRange());
326         }
327 
328         EXPECT_EQ(device_info.Next(), OkStatus());
329         EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::STATUS);
330         Result<DeviceInfo::DeviceStatus> device_info_status =
331             device_info.ReadStatus();
332         EXPECT_EQ(device_info_status.status(), OkStatus());
333         EXPECT_EQ(device_info_status.value(), DeviceInfo::DeviceStatus::PANIC);
334 
335         EXPECT_EQ(device_info.Next(), Status::OutOfRange());
336       }
337 
338       EXPECT_EQ(proto_pigweed.Next(), Status::OutOfRange());
339     }
340 
341     EXPECT_EQ(proto.Next(), Status::OutOfRange());
342   }
343 
344   for (int i = 0; i < 5; ++i) {
345     EXPECT_EQ(pigweed.Next(), OkStatus());
346     EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ID);
347 
348     Proto::ID::StreamDecoder id = pigweed.GetIdDecoder();
349 
350     EXPECT_EQ(id.Next(), OkStatus());
351     EXPECT_EQ(id.Field().value(), Proto::ID::Fields::ID);
352     Result<uint32_t> id_id = id.ReadId();
353     EXPECT_EQ(id_id.status(), OkStatus());
354     EXPECT_EQ(id_id.value(), 5u * i * i + 3 * i + 49);
355 
356     EXPECT_EQ(id.Next(), Status::OutOfRange());
357   }
358 
359   EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
360 }
361 
TEST(Codegen,ResourceExhausted)362 TEST(Codegen, ResourceExhausted) {
363   // clang-format off
364   constexpr uint8_t proto_data[] = {
365     // pigweed.error_message
366     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
367     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
368   };
369   // clang-format on
370 
371   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
372   Pigweed::StreamDecoder pigweed(reader);
373 
374   EXPECT_EQ(pigweed.Next(), OkStatus());
375   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
376   std::array<char, 8> error_message{};
377   StatusWithSize error_message_status = pigweed.ReadErrorMessage(error_message);
378   EXPECT_EQ(error_message_status.status(), Status::ResourceExhausted());
379   EXPECT_EQ(error_message_status.size(), 0u);
380 
381   EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
382 }
383 
TEST(Codegen,BytesReader)384 TEST(Codegen, BytesReader) {
385   // clang-format off
386   constexpr uint8_t proto_data[] = {
387     // pigweed.error_message
388     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
389     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
390   };
391   // clang-format on
392 
393   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
394   Pigweed::StreamDecoder pigweed(reader);
395 
396   constexpr std::string_view kExpectedErrorMessage{"not a typewriter"};
397 
398   EXPECT_EQ(pigweed.Next(), OkStatus());
399   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
400   {
401     StreamDecoder::BytesReader bytes_reader = pigweed.GetErrorMessageReader();
402     EXPECT_EQ(bytes_reader.field_size(), kExpectedErrorMessage.size());
403 
404     std::array<std::byte, 32> error_message{};
405     Result<ByteSpan> result = bytes_reader.Read(error_message);
406     EXPECT_EQ(result.status(), OkStatus());
407     EXPECT_EQ(result.value().size(), kExpectedErrorMessage.size());
408     EXPECT_EQ(std::memcmp(result.value().data(),
409                           kExpectedErrorMessage.data(),
410                           kExpectedErrorMessage.size()),
411               0);
412 
413     result = bytes_reader.Read(error_message);
414     EXPECT_EQ(result.status(), Status::OutOfRange());
415   }
416 
417   EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
418 }
419 
TEST(Codegen,Enum)420 TEST(Codegen, Enum) {
421   // clang-format off
422   constexpr uint8_t proto_data[] = {
423     // pigweed.bin (value value)
424     0x40, 0x01,
425     // pigweed.bin (invalid value)
426     0x40, 0xff,
427   };
428   // clang-format on
429 
430   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
431   Pigweed::StreamDecoder pigweed(reader);
432 
433   EXPECT_EQ(pigweed.Next(), OkStatus());
434   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::BIN);
435   Result<Pigweed::Protobuf::Binary> bin = pigweed.ReadBin();
436   EXPECT_EQ(bin.status(), OkStatus());
437   EXPECT_EQ(bin.value(), Pigweed::Protobuf::Binary::ZERO);
438 
439   EXPECT_EQ(pigweed.Next(), OkStatus());
440   EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::BIN);
441   bin = pigweed.ReadBin();
442   EXPECT_EQ(bin.status(), Status::DataLoss());
443 }
444 
TEST(Codegen,ImportedEnum)445 TEST(Codegen, ImportedEnum) {
446   // clang-format off
447   constexpr uint8_t proto_data[] = {
448     // result.status (value value)
449     0x08, 0x01,
450     // result.status (invalid value)
451     0x08, 0xff,
452   };
453   // clang-format on
454 
455   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
456   TestResult::StreamDecoder test_result(reader);
457 
458   EXPECT_EQ(test_result.Next(), OkStatus());
459   EXPECT_EQ(test_result.Field().value(), TestResult::Fields::STATUS);
460   Result<imported::Status> status = test_result.ReadStatus();
461   EXPECT_EQ(status.status(), OkStatus());
462   EXPECT_EQ(status.value(), imported::Status::NOT_OK);
463 
464   EXPECT_EQ(test_result.Next(), OkStatus());
465   EXPECT_EQ(test_result.Field().value(), TestResult::Fields::STATUS);
466   status = test_result.ReadStatus();
467   EXPECT_EQ(status.status(), Status::DataLoss());
468 }
469 
TEST(CodegenRepeated,NonPackedScalar)470 TEST(CodegenRepeated, NonPackedScalar) {
471   // clang-format off
472   constexpr uint8_t proto_data[] = {
473     // uint32s[], v={0, 16, 32, 48}
474     0x08, 0x00,
475     0x08, 0x10,
476     0x08, 0x20,
477     0x08, 0x30,
478     // fixed32s[]. v={0, 16, 32, 48}
479     0x35, 0x00, 0x00, 0x00, 0x00,
480     0x35, 0x10, 0x00, 0x00, 0x00,
481     0x35, 0x20, 0x00, 0x00, 0x00,
482     0x35, 0x30, 0x00, 0x00, 0x00,
483   };
484   // clang-format on
485 
486   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
487   RepeatedTest::StreamDecoder repeated_test(reader);
488 
489   for (int i = 0; i < 4; ++i) {
490     EXPECT_EQ(repeated_test.Next(), OkStatus());
491     EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
492 
493     Result<uint32_t> result = repeated_test.ReadUint32s();
494     EXPECT_EQ(result.status(), OkStatus());
495     EXPECT_EQ(result.value(), i * 16u);
496   }
497 
498   for (int i = 0; i < 4; ++i) {
499     EXPECT_EQ(repeated_test.Next(), OkStatus());
500     EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
501 
502     Result<uint32_t> result = repeated_test.ReadFixed32s();
503     EXPECT_EQ(result.status(), OkStatus());
504     EXPECT_EQ(result.value(), i * 16u);
505   }
506 
507   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
508 }
509 
TEST(CodegenRepeated,NonPackedScalarVector)510 TEST(CodegenRepeated, NonPackedScalarVector) {
511   // clang-format off
512   constexpr uint8_t proto_data[] = {
513     // uint32s[], v={0, 16, 32, 48}
514     0x08, 0x00,
515     0x08, 0x10,
516     0x08, 0x20,
517     0x08, 0x30,
518     // fixed32s[]. v={0, 16, 32, 48}
519     0x35, 0x00, 0x00, 0x00, 0x00,
520     0x35, 0x10, 0x00, 0x00, 0x00,
521     0x35, 0x20, 0x00, 0x00, 0x00,
522     0x35, 0x30, 0x00, 0x00, 0x00,
523   };
524   // clang-format on
525 
526   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
527   RepeatedTest::StreamDecoder repeated_test(reader);
528 
529   pw::Vector<uint32_t, 8> uint32s{};
530 
531   for (int i = 0; i < 4; ++i) {
532     EXPECT_EQ(repeated_test.Next(), OkStatus());
533     EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
534 
535     Status status = repeated_test.ReadUint32s(uint32s);
536     EXPECT_EQ(status, OkStatus());
537     EXPECT_EQ(uint32s.size(), i + 1u);
538   }
539 
540   for (int i = 0; i < 4; ++i) {
541     EXPECT_EQ(uint32s[i], i * 16u);
542   }
543 
544   pw::Vector<uint32_t, 8> fixed32s{};
545 
546   for (int i = 0; i < 4; ++i) {
547     EXPECT_EQ(repeated_test.Next(), OkStatus());
548     EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
549 
550     Status status = repeated_test.ReadFixed32s(fixed32s);
551     EXPECT_EQ(status, OkStatus());
552     EXPECT_EQ(fixed32s.size(), i + 1u);
553   }
554 
555   for (int i = 0; i < 4; ++i) {
556     EXPECT_EQ(fixed32s[i], i * 16u);
557   }
558 
559   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
560 }
561 
TEST(CodegenRepeated,NonPackedVarintScalarVectorFull)562 TEST(CodegenRepeated, NonPackedVarintScalarVectorFull) {
563   // clang-format off
564   constexpr uint8_t proto_data[] = {
565     // uint32s[], v={0, 16, 32, 48}
566     0x08, 0x00,
567     0x08, 0x10,
568     0x08, 0x20,
569     0x08, 0x30,
570   };
571   // clang-format on
572 
573   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
574   RepeatedTest::StreamDecoder repeated_test(reader);
575 
576   pw::Vector<uint32_t, 2> uint32s{};
577 
578   EXPECT_EQ(repeated_test.Next(), OkStatus());
579   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
580   Status status = repeated_test.ReadUint32s(uint32s);
581   EXPECT_EQ(status, OkStatus());
582   EXPECT_EQ(uint32s.size(), 1u);
583 
584   EXPECT_EQ(repeated_test.Next(), OkStatus());
585   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
586   status = repeated_test.ReadUint32s(uint32s);
587   EXPECT_EQ(status, OkStatus());
588   EXPECT_EQ(uint32s.size(), 2u);
589 
590   EXPECT_EQ(repeated_test.Next(), OkStatus());
591   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
592   status = repeated_test.ReadUint32s(uint32s);
593   EXPECT_EQ(status, Status::ResourceExhausted());
594   EXPECT_EQ(uint32s.size(), 2u);
595 
596   for (int i = 0; i < 2; ++i) {
597     EXPECT_EQ(uint32s[i], i * 16u);
598   }
599 }
600 
TEST(CodegenRepeated,NonPackedFixedScalarVectorFull)601 TEST(CodegenRepeated, NonPackedFixedScalarVectorFull) {
602   // clang-format off
603   constexpr uint8_t proto_data[] = {
604     // fixed32s[]. v={0, 16, 32, 48}
605     0x35, 0x00, 0x00, 0x00, 0x00,
606     0x35, 0x10, 0x00, 0x00, 0x00,
607     0x35, 0x20, 0x00, 0x00, 0x00,
608     0x35, 0x30, 0x00, 0x00, 0x00,
609   };
610   // clang-format on
611 
612   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
613   RepeatedTest::StreamDecoder repeated_test(reader);
614 
615   pw::Vector<uint32_t, 2> fixed32s{};
616 
617   EXPECT_EQ(repeated_test.Next(), OkStatus());
618   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
619   Status status = repeated_test.ReadFixed32s(fixed32s);
620   EXPECT_EQ(status, OkStatus());
621   EXPECT_EQ(fixed32s.size(), 1u);
622 
623   EXPECT_EQ(repeated_test.Next(), OkStatus());
624   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
625   status = repeated_test.ReadFixed32s(fixed32s);
626   EXPECT_EQ(status, OkStatus());
627   EXPECT_EQ(fixed32s.size(), 2u);
628 
629   EXPECT_EQ(repeated_test.Next(), OkStatus());
630   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
631   status = repeated_test.ReadFixed32s(fixed32s);
632   EXPECT_EQ(status, Status::ResourceExhausted());
633   EXPECT_EQ(fixed32s.size(), 2u);
634 
635   for (int i = 0; i < 2; ++i) {
636     EXPECT_EQ(fixed32s[i], i * 16u);
637   }
638 }
639 
TEST(CodegenRepeated,PackedScalar)640 TEST(CodegenRepeated, PackedScalar) {
641   // clang-format off
642   constexpr uint8_t proto_data[] = {
643     // uint32s[], v={0, 16, 32, 48}
644     0x0a, 0x04,
645     0x00,
646     0x10,
647     0x20,
648     0x30,
649     // fixed32s[]. v={0, 16, 32, 48}
650     0x32, 0x10,
651     0x00, 0x00, 0x00, 0x00,
652     0x10, 0x00, 0x00, 0x00,
653     0x20, 0x00, 0x00, 0x00,
654     0x30, 0x00, 0x00, 0x00,
655   };
656   // clang-format on
657 
658   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
659   RepeatedTest::StreamDecoder repeated_test(reader);
660 
661   EXPECT_EQ(repeated_test.Next(), OkStatus());
662   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
663   std::array<uint32_t, 8> uint32s{};
664   StatusWithSize sws = repeated_test.ReadUint32s(uint32s);
665   EXPECT_EQ(sws.status(), OkStatus());
666   EXPECT_EQ(sws.size(), 4u);
667 
668   for (int i = 0; i < 4; ++i) {
669     EXPECT_EQ(uint32s[i], i * 16u);
670   }
671 
672   EXPECT_EQ(repeated_test.Next(), OkStatus());
673   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
674   std::array<uint32_t, 8> fixed32s{};
675   sws = repeated_test.ReadFixed32s(fixed32s);
676   EXPECT_EQ(sws.status(), OkStatus());
677   EXPECT_EQ(sws.size(), 4u);
678 
679   for (int i = 0; i < 4; ++i) {
680     EXPECT_EQ(fixed32s[i], i * 16u);
681   }
682 
683   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
684 }
685 
TEST(CodegenRepeated,PackedVarintScalarExhausted)686 TEST(CodegenRepeated, PackedVarintScalarExhausted) {
687   // clang-format off
688   constexpr uint8_t proto_data[] = {
689     // uint32s[], v={0, 16, 32, 48}
690     0x0a, 0x04,
691     0x00,
692     0x10,
693     0x20,
694     0x30,
695   };
696   // clang-format on
697 
698   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
699   RepeatedTest::StreamDecoder repeated_test(reader);
700 
701   EXPECT_EQ(repeated_test.Next(), OkStatus());
702   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
703   std::array<uint32_t, 2> uint32s{};
704   StatusWithSize sws = repeated_test.ReadUint32s(uint32s);
705   EXPECT_EQ(sws.status(), Status::ResourceExhausted());
706   EXPECT_EQ(sws.size(), 2u);
707 
708   for (int i = 0; i < 2; ++i) {
709     EXPECT_EQ(uint32s[i], i * 16u);
710   }
711 }
712 
TEST(CodegenRepeated,PackedFixedScalarExhausted)713 TEST(CodegenRepeated, PackedFixedScalarExhausted) {
714   // clang-format off
715   constexpr uint8_t proto_data[] = {
716     // fixed32s[]. v={0, 16, 32, 48}
717     0x32, 0x10,
718     0x00, 0x00, 0x00, 0x00,
719     0x10, 0x00, 0x00, 0x00,
720     0x20, 0x00, 0x00, 0x00,
721     0x30, 0x00, 0x00, 0x00,
722   };
723   // clang-format on
724 
725   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
726   RepeatedTest::StreamDecoder repeated_test(reader);
727 
728   EXPECT_EQ(repeated_test.Next(), OkStatus());
729   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
730   std::array<uint32_t, 2> fixed32s{};
731   StatusWithSize sws = repeated_test.ReadFixed32s(fixed32s);
732   EXPECT_EQ(sws.status(), Status::ResourceExhausted());
733   EXPECT_EQ(sws.size(), 0u);
734 }
735 
TEST(CodegenRepeated,PackedScalarVector)736 TEST(CodegenRepeated, PackedScalarVector) {
737   // clang-format off
738   constexpr uint8_t proto_data[] = {
739     // uint32s[], v={0, 16, 32, 48}
740     0x0a, 0x04,
741     0x00,
742     0x10,
743     0x20,
744     0x30,
745     // fixed32s[]. v={0, 16, 32, 48}
746     0x32, 0x10,
747     0x00, 0x00, 0x00, 0x00,
748     0x10, 0x00, 0x00, 0x00,
749     0x20, 0x00, 0x00, 0x00,
750     0x30, 0x00, 0x00, 0x00,
751   };
752   // clang-format on
753 
754   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
755   RepeatedTest::StreamDecoder repeated_test(reader);
756 
757   EXPECT_EQ(repeated_test.Next(), OkStatus());
758   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
759   pw::Vector<uint32_t, 8> uint32s{};
760   Status status = repeated_test.ReadUint32s(uint32s);
761   EXPECT_EQ(status, OkStatus());
762   EXPECT_EQ(uint32s.size(), 4u);
763 
764   for (int i = 0; i < 4; ++i) {
765     EXPECT_EQ(uint32s[i], i * 16u);
766   }
767 
768   EXPECT_EQ(repeated_test.Next(), OkStatus());
769   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
770   pw::Vector<uint32_t, 8> fixed32s{};
771   status = repeated_test.ReadFixed32s(fixed32s);
772   EXPECT_EQ(status, OkStatus());
773   EXPECT_EQ(fixed32s.size(), 4u);
774 
775   for (int i = 0; i < 4; ++i) {
776     EXPECT_EQ(fixed32s[i], i * 16u);
777   }
778 
779   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
780 }
781 
TEST(CodegenRepeated,PackedVarintScalarVectorFull)782 TEST(CodegenRepeated, PackedVarintScalarVectorFull) {
783   // clang-format off
784   constexpr uint8_t proto_data[] = {
785     // uint32s[], v={0, 16, 32, 48}
786     0x0a, 0x04,
787     0x00,
788     0x10,
789     0x20,
790     0x30,
791   };
792   // clang-format on
793 
794   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
795   RepeatedTest::StreamDecoder repeated_test(reader);
796 
797   EXPECT_EQ(repeated_test.Next(), OkStatus());
798   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
799   pw::Vector<uint32_t, 2> uint32s{};
800   Status status = repeated_test.ReadUint32s(uint32s);
801   EXPECT_EQ(status, Status::ResourceExhausted());
802   EXPECT_EQ(uint32s.size(), 2u);
803 
804   for (int i = 0; i < 2; ++i) {
805     EXPECT_EQ(uint32s[i], i * 16u);
806   }
807 }
808 
TEST(CodegenRepeated,PackedFixedScalarVectorFull)809 TEST(CodegenRepeated, PackedFixedScalarVectorFull) {
810   // clang-format off
811   constexpr uint8_t proto_data[] = {
812     // fixed32s[]. v={0, 16, 32, 48}
813     0x32, 0x10,
814     0x00, 0x00, 0x00, 0x00,
815     0x10, 0x00, 0x00, 0x00,
816     0x20, 0x00, 0x00, 0x00,
817     0x30, 0x00, 0x00, 0x00,
818   };
819   // clang-format on
820 
821   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
822   RepeatedTest::StreamDecoder repeated_test(reader);
823 
824   EXPECT_EQ(repeated_test.Next(), OkStatus());
825   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
826   pw::Vector<uint32_t, 2> fixed32s{};
827   Status status = repeated_test.ReadFixed32s(fixed32s);
828   EXPECT_EQ(status, Status::ResourceExhausted());
829   EXPECT_EQ(fixed32s.size(), 0u);
830 }
831 
TEST(CodegenRepeated,PackedScalarVectorRepeated)832 TEST(CodegenRepeated, PackedScalarVectorRepeated) {
833   // clang-format off
834   constexpr uint8_t proto_data[] = {
835     // uint32s[], v={0, 16, 32, 48}
836     0x0a, 0x04,
837     0x00,
838     0x10,
839     0x20,
840     0x30,
841     // uint32s[], v={64, 80, 96, 112}
842     0x0a, 0x04,
843     0x40,
844     0x50,
845     0x60,
846     0x70,
847     // fixed32s[]. v={0, 16, 32, 48}
848     0x32, 0x10,
849     0x00, 0x00, 0x00, 0x00,
850     0x10, 0x00, 0x00, 0x00,
851     0x20, 0x00, 0x00, 0x00,
852     0x30, 0x00, 0x00, 0x00,
853     // fixed32s[]. v={64, 80, 96, 112}
854     0x32, 0x10,
855     0x40, 0x00, 0x00, 0x00,
856     0x50, 0x00, 0x00, 0x00,
857     0x60, 0x00, 0x00, 0x00,
858     0x70, 0x00, 0x00, 0x00,
859   };
860   // clang-format on
861 
862   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
863   RepeatedTest::StreamDecoder repeated_test(reader);
864 
865   EXPECT_EQ(repeated_test.Next(), OkStatus());
866   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
867   pw::Vector<uint32_t, 8> uint32s{};
868   Status status = repeated_test.ReadUint32s(uint32s);
869   EXPECT_EQ(status, OkStatus());
870   EXPECT_EQ(uint32s.size(), 4u);
871 
872   EXPECT_EQ(repeated_test.Next(), OkStatus());
873   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
874   status = repeated_test.ReadUint32s(uint32s);
875   EXPECT_EQ(status, OkStatus());
876   EXPECT_EQ(uint32s.size(), 8u);
877 
878   for (int i = 0; i < 8; ++i) {
879     EXPECT_EQ(uint32s[i], i * 16u);
880   }
881 
882   EXPECT_EQ(repeated_test.Next(), OkStatus());
883   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
884   pw::Vector<uint32_t, 8> fixed32s{};
885   status = repeated_test.ReadFixed32s(fixed32s);
886   EXPECT_EQ(status, OkStatus());
887   EXPECT_EQ(fixed32s.size(), 4u);
888 
889   EXPECT_EQ(repeated_test.Next(), OkStatus());
890   EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
891   status = repeated_test.ReadFixed32s(fixed32s);
892   EXPECT_EQ(status, OkStatus());
893   EXPECT_EQ(fixed32s.size(), 8u);
894 
895   for (int i = 0; i < 8; ++i) {
896     EXPECT_EQ(fixed32s[i], i * 16u);
897   }
898 
899   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
900 }
901 
TEST(CodegenRepeated,NonScalar)902 TEST(CodegenRepeated, NonScalar) {
903   // clang-format off
904   constexpr uint8_t proto_data[] = {
905     // strings[], v={"the", "quick", "brown", "fox"}
906     0x1a, 0x03, 't', 'h', 'e',
907     0x1a, 0x5, 'q',  'u', 'i', 'c', 'k',
908     0x1a, 0x5,  'b', 'r', 'o', 'w',  'n',
909     0x1a, 0x3, 'f', 'o', 'x'
910   };
911   // clang-format on
912 
913   stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
914   RepeatedTest::StreamDecoder repeated_test(reader);
915 
916   constexpr std::array<std::string_view, 4> kExpectedString{
917       {{"the"}, {"quick"}, {"brown"}, {"fox"}}};
918 
919   for (int i = 0; i < 4; ++i) {
920     EXPECT_EQ(repeated_test.Next(), OkStatus());
921     EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::STRINGS);
922     std::array<char, 32> string{};
923     StatusWithSize sws = repeated_test.ReadStrings(string);
924     EXPECT_EQ(sws.status(), OkStatus());
925     EXPECT_EQ(sws.size(), kExpectedString[i].size());
926     EXPECT_EQ(std::memcmp(string.data(),
927                           kExpectedString[i].data(),
928                           kExpectedString[i].size()),
929               0);
930   }
931 
932   EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
933 }
934 
935 }  // namespace
936 }  // namespace pw::protobuf
937