xref: /aosp_15_r20/external/pigweed/pw_protobuf/encoder_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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