Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_protobuf / encoder_test.cc
1 // Copyright 2019 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_protobuf/encoder.h"
16
17 #include "gtest/gtest.h"
18
19 namespace pw::protobuf {
20 namespace {
21
22 // The tests in this file use the following proto message schemas.
23 //
24 //   message TestProto {
25 //     uint32 magic_number = 1;
26 //     sint32 ziggy = 2;
27 //     fixed64 cycles = 3;
28 //     float ratio = 4;
29 //     string error_message = 5;
30 //     NestedProto nested = 6;
31 //   }
32 //
33 //   message NestedProto {
34 //     string hello = 1;
35 //     uint32 id = 2;
36 //     repeated DoubleNestedProto pair = 3;
37 //   }
38 //
39 //   message DoubleNestedProto {
40 //     string key = 1;
41 //     string value = 2;
42 //   }
43 //
44
45 constexpr uint32_t kTestProtoMagicNumberField = 1;
46 constexpr uint32_t kTestProtoZiggyField = 2;
47 constexpr uint32_t kTestProtoCyclesField = 3;
48 constexpr uint32_t kTestProtoRatioField = 4;
49 constexpr uint32_t kTestProtoErrorMessageField = 5;
50 constexpr uint32_t kTestProtoNestedField = 6;
51
52 constexpr uint32_t kNestedProtoHelloField = 1;
53 constexpr uint32_t kNestedProtoIdField = 2;
54 constexpr uint32_t kNestedProtoPairField = 3;
55
56 constexpr uint32_t kDoubleNestedProtoKeyField = 1;
57 constexpr uint32_t kDoubleNestedProtoValueField = 2;
58
59 TEST(Encoder, EncodePrimitives) {
60   // TestProto tp;
61   // tp.magic_number = 42;
62   // tp.ziggy = -13;
63   // tp.cycles = 0xdeadbeef8badf00d;
64   // tp.ratio = 1.618034;
65   // tp.error_message = "broken ðŸ’©";
66
67   // Hand-encoded version of the above.
68   // clang-format off
69   constexpr uint8_t encoded_proto[] = {
70     // magic_number [varint k=1]
71     0x08, 0x2a,
72     // ziggy [varint k=2]
73     0x10, 0x19,
74     // cycles [fixed64 k=3]
75     0x19, 0x0d, 0xf0, 0xad, 0x8b, 0xef, 0xbe, 0xad, 0xde,
76     // ratio [fixed32 k=4]
77     0x25, 0xbd, 0x1b, 0xcf, 0x3f,
78     // error_message [delimited k=5],
79     0x2a, 0x0b, 'b', 'r', 'o', 'k', 'e', 'n', ' ',
80     // poop!
81     0xf0, 0x9f, 0x92, 0xa9,
82   };
83   // clang-format on
84
85   std::byte encode_buffer[32];
86   NestedEncoder encoder(encode_buffer);
87
88   EXPECT_EQ(encoder.WriteUint32(kTestProtoMagicNumberField, 42), OkStatus());
89   EXPECT_EQ(encoder.WriteSint32(kTestProtoZiggyField, -13), OkStatus());
90   EXPECT_EQ(encoder.WriteFixed64(kTestProtoCyclesField, 0xdeadbeef8badf00d),
91             OkStatus());
92   EXPECT_EQ(encoder.WriteFloat(kTestProtoRatioField, 1.618034), OkStatus());
93   EXPECT_EQ(encoder.WriteString(kTestProtoErrorMessageField, "broken ðŸ’©"),
94             OkStatus());
95
96   Result result = encoder.Encode();
97   ASSERT_EQ(result.status(), OkStatus());
98   EXPECT_EQ(result.value().size(), sizeof(encoded_proto));
99   EXPECT_EQ(
100       std::memcmp(result.value().data(), encoded_proto, sizeof(encoded_proto)),
101       0);
102 }
103
104 TEST(Encoder, EncodeInsufficientSpace) {
105   std::byte encode_buffer[12];
106   NestedEncoder encoder(encode_buffer);
107
108   // 2 bytes.
109   EXPECT_EQ(encoder.WriteUint32(kTestProtoMagicNumberField, 42), OkStatus());
110   // 2 bytes.
111   EXPECT_EQ(encoder.WriteSint32(kTestProtoZiggyField, -13), OkStatus());
112   // 9 bytes; not enough space! The encoder will start writing the field but
113   // should rollback when it realizes it doesn't have enough space.
114   EXPECT_EQ(encoder.WriteFixed64(kTestProtoCyclesField, 0xdeadbeef8badf00d),
115             Status::ResourceExhausted());
116   // Any further write operations should fail.
117   EXPECT_EQ(encoder.WriteFloat(kTestProtoRatioField, 1.618034),
118             Status::ResourceExhausted());
119
120   ASSERT_EQ(encoder.Encode().status(), Status::ResourceExhausted());
121 }
122
123 TEST(Encoder, EncodeInvalidArguments) {
124   std::byte encode_buffer[12];
125   NestedEncoder encoder(encode_buffer);
126
127   EXPECT_EQ(encoder.WriteUint32(kTestProtoMagicNumberField, 42), OkStatus());
128   // Invalid proto field numbers.
129   EXPECT_EQ(encoder.WriteUint32(0, 1337), Status::InvalidArgument());
130   encoder.Clear();
131
132   EXPECT_EQ(encoder.WriteString(1u << 31, "ha"), Status::InvalidArgument());
133   encoder.Clear();
134
135   EXPECT_EQ(encoder.WriteBool(19091, false), Status::InvalidArgument());
136   ASSERT_EQ(encoder.Encode().status(), Status::InvalidArgument());
137 }
138
139 TEST(Encoder, Nested) {
140   std::byte encode_buffer[128];
141   NestedEncoder<5, 5> encoder(encode_buffer);
142
143   // TestProto test_proto;
144   // test_proto.magic_number = 42;
145   EXPECT_EQ(encoder.WriteUint32(kTestProtoMagicNumberField, 42), OkStatus());
146
147   {
148     // NestedProto& nested_proto = test_proto.nested;
149     EXPECT_EQ(encoder.Push(kTestProtoNestedField), OkStatus());
150     // nested_proto.hello = "world";
151     EXPECT_EQ(encoder.WriteString(kNestedProtoHelloField, "world"), OkStatus());
152     // nested_proto.id = 999;
153     EXPECT_EQ(encoder.WriteUint32(kNestedProtoIdField, 999), OkStatus());
154
155     {
156       // DoubleNestedProto& double_nested_proto = nested_proto.append_pair();
157       EXPECT_EQ(encoder.Push(kNestedProtoPairField), OkStatus());
158       // double_nested_proto.key = "version";
159       EXPECT_EQ(encoder.WriteString(kDoubleNestedProtoKeyField, "version"),
160                 OkStatus());
161       // double_nested_proto.value = "2.9.1";
162       EXPECT_EQ(encoder.WriteString(kDoubleNestedProtoValueField, "2.9.1"),
163                 OkStatus());
164
165       EXPECT_EQ(encoder.Pop(), OkStatus());
166     }  // end DoubleNestedProto
167
168     {
169       // DoubleNestedProto& double_nested_proto = nested_proto.append_pair();
170       EXPECT_EQ(encoder.Push(kNestedProtoPairField), OkStatus());
171       // double_nested_proto.key = "device";
172       EXPECT_EQ(encoder.WriteString(kDoubleNestedProtoKeyField, "device"),
173                 OkStatus());
174       // double_nested_proto.value = "left-soc";
175       EXPECT_EQ(encoder.WriteString(kDoubleNestedProtoValueField, "left-soc"),
176                 OkStatus());
177
178       EXPECT_EQ(encoder.Pop(), OkStatus());
179     }  // end DoubleNestedProto
180
181     EXPECT_EQ(encoder.Pop(), OkStatus());
182   }  // end NestedProto
183
184   // test_proto.ziggy = -13;
185   EXPECT_EQ(encoder.WriteSint32(kTestProtoZiggyField, -13), OkStatus());
186
187   // clang-format off
188   constexpr uint8_t encoded_proto[] = {
189     // magic_number
190     0x08, 0x2a,
191     // nested header (key, size)
192     0x32, 0x30,
193     // nested.hello
194     0x0a, 0x05, 'w', 'o', 'r', 'l', 'd',
195     // nested.id
196     0x10, 0xe7, 0x07,
197     // nested.pair[0] header (key, size)
198     0x1a, 0x10,
199     // nested.pair[0].key
200     0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
201     // nested.pair[0].value
202     0x12, 0x05, '2', '.', '9', '.', '1',
203     // nested.pair[1] header (key, size)
204     0x1a, 0x12,
205     // nested.pair[1].key
206     0x0a, 0x06, 'd', 'e', 'v', 'i', 'c', 'e',
207     // nested.pair[1].value
208     0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
209     // ziggy
210     0x10, 0x19
211   };
212   // clang-format on
213
214   Result result = encoder.Encode();
215   ASSERT_EQ(result.status(), OkStatus());
216   EXPECT_EQ(result.value().size(), sizeof(encoded_proto));
217   EXPECT_EQ(
218       std::memcmp(result.value().data(), encoded_proto, sizeof(encoded_proto)),
219       0);
220 }
221
222 TEST(Encoder, NestedDepthLimit) {
223   std::byte encode_buffer[128];
224   NestedEncoder<2, 2> encoder(encode_buffer);
225
226   // One level of nesting.
227   EXPECT_EQ(encoder.Push(2), OkStatus());
228   // Two levels of nesting.
229   EXPECT_EQ(encoder.Push(1), OkStatus());
230   // Three levels of nesting: error!
231   EXPECT_EQ(encoder.Push(1), Status::ResourceExhausted());
232
233   // Further operations should fail.
234   EXPECT_EQ(encoder.Pop(), Status::ResourceExhausted());
235   EXPECT_EQ(encoder.Pop(), Status::ResourceExhausted());
236   EXPECT_EQ(encoder.Pop(), Status::ResourceExhausted());
237 }
238
239 TEST(Encoder, NestedBlobLimit) {
240   std::byte encode_buffer[128];
241   NestedEncoder<3, 3> encoder(encode_buffer);
242
243   // Write first blob.
244   EXPECT_EQ(encoder.Push(1), OkStatus());
245   EXPECT_EQ(encoder.Pop(), OkStatus());
246
247   // Write second blob.
248   EXPECT_EQ(encoder.Push(2), OkStatus());
249
250   // Write nested third blob.
251   EXPECT_EQ(encoder.Push(3), OkStatus());
252   EXPECT_EQ(encoder.Pop(), OkStatus());
253
254   // End second blob.
255   EXPECT_EQ(encoder.Pop(), OkStatus());
256
257   // Write fourth blob: OK
258   EXPECT_EQ(encoder.Push(4), OkStatus());
259   EXPECT_EQ(encoder.Pop(), OkStatus());
260 }
261
262 TEST(Encoder, RepeatedField) {
263   std::byte encode_buffer[32];
264   NestedEncoder encoder(encode_buffer);
265
266   // repeated uint32 values = 1;
267   constexpr uint32_t values[] = {0, 50, 100, 150, 200};
268   for (int i = 0; i < 5; ++i) {
269     encoder.WriteUint32(1, values[i]);
270   }
271
272   constexpr uint8_t encoded_proto[] = {
273       0x08, 0x00, 0x08, 0x32, 0x08, 0x64, 0x08, 0x96, 0x01, 0x08, 0xc8, 0x01};
274
275   Result result = encoder.Encode();
276   ASSERT_EQ(result.status(), OkStatus());
277   EXPECT_EQ(result.value().size(), sizeof(encoded_proto));
278   EXPECT_EQ(
279       std::memcmp(result.value().data(), encoded_proto, sizeof(encoded_proto)),
280       0);
281 }
282
283 TEST(Encoder, PackedVarint) {
284   std::byte encode_buffer[32];
285   NestedEncoder encoder(encode_buffer);
286
287   // repeated uint32 values = 1;
288   constexpr uint32_t values[] = {0, 50, 100, 150, 200};
289   encoder.WritePackedUint32(1, values);
290
291   constexpr uint8_t encoded_proto[] = {
292       0x0a, 0x07, 0x00, 0x32, 0x64, 0x96, 0x01, 0xc8, 0x01};
293   //  key   size  v[0]  v[1]  v[2]  v[3]        v[4]
294
295   Result result = encoder.Encode();
296   ASSERT_EQ(result.status(), OkStatus());
297   EXPECT_EQ(result.value().size(), sizeof(encoded_proto));
298   EXPECT_EQ(
299       std::memcmp(result.value().data(), encoded_proto, sizeof(encoded_proto)),
300       0);
301 }
302
303 TEST(Encoder, PackedVarintInsufficientSpace) {
304   std::byte encode_buffer[8];
305   NestedEncoder encoder(encode_buffer);
306
307   constexpr uint32_t values[] = {0, 50, 100, 150, 200};
308   encoder.WritePackedUint32(1, values);
309
310   EXPECT_EQ(encoder.Encode().status(), Status::ResourceExhausted());
311 }
312
313 TEST(Encoder, PackedFixed) {
314   std::byte encode_buffer[32];
315   NestedEncoder encoder(encode_buffer);
316
317   // repeated fixed32 values = 1;
318   constexpr uint32_t values[] = {0, 50, 100, 150, 200};
319   encoder.WritePackedFixed32(1, values);
320
321   // repeated fixed64 values64 = 2;
322   constexpr uint64_t values64[] = {0x0102030405060708};
323   encoder.WritePackedFixed64(2, values64);
324
325   constexpr uint8_t encoded_proto[] = {
326       0x0a, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x64,
327       0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00,
328       0x12, 0x08, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
329
330   Result result = encoder.Encode();
331   ASSERT_EQ(result.status(), OkStatus());
332   EXPECT_EQ(result.value().size(), sizeof(encoded_proto));
333   EXPECT_EQ(
334       std::memcmp(result.value().data(), encoded_proto, sizeof(encoded_proto)),
335       0);
336 }
337
338 TEST(Encoder, PackedZigzag) {
339   std::byte encode_buffer[32];
340   NestedEncoder encoder(encode_buffer);
341
342   // repeated sint32 values = 1;
343   constexpr int32_t values[] = {-100, -25, -1, 0, 1, 25, 100};
344   encoder.WritePackedSint32(1, values);
345
346   constexpr uint8_t encoded_proto[] = {
347       0x0a, 0x09, 0xc7, 0x01, 0x31, 0x01, 0x00, 0x02, 0x32, 0xc8, 0x01};
348
349   Result result = encoder.Encode();
350   ASSERT_EQ(result.status(), OkStatus());
351   EXPECT_EQ(result.value().size(), sizeof(encoded_proto));
352   EXPECT_EQ(
353       std::memcmp(result.value().data(), encoded_proto, sizeof(encoded_proto)),
354       0);
355 }
356
357 }  // namespace
358 }  // namespace pw::protobuf