1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bytes/array.h"
16 #include "pw_protobuf/encoder.h"
17 #include "pw_protobuf/wire_format.h"
18 #include "pw_span/span.h"
19 #include "pw_stream/memory_stream.h"
20 #include "pw_unit_test/framework.h"
21
22 // These header files contain the code generated by the pw_protobuf plugin.
23 // They are re-generated every time the tests are built and are used by the
24 // tests to ensure that the interface remains consistent.
25 //
26 // The purpose of the tests in this file is primarily to verify that the
27 // generated C++ interface is valid rather than the correctness of the
28 // low-level encoder.
29 #include "pw_protobuf_test_protos/full_test.pwpb.h"
30 #include "pw_protobuf_test_protos/importer.pwpb.h"
31 #include "pw_protobuf_test_protos/non_pw_package.pwpb.h"
32 #include "pw_protobuf_test_protos/proto2.pwpb.h"
33 #include "pw_protobuf_test_protos/repeated.pwpb.h"
34
35 #define EXPECT_SEQ_EQ(seq1, seq2) \
36 EXPECT_TRUE(std::equal(seq1.begin(), seq1.end(), seq2.begin(), seq2.end()))
37
38 namespace pw::protobuf {
39 namespace {
40
41 using test::pwpb::Bool;
42 using test::pwpb::Enum;
43
44 namespace Bar = test::pwpb::Bar;
45 namespace BaseMessage = test::pwpb::BaseMessage;
46 namespace ConstrainedRepeatedTest = test::pwpb::ConstrainedRepeatedTest;
47 namespace Crate = test::pwpb::Crate;
48 namespace DeviceInfo = test::pwpb::DeviceInfo;
49 namespace Foo = test::pwpb::Foo;
50 namespace IntegerMetadata = test::pwpb::IntegerMetadata;
51 namespace KeyValuePair = test::pwpb::KeyValuePair;
52 namespace Overlay = test::pwpb::Overlay;
53 namespace Period = test::pwpb::Period;
54 namespace Pigweed = test::pwpb::Pigweed;
55 namespace Proto = test::pwpb::Proto;
56 namespace RepeatedTest = test::pwpb::RepeatedTest;
57
58 namespace imported {
59 namespace Timestamp = ::pw::protobuf::test::imported::pwpb::Timestamp;
60 } // namespace imported
61
62 template <uint32_t val>
ToByte()63 constexpr std::byte ToByte() {
64 static_assert(val <= 0xff);
65 return static_cast<std::byte>(val);
66 }
67
TEST(Codegen,Codegen)68 TEST(Codegen, Codegen) {
69 // The encoded size constants don't account for variable length values, so
70 // add some additional space for the expected sizes of values we intend to
71 // encode.
72 constexpr size_t kPigweedMaxValuesSize = 64;
73 constexpr size_t kDeviceInfoMaxValuesSize = 32;
74
75 std::byte encode_buffer[Pigweed::kMaxEncodedSizeBytesWithoutValues +
76 kPigweedMaxValuesSize +
77 DeviceInfo::kMaxEncodedSizeBytesWithoutValues +
78 kDeviceInfoMaxValuesSize];
79 std::byte temp_buffer[Pigweed::kScratchBufferSizeBytes +
80 kPigweedMaxValuesSize +
81 DeviceInfo::kMaxEncodedSizeBytesWithoutValues +
82 kDeviceInfoMaxValuesSize];
83 stream::MemoryWriter writer(encode_buffer);
84
85 Pigweed::StreamEncoder pigweed(writer, temp_buffer);
86 ASSERT_EQ(OkStatus(), pigweed.WriteMagicNumber(73));
87 ASSERT_EQ(OkStatus(), pigweed.WriteZiggy(-111));
88 ASSERT_EQ(OkStatus(), pigweed.WriteErrorMessage("not a typewriter"));
89 ASSERT_EQ(OkStatus(), pigweed.WriteBin(Pigweed::Protobuf::Binary::ZERO));
90
91 {
92 Pigweed::Pigweed::StreamEncoder pigweed_pigweed =
93 pigweed.GetPigweedEncoder();
94 ASSERT_EQ(OkStatus(), pigweed_pigweed.WriteStatus(Bool::FILE_NOT_FOUND));
95
96 ASSERT_EQ(pigweed_pigweed.status(), OkStatus());
97 }
98
99 {
100 Proto::StreamEncoder proto = pigweed.GetProtoEncoder();
101 ASSERT_EQ(OkStatus(), proto.WriteBin(Proto::Binary::OFF));
102 ASSERT_EQ(OkStatus(),
103 proto.WritePigweedPigweedBin(Pigweed::Pigweed::Binary::ZERO));
104 ASSERT_EQ(OkStatus(),
105 proto.WritePigweedProtobufBin(Pigweed::Protobuf::Binary::ZERO));
106
107 {
108 Pigweed::Protobuf::Compiler::StreamEncoder meta = proto.GetMetaEncoder();
109 ASSERT_EQ(OkStatus(), meta.WriteFileName("/etc/passwd"));
110 ASSERT_EQ(OkStatus(),
111 meta.WriteStatus(Pigweed::Protobuf::Compiler::Status::FUBAR));
112 }
113
114 {
115 Pigweed::StreamEncoder nested_pigweed = proto.GetPigweedEncoder();
116 ASSERT_EQ(OkStatus(),
117 nested_pigweed.WriteErrorMessage("here we go again"));
118 ASSERT_EQ(OkStatus(), nested_pigweed.WriteMagicNumber(616));
119
120 {
121 DeviceInfo::StreamEncoder device_info =
122 nested_pigweed.GetDeviceInfoEncoder();
123
124 {
125 KeyValuePair::StreamEncoder attributes =
126 device_info.GetAttributesEncoder();
127 ASSERT_EQ(OkStatus(), attributes.WriteKey("version"));
128 ASSERT_EQ(OkStatus(), attributes.WriteValue("5.3.1"));
129 }
130
131 {
132 KeyValuePair::StreamEncoder attributes =
133 device_info.GetAttributesEncoder();
134 ASSERT_EQ(OkStatus(), attributes.WriteKey("chip"));
135 ASSERT_EQ(OkStatus(), attributes.WriteValue("left-soc"));
136 }
137
138 ASSERT_EQ(OkStatus(),
139 device_info.WriteStatus(DeviceInfo::DeviceStatus::PANIC));
140 }
141 }
142 }
143
144 for (unsigned i = 0; i < 5; ++i) {
145 Proto::ID::StreamEncoder id = pigweed.GetIdEncoder();
146 ASSERT_EQ(OkStatus(), id.WriteId(5 * i * i + 3 * i + 49));
147 }
148
149 // clang-format off
150 constexpr uint8_t expected_proto[] = {
151 // pigweed.magic_number
152 0x08, 0x49,
153 // pigweed.ziggy
154 0x10, 0xdd, 0x01,
155 // pigweed.error_message
156 0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
157 't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
158 // pigweed.bin
159 0x40, 0x01,
160 // pigweed.pigweed
161 0x3a, 0x02,
162 // pigweed.pigweed.status
163 0x08, 0x02,
164 // pigweed.proto
165 0x4a, 0x56,
166 // pigweed.proto.bin
167 0x10, 0x00,
168 // pigweed.proto.pigweed_pigweed_bin
169 0x18, 0x00,
170 // pigweed.proto.pigweed_protobuf_bin
171 0x20, 0x01,
172 // pigweed.proto.meta
173 0x2a, 0x0f,
174 // pigweed.proto.meta.file_name
175 0x0a, 0x0b, '/', 'e', 't', 'c', '/', 'p', 'a', 's', 's', 'w', 'd',
176 // pigweed.proto.meta.status
177 0x10, 0x02,
178 // pigweed.proto.nested_pigweed
179 0x0a, 0x3d,
180 // pigweed.proto.nested_pigweed.error_message
181 0x2a, 0x10, 'h', 'e', 'r', 'e', ' ', 'w', 'e', ' ',
182 'g', 'o', ' ', 'a', 'g', 'a', 'i', 'n',
183 // pigweed.proto.nested_pigweed.magic_number
184 0x08, 0xe8, 0x04,
185 // pigweed.proto.nested_pigweed.device_info
186 0x32, 0x26,
187 // pigweed.proto.nested_pigweed.device_info.attributes[0]
188 0x22, 0x10,
189 // pigweed.proto.nested_pigweed.device_info.attributes[0].key
190 0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
191 // pigweed.proto.nested_pigweed.device_info.attributes[0].value
192 0x12, 0x05, '5', '.', '3', '.', '1',
193 // pigweed.proto.nested_pigweed.device_info.attributes[1]
194 0x22, 0x10,
195 // pigweed.proto.nested_pigweed.device_info.attributes[1].key
196 0x0a, 0x04, 'c', 'h', 'i', 'p',
197 // pigweed.proto.nested_pigweed.device_info.attributes[1].value
198 0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
199 // pigweed.proto.nested_pigweed.device_info.status
200 0x18, 0x03,
201 // pigweed.id[0]
202 0x52, 0x02,
203 // pigweed.id[0].id
204 0x08, 0x31,
205 // pigweed.id[1]
206 0x52, 0x02,
207 // pigweed.id[1].id
208 0x08, 0x39,
209 // pigweed.id[2]
210 0x52, 0x02,
211 // pigweed.id[2].id
212 0x08, 0x4b,
213 // pigweed.id[3]
214 0x52, 0x02,
215 // pigweed.id[3].id
216 0x08, 0x67,
217 // pigweed.id[4]
218 0x52, 0x03,
219 // pigweed.id[4].id
220 0x08, 0x8d, 0x01
221 };
222 // clang-format on
223
224 ConstByteSpan result = writer.WrittenData();
225 ASSERT_EQ(pigweed.status(), OkStatus());
226 EXPECT_EQ(result.size(), sizeof(expected_proto));
227 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
228 0);
229 }
230
TEST(Codegen,RecursiveSubmessage)231 TEST(Codegen, RecursiveSubmessage) {
232 // 12 here represents the longest name. Note that all field structure is taken
233 // care of, we just have to multiply by how many crates we're encoding, ie. 4.
234 std::byte encode_buffer[(Crate::kMaxEncodedSizeBytesWithoutValues + 12) * 4];
235
236 Crate::MemoryEncoder biggest_crate(encode_buffer);
237 ASSERT_EQ(OkStatus(), biggest_crate.WriteName("Huge crate"));
238
239 {
240 Crate::StreamEncoder medium_crate = biggest_crate.GetSmallerCratesEncoder();
241 ASSERT_EQ(OkStatus(), medium_crate.WriteName("Medium crate"));
242 {
243 Crate::StreamEncoder small_crate = medium_crate.GetSmallerCratesEncoder();
244 ASSERT_EQ(OkStatus(), small_crate.WriteName("Small crate"));
245 }
246 {
247 Crate::StreamEncoder tiny_crate = medium_crate.GetSmallerCratesEncoder();
248 ASSERT_EQ(OkStatus(), tiny_crate.WriteName("Tiny crate"));
249 }
250 }
251
252 // clang-format off
253 constexpr uint8_t expected_proto[] = {
254 // crate.name
255 0x0a, 0x0a, 'H', 'u', 'g', 'e', ' ', 'c', 'r', 'a', 't', 'e',
256 // crate.smaller_crate[0]
257 0x12, 0x2b,
258 // crate.smaller_crate[0].name
259 0x0a, 0x0c, 'M', 'e', 'd', 'i', 'u', 'm', ' ', 'c', 'r', 'a', 't', 'e',
260 // crate.smaller_crate[0].smaller_crate[0]
261 0x12, 0x0d,
262 // crate.smaller_crate[0].smaller_crate[0].name
263 0x0a, 0x0b, 'S', 'm', 'a', 'l', 'l', ' ', 'c', 'r', 'a', 't', 'e',
264 // crate.smaller_crate[0].smaller_crate[1]
265 0x12, 0x0c,
266 // crate.smaller_crate[0].smaller_crate[1].name
267 0x0a, 0x0a, 'T', 'i', 'n', 'y', ' ', 'c', 'r', 'a', 't', 'e',
268 };
269 // clang-format on
270
271 ConstByteSpan result(biggest_crate);
272 ASSERT_EQ(biggest_crate.status(), OkStatus());
273 EXPECT_EQ(result.size(), sizeof(expected_proto));
274 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
275 0);
276 }
277
TEST(CodegenRepeated,ConstrainedFull)278 TEST(CodegenRepeated, ConstrainedFull) {
279 // Write and expect non-packed since that's the worst-case size.
280
281 // clang-format off
282 constexpr auto expected_proto = bytes::Array<
283 // uint32s[], v={0xdeadbeef, 0x2b84f00d}
284 ToByte<FieldKey(1, WireType::kFixed32)>(), 0xef, 0xbe, 0xad, 0xde,
285 ToByte<FieldKey(1, WireType::kFixed32)>(), 0x0d, 0xf0, 0x84, 0x2b
286 >();
287 // clang-format on
288
289 std::byte encode_buffer[ConstrainedRepeatedTest::kMaxEncodedSizeBytes];
290
291 // In this test, we expect to exactly utilize the encoding buffer.
292 EXPECT_EQ(ConstrainedRepeatedTest::kMaxEncodedSizeBytes,
293 expected_proto.size());
294
295 stream::MemoryWriter writer(encode_buffer);
296 ConstrainedRepeatedTest::StreamEncoder encoder(writer, ByteSpan());
297
298 PW_TEST_ASSERT_OK(encoder.WriteFixed32s(0xdeadbeef));
299 PW_TEST_ASSERT_OK(encoder.WriteFixed32s(0x2b84f00d));
300
301 PW_TEST_ASSERT_OK(encoder.status());
302 EXPECT_SEQ_EQ(writer.WrittenData(), expected_proto);
303 }
304
TEST(CodegenRepeated,NonPackedScalar)305 TEST(CodegenRepeated, NonPackedScalar) {
306 std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytesWithoutValues + 32];
307
308 stream::MemoryWriter writer(encode_buffer);
309 RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
310 for (uint32_t i = 0; i < 4; ++i) {
311 ASSERT_EQ(OkStatus(), repeated_test.WriteUint32s(i * 16));
312 }
313
314 for (uint32_t i = 0; i < 4; ++i) {
315 ASSERT_EQ(OkStatus(), repeated_test.WriteFixed32s(i * 16));
316 }
317
318 // clang-format off
319 constexpr uint8_t expected_proto[] = {
320 // uint32s[], v={0, 16, 32, 48}
321 0x08, 0x00,
322 0x08, 0x10,
323 0x08, 0x20,
324 0x08, 0x30,
325 // fixed32s[]. v={0, 16, 32, 48}
326 0x35, 0x00, 0x00, 0x00, 0x00,
327 0x35, 0x10, 0x00, 0x00, 0x00,
328 0x35, 0x20, 0x00, 0x00, 0x00,
329 0x35, 0x30, 0x00, 0x00, 0x00,
330 };
331 // clang-format on
332
333 ConstByteSpan result = writer.WrittenData();
334 ASSERT_EQ(repeated_test.status(), OkStatus());
335 EXPECT_EQ(result.size(), sizeof(expected_proto));
336 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
337 0);
338 }
339
TEST(CodegenRepeated,PackedScalar)340 TEST(CodegenRepeated, PackedScalar) {
341 std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytesWithoutValues + 32];
342
343 stream::MemoryWriter writer(encode_buffer);
344 RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
345 constexpr uint32_t values[] = {0, 16, 32, 48};
346 ASSERT_EQ(OkStatus(), repeated_test.WriteUint32s(values));
347 ASSERT_EQ(OkStatus(), repeated_test.WriteFixed32s(values));
348
349 // clang-format off
350 constexpr uint8_t expected_proto[] = {
351 // uint32s[], v={0, 16, 32, 48}
352 0x0a, 0x04,
353 0x00,
354 0x10,
355 0x20,
356 0x30,
357 // fixed32s[]. v={0, 16, 32, 48}
358 0x32, 0x10,
359 0x00, 0x00, 0x00, 0x00,
360 0x10, 0x00, 0x00, 0x00,
361 0x20, 0x00, 0x00, 0x00,
362 0x30, 0x00, 0x00, 0x00,
363 };
364 // clang-format on
365
366 ConstByteSpan result = writer.WrittenData();
367 ASSERT_EQ(repeated_test.status(), OkStatus());
368 EXPECT_EQ(result.size(), sizeof(expected_proto));
369 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
370 0);
371 }
372
TEST(CodegenRepeated,PackedBool)373 TEST(CodegenRepeated, PackedBool) {
374 std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytesWithoutValues + 8];
375
376 stream::MemoryWriter writer(encode_buffer);
377 RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
378 constexpr bool values[] = {true, false, true, true, false};
379 ASSERT_EQ(OkStatus(), repeated_test.WriteBools(span(values)));
380
381 // clang-format off
382 constexpr uint8_t expected_proto[] = {
383 // bools[], v={true, false, true, true, false}
384 0x3a, 0x05, 0x01, 0x00, 0x01, 0x01, 0x00,
385 };
386 // clang-format on
387
388 ConstByteSpan result = writer.WrittenData();
389 ASSERT_EQ(repeated_test.status(), OkStatus());
390 EXPECT_EQ(result.size(), sizeof(expected_proto));
391 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
392 0);
393 }
394
TEST(CodegenRepeated,PackedScalarVector)395 TEST(CodegenRepeated, PackedScalarVector) {
396 std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytesWithoutValues + 32];
397
398 stream::MemoryWriter writer(encode_buffer);
399 RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
400 const pw::Vector<uint32_t, 4> values = {0, 16, 32, 48};
401 ASSERT_EQ(OkStatus(), repeated_test.WriteUint32s(values));
402 ASSERT_EQ(OkStatus(), repeated_test.WriteFixed32s(values));
403
404 // clang-format off
405 constexpr uint8_t expected_proto[] = {
406 // uint32s[], v={0, 16, 32, 48}
407 0x0a, 0x04,
408 0x00,
409 0x10,
410 0x20,
411 0x30,
412 // fixed32s[]. v={0, 16, 32, 48}
413 0x32, 0x10,
414 0x00, 0x00, 0x00, 0x00,
415 0x10, 0x00, 0x00, 0x00,
416 0x20, 0x00, 0x00, 0x00,
417 0x30, 0x00, 0x00, 0x00,
418 };
419 // clang-format on
420
421 ConstByteSpan result = writer.WrittenData();
422 ASSERT_EQ(repeated_test.status(), OkStatus());
423 EXPECT_EQ(result.size(), sizeof(expected_proto));
424 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
425 0);
426 }
427
TEST(CodegenRepeated,PackedEnum)428 TEST(CodegenRepeated, PackedEnum) {
429 std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytesWithoutValues + 8];
430
431 stream::MemoryWriter writer(encode_buffer);
432 RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
433 constexpr Enum values[] = {Enum::RED, Enum::GREEN, Enum::AMBER, Enum::RED};
434 ASSERT_EQ(repeated_test.WriteEnums(span(values)), OkStatus());
435
436 // clang-format off
437 constexpr uint8_t expected_proto[] = {
438 // enums[], v={RED, GREEN, AMBER, RED}
439 0x4a, 0x04, 0x00, 0x02, 0x01, 0x00
440 };
441 // clang-format on
442
443 ConstByteSpan result = writer.WrittenData();
444 ASSERT_EQ(repeated_test.status(), OkStatus());
445 EXPECT_EQ(result.size(), sizeof(expected_proto));
446 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
447 0);
448 }
449
TEST(CodegenRepeated,PackedEnumVector)450 TEST(CodegenRepeated, PackedEnumVector) {
451 std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytesWithoutValues + 8];
452
453 stream::MemoryWriter writer(encode_buffer);
454 RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
455 const pw::Vector<Enum, 4> values = {
456 Enum::RED, Enum::GREEN, Enum::AMBER, Enum::RED};
457 ASSERT_EQ(repeated_test.WriteEnums(values), OkStatus());
458
459 // clang-format off
460 constexpr uint8_t expected_proto[] = {
461 // enums[], v={RED, GREEN, AMBER, RED}
462 0x4a, 0x04, 0x00, 0x02, 0x01, 0x00
463 };
464 // clang-format on
465
466 ConstByteSpan result = writer.WrittenData();
467 ASSERT_EQ(repeated_test.status(), OkStatus());
468 EXPECT_EQ(result.size(), sizeof(expected_proto));
469 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
470 0);
471 }
472
TEST(CodegenRepeated,NonScalar)473 TEST(CodegenRepeated, NonScalar) {
474 std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytesWithoutValues + 32];
475
476 stream::MemoryWriter writer(encode_buffer);
477 RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
478 constexpr const char* strings[] = {"the", "quick", "brown", "fox"};
479 for (const char* s : strings) {
480 ASSERT_EQ(OkStatus(), repeated_test.WriteStrings(s));
481 }
482
483 constexpr uint8_t expected_proto[] = {
484 0x1a, 0x03, 't', 'h', 'e', 0x1a, 0x5, 'q', 'u', 'i', 'c', 'k',
485 0x1a, 0x5, 'b', 'r', 'o', 'w', 'n', 0x1a, 0x3, 'f', 'o', 'x'};
486 ConstByteSpan result = writer.WrittenData();
487 ASSERT_EQ(repeated_test.status(), OkStatus());
488 EXPECT_EQ(result.size(), sizeof(expected_proto));
489 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
490 0);
491 }
492
TEST(CodegenRepeated,Message)493 TEST(CodegenRepeated, Message) {
494 constexpr size_t kNumStructs = 3;
495
496 std::byte
497 encode_buffer[RepeatedTest::kMaxEncodedSizeBytesWithoutValues +
498 kNumStructs * test::pwpb::Struct::kMaxEncodedSizeBytes];
499
500 RepeatedTest::MemoryEncoder repeated_test(encode_buffer);
501 for (uint32_t i = 0; i < kNumStructs; ++i) {
502 auto structs = repeated_test.GetStructsEncoder();
503 ASSERT_EQ(OkStatus(), structs.WriteOne(i * 1));
504 ASSERT_EQ(OkStatus(), structs.WriteTwo(i * 2));
505 }
506
507 // clang-format off
508 constexpr uint8_t expected_proto[] = {
509 0x2a, 0x04, 0x08, 0x00, 0x10, 0x00, 0x2a, 0x04, 0x08,
510 0x01, 0x10, 0x02, 0x2a, 0x04, 0x08, 0x02, 0x10, 0x04};
511 // clang-format on
512
513 ConstByteSpan result(repeated_test);
514 ASSERT_EQ(repeated_test.status(), OkStatus());
515 EXPECT_EQ(result.size(), sizeof(expected_proto));
516 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
517 0);
518 }
519
TEST(Codegen,Proto2)520 TEST(Codegen, Proto2) {
521 std::byte encode_buffer[Foo::kMaxEncodedSizeBytesWithoutValues + 8];
522
523 Foo::MemoryEncoder foo(encode_buffer);
524 ASSERT_EQ(OkStatus(), foo.WriteInteger(3));
525
526 {
527 constexpr std::byte data[] = {
528 std::byte(0xde), std::byte(0xad), std::byte(0xbe), std::byte(0xef)};
529 Bar::StreamEncoder bar = foo.GetBarEncoder();
530 ASSERT_EQ(OkStatus(), bar.WriteData(data));
531 }
532
533 constexpr uint8_t expected_proto[] = {
534 0x08, 0x03, 0x1a, 0x06, 0x0a, 0x04, 0xde, 0xad, 0xbe, 0xef};
535
536 ConstByteSpan result(foo);
537 ASSERT_EQ(foo.status(), OkStatus());
538 EXPECT_EQ(result.size(), sizeof(expected_proto));
539 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
540 0);
541 }
542
TEST(Codegen,Import)543 TEST(Codegen, Import) {
544 std::byte encode_buffer[Period::kMaxEncodedSizeBytes];
545
546 Period::MemoryEncoder period(encode_buffer);
547 {
548 imported::Timestamp::StreamEncoder start = period.GetStartEncoder();
549 ASSERT_EQ(OkStatus(), start.WriteSeconds(1589501793));
550 ASSERT_EQ(OkStatus(), start.WriteNanoseconds(511613110));
551 }
552
553 {
554 imported::Timestamp::StreamEncoder end = period.GetEndEncoder();
555 ASSERT_EQ(OkStatus(), end.WriteSeconds(1589501841));
556 ASSERT_EQ(OkStatus(), end.WriteNanoseconds(490367432));
557 }
558
559 EXPECT_EQ(period.status(), OkStatus());
560 }
561
TEST(Codegen,NonPigweedPackage)562 TEST(Codegen, NonPigweedPackage) {
563 namespace Packed = ::non::pigweed::package::name::pwpb::Packed;
564
565 std::byte encode_buffer[Packed::kMaxEncodedSizeBytesWithoutValues + 8];
566 std::array<const int64_t, 2> repeated = {0, 1};
567 stream::MemoryWriter writer(encode_buffer);
568 Packed::StreamEncoder packed(writer, ByteSpan());
569 ASSERT_EQ(OkStatus(), packed.WriteRep(span<const int64_t>(repeated)));
570 ASSERT_EQ(OkStatus(), packed.WritePacked("packed"));
571
572 EXPECT_EQ(packed.status(), OkStatus());
573 }
574
TEST(Codegen,MemoryToStreamConversion)575 TEST(Codegen, MemoryToStreamConversion) {
576 std::byte encode_buffer[IntegerMetadata::kMaxEncodedSizeBytes];
577 IntegerMetadata::MemoryEncoder metadata(encode_buffer);
578 IntegerMetadata::StreamEncoder& streamed_metadata = metadata;
579 EXPECT_EQ(streamed_metadata.WriteBits(3), OkStatus());
580
581 constexpr uint8_t expected_proto[] = {0x08, 0x03};
582
583 ConstByteSpan result(metadata);
584 ASSERT_EQ(metadata.status(), OkStatus());
585 EXPECT_EQ(result.size(), sizeof(expected_proto));
586 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
587 0);
588 }
589
TEST(Codegen,OverlayConversion)590 TEST(Codegen, OverlayConversion) {
591 std::byte encode_buffer[BaseMessage::kMaxEncodedSizeBytes +
592 Overlay::kMaxEncodedSizeBytes];
593 BaseMessage::MemoryEncoder base(encode_buffer);
594 Overlay::StreamEncoder& overlay =
595 StreamEncoderCast<Overlay::StreamEncoder>(base);
596 EXPECT_EQ(overlay.WriteHeight(15), OkStatus());
597 EXPECT_EQ(base.WriteLength(7), OkStatus());
598
599 constexpr uint8_t expected_proto[] = {0x10, 0x0f, 0x08, 0x07};
600
601 ConstByteSpan result(base);
602 ASSERT_EQ(base.status(), OkStatus());
603 EXPECT_EQ(result.size(), sizeof(expected_proto));
604 EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
605 0);
606 }
607
TEST(Codegen,EnumToString)608 TEST(Codegen, EnumToString) {
609 EXPECT_STREQ(test::pwpb::BoolToString(test::pwpb::Bool::kTrue), "TRUE");
610 EXPECT_STREQ(test::pwpb::BoolToString(test::pwpb::Bool::kFalse), "FALSE");
611 EXPECT_STREQ(test::pwpb::BoolToString(test::pwpb::Bool::kFileNotFound),
612 "FILE_NOT_FOUND");
613 EXPECT_STREQ(test::pwpb::BoolToString(static_cast<test::pwpb::Bool>(12893)),
614 "");
615 }
616
TEST(Codegen,NestedEnumToString)617 TEST(Codegen, NestedEnumToString) {
618 EXPECT_STREQ(test::pwpb::Pigweed::Pigweed::BinaryToString(
619 test::pwpb::Pigweed::Pigweed::Binary::kZero),
620 "ZERO");
621 EXPECT_STREQ(test::pwpb::Pigweed::Pigweed::BinaryToString(
622 test::pwpb::Pigweed::Pigweed::Binary::kOne),
623 "ONE");
624 EXPECT_STREQ(test::pwpb::Pigweed::Pigweed::BinaryToString(
625 static_cast<test::pwpb::Pigweed::Pigweed::Binary>(12893)),
626 "");
627 }
628
629 } // namespace
630 } // namespace pw::protobuf
631