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