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 <stdexcept>
16 #include <string_view>
17
18 #include "gtest/gtest.h"
19 #include "pw_bytes/span.h"
20 #include "pw_containers/vector.h"
21 #include "pw_span/span.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 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 (int 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 (int 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 (int 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 (int 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 (int i = 0; i < 4; ++i) {
574 EXPECT_EQ(uint32s[i], i * 16u);
575 }
576
577 pw::Vector<uint32_t, 8> fixed32s{};
578
579 for (int 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 (int 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 (int 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 (int 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 (int 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 (int 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 (int 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 (int 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 (int 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 (int 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 (int 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 (int 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 (int 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 (int 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 (int 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
1028 } // namespace
1029 } // namespace pw::protobuf
1030