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