• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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