blob: cf8969bb7acbc7162951dbc05c7dd392051406ac [file] [log] [blame]
Alexei Frolove19ebb82020-05-14 17:21:20 -07001// Copyright 2020 The Pigweed Authors
Alexei Frolovbbf164c2019-12-16 12:51:59 -08002//
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 "gtest/gtest.h"
16#include "pw_protobuf/encoder.h"
17
18// These header files contain the code generated by the pw_protobuf plugin.
19// They are re-generated every time the tests are built and are used by the
20// tests to ensure that the interface remains consistent.
21//
22// The purpose of the tests in this file is primarily to verify that the
23// generated C++ interface is valid rather than the correctness of the
24// low-level encoder.
Alexei Frolovf39cd8b2020-04-13 17:59:20 -070025#include "pw_protobuf_protos/test_protos/full_test.pwpb.h"
Alexei Frolove19ebb82020-05-14 17:21:20 -070026#include "pw_protobuf_protos/test_protos/importer.pwpb.h"
Alexei Frolovf39cd8b2020-04-13 17:59:20 -070027#include "pw_protobuf_protos/test_protos/proto2.pwpb.h"
28#include "pw_protobuf_protos/test_protos/repeated.pwpb.h"
Alexei Frolovbbf164c2019-12-16 12:51:59 -080029
30namespace pw::protobuf {
31namespace {
32
33using namespace pw::protobuf::test;
34
35TEST(Codegen, Codegen) {
Alexei Frolov311c6202020-01-06 11:16:20 -080036 std::byte encode_buffer[512];
Alexei Frolovbbf164c2019-12-16 12:51:59 -080037 NestedEncoder<20, 20> encoder(encode_buffer);
38
39 Pigweed::Encoder pigweed(&encoder);
40 pigweed.WriteMagicNumber(73);
41 pigweed.WriteZiggy(-111);
42 pigweed.WriteErrorMessage("not a typewriter");
43 pigweed.WriteBin(Pigweed::Protobuf::Binary::kZero);
44
45 {
46 Pigweed::Pigweed::Encoder pigweed_pigweed = pigweed.GetPigweedEncoder();
47 pigweed_pigweed.WriteStatus(Bool::kFileNotFound);
48 }
49
50 {
51 Proto::Encoder proto = pigweed.GetProtoEncoder();
52 proto.WriteBin(Proto::Binary::kOff);
53 proto.WritePigweedPigweedBin(Pigweed::Pigweed::Binary::kZero);
54 proto.WritePigweedProtobufBin(Pigweed::Protobuf::Binary::kZero);
55
56 {
57 Pigweed::Protobuf::Compiler::Encoder meta = proto.GetMetaEncoder();
58 meta.WriteFileName("/etc/passwd");
59 meta.WriteStatus(Pigweed::Protobuf::Compiler::Status::kFubar);
60 }
61
62 {
63 Pigweed::Encoder nested_pigweed = proto.GetPigweedEncoder();
64 pigweed.WriteErrorMessage("here we go again");
65 pigweed.WriteMagicNumber(616);
66
67 {
68 DeviceInfo::Encoder device_info = nested_pigweed.GetDeviceInfoEncoder();
69
70 {
71 KeyValuePair::Encoder attributes = device_info.GetAttributesEncoder();
72 attributes.WriteKey("version");
73 attributes.WriteValue("5.3.1");
74 }
75
76 {
77 KeyValuePair::Encoder attributes = device_info.GetAttributesEncoder();
78 attributes.WriteKey("chip");
79 attributes.WriteValue("left-soc");
80 }
81
82 device_info.WriteStatus(DeviceInfo::DeviceStatus::kPanic);
83 }
84 }
85 }
86
87 for (int i = 0; i < 5; ++i) {
88 Proto::ID::Encoder id = pigweed.GetIdEncoder();
89 id.WriteId(5 * i * i + 3 * i + 49);
90 }
91
92 // clang-format off
93 constexpr uint8_t expected_proto[] = {
94 // pigweed.magic_number
95 0x08, 0x49,
96 // pigweed.ziggy
97 0x10, 0xdd, 0x01,
98 // pigweed.error_message
99 0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
100 't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
101 // pigweed.bin
102 0x40, 0x01,
103 // pigweed.pigweed
104 0x3a, 0x02,
105 // pigweed.pigweed.status
106 0x08, 0x02,
107 // pigweed.proto
108 0x4a, 0x56,
109 // pigweed.proto.bin
110 0x10, 0x00,
111 // pigweed.proto.pigweed_pigweed_bin
112 0x18, 0x00,
113 // pigweed.proto.pigweed_protobuf_bin
114 0x20, 0x01,
115 // pigweed.proto.meta
116 0x2a, 0x0f,
117 // pigweed.proto.meta.file_name
118 0x0a, 0x0b, '/', 'e', 't', 'c', '/', 'p', 'a', 's', 's', 'w', 'd',
119 // pigweed.proto.meta.status
120 0x10, 0x02,
121 // pigweed.proto.nested_pigweed
122 0x0a, 0x3d,
123 // pigweed.proto.nested_pigweed.error_message
124 0x2a, 0x10, 'h', 'e', 'r', 'e', ' ', 'w', 'e', ' ',
125 'g', 'o', ' ', 'a', 'g', 'a', 'i', 'n',
126 // pigweed.proto.nested_pigweed.magic_number
127 0x08, 0xe8, 0x04,
128 // pigweed.proto.nested_pigweed.device_info
129 0x32, 0x26,
130 // pigweed.proto.nested_pigweed.device_info.attributes[0]
131 0x22, 0x10,
132 // pigweed.proto.nested_pigweed.device_info.attributes[0].key
133 0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
134 // pigweed.proto.nested_pigweed.device_info.attributes[0].value
135 0x12, 0x05, '5', '.', '3', '.', '1',
136 // pigweed.proto.nested_pigweed.device_info.attributes[1]
137 0x22, 0x10,
138 // pigweed.proto.nested_pigweed.device_info.attributes[1].key
139 0x0a, 0x04, 'c', 'h', 'i', 'p',
140 // pigweed.proto.nested_pigweed.device_info.attributes[1].value
141 0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
142 // pigweed.proto.nested_pigweed.device_info.status
143 0x18, 0x03,
144 // pigweed.id[0]
145 0x52, 0x02,
146 // pigweed.id[0].id
147 0x08, 0x31,
148 // pigweed.id[1]
149 0x52, 0x02,
150 // pigweed.id[1].id
151 0x08, 0x39,
152 // pigweed.id[2]
153 0x52, 0x02,
154 // pigweed.id[2].id
155 0x08, 0x4b,
156 // pigweed.id[3]
157 0x52, 0x02,
158 // pigweed.id[3].id
159 0x08, 0x67,
160 // pigweed.id[4]
161 0x52, 0x03,
162 // pigweed.id[4].id
163 0x08, 0x8d, 0x01
164 };
165 // clang-format on
166
Alexei Frolov311c6202020-01-06 11:16:20 -0800167 span<const std::byte> proto;
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800168 EXPECT_EQ(encoder.Encode(&proto), Status::OK);
169 EXPECT_EQ(proto.size(), sizeof(expected_proto));
170 EXPECT_EQ(std::memcmp(proto.data(), expected_proto, sizeof(expected_proto)),
171 0);
172}
173
174TEST(CodegenRepeated, NonPackedScalar) {
Alexei Frolov311c6202020-01-06 11:16:20 -0800175 std::byte encode_buffer[32];
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800176 NestedEncoder encoder(encode_buffer);
177
178 RepeatedTest::Encoder repeated_test(&encoder);
179 for (int i = 0; i < 4; ++i) {
180 repeated_test.WriteUint32s(i * 16);
181 }
182
183 constexpr uint8_t expected_proto[] = {
184 0x08, 0x00, 0x08, 0x10, 0x08, 0x20, 0x08, 0x30};
185
Alexei Frolov311c6202020-01-06 11:16:20 -0800186 span<const std::byte> proto;
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800187 EXPECT_EQ(encoder.Encode(&proto), Status::OK);
188 EXPECT_EQ(proto.size(), sizeof(expected_proto));
189 EXPECT_EQ(std::memcmp(proto.data(), expected_proto, sizeof(expected_proto)),
190 0);
191}
192
193TEST(CodegenRepeated, PackedScalar) {
Alexei Frolov311c6202020-01-06 11:16:20 -0800194 std::byte encode_buffer[32];
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800195 NestedEncoder encoder(encode_buffer);
196
197 RepeatedTest::Encoder repeated_test(&encoder);
198 constexpr uint32_t values[] = {0, 16, 32, 48};
199 repeated_test.WriteUint32s(values);
200
201 constexpr uint8_t expected_proto[] = {0x0a, 0x04, 0x00, 0x10, 0x20, 0x30};
Alexei Frolov311c6202020-01-06 11:16:20 -0800202 span<const std::byte> proto;
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800203 EXPECT_EQ(encoder.Encode(&proto), Status::OK);
204 EXPECT_EQ(proto.size(), sizeof(expected_proto));
205 EXPECT_EQ(std::memcmp(proto.data(), expected_proto, sizeof(expected_proto)),
206 0);
207}
208
209TEST(CodegenRepeated, NonScalar) {
Alexei Frolov311c6202020-01-06 11:16:20 -0800210 std::byte encode_buffer[32];
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800211 NestedEncoder encoder(encode_buffer);
212
213 RepeatedTest::Encoder repeated_test(&encoder);
214 constexpr const char* strings[] = {"the", "quick", "brown", "fox"};
215 for (const char* s : strings) {
216 repeated_test.WriteStrings(s);
217 }
218
219 constexpr uint8_t expected_proto[] = {
220 0x1a, 0x03, 't', 'h', 'e', 0x1a, 0x5, 'q', 'u', 'i', 'c', 'k',
221 0x1a, 0x5, 'b', 'r', 'o', 'w', 'n', 0x1a, 0x3, 'f', 'o', 'x'};
Alexei Frolov311c6202020-01-06 11:16:20 -0800222 span<const std::byte> proto;
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800223 EXPECT_EQ(encoder.Encode(&proto), Status::OK);
224 EXPECT_EQ(proto.size(), sizeof(expected_proto));
225 EXPECT_EQ(std::memcmp(proto.data(), expected_proto, sizeof(expected_proto)),
226 0);
227}
228
229TEST(CodegenRepeated, Message) {
Alexei Frolov311c6202020-01-06 11:16:20 -0800230 std::byte encode_buffer[64];
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800231 NestedEncoder<1, 3> encoder(encode_buffer);
232
233 RepeatedTest::Encoder repeated_test(&encoder);
234 for (int i = 0; i < 3; ++i) {
235 auto structs = repeated_test.GetStructsEncoder();
236 structs.WriteOne(i * 1);
237 structs.WriteTwo(i * 2);
238 }
239
240 // clang-format off
241 constexpr uint8_t expected_proto[] = {
242 0x2a, 0x04, 0x08, 0x00, 0x10, 0x00, 0x2a, 0x04, 0x08,
243 0x01, 0x10, 0x02, 0x2a, 0x04, 0x08, 0x02, 0x10, 0x04};
244 // clang-format on
245
Alexei Frolov311c6202020-01-06 11:16:20 -0800246 span<const std::byte> proto;
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800247 EXPECT_EQ(encoder.Encode(&proto), Status::OK);
248 EXPECT_EQ(proto.size(), sizeof(expected_proto));
249 EXPECT_EQ(std::memcmp(proto.data(), expected_proto, sizeof(expected_proto)),
250 0);
251}
252
253TEST(Codegen, Proto2) {
Alexei Frolov311c6202020-01-06 11:16:20 -0800254 std::byte encode_buffer[64];
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800255 NestedEncoder<1, 3> encoder(encode_buffer);
256
257 Foo::Encoder foo(&encoder);
258 foo.WriteInt(3);
259
260 {
261 constexpr std::byte data[] = {
262 std::byte(0xde), std::byte(0xad), std::byte(0xbe), std::byte(0xef)};
263 Bar::Encoder bar = foo.GetBarEncoder();
264 bar.WriteData(data);
265 }
266
267 constexpr uint8_t expected_proto[] = {
268 0x08, 0x03, 0x1a, 0x06, 0x0a, 0x04, 0xde, 0xad, 0xbe, 0xef};
269
Alexei Frolov311c6202020-01-06 11:16:20 -0800270 span<const std::byte> proto;
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800271 EXPECT_EQ(encoder.Encode(&proto), Status::OK);
272 EXPECT_EQ(proto.size(), sizeof(expected_proto));
273 EXPECT_EQ(std::memcmp(proto.data(), expected_proto, sizeof(expected_proto)),
274 0);
275}
276
Alexei Frolove19ebb82020-05-14 17:21:20 -0700277TEST(Codegen, Import) {
278 std::byte encode_buffer[64];
279 NestedEncoder<1, 3> encoder(encode_buffer);
280
281 Period::Encoder period(&encoder);
282 {
283 imported::Timestamp::Encoder start = period.GetStartEncoder();
284 start.WriteSeconds(1589501793);
285 start.WriteNanoseconds(511613110);
286 }
287
288 {
289 imported::Timestamp::Encoder end = period.GetEndEncoder();
290 end.WriteSeconds(1589501841);
291 end.WriteNanoseconds(490367432);
292 }
293
294 span<const std::byte> proto;
295 EXPECT_EQ(encoder.Encode(&proto), Status::OK);
296}
297
Alexei Frolovbbf164c2019-12-16 12:51:59 -0800298} // namespace
299} // namespace pw::protobuf