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