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