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