1 // Copyright 2021 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 "pw_bytes/span.h"
18 #include "pw_span/span.h"
19 #include "pw_stream/memory_stream.h"
20 #include "pw_unit_test/framework.h"
21
22 namespace pw::protobuf {
23 namespace {
24
25 using stream::MemoryWriter;
26
27 // The tests in this file use the following proto message schemas.
28 //
29 // message TestProto {
30 // uint32 magic_number = 1;
31 // sint32 ziggy = 2;
32 // fixed64 cycles = 3;
33 // float ratio = 4;
34 // string error_message = 5;
35 // NestedProto nested = 6;
36 // }
37 //
38 // message NestedProto {
39 // string hello = 1;
40 // uint32 id = 2;
41 // repeated DoubleNestedProto pair = 3;
42 // }
43 //
44 // message DoubleNestedProto {
45 // string key = 1;
46 // string value = 2;
47 // }
48 //
49
50 constexpr uint32_t kTestProtoMagicNumberField = 1;
51 constexpr uint32_t kTestProtoZiggyField = 2;
52 constexpr uint32_t kTestProtoCyclesField = 3;
53 constexpr uint32_t kTestProtoRatioField = 4;
54 constexpr uint32_t kTestProtoErrorMessageField = 5;
55 constexpr uint32_t kTestProtoNestedField = 6;
56 constexpr uint32_t kTestProtoPayloadFromStreamField = 7;
57
58 constexpr uint32_t kNestedProtoHelloField = 1;
59 constexpr uint32_t kNestedProtoIdField = 2;
60 constexpr uint32_t kNestedProtoPairField = 3;
61
62 constexpr uint32_t kDoubleNestedProtoKeyField = 1;
63 constexpr uint32_t kDoubleNestedProtoValueField = 2;
64
TEST(StreamEncoder,EncodePrimitives)65 TEST(StreamEncoder, EncodePrimitives) {
66 // TestProto tp;
67 // tp.magic_number = 42;
68 // tp.ziggy = -13;
69 // tp.cycles = 0xdeadbeef8badf00d;
70 // tp.ratio = 1.618034;
71 // tp.error_message = "broken ";
72 // tp.payload_from_stream = "byreader"
73
74 // Hand-encoded version of the above.
75 // clang-format off
76 constexpr uint8_t encoded_proto[] = {
77 // magic_number [varint k=1]
78 0x08, 0x2a,
79 // ziggy [varint k=2]
80 0x10, 0x19,
81 // cycles [fixed64 k=3]
82 0x19, 0x0d, 0xf0, 0xad, 0x8b, 0xef, 0xbe, 0xad, 0xde,
83 // ratio [fixed32 k=4]
84 0x25, 0xbd, 0x1b, 0xcf, 0x3f,
85 // error_message [delimited k=5],
86 0x2a, 0x0b, 'b', 'r', 'o', 'k', 'e', 'n', ' ',
87 // poop!
88 0xf0, 0x9f, 0x92, 0xa9,
89 // payload_from_stream [delimited k=7]
90 0x3a, 0x08, 'b', 'y', 'r', 'e', 'a', 'd', 'e', 'r',
91 };
92 // clang-format on
93 std::byte encode_buffer[64];
94 std::byte dest_buffer[64];
95 // This writer isn't necessary, it's just the most testable way to exercise
96 // a stream interface. Use a MemoryEncoder when encoding a proto directly to
97 // an in-memory buffer.
98 MemoryWriter writer(dest_buffer);
99 StreamEncoder encoder(writer, encode_buffer);
100
101 EXPECT_EQ(encoder.WriteUint32(kTestProtoMagicNumberField, 42), OkStatus());
102 EXPECT_EQ(writer.bytes_written(), 2u);
103 EXPECT_EQ(encoder.WriteSint32(kTestProtoZiggyField, -13), OkStatus());
104 EXPECT_EQ(encoder.WriteFixed64(kTestProtoCyclesField, 0xdeadbeef8badf00d),
105 OkStatus());
106 EXPECT_EQ(encoder.WriteFloat(kTestProtoRatioField, 1.618034f), OkStatus());
107 EXPECT_EQ(encoder.WriteString(kTestProtoErrorMessageField, "broken "),
108 OkStatus());
109
110 const std::string_view kReaderMessage = "byreader";
111 stream::MemoryReader msg_reader(as_bytes(span(kReaderMessage)));
112 std::byte stream_pipe_buffer[1];
113 EXPECT_EQ(encoder.WriteStringFromStream(kTestProtoPayloadFromStreamField,
114 msg_reader,
115 kReaderMessage.size(),
116 stream_pipe_buffer),
117 OkStatus());
118
119 ASSERT_EQ(encoder.status(), OkStatus());
120 ConstByteSpan result = writer.WrittenData();
121 EXPECT_EQ(result.size(), sizeof(encoded_proto));
122 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
123 0);
124 }
125
TEST(StreamEncoder,EncodeInsufficientSpace)126 TEST(StreamEncoder, EncodeInsufficientSpace) {
127 std::byte encode_buffer[12];
128 MemoryEncoder encoder(encode_buffer);
129
130 // 2 bytes.
131 EXPECT_EQ(encoder.WriteUint32(kTestProtoMagicNumberField, 42), OkStatus());
132 // 2 bytes.
133 EXPECT_EQ(encoder.WriteSint32(kTestProtoZiggyField, -13), OkStatus());
134 // 9 bytes; not enough space! The encoder will start writing the field but
135 // should rollback when it realizes it doesn't have enough space.
136 EXPECT_EQ(encoder.WriteFixed64(kTestProtoCyclesField, 0xdeadbeef8badf00d),
137 Status::ResourceExhausted());
138 // Any further write operations should fail.
139 EXPECT_EQ(encoder.WriteFloat(kTestProtoRatioField, 1.618034f),
140 Status::ResourceExhausted());
141
142 ASSERT_EQ(encoder.status(), Status::ResourceExhausted());
143 }
144
TEST(StreamEncoder,EncodeInvalidArguments)145 TEST(StreamEncoder, EncodeInvalidArguments) {
146 std::byte encode_buffer[12];
147 MemoryEncoder encoder(encode_buffer);
148
149 EXPECT_EQ(encoder.WriteUint32(kTestProtoMagicNumberField, 42), OkStatus());
150 // Invalid proto field numbers.
151 EXPECT_EQ(encoder.WriteUint32(0, 1337), Status::InvalidArgument());
152
153 // TODO(amontanez): Does it make sense to support this?
154 // encoder.Clear();
155
156 EXPECT_EQ(encoder.WriteString(1u << 31, "ha"), Status::InvalidArgument());
157
158 // TODO(amontanez): Does it make sense to support this?
159 // encoder.Clear();
160
161 EXPECT_EQ(encoder.WriteBool(19091, false), Status::InvalidArgument());
162 ASSERT_EQ(encoder.status(), Status::InvalidArgument());
163 }
164
TEST(StreamEncoder,Nested)165 TEST(StreamEncoder, Nested) {
166 // This is the largest complete submessage in this test.
167 constexpr size_t kLargestSubmessageSize = 0x30;
168 constexpr size_t kScratchBufferSize =
169 MaxScratchBufferSize(kLargestSubmessageSize, 2);
170 std::byte encode_buffer[kScratchBufferSize];
171 std::byte dest_buffer[128];
172 MemoryWriter writer(dest_buffer);
173 StreamEncoder encoder(writer, encode_buffer);
174
175 // TestProto test_proto;
176 // test_proto.magic_number = 42;
177 EXPECT_EQ(encoder.WriteUint32(kTestProtoMagicNumberField, 42), OkStatus());
178
179 {
180 // NestedProto& nested_proto = test_proto.nested;
181 StreamEncoder nested_proto =
182 encoder.GetNestedEncoder(kTestProtoNestedField);
183 // nested_proto.hello = "world";
184 EXPECT_EQ(nested_proto.WriteString(kNestedProtoHelloField, "world"),
185 OkStatus());
186
187 {
188 // DoubleNestedProto& double_nested_proto = nested_proto.append_pair();
189 StreamEncoder double_nested_proto =
190 nested_proto.GetNestedEncoder(kNestedProtoPairField);
191 // double_nested_proto.key = "version";
192 EXPECT_EQ(double_nested_proto.WriteString(kDoubleNestedProtoKeyField,
193 "version"),
194 OkStatus());
195 // double_nested_proto.value = "2.9.1";
196 EXPECT_EQ(double_nested_proto.WriteString(kDoubleNestedProtoValueField,
197 "2.9.1"),
198 OkStatus());
199 } // end DoubleNestedProto
200
201 // nested_proto.id = 999;
202 EXPECT_EQ(nested_proto.WriteUint32(kNestedProtoIdField, 999), OkStatus());
203
204 {
205 // DoubleNestedProto& double_nested_proto = nested_proto.append_pair();
206 StreamEncoder double_nested_proto =
207 nested_proto.GetNestedEncoder(kNestedProtoPairField);
208 // double_nested_proto.key = "device";
209 EXPECT_EQ(
210 double_nested_proto.WriteString(kDoubleNestedProtoKeyField, "device"),
211 OkStatus());
212 // double_nested_proto.value = "left-soc";
213 EXPECT_EQ(double_nested_proto.WriteString(kDoubleNestedProtoValueField,
214 "left-soc"),
215 OkStatus());
216 // Rely on destructor for finalization.
217 } // end DoubleNestedProto
218 } // end NestedProto
219
220 // test_proto.ziggy = -13;
221 EXPECT_EQ(encoder.WriteSint32(kTestProtoZiggyField, -13), OkStatus());
222
223 // clang-format off
224 constexpr uint8_t encoded_proto[] = {
225 // magic_number
226 0x08, 0x2a,
227 // nested header (key, size)
228 0x32, 0x30,
229 // nested.hello
230 0x0a, 0x05, 'w', 'o', 'r', 'l', 'd',
231 // nested.pair[0] header (key, size)
232 0x1a, 0x10,
233 // nested.pair[0].key
234 0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
235 // nested.pair[0].value
236 0x12, 0x05, '2', '.', '9', '.', '1',
237 // nested.id
238 0x10, 0xe7, 0x07,
239 // nested.pair[1] header (key, size)
240 0x1a, 0x12,
241 // nested.pair[1].key
242 0x0a, 0x06, 'd', 'e', 'v', 'i', 'c', 'e',
243 // nested.pair[1].value
244 0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
245 // ziggy
246 0x10, 0x19
247 };
248 // clang-format on
249
250 ASSERT_EQ(encoder.status(), OkStatus());
251 ConstByteSpan result = ConstByteSpan(writer.data(), writer.bytes_written());
252 EXPECT_EQ(result.size(), sizeof(encoded_proto));
253 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
254 0);
255 }
256
TEST(StreamEncoder,RepeatedField)257 TEST(StreamEncoder, RepeatedField) {
258 std::byte encode_buffer[32];
259 MemoryEncoder encoder(encode_buffer);
260
261 // repeated uint32 values = 1;
262 constexpr uint32_t values[] = {0, 50, 100, 150, 200};
263 for (int i = 0; i < 5; ++i) {
264 ASSERT_EQ(OkStatus(), encoder.WriteUint32(1, values[i]));
265 }
266
267 constexpr uint8_t encoded_proto[] = {
268 0x08, 0x00, 0x08, 0x32, 0x08, 0x64, 0x08, 0x96, 0x01, 0x08, 0xc8, 0x01};
269
270 ASSERT_EQ(encoder.status(), OkStatus());
271 ConstByteSpan result(encoder);
272 EXPECT_EQ(result.size(), sizeof(encoded_proto));
273 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
274 0);
275 }
276
TEST(StreamEncoder,PackedVarint)277 TEST(StreamEncoder, PackedVarint) {
278 std::byte encode_buffer[32];
279 MemoryEncoder encoder(encode_buffer);
280
281 // repeated uint32 values = 1;
282 constexpr uint32_t values[] = {0, 50, 100, 150, 200};
283 ASSERT_EQ(OkStatus(), encoder.WritePackedUint32(1, values));
284
285 constexpr uint8_t encoded_proto[] = {
286 0x0a, 0x07, 0x00, 0x32, 0x64, 0x96, 0x01, 0xc8, 0x01};
287 // key size v[0] v[1] v[2] v[3] v[4]
288
289 ASSERT_EQ(encoder.status(), OkStatus());
290 ConstByteSpan result(encoder);
291 EXPECT_EQ(result.size(), sizeof(encoded_proto));
292 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
293 0);
294 }
295
TEST(StreamEncoder,PackedVarintInsufficientSpace)296 TEST(StreamEncoder, PackedVarintInsufficientSpace) {
297 std::byte encode_buffer[8];
298 MemoryEncoder encoder(encode_buffer);
299
300 constexpr uint32_t values[] = {0, 50, 100, 150, 200};
301 ASSERT_EQ(Status::ResourceExhausted(), encoder.WritePackedUint32(1, values));
302
303 EXPECT_EQ(encoder.status(), Status::ResourceExhausted());
304 }
305
TEST(StreamEncoder,PackedVarintVector)306 TEST(StreamEncoder, PackedVarintVector) {
307 std::byte encode_buffer[32];
308 MemoryEncoder encoder(encode_buffer);
309
310 // repeated uint32 values = 1;
311 const pw::Vector<uint32_t, 5> values = {0, 50, 100, 150, 200};
312 ASSERT_EQ(OkStatus(), encoder.WriteRepeatedUint32(1, values));
313
314 constexpr uint8_t encoded_proto[] = {
315 0x0a, 0x07, 0x00, 0x32, 0x64, 0x96, 0x01, 0xc8, 0x01};
316 // key size v[0] v[1] v[2] v[3] v[4]
317
318 ASSERT_EQ(encoder.status(), OkStatus());
319 ConstByteSpan result(encoder);
320 EXPECT_EQ(result.size(), sizeof(encoded_proto));
321 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
322 0);
323 }
324
TEST(StreamEncoder,PackedVarintVectorInsufficientSpace)325 TEST(StreamEncoder, PackedVarintVectorInsufficientSpace) {
326 std::byte encode_buffer[8];
327 MemoryEncoder encoder(encode_buffer);
328
329 const pw::Vector<uint32_t, 5> values = {0, 50, 100, 150, 200};
330 ASSERT_EQ(Status::ResourceExhausted(),
331 encoder.WriteRepeatedUint32(1, values));
332
333 EXPECT_EQ(encoder.status(), Status::ResourceExhausted());
334 }
335
TEST(StreamEncoder,PackedBool)336 TEST(StreamEncoder, PackedBool) {
337 std::byte encode_buffer[32];
338 MemoryEncoder encoder(encode_buffer);
339
340 // repeated bool values = 1;
341 constexpr bool values[] = {true, false, true, true, false};
342 ASSERT_EQ(OkStatus(), encoder.WritePackedBool(1, values));
343
344 constexpr uint8_t encoded_proto[] = {
345 0x0a, 0x05, 0x01, 0x00, 0x01, 0x01, 0x00};
346 // key size v[0] v[1] v[2] v[3] v[4]
347
348 ASSERT_EQ(encoder.status(), OkStatus());
349 ConstByteSpan result(encoder);
350 EXPECT_EQ(result.size(), sizeof(encoded_proto));
351 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
352 0);
353 }
354
TEST(StreamEncoder,PackedFixed)355 TEST(StreamEncoder, PackedFixed) {
356 std::byte encode_buffer[32];
357 MemoryEncoder encoder(encode_buffer);
358
359 // repeated fixed32 values = 1;
360 constexpr uint32_t values[] = {0, 50, 100, 150, 200};
361 ASSERT_EQ(OkStatus(), encoder.WritePackedFixed32(1, values));
362
363 // repeated fixed64 values64 = 2;
364 constexpr uint64_t values64[] = {0x0102030405060708};
365 ASSERT_EQ(OkStatus(), encoder.WritePackedFixed64(2, values64));
366
367 constexpr uint8_t encoded_proto[] = {
368 0x0a, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x64,
369 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00,
370 0x12, 0x08, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
371
372 ASSERT_EQ(encoder.status(), OkStatus());
373 ConstByteSpan result(encoder);
374 EXPECT_EQ(result.size(), sizeof(encoded_proto));
375 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
376 0);
377 }
378
TEST(StreamEncoder,PackedFixedVector)379 TEST(StreamEncoder, PackedFixedVector) {
380 std::byte encode_buffer[32];
381 MemoryEncoder encoder(encode_buffer);
382
383 // repeated fixed32 values = 1;
384 const pw::Vector<uint32_t, 5> values = {0, 50, 100, 150, 200};
385 ASSERT_EQ(OkStatus(), encoder.WriteRepeatedFixed32(1, values));
386
387 // repeated fixed64 values64 = 2;
388 const pw::Vector<uint64_t, 1> values64 = {0x0102030405060708};
389 ASSERT_EQ(OkStatus(), encoder.WriteRepeatedFixed64(2, values64));
390
391 constexpr uint8_t encoded_proto[] = {
392 0x0a, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x64,
393 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00,
394 0x12, 0x08, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
395
396 ASSERT_EQ(encoder.status(), OkStatus());
397 ConstByteSpan result(encoder);
398 EXPECT_EQ(result.size(), sizeof(encoded_proto));
399 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
400 0);
401 }
402
TEST(StreamEncoder,PackedSfixedVector)403 TEST(StreamEncoder, PackedSfixedVector) {
404 std::byte encode_buffer[32];
405 MemoryEncoder encoder(encode_buffer);
406
407 // repeated fixed32 values = 1;
408 const pw::Vector<int32_t, 5> values = {0, 50, 100, 150, 200};
409 ASSERT_EQ(OkStatus(), encoder.WriteRepeatedSfixed32(1, values));
410
411 // repeated fixed64 values64 = 2;
412 const pw::Vector<int64_t, 1> values64 = {-2};
413 ASSERT_EQ(OkStatus(), encoder.WriteRepeatedSfixed64(2, values64));
414
415 constexpr uint8_t encoded_proto[] = {
416 0x0a, 0x14, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x64,
417 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00,
418 0x12, 0x08, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
419
420 ASSERT_EQ(encoder.status(), OkStatus());
421 ConstByteSpan result(encoder);
422 EXPECT_EQ(result.size(), sizeof(encoded_proto));
423 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
424 0);
425 }
426
TEST(StreamEncoder,PackedZigzag)427 TEST(StreamEncoder, PackedZigzag) {
428 std::byte encode_buffer[32];
429 MemoryEncoder encoder(encode_buffer);
430
431 // repeated sint32 values = 1;
432 constexpr int32_t values[] = {-100, -25, -1, 0, 1, 25, 100};
433 ASSERT_EQ(OkStatus(), encoder.WritePackedSint32(1, values));
434
435 constexpr uint8_t encoded_proto[] = {
436 0x0a, 0x09, 0xc7, 0x01, 0x31, 0x01, 0x00, 0x02, 0x32, 0xc8, 0x01};
437
438 ASSERT_EQ(encoder.status(), OkStatus());
439 ConstByteSpan result(encoder);
440 EXPECT_EQ(result.size(), sizeof(encoded_proto));
441 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
442 0);
443 }
444
TEST(StreamEncoder,PackedZigzagVector)445 TEST(StreamEncoder, PackedZigzagVector) {
446 std::byte encode_buffer[32];
447 MemoryEncoder encoder(encode_buffer);
448
449 // repeated sint32 values = 1;
450 const pw::Vector<int32_t, 7> values = {-100, -25, -1, 0, 1, 25, 100};
451 ASSERT_EQ(OkStatus(), encoder.WriteRepeatedSint32(1, values));
452
453 constexpr uint8_t encoded_proto[] = {
454 0x0a, 0x09, 0xc7, 0x01, 0x31, 0x01, 0x00, 0x02, 0x32, 0xc8, 0x01};
455
456 ASSERT_EQ(encoder.status(), OkStatus());
457 ConstByteSpan result(encoder);
458 EXPECT_EQ(result.size(), sizeof(encoded_proto));
459 EXPECT_EQ(std::memcmp(result.data(), encoded_proto, sizeof(encoded_proto)),
460 0);
461 }
462
TEST(StreamEncoder,ParentUnavailable)463 TEST(StreamEncoder, ParentUnavailable) {
464 std::byte encode_buffer[32];
465 MemoryEncoder parent(encode_buffer);
466 {
467 StreamEncoder child = parent.GetNestedEncoder(kTestProtoNestedField);
468 ASSERT_EQ(child.status(), OkStatus());
469 }
470 ASSERT_EQ(parent.status(), OkStatus());
471 }
472
TEST(StreamEncoder,NestedEncoderRequiresBuffer)473 TEST(StreamEncoder, NestedEncoderRequiresBuffer) {
474 MemoryEncoder parent((ByteSpan()));
475 {
476 StreamEncoder child = parent.GetNestedEncoder(kTestProtoNestedField);
477
478 ASSERT_EQ(child.status(), Status::ResourceExhausted());
479 }
480 ASSERT_EQ(parent.status(), Status::ResourceExhausted());
481 }
482
TEST(StreamEncoder,WriteTooBig)483 TEST(StreamEncoder, WriteTooBig) {
484 constexpr size_t kTempBufferSize = 32;
485 constexpr size_t kWriteSize = 2;
486 std::byte encode_buffer[32];
487 MemoryEncoder encoder(encode_buffer);
488 // Each write is 2 bytes. Ensure we can write 16 times.
489 for (size_t i = 0; i < kTempBufferSize; i += kWriteSize) {
490 ASSERT_EQ(encoder.WriteUint32(1, 12), OkStatus());
491 }
492 ASSERT_EQ(encoder.size(), kTempBufferSize);
493 ASSERT_EQ(encoder.WriteUint32(1, 12), Status::ResourceExhausted());
494 }
495
TEST(StreamEncoder,EmptyChildWrites)496 TEST(StreamEncoder, EmptyChildWrites) {
497 std::byte encode_buffer[32];
498 MemoryEncoder parent(encode_buffer);
499 {
500 StreamEncoder child = parent.GetNestedEncoder(kTestProtoNestedField);
501 }
502 ASSERT_EQ(parent.status(), OkStatus());
503 const size_t kExpectedSize =
504 varint::EncodedSize(
505 FieldKey(kTestProtoNestedField, WireType::kDelimited)) +
506 varint::EncodedSize(0);
507 ASSERT_EQ(parent.size(), kExpectedSize);
508 }
509
TEST(StreamEncoder,InvalidChildFieldNumber)510 TEST(StreamEncoder, InvalidChildFieldNumber) {
511 std::byte encode_buffer[32];
512 MemoryEncoder parent(encode_buffer);
513 {
514 StreamEncoder child = parent.GetNestedEncoder(0);
515 EXPECT_EQ(child.status(), Status::InvalidArgument());
516 }
517 EXPECT_EQ(parent.status(), Status::InvalidArgument());
518 }
519
TEST(StreamEncoder,NestedStatusPropagates)520 TEST(StreamEncoder, NestedStatusPropagates) {
521 std::byte encode_buffer[32];
522 MemoryEncoder parent(encode_buffer);
523 {
524 StreamEncoder child = parent.GetNestedEncoder(kTestProtoNestedField);
525 ASSERT_EQ(child.WriteUint32(0, 0), Status::InvalidArgument());
526 }
527 ASSERT_EQ(parent.status(), Status::InvalidArgument());
528 }
529
TEST(StreamEncoder,ManualCloseEncoderWrites)530 TEST(StreamEncoder, ManualCloseEncoderWrites) {
531 std::byte encode_buffer[32];
532 MemoryEncoder parent(encode_buffer);
533 StreamEncoder child = parent.GetNestedEncoder(kTestProtoNestedField);
534 child.CloseEncoder();
535 ASSERT_EQ(parent.status(), OkStatus());
536 const size_t kExpectedSize =
537 varint::EncodedSize(
538 FieldKey(kTestProtoNestedField, WireType::kDelimited)) +
539 varint::EncodedSize(0);
540 ASSERT_EQ(parent.size(), kExpectedSize);
541 }
542
543 } // namespace
544 } // namespace pw::protobuf
545