xref: /aosp_15_r20/external/pigweed/pw_protobuf/codegen_message_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2023 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include <array>
16*61c4878aSAndroid Build Coastguard Worker #include <string_view>
17*61c4878aSAndroid Build Coastguard Worker #include <tuple>
18*61c4878aSAndroid Build Coastguard Worker 
19*61c4878aSAndroid Build Coastguard Worker #include "pw_preprocessor/compiler.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/internal/codegen.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_span/span.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status_with_size.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/memory_stream.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
26*61c4878aSAndroid Build Coastguard Worker 
27*61c4878aSAndroid Build Coastguard Worker // These header files contain the code generated by the pw_protobuf plugin.
28*61c4878aSAndroid Build Coastguard Worker // They are re-generated every time the tests are built and are used by the
29*61c4878aSAndroid Build Coastguard Worker // tests to ensure that the interface remains consistent.
30*61c4878aSAndroid Build Coastguard Worker //
31*61c4878aSAndroid Build Coastguard Worker // The purpose of the tests in this file is primarily to verify that the
32*61c4878aSAndroid Build Coastguard Worker // generated C++ interface is valid rather than the correctness of the
33*61c4878aSAndroid Build Coastguard Worker // low-level encoder.
34*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf_test_protos/full_test.pwpb.h"
35*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf_test_protos/importer.pwpb.h"
36*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf_test_protos/optional.pwpb.h"
37*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf_test_protos/repeated.pwpb.h"
38*61c4878aSAndroid Build Coastguard Worker 
39*61c4878aSAndroid Build Coastguard Worker namespace pw::protobuf {
40*61c4878aSAndroid Build Coastguard Worker namespace {
41*61c4878aSAndroid Build Coastguard Worker 
42*61c4878aSAndroid Build Coastguard Worker using namespace ::pw::protobuf::test::pwpb;
43*61c4878aSAndroid Build Coastguard Worker 
44*61c4878aSAndroid Build Coastguard Worker PW_MODIFY_DIAGNOSTICS_PUSH();
45*61c4878aSAndroid Build Coastguard Worker PW_MODIFY_DIAGNOSTIC(ignored, "-Wmissing-field-initializers");
46*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,Equality)47*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, Equality) {
48*61c4878aSAndroid Build Coastguard Worker   const Pigweed::Message one{
49*61c4878aSAndroid Build Coastguard Worker       .magic_number = 0x49u,
50*61c4878aSAndroid Build Coastguard Worker       .ziggy = -111,
51*61c4878aSAndroid Build Coastguard Worker       .cycles = 0x40302010fecaaddeu,
52*61c4878aSAndroid Build Coastguard Worker       .ratio = -1.42f,
53*61c4878aSAndroid Build Coastguard Worker       .error_message = "not a typewriter",
54*61c4878aSAndroid Build Coastguard Worker       .pigweed = {.status = Bool::FILE_NOT_FOUND},
55*61c4878aSAndroid Build Coastguard Worker       .bin = Pigweed::Protobuf::Binary::ZERO,
56*61c4878aSAndroid Build Coastguard Worker       .proto = {.bin = Proto::Binary::OFF,
57*61c4878aSAndroid Build Coastguard Worker                 .pigweed_pigweed_bin = Pigweed::Pigweed::Binary::ZERO,
58*61c4878aSAndroid Build Coastguard Worker                 .pigweed_protobuf_bin = Pigweed::Protobuf::Binary::ZERO,
59*61c4878aSAndroid Build Coastguard Worker                 .meta =
60*61c4878aSAndroid Build Coastguard Worker                     {
61*61c4878aSAndroid Build Coastguard Worker                         .file_name = "/etc/passwd",
62*61c4878aSAndroid Build Coastguard Worker                         .status = Pigweed::Protobuf::Compiler::Status::FUBAR,
63*61c4878aSAndroid Build Coastguard Worker                         .protobuf_bin = Pigweed::Protobuf::Binary::ONE,
64*61c4878aSAndroid Build Coastguard Worker                         .pigweed_bin = Pigweed::Pigweed::Binary::ONE,
65*61c4878aSAndroid Build Coastguard Worker                     }},
66*61c4878aSAndroid Build Coastguard Worker       .data = {std::byte{0x10},
67*61c4878aSAndroid Build Coastguard Worker                std::byte{0x20},
68*61c4878aSAndroid Build Coastguard Worker                std::byte{0x30},
69*61c4878aSAndroid Build Coastguard Worker                std::byte{0x40},
70*61c4878aSAndroid Build Coastguard Worker                std::byte{0x50},
71*61c4878aSAndroid Build Coastguard Worker                std::byte{0x60},
72*61c4878aSAndroid Build Coastguard Worker                std::byte{0x70},
73*61c4878aSAndroid Build Coastguard Worker                std::byte{0x80}},
74*61c4878aSAndroid Build Coastguard Worker       .bungle = -111,
75*61c4878aSAndroid Build Coastguard Worker   };
76*61c4878aSAndroid Build Coastguard Worker 
77*61c4878aSAndroid Build Coastguard Worker   const Pigweed::Message two{
78*61c4878aSAndroid Build Coastguard Worker       .magic_number = 0x49u,
79*61c4878aSAndroid Build Coastguard Worker       .ziggy = -111,
80*61c4878aSAndroid Build Coastguard Worker       .cycles = 0x40302010fecaaddeu,
81*61c4878aSAndroid Build Coastguard Worker       .ratio = -1.42f,
82*61c4878aSAndroid Build Coastguard Worker       .error_message = "not a typewriter",
83*61c4878aSAndroid Build Coastguard Worker       .pigweed = {.status = Bool::FILE_NOT_FOUND},
84*61c4878aSAndroid Build Coastguard Worker       .bin = Pigweed::Protobuf::Binary::ZERO,
85*61c4878aSAndroid Build Coastguard Worker       .proto = {.bin = Proto::Binary::OFF,
86*61c4878aSAndroid Build Coastguard Worker                 .pigweed_pigweed_bin = Pigweed::Pigweed::Binary::ZERO,
87*61c4878aSAndroid Build Coastguard Worker                 .pigweed_protobuf_bin = Pigweed::Protobuf::Binary::ZERO,
88*61c4878aSAndroid Build Coastguard Worker                 .meta =
89*61c4878aSAndroid Build Coastguard Worker                     {
90*61c4878aSAndroid Build Coastguard Worker                         .file_name = "/etc/passwd",
91*61c4878aSAndroid Build Coastguard Worker                         .status = Pigweed::Protobuf::Compiler::Status::FUBAR,
92*61c4878aSAndroid Build Coastguard Worker                         .protobuf_bin = Pigweed::Protobuf::Binary::ONE,
93*61c4878aSAndroid Build Coastguard Worker                         .pigweed_bin = Pigweed::Pigweed::Binary::ONE,
94*61c4878aSAndroid Build Coastguard Worker                     }},
95*61c4878aSAndroid Build Coastguard Worker       .data = {std::byte{0x10},
96*61c4878aSAndroid Build Coastguard Worker                std::byte{0x20},
97*61c4878aSAndroid Build Coastguard Worker                std::byte{0x30},
98*61c4878aSAndroid Build Coastguard Worker                std::byte{0x40},
99*61c4878aSAndroid Build Coastguard Worker                std::byte{0x50},
100*61c4878aSAndroid Build Coastguard Worker                std::byte{0x60},
101*61c4878aSAndroid Build Coastguard Worker                std::byte{0x70},
102*61c4878aSAndroid Build Coastguard Worker                std::byte{0x80}},
103*61c4878aSAndroid Build Coastguard Worker       .bungle = -111,
104*61c4878aSAndroid Build Coastguard Worker   };
105*61c4878aSAndroid Build Coastguard Worker 
106*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(one == two);
107*61c4878aSAndroid Build Coastguard Worker }
108*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,CopyEquality)109*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, CopyEquality) {
110*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message one{
111*61c4878aSAndroid Build Coastguard Worker       .magic_number = 0x49u,
112*61c4878aSAndroid Build Coastguard Worker       .ziggy = -111,
113*61c4878aSAndroid Build Coastguard Worker       .cycles = 0x40302010fecaaddeu,
114*61c4878aSAndroid Build Coastguard Worker       .ratio = -1.42f,
115*61c4878aSAndroid Build Coastguard Worker       .error_message = "not a typewriter",
116*61c4878aSAndroid Build Coastguard Worker       .pigweed = {.status = Bool::FILE_NOT_FOUND},
117*61c4878aSAndroid Build Coastguard Worker       .bin = Pigweed::Protobuf::Binary::ZERO,
118*61c4878aSAndroid Build Coastguard Worker       .proto = {.bin = Proto::Binary::OFF,
119*61c4878aSAndroid Build Coastguard Worker                 .pigweed_pigweed_bin = Pigweed::Pigweed::Binary::ZERO,
120*61c4878aSAndroid Build Coastguard Worker                 .pigweed_protobuf_bin = Pigweed::Protobuf::Binary::ZERO,
121*61c4878aSAndroid Build Coastguard Worker                 .meta =
122*61c4878aSAndroid Build Coastguard Worker                     {
123*61c4878aSAndroid Build Coastguard Worker                         .file_name = "/etc/passwd",
124*61c4878aSAndroid Build Coastguard Worker                         .status = Pigweed::Protobuf::Compiler::Status::FUBAR,
125*61c4878aSAndroid Build Coastguard Worker                         .protobuf_bin = Pigweed::Protobuf::Binary::ONE,
126*61c4878aSAndroid Build Coastguard Worker                         .pigweed_bin = Pigweed::Pigweed::Binary::ONE,
127*61c4878aSAndroid Build Coastguard Worker                     }},
128*61c4878aSAndroid Build Coastguard Worker       .data = {std::byte{0x10},
129*61c4878aSAndroid Build Coastguard Worker                std::byte{0x20},
130*61c4878aSAndroid Build Coastguard Worker                std::byte{0x30},
131*61c4878aSAndroid Build Coastguard Worker                std::byte{0x40},
132*61c4878aSAndroid Build Coastguard Worker                std::byte{0x50},
133*61c4878aSAndroid Build Coastguard Worker                std::byte{0x60},
134*61c4878aSAndroid Build Coastguard Worker                std::byte{0x70},
135*61c4878aSAndroid Build Coastguard Worker                std::byte{0x80}},
136*61c4878aSAndroid Build Coastguard Worker       .bungle = -111,
137*61c4878aSAndroid Build Coastguard Worker   };
138*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message two = one;
139*61c4878aSAndroid Build Coastguard Worker 
140*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(one == two);
141*61c4878aSAndroid Build Coastguard Worker }
142*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,EmptyEquality)143*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, EmptyEquality) {
144*61c4878aSAndroid Build Coastguard Worker   const Pigweed::Message one{};
145*61c4878aSAndroid Build Coastguard Worker   const Pigweed::Message two{};
146*61c4878aSAndroid Build Coastguard Worker 
147*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(one == two);
148*61c4878aSAndroid Build Coastguard Worker }
149*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,Inequality)150*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, Inequality) {
151*61c4878aSAndroid Build Coastguard Worker   const Pigweed::Message one{
152*61c4878aSAndroid Build Coastguard Worker       .magic_number = 0x49u,
153*61c4878aSAndroid Build Coastguard Worker       .ziggy = -111,
154*61c4878aSAndroid Build Coastguard Worker       .cycles = 0x40302010fecaaddeu,
155*61c4878aSAndroid Build Coastguard Worker       .ratio = -1.42f,
156*61c4878aSAndroid Build Coastguard Worker       .error_message = "not a typewriter",
157*61c4878aSAndroid Build Coastguard Worker       .pigweed = {.status = Bool::FILE_NOT_FOUND},
158*61c4878aSAndroid Build Coastguard Worker       .bin = Pigweed::Protobuf::Binary::ZERO,
159*61c4878aSAndroid Build Coastguard Worker       .proto = {.bin = Proto::Binary::OFF,
160*61c4878aSAndroid Build Coastguard Worker                 .pigweed_pigweed_bin = Pigweed::Pigweed::Binary::ZERO,
161*61c4878aSAndroid Build Coastguard Worker                 .pigweed_protobuf_bin = Pigweed::Protobuf::Binary::ZERO,
162*61c4878aSAndroid Build Coastguard Worker                 .meta =
163*61c4878aSAndroid Build Coastguard Worker                     {
164*61c4878aSAndroid Build Coastguard Worker                         .file_name = "/etc/passwd",
165*61c4878aSAndroid Build Coastguard Worker                         .status = Pigweed::Protobuf::Compiler::Status::FUBAR,
166*61c4878aSAndroid Build Coastguard Worker                         .protobuf_bin = Pigweed::Protobuf::Binary::ONE,
167*61c4878aSAndroid Build Coastguard Worker                         .pigweed_bin = Pigweed::Pigweed::Binary::ONE,
168*61c4878aSAndroid Build Coastguard Worker                     }},
169*61c4878aSAndroid Build Coastguard Worker       .data = {std::byte{0x10},
170*61c4878aSAndroid Build Coastguard Worker                std::byte{0x20},
171*61c4878aSAndroid Build Coastguard Worker                std::byte{0x30},
172*61c4878aSAndroid Build Coastguard Worker                std::byte{0x40},
173*61c4878aSAndroid Build Coastguard Worker                std::byte{0x50},
174*61c4878aSAndroid Build Coastguard Worker                std::byte{0x60},
175*61c4878aSAndroid Build Coastguard Worker                std::byte{0x70},
176*61c4878aSAndroid Build Coastguard Worker                std::byte{0x80}},
177*61c4878aSAndroid Build Coastguard Worker       .bungle = -111,
178*61c4878aSAndroid Build Coastguard Worker   };
179*61c4878aSAndroid Build Coastguard Worker 
180*61c4878aSAndroid Build Coastguard Worker   const Pigweed::Message two{
181*61c4878aSAndroid Build Coastguard Worker       .magic_number = 0x43u,
182*61c4878aSAndroid Build Coastguard Worker       .ziggy = 128,
183*61c4878aSAndroid Build Coastguard Worker       .ratio = -1.42f,
184*61c4878aSAndroid Build Coastguard Worker       .error_message = "not a typewriter",
185*61c4878aSAndroid Build Coastguard Worker       .pigweed = {.status = Bool::TRUE},
186*61c4878aSAndroid Build Coastguard Worker       .bin = Pigweed::Protobuf::Binary::ZERO,
187*61c4878aSAndroid Build Coastguard Worker       .proto = {.bin = Proto::Binary::OFF,
188*61c4878aSAndroid Build Coastguard Worker                 .pigweed_pigweed_bin = Pigweed::Pigweed::Binary::ZERO,
189*61c4878aSAndroid Build Coastguard Worker                 .pigweed_protobuf_bin = Pigweed::Protobuf::Binary::ONE,
190*61c4878aSAndroid Build Coastguard Worker                 .meta =
191*61c4878aSAndroid Build Coastguard Worker                     {
192*61c4878aSAndroid Build Coastguard Worker                         .file_name = "/etc/passwd",
193*61c4878aSAndroid Build Coastguard Worker                         .status = Pigweed::Protobuf::Compiler::Status::FUBAR,
194*61c4878aSAndroid Build Coastguard Worker                         .protobuf_bin = Pigweed::Protobuf::Binary::ONE,
195*61c4878aSAndroid Build Coastguard Worker                         .pigweed_bin = Pigweed::Pigweed::Binary::ONE,
196*61c4878aSAndroid Build Coastguard Worker                     }},
197*61c4878aSAndroid Build Coastguard Worker       .data = {std::byte{0x20},
198*61c4878aSAndroid Build Coastguard Worker                std::byte{0x30},
199*61c4878aSAndroid Build Coastguard Worker                std::byte{0x40},
200*61c4878aSAndroid Build Coastguard Worker                std::byte{0x50},
201*61c4878aSAndroid Build Coastguard Worker                std::byte{0x60},
202*61c4878aSAndroid Build Coastguard Worker                std::byte{0x70},
203*61c4878aSAndroid Build Coastguard Worker                std::byte{0x80},
204*61c4878aSAndroid Build Coastguard Worker                std::byte{0x90}},
205*61c4878aSAndroid Build Coastguard Worker   };
206*61c4878aSAndroid Build Coastguard Worker 
207*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(one == two);
208*61c4878aSAndroid Build Coastguard Worker }
209*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,TriviallyComparable)210*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, TriviallyComparable) {
211*61c4878aSAndroid Build Coastguard Worker   static_assert(IsTriviallyComparable<IntegerMetadata::Message>());
212*61c4878aSAndroid Build Coastguard Worker   static_assert(IsTriviallyComparable<KeyValuePair::Message>());
213*61c4878aSAndroid Build Coastguard Worker   static_assert(!IsTriviallyComparable<Pigweed::Message>());
214*61c4878aSAndroid Build Coastguard Worker }
215*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ConstCopyable)216*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ConstCopyable) {
217*61c4878aSAndroid Build Coastguard Worker   const Pigweed::Message one{
218*61c4878aSAndroid Build Coastguard Worker       .magic_number = 0x49u,
219*61c4878aSAndroid Build Coastguard Worker       .ziggy = -111,
220*61c4878aSAndroid Build Coastguard Worker       .cycles = 0x40302010fecaaddeu,
221*61c4878aSAndroid Build Coastguard Worker       .ratio = -1.42f,
222*61c4878aSAndroid Build Coastguard Worker       .error_message = "not a typewriter",
223*61c4878aSAndroid Build Coastguard Worker       .pigweed = {.status = Bool::FILE_NOT_FOUND},
224*61c4878aSAndroid Build Coastguard Worker       .bin = Pigweed::Protobuf::Binary::ZERO,
225*61c4878aSAndroid Build Coastguard Worker       .proto = {.bin = Proto::Binary::OFF,
226*61c4878aSAndroid Build Coastguard Worker                 .pigweed_pigweed_bin = Pigweed::Pigweed::Binary::ZERO,
227*61c4878aSAndroid Build Coastguard Worker                 .pigweed_protobuf_bin = Pigweed::Protobuf::Binary::ZERO,
228*61c4878aSAndroid Build Coastguard Worker                 .meta =
229*61c4878aSAndroid Build Coastguard Worker                     {
230*61c4878aSAndroid Build Coastguard Worker                         .file_name = "/etc/passwd",
231*61c4878aSAndroid Build Coastguard Worker                         .status = Pigweed::Protobuf::Compiler::Status::FUBAR,
232*61c4878aSAndroid Build Coastguard Worker                         .protobuf_bin = Pigweed::Protobuf::Binary::ONE,
233*61c4878aSAndroid Build Coastguard Worker                         .pigweed_bin = Pigweed::Pigweed::Binary::ONE,
234*61c4878aSAndroid Build Coastguard Worker                     }},
235*61c4878aSAndroid Build Coastguard Worker       .data = {std::byte{0x10},
236*61c4878aSAndroid Build Coastguard Worker                std::byte{0x20},
237*61c4878aSAndroid Build Coastguard Worker                std::byte{0x30},
238*61c4878aSAndroid Build Coastguard Worker                std::byte{0x40},
239*61c4878aSAndroid Build Coastguard Worker                std::byte{0x50},
240*61c4878aSAndroid Build Coastguard Worker                std::byte{0x60},
241*61c4878aSAndroid Build Coastguard Worker                std::byte{0x70},
242*61c4878aSAndroid Build Coastguard Worker                std::byte{0x80}},
243*61c4878aSAndroid Build Coastguard Worker       .bungle = -111,
244*61c4878aSAndroid Build Coastguard Worker   };
245*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message two = one;
246*61c4878aSAndroid Build Coastguard Worker 
247*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(one == two);
248*61c4878aSAndroid Build Coastguard Worker }
249*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,FixReservedIdentifiers)250*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, FixReservedIdentifiers) {
251*61c4878aSAndroid Build Coastguard Worker   // This test checks that the code was generated as expected, so it will simply
252*61c4878aSAndroid Build Coastguard Worker   // fail to compile if its expectations are not met.
253*61c4878aSAndroid Build Coastguard Worker 
254*61c4878aSAndroid Build Coastguard Worker   // Make sure that the `signed` field was renamed to `signed_`.
255*61c4878aSAndroid Build Coastguard Worker   std::ignore = IntegerMetadata::Message{
256*61c4878aSAndroid Build Coastguard Worker       .bits = 32,
257*61c4878aSAndroid Build Coastguard Worker       .signed_ = true,
258*61c4878aSAndroid Build Coastguard Worker       .null = false,
259*61c4878aSAndroid Build Coastguard Worker   };
260*61c4878aSAndroid Build Coastguard Worker 
261*61c4878aSAndroid Build Coastguard Worker   // Make sure that the internal enum describing the struct's fields was
262*61c4878aSAndroid Build Coastguard Worker   // generated as expected:
263*61c4878aSAndroid Build Coastguard Worker   // - `BITS` doesn't need an underscore.
264*61c4878aSAndroid Build Coastguard Worker   // - `SIGNED_` has an underscore to match the corresponding `signed_` field.
265*61c4878aSAndroid Build Coastguard Worker   // - `NULL_` has an underscore to avoid a collision with `NULL` (even though
266*61c4878aSAndroid Build Coastguard Worker   //   the field `null` doesn't have or need an underscore).
267*61c4878aSAndroid Build Coastguard Worker   std::ignore = IntegerMetadata::Fields::kBits;
268*61c4878aSAndroid Build Coastguard Worker   std::ignore = IntegerMetadata::Fields::kSigned;
269*61c4878aSAndroid Build Coastguard Worker   std::ignore = IntegerMetadata::Fields::kNull;
270*61c4878aSAndroid Build Coastguard Worker 
271*61c4878aSAndroid Build Coastguard Worker   // Make sure that the `ReservedWord` enum values were renamed as expected.
272*61c4878aSAndroid Build Coastguard Worker   // Specifically, only enum-value names that are reserved in UPPER_SNAKE_CASE
273*61c4878aSAndroid Build Coastguard Worker   // should be modified. Names that are only reserved in lower_snake_case should
274*61c4878aSAndroid Build Coastguard Worker   // be left alone since they'll never appear in that form in the generated
275*61c4878aSAndroid Build Coastguard Worker   // code.
276*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::NULL_;    // Add underscore since NULL is a macro.
277*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::kNull;    // No underscore necessary.
278*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::INT;      // No underscore necessary.
279*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::kInt;     // No underscore necessary.
280*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::RETURN;   // No underscore necessary.
281*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::kReturn;  // No underscore necessary.
282*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::BREAK;    // No underscore necessary.
283*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::kBreak;   // No underscore necessary.
284*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::FOR;      // No underscore necessary.
285*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::kFor;     // No underscore necessary.
286*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::DO;       // No underscore necessary.
287*61c4878aSAndroid Build Coastguard Worker   std::ignore = ReservedWord::kDo;      // No underscore necessary.
288*61c4878aSAndroid Build Coastguard Worker 
289*61c4878aSAndroid Build Coastguard Worker   // Instantiate an extremely degenerately named set of nested types in order to
290*61c4878aSAndroid Build Coastguard Worker   // make sure that name conflicts with the codegen internals are properly
291*61c4878aSAndroid Build Coastguard Worker   // prevented.
292*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Message{
293*61c4878aSAndroid Build Coastguard Worker       .description =
294*61c4878aSAndroid Build Coastguard Worker           Function::Message_::Message{
295*61c4878aSAndroid Build Coastguard Worker               .content = "multiplication (mod 5)",
296*61c4878aSAndroid Build Coastguard Worker           },
297*61c4878aSAndroid Build Coastguard Worker       .domain_field = Function::Fields_::INTEGERS_MOD_5,
298*61c4878aSAndroid Build Coastguard Worker       .codomain_field = Function::Fields_::INTEGERS_MOD_5,
299*61c4878aSAndroid Build Coastguard Worker   };
300*61c4878aSAndroid Build Coastguard Worker 
301*61c4878aSAndroid Build Coastguard Worker   // Check for expected values of `enum class Function::Fields`:
302*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields::kDescription;
303*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields::kDomainField;
304*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields::kCodomainField;
305*61c4878aSAndroid Build Coastguard Worker 
306*61c4878aSAndroid Build Coastguard Worker   // Check for expected values of `enum class Function::Message_::Fields`:
307*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Message_::Fields::kContent;
308*61c4878aSAndroid Build Coastguard Worker 
309*61c4878aSAndroid Build Coastguard Worker   // Check for expected values of `enum class Function::Fields_`:
310*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields_::NONE;
311*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields_::kNone;
312*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields_::COMPLEX_NUMBERS;
313*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields_::kComplexNumbers;
314*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields_::INTEGERS_MOD_5;
315*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields_::kIntegersMod5;
316*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields_::MEROMORPHIC_FUNCTIONS_ON_COMPLEX_PLANE;
317*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields_::kMeromorphicFunctionsOnComplexPlane;
318*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields_::OTHER;
319*61c4878aSAndroid Build Coastguard Worker   std::ignore = Function::Fields_::kOther;
320*61c4878aSAndroid Build Coastguard Worker }
321*61c4878aSAndroid Build Coastguard Worker 
322*61c4878aSAndroid Build Coastguard Worker PW_MODIFY_DIAGNOSTICS_POP();
323*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,SetEncoder)324*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, SetEncoder) {
325*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message msg{};
326*61c4878aSAndroid Build Coastguard Worker 
327*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(msg.id);
328*61c4878aSAndroid Build Coastguard Worker   msg.id.SetEncoder(
329*61c4878aSAndroid Build Coastguard Worker       [](Pigweed::StreamEncoder&) -> Status { return OkStatus(); });
330*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(msg.id);
331*61c4878aSAndroid Build Coastguard Worker }
332*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,SetDecoder)333*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, SetDecoder) {
334*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message msg{};
335*61c4878aSAndroid Build Coastguard Worker 
336*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(msg.id);
337*61c4878aSAndroid Build Coastguard Worker   msg.id.SetDecoder(
338*61c4878aSAndroid Build Coastguard Worker       [](Pigweed::StreamDecoder&) -> Status { return OkStatus(); });
339*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(msg.id);
340*61c4878aSAndroid Build Coastguard Worker }
341*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,SetEncoderAndDecoder)342*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, SetEncoderAndDecoder) {
343*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message msg{};
344*61c4878aSAndroid Build Coastguard Worker 
345*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(msg.id);
346*61c4878aSAndroid Build Coastguard Worker   msg.id.SetEncoder(
347*61c4878aSAndroid Build Coastguard Worker       [](Pigweed::StreamEncoder&) -> Status { return OkStatus(); });
348*61c4878aSAndroid Build Coastguard Worker   msg.id.SetDecoder(
349*61c4878aSAndroid Build Coastguard Worker       [](Pigweed::StreamDecoder&) -> Status { return OkStatus(); });
350*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(msg.id);
351*61c4878aSAndroid Build Coastguard Worker }
352*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,Read)353*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, Read) {
354*61c4878aSAndroid Build Coastguard Worker   // clang-format off
355*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
356*61c4878aSAndroid Build Coastguard Worker     // pigweed.magic_number
357*61c4878aSAndroid Build Coastguard Worker     0x08, 0x49,
358*61c4878aSAndroid Build Coastguard Worker     // pigweed.ziggy
359*61c4878aSAndroid Build Coastguard Worker     0x10, 0xdd, 0x01,
360*61c4878aSAndroid Build Coastguard Worker     // pigweed.cycles
361*61c4878aSAndroid Build Coastguard Worker     0x19, 0xde, 0xad, 0xca, 0xfe, 0x10, 0x20, 0x30, 0x40,
362*61c4878aSAndroid Build Coastguard Worker     // pigweed.ratio
363*61c4878aSAndroid Build Coastguard Worker     0x25, 0x8f, 0xc2, 0xb5, 0xbf,
364*61c4878aSAndroid Build Coastguard Worker     // pigweed.error_message
365*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
366*61c4878aSAndroid Build Coastguard Worker     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
367*61c4878aSAndroid Build Coastguard Worker     // pigweed.bin
368*61c4878aSAndroid Build Coastguard Worker     0x40, 0x01,
369*61c4878aSAndroid Build Coastguard Worker     // pigweed.bungle
370*61c4878aSAndroid Build Coastguard Worker     0x70, 0x91, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
371*61c4878aSAndroid Build Coastguard Worker   };
372*61c4878aSAndroid Build Coastguard Worker   // clang-format on
373*61c4878aSAndroid Build Coastguard Worker 
374*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
375*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamDecoder pigweed(reader);
376*61c4878aSAndroid Build Coastguard Worker 
377*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
378*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Read(message);
379*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
380*61c4878aSAndroid Build Coastguard Worker 
381*61c4878aSAndroid Build Coastguard Worker   constexpr std::string_view kExpectedErrorMessage{"not a typewriter"};
382*61c4878aSAndroid Build Coastguard Worker 
383*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.magic_number, 0x49u);
384*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.ziggy, -111);
385*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.cycles, 0x40302010fecaaddeu);
386*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.ratio, -1.42f);
387*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.error_message.size(), kExpectedErrorMessage.size());
388*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(message.error_message.data(),
389*61c4878aSAndroid Build Coastguard Worker                         kExpectedErrorMessage.data(),
390*61c4878aSAndroid Build Coastguard Worker                         kExpectedErrorMessage.size()),
391*61c4878aSAndroid Build Coastguard Worker             0);
392*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.bin, Pigweed::Protobuf::Binary::ZERO);
393*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.bungle, -111);
394*61c4878aSAndroid Build Coastguard Worker }
395*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadNonPackedScalar)396*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadNonPackedScalar) {
397*61c4878aSAndroid Build Coastguard Worker   // clang-format off
398*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
399*61c4878aSAndroid Build Coastguard Worker     // uint32s[], v={0, 16, 32, 48}
400*61c4878aSAndroid Build Coastguard Worker     0x08, 0x00,
401*61c4878aSAndroid Build Coastguard Worker     0x08, 0x10,
402*61c4878aSAndroid Build Coastguard Worker     0x08, 0x20,
403*61c4878aSAndroid Build Coastguard Worker     0x08, 0x30,
404*61c4878aSAndroid Build Coastguard Worker     // fixed32s[]. v={0, 16, 32, 48}
405*61c4878aSAndroid Build Coastguard Worker     0x35, 0x00, 0x00, 0x00, 0x00,
406*61c4878aSAndroid Build Coastguard Worker     0x35, 0x10, 0x00, 0x00, 0x00,
407*61c4878aSAndroid Build Coastguard Worker     0x35, 0x20, 0x00, 0x00, 0x00,
408*61c4878aSAndroid Build Coastguard Worker     0x35, 0x30, 0x00, 0x00, 0x00,
409*61c4878aSAndroid Build Coastguard Worker   };
410*61c4878aSAndroid Build Coastguard Worker   // clang-format on
411*61c4878aSAndroid Build Coastguard Worker 
412*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
413*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
414*61c4878aSAndroid Build Coastguard Worker 
415*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
416*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
417*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
418*61c4878aSAndroid Build Coastguard Worker 
419*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(message.uint32s.size(), 4u);
420*61c4878aSAndroid Build Coastguard Worker   for (unsigned short i = 0; i < 4; ++i) {
421*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(message.uint32s[i], i * 16u);
422*61c4878aSAndroid Build Coastguard Worker   }
423*61c4878aSAndroid Build Coastguard Worker 
424*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(message.fixed32s.size(), 4u);
425*61c4878aSAndroid Build Coastguard Worker   for (unsigned short i = 0; i < 4; ++i) {
426*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(message.fixed32s[i], i * 16u);
427*61c4878aSAndroid Build Coastguard Worker   }
428*61c4878aSAndroid Build Coastguard Worker }
429*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadPackedScalar)430*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadPackedScalar) {
431*61c4878aSAndroid Build Coastguard Worker   // clang-format off
432*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
433*61c4878aSAndroid Build Coastguard Worker     // uint32s[], v={0, 16, 32, 48}
434*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x04,
435*61c4878aSAndroid Build Coastguard Worker     0x00,
436*61c4878aSAndroid Build Coastguard Worker     0x10,
437*61c4878aSAndroid Build Coastguard Worker     0x20,
438*61c4878aSAndroid Build Coastguard Worker     0x30,
439*61c4878aSAndroid Build Coastguard Worker     // fixed32s[]. v={0, 16, 32, 48}
440*61c4878aSAndroid Build Coastguard Worker     0x32, 0x10,
441*61c4878aSAndroid Build Coastguard Worker     0x00, 0x00, 0x00, 0x00,
442*61c4878aSAndroid Build Coastguard Worker     0x10, 0x00, 0x00, 0x00,
443*61c4878aSAndroid Build Coastguard Worker     0x20, 0x00, 0x00, 0x00,
444*61c4878aSAndroid Build Coastguard Worker     0x30, 0x00, 0x00, 0x00,
445*61c4878aSAndroid Build Coastguard Worker   };
446*61c4878aSAndroid Build Coastguard Worker   // clang-format on
447*61c4878aSAndroid Build Coastguard Worker 
448*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
449*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
450*61c4878aSAndroid Build Coastguard Worker 
451*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
452*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
453*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
454*61c4878aSAndroid Build Coastguard Worker 
455*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(message.uint32s.size(), 4u);
456*61c4878aSAndroid Build Coastguard Worker   for (unsigned short i = 0; i < 4; ++i) {
457*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(message.uint32s[i], i * 16u);
458*61c4878aSAndroid Build Coastguard Worker   }
459*61c4878aSAndroid Build Coastguard Worker 
460*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(message.fixed32s.size(), 4u);
461*61c4878aSAndroid Build Coastguard Worker   for (unsigned short i = 0; i < 4; ++i) {
462*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(message.fixed32s[i], i * 16u);
463*61c4878aSAndroid Build Coastguard Worker   }
464*61c4878aSAndroid Build Coastguard Worker }
465*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadPackedScalarRepeated)466*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadPackedScalarRepeated) {
467*61c4878aSAndroid Build Coastguard Worker   // clang-format off
468*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
469*61c4878aSAndroid Build Coastguard Worker     // uint32s[], v={0, 16, 32, 48}
470*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x04,
471*61c4878aSAndroid Build Coastguard Worker     0x00,
472*61c4878aSAndroid Build Coastguard Worker     0x10,
473*61c4878aSAndroid Build Coastguard Worker     0x20,
474*61c4878aSAndroid Build Coastguard Worker     0x30,
475*61c4878aSAndroid Build Coastguard Worker     // uint32s[], v={64, 80, 96, 112}
476*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x04,
477*61c4878aSAndroid Build Coastguard Worker     0x40,
478*61c4878aSAndroid Build Coastguard Worker     0x50,
479*61c4878aSAndroid Build Coastguard Worker     0x60,
480*61c4878aSAndroid Build Coastguard Worker     0x70,
481*61c4878aSAndroid Build Coastguard Worker     // fixed32s[]. v={0, 16, 32, 48}
482*61c4878aSAndroid Build Coastguard Worker     0x32, 0x10,
483*61c4878aSAndroid Build Coastguard Worker     0x00, 0x00, 0x00, 0x00,
484*61c4878aSAndroid Build Coastguard Worker     0x10, 0x00, 0x00, 0x00,
485*61c4878aSAndroid Build Coastguard Worker     0x20, 0x00, 0x00, 0x00,
486*61c4878aSAndroid Build Coastguard Worker     0x30, 0x00, 0x00, 0x00,
487*61c4878aSAndroid Build Coastguard Worker     // fixed32s[]. v={64, 80, 96, 112}
488*61c4878aSAndroid Build Coastguard Worker     0x32, 0x10,
489*61c4878aSAndroid Build Coastguard Worker     0x40, 0x00, 0x00, 0x00,
490*61c4878aSAndroid Build Coastguard Worker     0x50, 0x00, 0x00, 0x00,
491*61c4878aSAndroid Build Coastguard Worker     0x60, 0x00, 0x00, 0x00,
492*61c4878aSAndroid Build Coastguard Worker     0x70, 0x00, 0x00, 0x00,
493*61c4878aSAndroid Build Coastguard Worker   };
494*61c4878aSAndroid Build Coastguard Worker   // clang-format on
495*61c4878aSAndroid Build Coastguard Worker 
496*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
497*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
498*61c4878aSAndroid Build Coastguard Worker 
499*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
500*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
501*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
502*61c4878aSAndroid Build Coastguard Worker 
503*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(message.uint32s.size(), 8u);
504*61c4878aSAndroid Build Coastguard Worker   for (unsigned short i = 0; i < 8; ++i) {
505*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(message.uint32s[i], i * 16u);
506*61c4878aSAndroid Build Coastguard Worker   }
507*61c4878aSAndroid Build Coastguard Worker 
508*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(message.fixed32s.size(), 8u);
509*61c4878aSAndroid Build Coastguard Worker   for (unsigned short i = 0; i < 8; ++i) {
510*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(message.fixed32s[i], i * 16u);
511*61c4878aSAndroid Build Coastguard Worker   }
512*61c4878aSAndroid Build Coastguard Worker }
513*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadPackedScalarExhausted)514*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadPackedScalarExhausted) {
515*61c4878aSAndroid Build Coastguard Worker   // clang-format off
516*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
517*61c4878aSAndroid Build Coastguard Worker     // uint32s[], v={0, 16, 32, 48, 64, 80, 96, 112, 128}
518*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x09,
519*61c4878aSAndroid Build Coastguard Worker     0x00,
520*61c4878aSAndroid Build Coastguard Worker     0x10,
521*61c4878aSAndroid Build Coastguard Worker     0x20,
522*61c4878aSAndroid Build Coastguard Worker     0x30,
523*61c4878aSAndroid Build Coastguard Worker     0x40,
524*61c4878aSAndroid Build Coastguard Worker     0x50,
525*61c4878aSAndroid Build Coastguard Worker     0x60,
526*61c4878aSAndroid Build Coastguard Worker     0x70,
527*61c4878aSAndroid Build Coastguard Worker     0x80,
528*61c4878aSAndroid Build Coastguard Worker   };
529*61c4878aSAndroid Build Coastguard Worker   // clang-format on
530*61c4878aSAndroid Build Coastguard Worker 
531*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
532*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
533*61c4878aSAndroid Build Coastguard Worker 
534*61c4878aSAndroid Build Coastguard Worker   // uint32s has max_size=8, so this will exhaust the vector.
535*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
536*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
537*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, Status::ResourceExhausted());
538*61c4878aSAndroid Build Coastguard Worker }
539*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadPackedScalarCallback)540*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadPackedScalarCallback) {
541*61c4878aSAndroid Build Coastguard Worker   // clang-format off
542*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
543*61c4878aSAndroid Build Coastguard Worker     // sint32s[], v={-25, -1, 0, 1, 25}
544*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05,
545*61c4878aSAndroid Build Coastguard Worker     0x31,
546*61c4878aSAndroid Build Coastguard Worker     0x01,
547*61c4878aSAndroid Build Coastguard Worker     0x00,
548*61c4878aSAndroid Build Coastguard Worker     0x02,
549*61c4878aSAndroid Build Coastguard Worker     0x32,
550*61c4878aSAndroid Build Coastguard Worker   };
551*61c4878aSAndroid Build Coastguard Worker   // clang-format on
552*61c4878aSAndroid Build Coastguard Worker 
553*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
554*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
555*61c4878aSAndroid Build Coastguard Worker 
556*61c4878aSAndroid Build Coastguard Worker   // sint32s is a repeated field declared without max_count, so requirses a
557*61c4878aSAndroid Build Coastguard Worker   // callback to be decoded.
558*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
559*61c4878aSAndroid Build Coastguard Worker   message.sint32s.SetDecoder([](RepeatedTest::StreamDecoder& decoder) {
560*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(decoder.Field().value(), RepeatedTest::Fields::kSint32s);
561*61c4878aSAndroid Build Coastguard Worker 
562*61c4878aSAndroid Build Coastguard Worker     pw::Vector<int32_t, 8> sint32s{};
563*61c4878aSAndroid Build Coastguard Worker     const auto status = decoder.ReadSint32s(sint32s);
564*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(status, OkStatus());
565*61c4878aSAndroid Build Coastguard Worker 
566*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sint32s.size(), 5u);
567*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sint32s[0], -25);
568*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sint32s[1], -1);
569*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sint32s[2], 0);
570*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sint32s[3], 1);
571*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sint32s[4], 25);
572*61c4878aSAndroid Build Coastguard Worker 
573*61c4878aSAndroid Build Coastguard Worker     return status;
574*61c4878aSAndroid Build Coastguard Worker   });
575*61c4878aSAndroid Build Coastguard Worker 
576*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
577*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
578*61c4878aSAndroid Build Coastguard Worker }
579*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadPackedScalarFixedLength)580*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadPackedScalarFixedLength) {
581*61c4878aSAndroid Build Coastguard Worker   // clang-format off
582*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
583*61c4878aSAndroid Build Coastguard Worker     // uint64s[], v={1000, 2000, 3000, 4000}
584*61c4878aSAndroid Build Coastguard Worker     0x42, 0x08, 0xe8, 0x07, 0xd0, 0x0f, 0xb8, 0x17, 0xa0, 0x1f,
585*61c4878aSAndroid Build Coastguard Worker     // doubles[], v={3.14159, 2.71828}
586*61c4878aSAndroid Build Coastguard Worker     0x22, 0x10,
587*61c4878aSAndroid Build Coastguard Worker     0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
588*61c4878aSAndroid Build Coastguard Worker     0x90, 0xf7, 0xaa, 0x95, 0x09, 0xbf, 0x05, 0x40,
589*61c4878aSAndroid Build Coastguard Worker   };
590*61c4878aSAndroid Build Coastguard Worker   // clang-format on
591*61c4878aSAndroid Build Coastguard Worker 
592*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
593*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
594*61c4878aSAndroid Build Coastguard Worker 
595*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
596*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
597*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
598*61c4878aSAndroid Build Coastguard Worker 
599*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.uint64s[0], 1000u);
600*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.uint64s[1], 2000u);
601*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.uint64s[2], 3000u);
602*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.uint64s[3], 4000u);
603*61c4878aSAndroid Build Coastguard Worker 
604*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.doubles[0], 3.14159);
605*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.doubles[1], 2.71828);
606*61c4878aSAndroid Build Coastguard Worker }
607*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadPackedScalarFixedLengthShort)608*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadPackedScalarFixedLengthShort) {
609*61c4878aSAndroid Build Coastguard Worker   // clang-format off
610*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
611*61c4878aSAndroid Build Coastguard Worker     // uint64s[], v={1000, 2000}
612*61c4878aSAndroid Build Coastguard Worker     0x42, 0x04, 0xe8, 0x07, 0xd0, 0x0f,
613*61c4878aSAndroid Build Coastguard Worker     // doubles[], v={3.14159}
614*61c4878aSAndroid Build Coastguard Worker     0x22, 0x08,
615*61c4878aSAndroid Build Coastguard Worker     0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
616*61c4878aSAndroid Build Coastguard Worker   };
617*61c4878aSAndroid Build Coastguard Worker   // clang-format on
618*61c4878aSAndroid Build Coastguard Worker 
619*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
620*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
621*61c4878aSAndroid Build Coastguard Worker 
622*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
623*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
624*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
625*61c4878aSAndroid Build Coastguard Worker 
626*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.uint64s[0], 1000u);
627*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.uint64s[1], 2000u);
628*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.uint64s[2], 0u);
629*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.uint64s[3], 0u);
630*61c4878aSAndroid Build Coastguard Worker 
631*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.doubles[0], 3.14159);
632*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.doubles[1], 0);
633*61c4878aSAndroid Build Coastguard Worker }
634*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadPackedScalarVarintFixedLengthExhausted)635*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadPackedScalarVarintFixedLengthExhausted) {
636*61c4878aSAndroid Build Coastguard Worker   // clang-format off
637*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
638*61c4878aSAndroid Build Coastguard Worker     // uint64s[], v={0, 1000, 2000, 3000, 4000}
639*61c4878aSAndroid Build Coastguard Worker     0x42, 0x09, 0x08, 0xe8, 0x07, 0xd0, 0x0f, 0xb8, 0x17, 0xa0, 0x1f,
640*61c4878aSAndroid Build Coastguard Worker   };
641*61c4878aSAndroid Build Coastguard Worker   // clang-format on
642*61c4878aSAndroid Build Coastguard Worker 
643*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
644*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
645*61c4878aSAndroid Build Coastguard Worker 
646*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
647*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
648*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, Status::ResourceExhausted());
649*61c4878aSAndroid Build Coastguard Worker }
650*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadPackedScalarFixedLengthExhausted)651*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadPackedScalarFixedLengthExhausted) {
652*61c4878aSAndroid Build Coastguard Worker   // clang-format off
653*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
654*61c4878aSAndroid Build Coastguard Worker     // doubles[], v={3.14159, 2.71828, 1.41429, 1.73205}
655*61c4878aSAndroid Build Coastguard Worker     0x22, 0x20,
656*61c4878aSAndroid Build Coastguard Worker     0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
657*61c4878aSAndroid Build Coastguard Worker     0x90, 0xf7, 0xaa, 0x95, 0x09, 0xbf, 0x05, 0x40,
658*61c4878aSAndroid Build Coastguard Worker     0x1b, 0xf5, 0x10, 0x8d, 0xee, 0xa0, 0xf6, 0x3f,
659*61c4878aSAndroid Build Coastguard Worker     0xbc, 0x96, 0x90, 0x0f, 0x7a, 0xb6, 0xfb, 0x3f,
660*61c4878aSAndroid Build Coastguard Worker   };
661*61c4878aSAndroid Build Coastguard Worker   // clang-format on
662*61c4878aSAndroid Build Coastguard Worker 
663*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
664*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
665*61c4878aSAndroid Build Coastguard Worker 
666*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
667*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
668*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, Status::ResourceExhausted());
669*61c4878aSAndroid Build Coastguard Worker }
670*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadPackedEnum)671*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadPackedEnum) {
672*61c4878aSAndroid Build Coastguard Worker   // clang-format off
673*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
674*61c4878aSAndroid Build Coastguard Worker     // enums[], v={RED, GREEN, AMBER, RED}
675*61c4878aSAndroid Build Coastguard Worker     0x4a, 0x04, 0x00, 0x02, 0x01, 0x00,
676*61c4878aSAndroid Build Coastguard Worker   };
677*61c4878aSAndroid Build Coastguard Worker   // clang-format on
678*61c4878aSAndroid Build Coastguard Worker 
679*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
680*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
681*61c4878aSAndroid Build Coastguard Worker 
682*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
683*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
684*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
685*61c4878aSAndroid Build Coastguard Worker 
686*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(message.enums.size(), 4u);
687*61c4878aSAndroid Build Coastguard Worker   for (unsigned short i = 0; i < 4; ++i) {
688*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(IsValidEnum(message.enums[i]));
689*61c4878aSAndroid Build Coastguard Worker   }
690*61c4878aSAndroid Build Coastguard Worker 
691*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.enums[0], Enum::RED);
692*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.enums[1], Enum::GREEN);
693*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.enums[2], Enum::AMBER);
694*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.enums[3], Enum::RED);
695*61c4878aSAndroid Build Coastguard Worker }
696*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadStringExhausted)697*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadStringExhausted) {
698*61c4878aSAndroid Build Coastguard Worker   // clang-format off
699*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
700*61c4878aSAndroid Build Coastguard Worker     // pigweed.error_message
701*61c4878aSAndroid Build Coastguard Worker     0x2a, 0xd3, 0x01, 'T', 'h', 'i', 's', ' ', 'l', 'a', 'b', 'e', 'l', ' ', 'i',
702*61c4878aSAndroid Build Coastguard Worker     's', ' ', 't', 'h', 'e', ' ', 't', 'a', 'r', 'g', 'e', 't', ' ', 'o', 'f',
703*61c4878aSAndroid Build Coastguard Worker     ' ', 'a', ' ', 'g', 'o', 't', 'o', ' ', 'f', 'r', 'o', 'm', ' ', 'o', 'u',
704*61c4878aSAndroid Build Coastguard Worker     't', 's', 'i', 'd', 'e', ' ', 'o', 'f', ' ', 't', 'h', 'e', ' ', 'b', 'l',
705*61c4878aSAndroid Build Coastguard Worker     'o', 'c', 'k', ' ', 'c', 'o', 'n', 't', 'a', 'i', 'n', 'i', 'n', 'g', ' ',
706*61c4878aSAndroid Build Coastguard Worker     't', 'h', 'i', 's', ' ', 'l', 'a', 'b', 'e', 'l', ' ', 'A', 'N', 'D', ' ',
707*61c4878aSAndroid Build Coastguard Worker     't', 'h', 'i', 's', ' ', 'b', 'l', 'o', 'c', 'k', ' ', 'h', 'a', 's', ' ',
708*61c4878aSAndroid Build Coastguard Worker     'a', 'n', ' ', 'a', 'u', 't', 'o', 'm', 'a', 't', 'i', 'c', ' ', 'v', 'a',
709*61c4878aSAndroid Build Coastguard Worker     'r', 'i', 'a', 'b', 'l', 'e', ' ', 'w', 'i', 't', 'h', ' ', 'a', 'n', ' ',
710*61c4878aSAndroid Build Coastguard Worker     'i', 'n', 'i', 't', 'i', 'a', 'l', 'i', 'z', 'e', 'r', ' ', 'A', 'N', 'D',
711*61c4878aSAndroid Build Coastguard Worker     ' ', 'y', 'o', 'u', 'r', ' ', 'w', 'i', 'n', 'd', 'o', 'w', ' ', 'w', 'a',
712*61c4878aSAndroid Build Coastguard Worker     's', 'n', '\'', 't', ' ', 'w', 'i', 'd', 'e', ' ', 'e', 'n', 'o', 'u', 'g',
713*61c4878aSAndroid Build Coastguard Worker     'h', ' ', 't', 'o', ' ', 'r', 'e', 'a', 'd', ' ', 't', 'h', 'i', 's', ' ',
714*61c4878aSAndroid Build Coastguard Worker     'w', 'h', 'o', 'l', 'e', ' ', 'e', 'r', 'r', 'o', 'r', ' ', 'm', 'e', 's',
715*61c4878aSAndroid Build Coastguard Worker     's', 'a', 'g', 'e'
716*61c4878aSAndroid Build Coastguard Worker   };
717*61c4878aSAndroid Build Coastguard Worker   // clang-format on
718*61c4878aSAndroid Build Coastguard Worker 
719*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
720*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamDecoder pigweed(reader);
721*61c4878aSAndroid Build Coastguard Worker 
722*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
723*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Read(message);
724*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, Status::ResourceExhausted());
725*61c4878aSAndroid Build Coastguard Worker }
726*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadStringCallback)727*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadStringCallback) {
728*61c4878aSAndroid Build Coastguard Worker   // clang-format off
729*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
730*61c4878aSAndroid Build Coastguard Worker     // pigweed.description
731*61c4878aSAndroid Build Coastguard Worker     0x62, 0x5c, 'a', 'n', ' ', 'o', 'p', 'e', 'n', ' ', 's', 'o', 'u', 'r', 'c',
732*61c4878aSAndroid Build Coastguard Worker     'e', ' ', 'c', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', ' ', 'o', 'f',
733*61c4878aSAndroid Build Coastguard Worker     ' ', 'e', 'm', 'b', 'e', 'd', 'd', 'e', 'd', '-', 't', 'a', 'r', 'g', 'e',
734*61c4878aSAndroid Build Coastguard Worker     't', 'e', 'd', ' ', 'l', 'i', 'b', 'r', 'a', 'r', 'i', 'e', 's', '-', 'o',
735*61c4878aSAndroid Build Coastguard Worker     'r', ' ', 'a', 's', ' ', 'w', 'e', ' ', 'l', 'i', 'k', 'e', ' ', 't', 'o',
736*61c4878aSAndroid Build Coastguard Worker     ' ', 'c', 'a', 'l', 'l', ' ', 't', 'h', 'e', 'm', ',', ' ', 'm', 'o', 'd',
737*61c4878aSAndroid Build Coastguard Worker     'u', 'l', 'e', 's'
738*61c4878aSAndroid Build Coastguard Worker   };
739*61c4878aSAndroid Build Coastguard Worker   // clang-format on
740*61c4878aSAndroid Build Coastguard Worker 
741*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
742*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamDecoder pigweed(reader);
743*61c4878aSAndroid Build Coastguard Worker 
744*61c4878aSAndroid Build Coastguard Worker   // pigweed.description has no max_size specified so a callback must be
745*61c4878aSAndroid Build Coastguard Worker   // set to read the value if present.
746*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
747*61c4878aSAndroid Build Coastguard Worker   message.description.SetDecoder([](Pigweed::StreamDecoder& decoder) {
748*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(decoder.Field().value(), Pigweed::Fields::kDescription);
749*61c4878aSAndroid Build Coastguard Worker 
750*61c4878aSAndroid Build Coastguard Worker     constexpr std::string_view kExpectedDescription{
751*61c4878aSAndroid Build Coastguard Worker         "an open source collection of embedded-targeted libraries-or as we "
752*61c4878aSAndroid Build Coastguard Worker         "like to call them, modules"};
753*61c4878aSAndroid Build Coastguard Worker 
754*61c4878aSAndroid Build Coastguard Worker     std::array<char, 128> description{};
755*61c4878aSAndroid Build Coastguard Worker     const auto sws = decoder.ReadDescription(description);
756*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sws.status(), OkStatus());
757*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sws.size(), kExpectedDescription.size());
758*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(std::memcmp(description.data(),
759*61c4878aSAndroid Build Coastguard Worker                           kExpectedDescription.data(),
760*61c4878aSAndroid Build Coastguard Worker                           kExpectedDescription.size()),
761*61c4878aSAndroid Build Coastguard Worker               0);
762*61c4878aSAndroid Build Coastguard Worker 
763*61c4878aSAndroid Build Coastguard Worker     return sws.status();
764*61c4878aSAndroid Build Coastguard Worker   });
765*61c4878aSAndroid Build Coastguard Worker 
766*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Read(message);
767*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
768*61c4878aSAndroid Build Coastguard Worker }
769*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadMultipleString)770*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadMultipleString) {
771*61c4878aSAndroid Build Coastguard Worker   // clang-format off
772*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
773*61c4878aSAndroid Build Coastguard Worker     // pigweed.error_message
774*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
775*61c4878aSAndroid Build Coastguard Worker     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
776*61c4878aSAndroid Build Coastguard Worker     // pigweed.error_message
777*61c4878aSAndroid Build Coastguard Worker     0x02a, 0x07, 'o', 'n', ' ', 'f', 'i', 'r', 'e'
778*61c4878aSAndroid Build Coastguard Worker   };
779*61c4878aSAndroid Build Coastguard Worker   // clang-format on
780*61c4878aSAndroid Build Coastguard Worker 
781*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
782*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamDecoder pigweed(reader);
783*61c4878aSAndroid Build Coastguard Worker 
784*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
785*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Read(message);
786*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
787*61c4878aSAndroid Build Coastguard Worker 
788*61c4878aSAndroid Build Coastguard Worker   constexpr std::string_view kExpectedErrorMessage{"on fire"};
789*61c4878aSAndroid Build Coastguard Worker 
790*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.error_message.size(), kExpectedErrorMessage.size());
791*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(message.error_message.data(),
792*61c4878aSAndroid Build Coastguard Worker                         kExpectedErrorMessage.data(),
793*61c4878aSAndroid Build Coastguard Worker                         kExpectedErrorMessage.size()),
794*61c4878aSAndroid Build Coastguard Worker             0);
795*61c4878aSAndroid Build Coastguard Worker }
796*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadRepeatedStrings)797*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadRepeatedStrings) {
798*61c4878aSAndroid Build Coastguard Worker   // clang-format off
799*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
800*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
801*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x25, 'i', 'f', ' ', 'm', 'u', 's', 'i', 'c', ' ', 'b', 'e', ' ',
802*61c4878aSAndroid Build Coastguard Worker     't', 'h', 'e', ' ', 'f', 'o', 'o', 'd', ' ', 'o', 'f', ' ',
803*61c4878aSAndroid Build Coastguard Worker     'l', 'o', 'v', 'e', ',', ' ', 'p', 'l', 'a', 'y', ' ', 'o', 'n',
804*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
805*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x26, 'g', 'i', 'v', 'e', ' ', 'm', 'e', ' ', 'e', 'x', 'c', 'e',
806*61c4878aSAndroid Build Coastguard Worker     's', 's', ' ', 'o', 'f', ' ', 'i', 't', ',', ' ', 't', 'h', 'a', 't', ',',
807*61c4878aSAndroid Build Coastguard Worker     ' ', 's', 'u', 'r', 'f', 'e', 'i', 't', 'i', 'n', 'g',
808*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
809*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x23, 't', 'h', 'e', ' ', 'a', 'p', 'p', 'e', 't', 'i', 't', 'e', ' ',
810*61c4878aSAndroid Build Coastguard Worker     'm', 'a', 'y', ' ', 's', 'i', 'c', 'k', 'e', 'n', ',', ' ', 'a', 'n', 'd',
811*61c4878aSAndroid Build Coastguard Worker     ' ', 's', 'o', ' ', 'd', 'i', 'e',
812*61c4878aSAndroid Build Coastguard Worker   };
813*61c4878aSAndroid Build Coastguard Worker   // clang-format on
814*61c4878aSAndroid Build Coastguard Worker 
815*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
816*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
817*61c4878aSAndroid Build Coastguard Worker 
818*61c4878aSAndroid Build Coastguard Worker   // Repeated strings require a callback to avoid forcing multi-dimensional
819*61c4878aSAndroid Build Coastguard Worker   // arrays upon the caller.
820*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
821*61c4878aSAndroid Build Coastguard Worker   int i = 0;
822*61c4878aSAndroid Build Coastguard Worker   message.strings.SetDecoder([&i](RepeatedTest::StreamDecoder& decoder) {
823*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(decoder.Field().value(), RepeatedTest::Fields::kStrings);
824*61c4878aSAndroid Build Coastguard Worker 
825*61c4878aSAndroid Build Coastguard Worker     constexpr std::string_view kExpectedStrings[] = {
826*61c4878aSAndroid Build Coastguard Worker         {"if music be the food of love, play on"},
827*61c4878aSAndroid Build Coastguard Worker         {"give me excess of it, that, surfeiting"},
828*61c4878aSAndroid Build Coastguard Worker         {"the appetite may sicken, and so die"}};
829*61c4878aSAndroid Build Coastguard Worker 
830*61c4878aSAndroid Build Coastguard Worker     std::array<char, 40> strings{};
831*61c4878aSAndroid Build Coastguard Worker     const StatusWithSize sws = decoder.ReadStrings(strings);
832*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sws.status(), OkStatus());
833*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sws.size(), kExpectedStrings[i].size());
834*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(std::memcmp(strings.data(),
835*61c4878aSAndroid Build Coastguard Worker                           kExpectedStrings[i].data(),
836*61c4878aSAndroid Build Coastguard Worker                           kExpectedStrings[i].size()),
837*61c4878aSAndroid Build Coastguard Worker               0);
838*61c4878aSAndroid Build Coastguard Worker 
839*61c4878aSAndroid Build Coastguard Worker     ++i;
840*61c4878aSAndroid Build Coastguard Worker     return sws.status();
841*61c4878aSAndroid Build Coastguard Worker   });
842*61c4878aSAndroid Build Coastguard Worker 
843*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
844*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
845*61c4878aSAndroid Build Coastguard Worker }
846*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadForcedCallback)847*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadForcedCallback) {
848*61c4878aSAndroid Build Coastguard Worker   // clang-format off
849*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
850*61c4878aSAndroid Build Coastguard Worker     // pigweed.special_property
851*61c4878aSAndroid Build Coastguard Worker     0x68, 0x2a,
852*61c4878aSAndroid Build Coastguard Worker   };
853*61c4878aSAndroid Build Coastguard Worker   // clang-format on
854*61c4878aSAndroid Build Coastguard Worker 
855*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
856*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamDecoder pigweed(reader);
857*61c4878aSAndroid Build Coastguard Worker 
858*61c4878aSAndroid Build Coastguard Worker   // pigweed.special_property has use_callback=true to force the use of a
859*61c4878aSAndroid Build Coastguard Worker   // callback even though it's a simple scalar.
860*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
861*61c4878aSAndroid Build Coastguard Worker   message.special_property.SetDecoder([](Pigweed::StreamDecoder& decoder) {
862*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(decoder.Field().value(), Pigweed::Fields::kSpecialProperty);
863*61c4878aSAndroid Build Coastguard Worker 
864*61c4878aSAndroid Build Coastguard Worker     pw::Result<uint32_t> result = decoder.ReadSpecialProperty();
865*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(result.status(), OkStatus());
866*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(result.value(), 42u);
867*61c4878aSAndroid Build Coastguard Worker 
868*61c4878aSAndroid Build Coastguard Worker     return result.status();
869*61c4878aSAndroid Build Coastguard Worker   });
870*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Read(message);
871*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
872*61c4878aSAndroid Build Coastguard Worker }
873*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadMissingCallback)874*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadMissingCallback) {
875*61c4878aSAndroid Build Coastguard Worker   // clang-format off
876*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
877*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
878*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x25, 'i', 'f', ' ', 'm', 'u', 's', 'i', 'c', ' ', 'b', 'e', ' ',
879*61c4878aSAndroid Build Coastguard Worker     't', 'h', 'e', ' ', 'f', 'o', 'o', 'd', ' ', 'o', 'f', ' ',
880*61c4878aSAndroid Build Coastguard Worker     'l', 'o', 'v', 'e', ',', ' ', 'p', 'l', 'a', 'y', ' ', 'o', 'n',
881*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
882*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x26, 'g', 'i', 'v', 'e', ' ', 'm', 'e', ' ', 'e', 'x', 'c', 'e',
883*61c4878aSAndroid Build Coastguard Worker     's', 's', ' ', 'o', 'f', ' ', 'i', 't', ',', ' ', 't', 'h', 'a', 't', ',',
884*61c4878aSAndroid Build Coastguard Worker     ' ', 's', 'u', 'r', 'f', 'e', 'i', 't', 'i', 'n', 'g',
885*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
886*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x23, 't', 'h', 'e', ' ', 'a', 'p', 'p', 'e', 't', 'i', 't', 'e', ' ',
887*61c4878aSAndroid Build Coastguard Worker     'm', 'a', 'y', ' ', 's', 'i', 'c', 'k', 'e', 'n', ',', ' ', 'a', 'n', 'd',
888*61c4878aSAndroid Build Coastguard Worker     ' ', 's', 'o', ' ', 'd', 'i', 'e',
889*61c4878aSAndroid Build Coastguard Worker   };
890*61c4878aSAndroid Build Coastguard Worker   // clang-format on
891*61c4878aSAndroid Build Coastguard Worker 
892*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
893*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
894*61c4878aSAndroid Build Coastguard Worker 
895*61c4878aSAndroid Build Coastguard Worker   // Failing to set a callback will give a DataLoss error if that field is
896*61c4878aSAndroid Build Coastguard Worker   // present in the decoded data.
897*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
898*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
899*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, Status::DataLoss());
900*61c4878aSAndroid Build Coastguard Worker }
901*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadFixedLength)902*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadFixedLength) {
903*61c4878aSAndroid Build Coastguard Worker   // clang-format off
904*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
905*61c4878aSAndroid Build Coastguard Worker     // pigweed.data
906*61c4878aSAndroid Build Coastguard Worker     0x5a, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
907*61c4878aSAndroid Build Coastguard Worker   };
908*61c4878aSAndroid Build Coastguard Worker   // clang-format on
909*61c4878aSAndroid Build Coastguard Worker 
910*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
911*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamDecoder pigweed(reader);
912*61c4878aSAndroid Build Coastguard Worker 
913*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
914*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Read(message);
915*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
916*61c4878aSAndroid Build Coastguard Worker 
917*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[0], std::byte{0x01});
918*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[1], std::byte{0x02});
919*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[2], std::byte{0x03});
920*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[3], std::byte{0x04});
921*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[4], std::byte{0x05});
922*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[5], std::byte{0x06});
923*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[6], std::byte{0x07});
924*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[7], std::byte{0x08});
925*61c4878aSAndroid Build Coastguard Worker }
926*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadFixedLengthShort)927*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadFixedLengthShort) {
928*61c4878aSAndroid Build Coastguard Worker   // clang-format off
929*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
930*61c4878aSAndroid Build Coastguard Worker     // pigweed.data
931*61c4878aSAndroid Build Coastguard Worker     0x5a, 0x04, 0x01, 0x02, 0x03, 0x04
932*61c4878aSAndroid Build Coastguard Worker   };
933*61c4878aSAndroid Build Coastguard Worker   // clang-format on
934*61c4878aSAndroid Build Coastguard Worker 
935*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
936*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamDecoder pigweed(reader);
937*61c4878aSAndroid Build Coastguard Worker 
938*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
939*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Read(message);
940*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
941*61c4878aSAndroid Build Coastguard Worker 
942*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[0], std::byte{0x01});
943*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[1], std::byte{0x02});
944*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[2], std::byte{0x03});
945*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[3], std::byte{0x04});
946*61c4878aSAndroid Build Coastguard Worker   // Remaining bytes are whatever you initialized them to.
947*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[4], std::byte{0x00});
948*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[5], std::byte{0x00});
949*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[6], std::byte{0x00});
950*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.data[7], std::byte{0x00});
951*61c4878aSAndroid Build Coastguard Worker }
952*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadFixedLengthExhausted)953*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadFixedLengthExhausted) {
954*61c4878aSAndroid Build Coastguard Worker   // clang-format off
955*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
956*61c4878aSAndroid Build Coastguard Worker     // pigweed.data
957*61c4878aSAndroid Build Coastguard Worker     0x5a, 0x0c, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
958*61c4878aSAndroid Build Coastguard Worker     0x09, 0x0a, 0x0b, 0x0c
959*61c4878aSAndroid Build Coastguard Worker   };
960*61c4878aSAndroid Build Coastguard Worker   // clang-format on
961*61c4878aSAndroid Build Coastguard Worker 
962*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
963*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamDecoder pigweed(reader);
964*61c4878aSAndroid Build Coastguard Worker 
965*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
966*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Read(message);
967*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, Status::ResourceExhausted());
968*61c4878aSAndroid Build Coastguard Worker }
969*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadNested)970*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadNested) {
971*61c4878aSAndroid Build Coastguard Worker   // clang-format off
972*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
973*61c4878aSAndroid Build Coastguard Worker     // pigweed.magic_number
974*61c4878aSAndroid Build Coastguard Worker     0x08, 0x49,
975*61c4878aSAndroid Build Coastguard Worker     // pigweed.pigweed
976*61c4878aSAndroid Build Coastguard Worker     0x3a, 0x02,
977*61c4878aSAndroid Build Coastguard Worker     // pigweed.pigweed.status
978*61c4878aSAndroid Build Coastguard Worker     0x08, 0x02,
979*61c4878aSAndroid Build Coastguard Worker     // pigweed.ziggy
980*61c4878aSAndroid Build Coastguard Worker     0x10, 0xdd, 0x01,
981*61c4878aSAndroid Build Coastguard Worker   };
982*61c4878aSAndroid Build Coastguard Worker   // clang-format on
983*61c4878aSAndroid Build Coastguard Worker 
984*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
985*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamDecoder pigweed(reader);
986*61c4878aSAndroid Build Coastguard Worker 
987*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
988*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Read(message);
989*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
990*61c4878aSAndroid Build Coastguard Worker 
991*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.magic_number, 0x49u);
992*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.pigweed.status, Bool::FILE_NOT_FOUND);
993*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.ziggy, -111);
994*61c4878aSAndroid Build Coastguard Worker }
995*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadNestedImported)996*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadNestedImported) {
997*61c4878aSAndroid Build Coastguard Worker   // clang-format off
998*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
999*61c4878aSAndroid Build Coastguard Worker     // period.start
1000*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x08,
1001*61c4878aSAndroid Build Coastguard Worker     // period.start.seconds v=1517949900
1002*61c4878aSAndroid Build Coastguard Worker     0x08, 0xcc, 0xa7, 0xe8, 0xd3, 0x05,
1003*61c4878aSAndroid Build Coastguard Worker     // period.start.nanoseconds v=0
1004*61c4878aSAndroid Build Coastguard Worker     0x10, 0x00,
1005*61c4878aSAndroid Build Coastguard Worker     // period.end
1006*61c4878aSAndroid Build Coastguard Worker     0x12, 0x08,
1007*61c4878aSAndroid Build Coastguard Worker     // period.end.seconds, v=1517950378
1008*61c4878aSAndroid Build Coastguard Worker     0x08, 0xaa, 0xab, 0xe8, 0xd3, 0x05,
1009*61c4878aSAndroid Build Coastguard Worker     // period.end.nanoseconds, v=0
1010*61c4878aSAndroid Build Coastguard Worker     0x10, 0x00,
1011*61c4878aSAndroid Build Coastguard Worker   };
1012*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1013*61c4878aSAndroid Build Coastguard Worker 
1014*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
1015*61c4878aSAndroid Build Coastguard Worker   Period::StreamDecoder period(reader);
1016*61c4878aSAndroid Build Coastguard Worker 
1017*61c4878aSAndroid Build Coastguard Worker   // Messages imported from another file can be directly embedded in a message.
1018*61c4878aSAndroid Build Coastguard Worker   Period::Message message{};
1019*61c4878aSAndroid Build Coastguard Worker   const auto status = period.Read(message);
1020*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1021*61c4878aSAndroid Build Coastguard Worker 
1022*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.start.seconds, 1517949900u);
1023*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.start.nanoseconds, 0u);
1024*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.end.seconds, 1517950378u);
1025*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.end.nanoseconds, 0u);
1026*61c4878aSAndroid Build Coastguard Worker }
1027*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadNestedRepeated)1028*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadNestedRepeated) {
1029*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1030*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
1031*61c4878aSAndroid Build Coastguard Worker     // repeated.structs
1032*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x04,
1033*61c4878aSAndroid Build Coastguard Worker     // repeated.structs.one v=16
1034*61c4878aSAndroid Build Coastguard Worker     0x08, 0x10,
1035*61c4878aSAndroid Build Coastguard Worker     // repeated.structs.two v=32
1036*61c4878aSAndroid Build Coastguard Worker     0x10, 0x20,
1037*61c4878aSAndroid Build Coastguard Worker     // repeated.structs
1038*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x04,
1039*61c4878aSAndroid Build Coastguard Worker     // repeated.structs.one v=48
1040*61c4878aSAndroid Build Coastguard Worker     0x08, 0x30,
1041*61c4878aSAndroid Build Coastguard Worker     // repeated.structs.two v=64
1042*61c4878aSAndroid Build Coastguard Worker     0x10, 0x40,
1043*61c4878aSAndroid Build Coastguard Worker   };
1044*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1045*61c4878aSAndroid Build Coastguard Worker 
1046*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
1047*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
1048*61c4878aSAndroid Build Coastguard Worker 
1049*61c4878aSAndroid Build Coastguard Worker   // Repeated nested messages require a callback since there would otherwise be
1050*61c4878aSAndroid Build Coastguard Worker   // no way to set callbacks on the nested message.
1051*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
1052*61c4878aSAndroid Build Coastguard Worker   unsigned i = 0;
1053*61c4878aSAndroid Build Coastguard Worker   message.structs.SetDecoder([&i](RepeatedTest::StreamDecoder& decoder) {
1054*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(decoder.Field().value(), RepeatedTest::Fields::kStructs);
1055*61c4878aSAndroid Build Coastguard Worker 
1056*61c4878aSAndroid Build Coastguard Worker     Struct::Message structs_message{};
1057*61c4878aSAndroid Build Coastguard Worker     auto structs_decoder = decoder.GetStructsDecoder();
1058*61c4878aSAndroid Build Coastguard Worker     const auto status = structs_decoder.Read(structs_message);
1059*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(status, OkStatus());
1060*61c4878aSAndroid Build Coastguard Worker 
1061*61c4878aSAndroid Build Coastguard Worker     EXPECT_LT(i, 2u);
1062*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(structs_message.one, i * 32 + 16u);
1063*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(structs_message.two, i * 32 + 32u);
1064*61c4878aSAndroid Build Coastguard Worker     ++i;
1065*61c4878aSAndroid Build Coastguard Worker 
1066*61c4878aSAndroid Build Coastguard Worker     return status;
1067*61c4878aSAndroid Build Coastguard Worker   });
1068*61c4878aSAndroid Build Coastguard Worker 
1069*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
1070*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1071*61c4878aSAndroid Build Coastguard Worker }
1072*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadNestedForcedCallback)1073*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadNestedForcedCallback) {
1074*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1075*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
1076*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info
1077*61c4878aSAndroid Build Coastguard Worker     0x32, 0x0e,
1078*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.device_name
1079*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'p', 'i', 'x', 'e', 'l',
1080*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.device_id
1081*61c4878aSAndroid Build Coastguard Worker     0x15, 0x08, 0x08, 0x08, 0x08,
1082*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.status
1083*61c4878aSAndroid Build Coastguard Worker     0x18, 0x00,
1084*61c4878aSAndroid Build Coastguard Worker       };
1085*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1086*61c4878aSAndroid Build Coastguard Worker 
1087*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
1088*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamDecoder pigweed(reader);
1089*61c4878aSAndroid Build Coastguard Worker 
1090*61c4878aSAndroid Build Coastguard Worker   // pigweed.device_info has use_callback=true to force the use of a callback.
1091*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
1092*61c4878aSAndroid Build Coastguard Worker   message.device_info.SetDecoder([](Pigweed::StreamDecoder& decoder) {
1093*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(decoder.Field().value(), Pigweed::Fields::kDeviceInfo);
1094*61c4878aSAndroid Build Coastguard Worker 
1095*61c4878aSAndroid Build Coastguard Worker     DeviceInfo::Message device_info{};
1096*61c4878aSAndroid Build Coastguard Worker     DeviceInfo::StreamDecoder device_info_decoder =
1097*61c4878aSAndroid Build Coastguard Worker         decoder.GetDeviceInfoDecoder();
1098*61c4878aSAndroid Build Coastguard Worker     const auto status = device_info_decoder.Read(device_info);
1099*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(status, OkStatus());
1100*61c4878aSAndroid Build Coastguard Worker 
1101*61c4878aSAndroid Build Coastguard Worker     constexpr std::string_view kExpectedDeviceName{"pixel"};
1102*61c4878aSAndroid Build Coastguard Worker 
1103*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(device_info.device_name.size(), kExpectedDeviceName.size());
1104*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(std::memcmp(device_info.device_name.data(),
1105*61c4878aSAndroid Build Coastguard Worker                           kExpectedDeviceName.data(),
1106*61c4878aSAndroid Build Coastguard Worker                           kExpectedDeviceName.size()),
1107*61c4878aSAndroid Build Coastguard Worker               0);
1108*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(device_info.device_id, 0x08080808u);
1109*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(device_info.status, DeviceInfo::DeviceStatus::OK);
1110*61c4878aSAndroid Build Coastguard Worker 
1111*61c4878aSAndroid Build Coastguard Worker     return status;
1112*61c4878aSAndroid Build Coastguard Worker   });
1113*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Read(message);
1114*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1115*61c4878aSAndroid Build Coastguard Worker }
1116*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadOptionalPresent)1117*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadOptionalPresent) {
1118*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1119*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
1120*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_present_fixed
1121*61c4878aSAndroid Build Coastguard Worker     0x0d, 0x2a, 0x00, 0x00, 0x00,
1122*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_present_varint
1123*61c4878aSAndroid Build Coastguard Worker     0x10, 0x2a,
1124*61c4878aSAndroid Build Coastguard Worker     // optional.explicitly_present_fixed
1125*61c4878aSAndroid Build Coastguard Worker     0x1d, 0x45, 0x00, 0x00, 0x00,
1126*61c4878aSAndroid Build Coastguard Worker     // optional.explicitly_present_varint
1127*61c4878aSAndroid Build Coastguard Worker     0x20, 0x45,
1128*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_empty_fixed
1129*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x04, 0x63, 0x00, 0x00, 0x00,
1130*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_empty_varint
1131*61c4878aSAndroid Build Coastguard Worker     0x32, 0x01, 0x63,
1132*61c4878aSAndroid Build Coastguard Worker   };
1133*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1134*61c4878aSAndroid Build Coastguard Worker 
1135*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
1136*61c4878aSAndroid Build Coastguard Worker   OptionalTest::StreamDecoder optional_test(reader);
1137*61c4878aSAndroid Build Coastguard Worker 
1138*61c4878aSAndroid Build Coastguard Worker   OptionalTest::Message message{};
1139*61c4878aSAndroid Build Coastguard Worker   const auto status = optional_test.Read(message);
1140*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1141*61c4878aSAndroid Build Coastguard Worker 
1142*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_present_fixed, 0x2a);
1143*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_present_varint, 0x2a);
1144*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(message.explicitly_present_fixed);
1145*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(*message.explicitly_present_fixed, 0x45);
1146*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(message.explicitly_present_varint);
1147*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(*message.explicitly_present_varint, 0x45);
1148*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(message.sometimes_empty_fixed.empty());
1149*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_empty_fixed.size(), 1u);
1150*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_empty_fixed[0], 0x63);
1151*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(message.sometimes_empty_varint.empty());
1152*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_empty_varint.size(), 1u);
1153*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_empty_varint[0], 0x63);
1154*61c4878aSAndroid Build Coastguard Worker }
1155*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadOptionalNotPresent)1156*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadOptionalNotPresent) {
1157*61c4878aSAndroid Build Coastguard Worker   constexpr std::array<std::byte, 0> proto_data{};
1158*61c4878aSAndroid Build Coastguard Worker 
1159*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(proto_data);
1160*61c4878aSAndroid Build Coastguard Worker   OptionalTest::StreamDecoder optional_test(reader);
1161*61c4878aSAndroid Build Coastguard Worker 
1162*61c4878aSAndroid Build Coastguard Worker   OptionalTest::Message message{};
1163*61c4878aSAndroid Build Coastguard Worker   const auto status = optional_test.Read(message);
1164*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1165*61c4878aSAndroid Build Coastguard Worker 
1166*61c4878aSAndroid Build Coastguard Worker   // Non-optional fields have their default value.
1167*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_present_fixed, 0);
1168*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_present_varint, 0);
1169*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(message.sometimes_empty_fixed.empty());
1170*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(message.sometimes_empty_varint.empty());
1171*61c4878aSAndroid Build Coastguard Worker 
1172*61c4878aSAndroid Build Coastguard Worker   // Optional fields are explicitly not present.
1173*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(message.explicitly_present_fixed);
1174*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(message.explicitly_present_varint);
1175*61c4878aSAndroid Build Coastguard Worker }
1176*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadOptionalPresentDefaults)1177*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadOptionalPresentDefaults) {
1178*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1179*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
1180*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_present_fixed
1181*61c4878aSAndroid Build Coastguard Worker     0x0d, 0x00, 0x00, 0x00, 0x00,
1182*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_present_varint
1183*61c4878aSAndroid Build Coastguard Worker     0x10, 0x00,
1184*61c4878aSAndroid Build Coastguard Worker     // optional.explicitly_present_fixed
1185*61c4878aSAndroid Build Coastguard Worker     0x1d, 0x00, 0x00, 0x00, 0x00,
1186*61c4878aSAndroid Build Coastguard Worker     // optional.explicitly_present_varint
1187*61c4878aSAndroid Build Coastguard Worker     0x20, 0x00,
1188*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_empty_fixed
1189*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x04, 0x00, 0x00, 0x00, 0x00,
1190*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_empty_varint
1191*61c4878aSAndroid Build Coastguard Worker     0x32, 0x01, 0x00,
1192*61c4878aSAndroid Build Coastguard Worker   };
1193*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1194*61c4878aSAndroid Build Coastguard Worker 
1195*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
1196*61c4878aSAndroid Build Coastguard Worker   OptionalTest::StreamDecoder optional_test(reader);
1197*61c4878aSAndroid Build Coastguard Worker 
1198*61c4878aSAndroid Build Coastguard Worker   OptionalTest::Message message{};
1199*61c4878aSAndroid Build Coastguard Worker   const auto status = optional_test.Read(message);
1200*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1201*61c4878aSAndroid Build Coastguard Worker 
1202*61c4878aSAndroid Build Coastguard Worker   // Non-optional fields have their default value and aren't meaningfully
1203*61c4878aSAndroid Build Coastguard Worker   // different from missing.
1204*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_present_fixed, 0x00);
1205*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_present_varint, 0x00);
1206*61c4878aSAndroid Build Coastguard Worker 
1207*61c4878aSAndroid Build Coastguard Worker   // Optional fields are explicitly present with a default value.
1208*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(message.explicitly_present_fixed);
1209*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(*message.explicitly_present_fixed, 0x00);
1210*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(message.explicitly_present_varint);
1211*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(*message.explicitly_present_varint, 0x00);
1212*61c4878aSAndroid Build Coastguard Worker 
1213*61c4878aSAndroid Build Coastguard Worker   // Repeated fields with a default value are meaningfully non-empty.
1214*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(message.sometimes_empty_fixed.empty());
1215*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_empty_fixed.size(), 1u);
1216*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_empty_fixed[0], 0x00);
1217*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(message.sometimes_empty_varint.empty());
1218*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_empty_varint.size(), 1u);
1219*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.sometimes_empty_varint[0], 0x00);
1220*61c4878aSAndroid Build Coastguard Worker }
1221*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadImportedOptions)1222*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadImportedOptions) {
1223*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1224*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
1225*61c4878aSAndroid Build Coastguard Worker     // notice
1226*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x0f,
1227*61c4878aSAndroid Build Coastguard Worker     // notice.message
1228*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x0d, 'P', 'r', 'e', 's', 's', ' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y'
1229*61c4878aSAndroid Build Coastguard Worker   };
1230*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1231*61c4878aSAndroid Build Coastguard Worker 
1232*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
1233*61c4878aSAndroid Build Coastguard Worker   TestMessage::StreamDecoder test_message(reader);
1234*61c4878aSAndroid Build Coastguard Worker 
1235*61c4878aSAndroid Build Coastguard Worker   // The options file for the imported proto is applied, making the string
1236*61c4878aSAndroid Build Coastguard Worker   // field a vector rather than requiring a callback.
1237*61c4878aSAndroid Build Coastguard Worker   TestMessage::Message message{};
1238*61c4878aSAndroid Build Coastguard Worker   const auto status = test_message.Read(message);
1239*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1240*61c4878aSAndroid Build Coastguard Worker 
1241*61c4878aSAndroid Build Coastguard Worker   constexpr std::string_view kExpectedMessage{"Press any key"};
1242*61c4878aSAndroid Build Coastguard Worker 
1243*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.notice.message.size(), kExpectedMessage.size());
1244*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(message.notice.message.data(),
1245*61c4878aSAndroid Build Coastguard Worker                         kExpectedMessage.data(),
1246*61c4878aSAndroid Build Coastguard Worker                         kExpectedMessage.size()),
1247*61c4878aSAndroid Build Coastguard Worker             0);
1248*61c4878aSAndroid Build Coastguard Worker }
1249*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,ReadImportedFromDepsOptions)1250*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, ReadImportedFromDepsOptions) {
1251*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1252*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
1253*61c4878aSAndroid Build Coastguard Worker     // debug
1254*61c4878aSAndroid Build Coastguard Worker     0x12, 0x0f,
1255*61c4878aSAndroid Build Coastguard Worker     // debug.message
1256*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x0d, 'P', 'r', 'e', 's', 's', ' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y'
1257*61c4878aSAndroid Build Coastguard Worker   };
1258*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1259*61c4878aSAndroid Build Coastguard Worker 
1260*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
1261*61c4878aSAndroid Build Coastguard Worker   TestMessage::StreamDecoder test_message(reader);
1262*61c4878aSAndroid Build Coastguard Worker 
1263*61c4878aSAndroid Build Coastguard Worker   // The options file for the imported proto is applied, making the string
1264*61c4878aSAndroid Build Coastguard Worker   // fields a vector rather than requiring a callback. This will not compile if
1265*61c4878aSAndroid Build Coastguard Worker   // the .pwpb_options files aren't applied correctly.
1266*61c4878aSAndroid Build Coastguard Worker   TestMessage::Message message{};
1267*61c4878aSAndroid Build Coastguard Worker   const auto status = test_message.Read(message);
1268*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1269*61c4878aSAndroid Build Coastguard Worker 
1270*61c4878aSAndroid Build Coastguard Worker   constexpr std::string_view kExpectedMessage{"Press any key"};
1271*61c4878aSAndroid Build Coastguard Worker 
1272*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.debug.message.size(), kExpectedMessage.size());
1273*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(message.debug.message.data(),
1274*61c4878aSAndroid Build Coastguard Worker                         kExpectedMessage.data(),
1275*61c4878aSAndroid Build Coastguard Worker                         kExpectedMessage.size()),
1276*61c4878aSAndroid Build Coastguard Worker             0);
1277*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.prefix_debug.message.size(), 0U);
1278*61c4878aSAndroid Build Coastguard Worker }
1279*61c4878aSAndroid Build Coastguard Worker 
1280*61c4878aSAndroid Build Coastguard Worker class BreakableDecoder : public KeyValuePair::StreamDecoder {
1281*61c4878aSAndroid Build Coastguard Worker  public:
BreakableDecoder(stream::Reader & reader)1282*61c4878aSAndroid Build Coastguard Worker   constexpr BreakableDecoder(stream::Reader& reader) : StreamDecoder(reader) {}
1283*61c4878aSAndroid Build Coastguard Worker 
Read(KeyValuePair::Message & message,span<const internal::MessageField> table)1284*61c4878aSAndroid Build Coastguard Worker   Status Read(KeyValuePair::Message& message,
1285*61c4878aSAndroid Build Coastguard Worker               span<const internal::MessageField> table) {
1286*61c4878aSAndroid Build Coastguard Worker     return ::pw::protobuf::StreamDecoder::Read(
1287*61c4878aSAndroid Build Coastguard Worker         as_writable_bytes(span(&message, 1)), table);
1288*61c4878aSAndroid Build Coastguard Worker   }
1289*61c4878aSAndroid Build Coastguard Worker };
1290*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,DISABLED_ReadDoesNotOverrun)1291*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, DISABLED_ReadDoesNotOverrun) {
1292*61c4878aSAndroid Build Coastguard Worker   // Deliberately construct a message table that attempts to violate the bounds
1293*61c4878aSAndroid Build Coastguard Worker   // of the structure. We're not testing that a developer can't do this, rather
1294*61c4878aSAndroid Build Coastguard Worker   // that the protobuf decoder can't be exploited in this way.
1295*61c4878aSAndroid Build Coastguard Worker   constexpr internal::MessageField kMessageFields[] = {
1296*61c4878aSAndroid Build Coastguard Worker       {1,
1297*61c4878aSAndroid Build Coastguard Worker        WireType::kDelimited,
1298*61c4878aSAndroid Build Coastguard Worker        sizeof(std::byte),
1299*61c4878aSAndroid Build Coastguard Worker        static_cast<internal::VarintType>(0),
1300*61c4878aSAndroid Build Coastguard Worker        false,
1301*61c4878aSAndroid Build Coastguard Worker        false,
1302*61c4878aSAndroid Build Coastguard Worker        false,
1303*61c4878aSAndroid Build Coastguard Worker        false,
1304*61c4878aSAndroid Build Coastguard Worker        internal::CallbackType::kNone,
1305*61c4878aSAndroid Build Coastguard Worker        0,
1306*61c4878aSAndroid Build Coastguard Worker        sizeof(KeyValuePair::Message) * 2,
1307*61c4878aSAndroid Build Coastguard Worker        {}},
1308*61c4878aSAndroid Build Coastguard Worker   };
1309*61c4878aSAndroid Build Coastguard Worker 
1310*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1311*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
1312*61c4878aSAndroid Build Coastguard Worker     // id=1, len=9,
1313*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x08, 'd', 'o', 'n', 't', 'e', 'a', 't', 'm', 'e',
1314*61c4878aSAndroid Build Coastguard Worker   };
1315*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1316*61c4878aSAndroid Build Coastguard Worker 
1317*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
1318*61c4878aSAndroid Build Coastguard Worker   BreakableDecoder decoder(reader);
1319*61c4878aSAndroid Build Coastguard Worker 
1320*61c4878aSAndroid Build Coastguard Worker   KeyValuePair::Message message{};
1321*61c4878aSAndroid Build Coastguard Worker   // ASSERT_CRASH
1322*61c4878aSAndroid Build Coastguard Worker   std::ignore = decoder.Read(message, kMessageFields);
1323*61c4878aSAndroid Build Coastguard Worker }
1324*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,Write)1325*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, Write) {
1326*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t pigweed_data[] = {
1327*61c4878aSAndroid Build Coastguard Worker       0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
1328*61c4878aSAndroid Build Coastguard Worker 
1329*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
1330*61c4878aSAndroid Build Coastguard Worker   message.magic_number = 0x49u;
1331*61c4878aSAndroid Build Coastguard Worker   message.ziggy = -111;
1332*61c4878aSAndroid Build Coastguard Worker   message.cycles = 0x40302010fecaaddeu;
1333*61c4878aSAndroid Build Coastguard Worker   message.ratio = -1.42f;
1334*61c4878aSAndroid Build Coastguard Worker   message.error_message = "not a typewriter";
1335*61c4878aSAndroid Build Coastguard Worker   message.pigweed.status = Bool::FILE_NOT_FOUND;
1336*61c4878aSAndroid Build Coastguard Worker   message.bin = Pigweed::Protobuf::Binary::ZERO;
1337*61c4878aSAndroid Build Coastguard Worker   message.bungle = -111;
1338*61c4878aSAndroid Build Coastguard Worker   message.proto.bin = Proto::Binary::OFF;
1339*61c4878aSAndroid Build Coastguard Worker   message.proto.pigweed_pigweed_bin = Pigweed::Pigweed::Binary::ZERO;
1340*61c4878aSAndroid Build Coastguard Worker   message.proto.pigweed_protobuf_bin = Pigweed::Protobuf::Binary::ZERO;
1341*61c4878aSAndroid Build Coastguard Worker   message.proto.meta.file_name = "/etc/passwd";
1342*61c4878aSAndroid Build Coastguard Worker   message.proto.meta.status = Pigweed::Protobuf::Compiler::Status::FUBAR;
1343*61c4878aSAndroid Build Coastguard Worker   message.proto.meta.protobuf_bin = Pigweed::Protobuf::Binary::ONE;
1344*61c4878aSAndroid Build Coastguard Worker   message.proto.meta.pigweed_bin = Pigweed::Pigweed::Binary::ONE;
1345*61c4878aSAndroid Build Coastguard Worker   std::memcpy(message.data.data(), pigweed_data, sizeof(pigweed_data));
1346*61c4878aSAndroid Build Coastguard Worker 
1347*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[Pigweed::kMaxEncodedSizeBytes];
1348*61c4878aSAndroid Build Coastguard Worker   std::byte temp_buffer[Pigweed::kScratchBufferSizeBytes];
1349*61c4878aSAndroid Build Coastguard Worker 
1350*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1351*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamEncoder pigweed(writer, temp_buffer);
1352*61c4878aSAndroid Build Coastguard Worker 
1353*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Write(message);
1354*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1355*61c4878aSAndroid Build Coastguard Worker 
1356*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1357*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1358*61c4878aSAndroid Build Coastguard Worker     // pigweed.magic_number
1359*61c4878aSAndroid Build Coastguard Worker     0x08, 0x49,
1360*61c4878aSAndroid Build Coastguard Worker     // pigweed.ziggy
1361*61c4878aSAndroid Build Coastguard Worker     0x10, 0xdd, 0x01,
1362*61c4878aSAndroid Build Coastguard Worker     // pigweed.cycles
1363*61c4878aSAndroid Build Coastguard Worker     0x19, 0xde, 0xad, 0xca, 0xfe, 0x10, 0x20, 0x30, 0x40,
1364*61c4878aSAndroid Build Coastguard Worker     // pigweed.ratio
1365*61c4878aSAndroid Build Coastguard Worker     0x25, 0x8f, 0xc2, 0xb5, 0xbf,
1366*61c4878aSAndroid Build Coastguard Worker     // pigweed.error_message
1367*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
1368*61c4878aSAndroid Build Coastguard Worker     't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
1369*61c4878aSAndroid Build Coastguard Worker     // pigweed.pigweed
1370*61c4878aSAndroid Build Coastguard Worker     0x3a, 0x02,
1371*61c4878aSAndroid Build Coastguard Worker     // pigweed.pigweed.status
1372*61c4878aSAndroid Build Coastguard Worker     0x08, 0x02,
1373*61c4878aSAndroid Build Coastguard Worker     // pigweed.bin
1374*61c4878aSAndroid Build Coastguard Worker     0x40, 0x01,
1375*61c4878aSAndroid Build Coastguard Worker     // pigweed.proto
1376*61c4878aSAndroid Build Coastguard Worker     0x4a, 0x15,
1377*61c4878aSAndroid Build Coastguard Worker     // pigweed.proto.pigweed_protobuf_bin
1378*61c4878aSAndroid Build Coastguard Worker     0x20, 0x01,
1379*61c4878aSAndroid Build Coastguard Worker     // pigweed.proto.meta
1380*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x11,
1381*61c4878aSAndroid Build Coastguard Worker     // pigweed.proto.meta.file_name
1382*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x0b, '/', 'e', 't', 'c', '/', 'p', 'a', 's', 's', 'w', 'd',
1383*61c4878aSAndroid Build Coastguard Worker     // pigweed.proto.meta.status
1384*61c4878aSAndroid Build Coastguard Worker     0x10, 0x02,
1385*61c4878aSAndroid Build Coastguard Worker     // pigweed.proto.meta.pigweed_bin
1386*61c4878aSAndroid Build Coastguard Worker     0x20, 0x01,
1387*61c4878aSAndroid Build Coastguard Worker     // pigweed.bytes
1388*61c4878aSAndroid Build Coastguard Worker     0x5a, 0x08, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
1389*61c4878aSAndroid Build Coastguard Worker     // pigweed.bungle
1390*61c4878aSAndroid Build Coastguard Worker     0x70, 0x91, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
1391*61c4878aSAndroid Build Coastguard Worker   };
1392*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1393*61c4878aSAndroid Build Coastguard Worker 
1394*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1395*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1396*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1397*61c4878aSAndroid Build Coastguard Worker             0);
1398*61c4878aSAndroid Build Coastguard Worker }
1399*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WriteDefaults)1400*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WriteDefaults) {
1401*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
1402*61c4878aSAndroid Build Coastguard Worker 
1403*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[Pigweed::kMaxEncodedSizeBytes];
1404*61c4878aSAndroid Build Coastguard Worker   std::byte temp_buffer[Pigweed::kScratchBufferSizeBytes];
1405*61c4878aSAndroid Build Coastguard Worker 
1406*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1407*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamEncoder pigweed(writer, temp_buffer);
1408*61c4878aSAndroid Build Coastguard Worker 
1409*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Write(message);
1410*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1411*61c4878aSAndroid Build Coastguard Worker 
1412*61c4878aSAndroid Build Coastguard Worker   // Since all fields are at their default, the output should be zero sized.
1413*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1414*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), 0u);
1415*61c4878aSAndroid Build Coastguard Worker }
1416*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WritePackedScalar)1417*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WritePackedScalar) {
1418*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
1419*61c4878aSAndroid Build Coastguard Worker   for (unsigned i = 0; i < 4; ++i) {
1420*61c4878aSAndroid Build Coastguard Worker     message.uint32s.push_back(i * 16u);
1421*61c4878aSAndroid Build Coastguard Worker     message.fixed32s.push_back(i * 16u);
1422*61c4878aSAndroid Build Coastguard Worker   }
1423*61c4878aSAndroid Build Coastguard Worker 
1424*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytes];
1425*61c4878aSAndroid Build Coastguard Worker 
1426*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1427*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
1428*61c4878aSAndroid Build Coastguard Worker 
1429*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Write(message);
1430*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1431*61c4878aSAndroid Build Coastguard Worker 
1432*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1433*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1434*61c4878aSAndroid Build Coastguard Worker     // uint32s[], v={0, 16, 32, 48}
1435*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x04,
1436*61c4878aSAndroid Build Coastguard Worker     0x00,
1437*61c4878aSAndroid Build Coastguard Worker     0x10,
1438*61c4878aSAndroid Build Coastguard Worker     0x20,
1439*61c4878aSAndroid Build Coastguard Worker     0x30,
1440*61c4878aSAndroid Build Coastguard Worker     // fixed32s[]. v={0, 16, 32, 48}
1441*61c4878aSAndroid Build Coastguard Worker     0x32, 0x10,
1442*61c4878aSAndroid Build Coastguard Worker     0x00, 0x00, 0x00, 0x00,
1443*61c4878aSAndroid Build Coastguard Worker     0x10, 0x00, 0x00, 0x00,
1444*61c4878aSAndroid Build Coastguard Worker     0x20, 0x00, 0x00, 0x00,
1445*61c4878aSAndroid Build Coastguard Worker     0x30, 0x00, 0x00, 0x00,
1446*61c4878aSAndroid Build Coastguard Worker   };
1447*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1448*61c4878aSAndroid Build Coastguard Worker 
1449*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1450*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1451*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1452*61c4878aSAndroid Build Coastguard Worker             0);
1453*61c4878aSAndroid Build Coastguard Worker }
1454*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WritePackedScalarFixedLength)1455*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WritePackedScalarFixedLength) {
1456*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
1457*61c4878aSAndroid Build Coastguard Worker   for (unsigned i = 0; i < 4; ++i) {
1458*61c4878aSAndroid Build Coastguard Worker     message.uint64s[i] = (i + 1) * 1000u;
1459*61c4878aSAndroid Build Coastguard Worker   }
1460*61c4878aSAndroid Build Coastguard Worker   message.doubles[0] = 3.14159;
1461*61c4878aSAndroid Build Coastguard Worker   message.doubles[1] = 2.71828;
1462*61c4878aSAndroid Build Coastguard Worker 
1463*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytes];
1464*61c4878aSAndroid Build Coastguard Worker 
1465*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1466*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
1467*61c4878aSAndroid Build Coastguard Worker 
1468*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Write(message);
1469*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1470*61c4878aSAndroid Build Coastguard Worker 
1471*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1472*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1473*61c4878aSAndroid Build Coastguard Worker     // doubles[], v={3.14159, 2.71828}
1474*61c4878aSAndroid Build Coastguard Worker     0x22, 0x10,
1475*61c4878aSAndroid Build Coastguard Worker     0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
1476*61c4878aSAndroid Build Coastguard Worker     0x90, 0xf7, 0xaa, 0x95, 0x09, 0xbf, 0x05, 0x40,
1477*61c4878aSAndroid Build Coastguard Worker     // uint64s[], v={1000, 2000, 3000, 4000}
1478*61c4878aSAndroid Build Coastguard Worker     0x42, 0x08, 0xe8, 0x07, 0xd0, 0x0f, 0xb8, 0x17, 0xa0, 0x1f,
1479*61c4878aSAndroid Build Coastguard Worker   };
1480*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1481*61c4878aSAndroid Build Coastguard Worker 
1482*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1483*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1484*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1485*61c4878aSAndroid Build Coastguard Worker             0);
1486*61c4878aSAndroid Build Coastguard Worker }
1487*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WritePackedScalarCallback)1488*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WritePackedScalarCallback) {
1489*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
1490*61c4878aSAndroid Build Coastguard Worker   message.sint32s.SetEncoder([](RepeatedTest::StreamEncoder& encoder) {
1491*61c4878aSAndroid Build Coastguard Worker     constexpr int32_t sint32s[] = {-25, -1, 0, 1, 25};
1492*61c4878aSAndroid Build Coastguard Worker     return encoder.WriteSint32s(sint32s);
1493*61c4878aSAndroid Build Coastguard Worker   });
1494*61c4878aSAndroid Build Coastguard Worker 
1495*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytes +
1496*61c4878aSAndroid Build Coastguard Worker                           varint::kMaxVarint32SizeBytes * 5];
1497*61c4878aSAndroid Build Coastguard Worker 
1498*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1499*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
1500*61c4878aSAndroid Build Coastguard Worker 
1501*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Write(message);
1502*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1503*61c4878aSAndroid Build Coastguard Worker 
1504*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1505*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1506*61c4878aSAndroid Build Coastguard Worker     // sint32s[], v={-25, -1, 0, 1, 25}
1507*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05,
1508*61c4878aSAndroid Build Coastguard Worker     0x31,
1509*61c4878aSAndroid Build Coastguard Worker     0x01,
1510*61c4878aSAndroid Build Coastguard Worker     0x00,
1511*61c4878aSAndroid Build Coastguard Worker     0x02,
1512*61c4878aSAndroid Build Coastguard Worker     0x32,
1513*61c4878aSAndroid Build Coastguard Worker   };
1514*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1515*61c4878aSAndroid Build Coastguard Worker 
1516*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1517*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1518*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1519*61c4878aSAndroid Build Coastguard Worker             0);
1520*61c4878aSAndroid Build Coastguard Worker }
1521*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WritePackedEnum)1522*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WritePackedEnum) {
1523*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
1524*61c4878aSAndroid Build Coastguard Worker   message.enums.push_back(Enum::RED);
1525*61c4878aSAndroid Build Coastguard Worker   message.enums.push_back(Enum::GREEN);
1526*61c4878aSAndroid Build Coastguard Worker   message.enums.push_back(Enum::AMBER);
1527*61c4878aSAndroid Build Coastguard Worker   message.enums.push_back(Enum::RED);
1528*61c4878aSAndroid Build Coastguard Worker 
1529*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytes];
1530*61c4878aSAndroid Build Coastguard Worker 
1531*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1532*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamEncoder repeated_test(writer, ByteSpan());
1533*61c4878aSAndroid Build Coastguard Worker 
1534*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Write(message);
1535*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1536*61c4878aSAndroid Build Coastguard Worker 
1537*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1538*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1539*61c4878aSAndroid Build Coastguard Worker     // enums[], v={RED, GREEN, AMBER, RED}
1540*61c4878aSAndroid Build Coastguard Worker     0x4a, 0x04, 0x00, 0x02, 0x01, 0x00,
1541*61c4878aSAndroid Build Coastguard Worker   };
1542*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1543*61c4878aSAndroid Build Coastguard Worker 
1544*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1545*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1546*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1547*61c4878aSAndroid Build Coastguard Worker             0);
1548*61c4878aSAndroid Build Coastguard Worker }
1549*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WriteStringCallback)1550*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WriteStringCallback) {
1551*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
1552*61c4878aSAndroid Build Coastguard Worker   // pigweed.description has no max_size specified so a callback must be
1553*61c4878aSAndroid Build Coastguard Worker   // set to write the value.
1554*61c4878aSAndroid Build Coastguard Worker   message.description.SetEncoder([](Pigweed::StreamEncoder& encoder) {
1555*61c4878aSAndroid Build Coastguard Worker     return encoder.WriteDescription(
1556*61c4878aSAndroid Build Coastguard Worker         "an open source collection of embedded-targeted "
1557*61c4878aSAndroid Build Coastguard Worker         "libraries-or as we like to call them, modules");
1558*61c4878aSAndroid Build Coastguard Worker   });
1559*61c4878aSAndroid Build Coastguard Worker 
1560*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[Pigweed::kMaxEncodedSizeBytes + 92];
1561*61c4878aSAndroid Build Coastguard Worker   std::byte temp_buffer[Pigweed::kScratchBufferSizeBytes];
1562*61c4878aSAndroid Build Coastguard Worker 
1563*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1564*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamEncoder pigweed(writer, temp_buffer);
1565*61c4878aSAndroid Build Coastguard Worker 
1566*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Write(message);
1567*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1568*61c4878aSAndroid Build Coastguard Worker 
1569*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1570*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1571*61c4878aSAndroid Build Coastguard Worker     // pigweed.description
1572*61c4878aSAndroid Build Coastguard Worker     0x62, 0x5c, 'a', 'n', ' ', 'o', 'p', 'e', 'n', ' ', 's', 'o', 'u', 'r', 'c',
1573*61c4878aSAndroid Build Coastguard Worker     'e', ' ', 'c', 'o', 'l', 'l', 'e', 'c', 't', 'i', 'o', 'n', ' ', 'o', 'f',
1574*61c4878aSAndroid Build Coastguard Worker     ' ', 'e', 'm', 'b', 'e', 'd', 'd', 'e', 'd', '-', 't', 'a', 'r', 'g', 'e',
1575*61c4878aSAndroid Build Coastguard Worker     't', 'e', 'd', ' ', 'l', 'i', 'b', 'r', 'a', 'r', 'i', 'e', 's', '-', 'o',
1576*61c4878aSAndroid Build Coastguard Worker     'r', ' ', 'a', 's', ' ', 'w', 'e', ' ', 'l', 'i', 'k', 'e', ' ', 't', 'o',
1577*61c4878aSAndroid Build Coastguard Worker     ' ', 'c', 'a', 'l', 'l', ' ', 't', 'h', 'e', 'm', ',', ' ', 'm', 'o', 'd',
1578*61c4878aSAndroid Build Coastguard Worker     'u', 'l', 'e', 's',
1579*61c4878aSAndroid Build Coastguard Worker   };
1580*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1581*61c4878aSAndroid Build Coastguard Worker 
1582*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1583*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1584*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1585*61c4878aSAndroid Build Coastguard Worker             0);
1586*61c4878aSAndroid Build Coastguard Worker }
1587*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WriteForcedCallback)1588*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WriteForcedCallback) {
1589*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
1590*61c4878aSAndroid Build Coastguard Worker   // pigweed.special_property has use_callback=true to force the use of a
1591*61c4878aSAndroid Build Coastguard Worker   // callback even though it's a simple scalar.
1592*61c4878aSAndroid Build Coastguard Worker   message.special_property.SetEncoder([](Pigweed::StreamEncoder& encoder) {
1593*61c4878aSAndroid Build Coastguard Worker     return encoder.WriteSpecialProperty(42u);
1594*61c4878aSAndroid Build Coastguard Worker   });
1595*61c4878aSAndroid Build Coastguard Worker 
1596*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[Pigweed::kMaxEncodedSizeBytes];
1597*61c4878aSAndroid Build Coastguard Worker   std::byte temp_buffer[Pigweed::kScratchBufferSizeBytes];
1598*61c4878aSAndroid Build Coastguard Worker 
1599*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1600*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamEncoder pigweed(writer, temp_buffer);
1601*61c4878aSAndroid Build Coastguard Worker 
1602*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Write(message);
1603*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1604*61c4878aSAndroid Build Coastguard Worker 
1605*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1606*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1607*61c4878aSAndroid Build Coastguard Worker     // pigweed.special_property
1608*61c4878aSAndroid Build Coastguard Worker     0x68, 0x2a,
1609*61c4878aSAndroid Build Coastguard Worker   };
1610*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1611*61c4878aSAndroid Build Coastguard Worker 
1612*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1613*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1614*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1615*61c4878aSAndroid Build Coastguard Worker             0);
1616*61c4878aSAndroid Build Coastguard Worker }
1617*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WriteNestedImported)1618*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WriteNestedImported) {
1619*61c4878aSAndroid Build Coastguard Worker   Period::Message message{};
1620*61c4878aSAndroid Build Coastguard Worker   message.start.seconds = 1517949900u;
1621*61c4878aSAndroid Build Coastguard Worker   message.end.seconds = 1517950378u;
1622*61c4878aSAndroid Build Coastguard Worker 
1623*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[Period::kMaxEncodedSizeBytes];
1624*61c4878aSAndroid Build Coastguard Worker   std::byte temp_buffer[Period::kScratchBufferSizeBytes];
1625*61c4878aSAndroid Build Coastguard Worker 
1626*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1627*61c4878aSAndroid Build Coastguard Worker   Period::StreamEncoder period(writer, temp_buffer);
1628*61c4878aSAndroid Build Coastguard Worker 
1629*61c4878aSAndroid Build Coastguard Worker   const auto status = period.Write(message);
1630*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1631*61c4878aSAndroid Build Coastguard Worker 
1632*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1633*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1634*61c4878aSAndroid Build Coastguard Worker     // period.start
1635*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x06,
1636*61c4878aSAndroid Build Coastguard Worker     // period.start.seconds v=1517949900
1637*61c4878aSAndroid Build Coastguard Worker     0x08, 0xcc, 0xa7, 0xe8, 0xd3, 0x05,
1638*61c4878aSAndroid Build Coastguard Worker     // period.end
1639*61c4878aSAndroid Build Coastguard Worker     0x12, 0x06,
1640*61c4878aSAndroid Build Coastguard Worker     // period.end.seconds, v=1517950378
1641*61c4878aSAndroid Build Coastguard Worker     0x08, 0xaa, 0xab, 0xe8, 0xd3, 0x05,
1642*61c4878aSAndroid Build Coastguard Worker   };
1643*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1644*61c4878aSAndroid Build Coastguard Worker 
1645*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1646*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1647*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1648*61c4878aSAndroid Build Coastguard Worker             0);
1649*61c4878aSAndroid Build Coastguard Worker }
1650*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WriteNestedRepeated)1651*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WriteNestedRepeated) {
1652*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message message{};
1653*61c4878aSAndroid Build Coastguard Worker   // Repeated nested messages require a callback since there would otherwise be
1654*61c4878aSAndroid Build Coastguard Worker   // no way to set callbacks on the nested message.
1655*61c4878aSAndroid Build Coastguard Worker   message.structs.SetEncoder([](RepeatedTest::StreamEncoder& encoder) {
1656*61c4878aSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < 2; ++i) {
1657*61c4878aSAndroid Build Coastguard Worker       Struct::Message struct_message{};
1658*61c4878aSAndroid Build Coastguard Worker       struct_message.one = i * 32 + 16u;
1659*61c4878aSAndroid Build Coastguard Worker       struct_message.two = i * 32 + 32u;
1660*61c4878aSAndroid Build Coastguard Worker 
1661*61c4878aSAndroid Build Coastguard Worker       const auto status = encoder.GetStructsEncoder().Write(struct_message);
1662*61c4878aSAndroid Build Coastguard Worker       EXPECT_EQ(status, OkStatus());
1663*61c4878aSAndroid Build Coastguard Worker     }
1664*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
1665*61c4878aSAndroid Build Coastguard Worker   });
1666*61c4878aSAndroid Build Coastguard Worker 
1667*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[RepeatedTest::kMaxEncodedSizeBytes +
1668*61c4878aSAndroid Build Coastguard Worker                           Struct::kMaxEncodedSizeBytes * 2];
1669*61c4878aSAndroid Build Coastguard Worker   std::byte temp_buffer[RepeatedTest::kScratchBufferSizeBytes +
1670*61c4878aSAndroid Build Coastguard Worker                         Struct::kMaxEncodedSizeBytes];
1671*61c4878aSAndroid Build Coastguard Worker 
1672*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1673*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamEncoder repeated_test(writer, temp_buffer);
1674*61c4878aSAndroid Build Coastguard Worker 
1675*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Write(message);
1676*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1677*61c4878aSAndroid Build Coastguard Worker 
1678*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1679*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1680*61c4878aSAndroid Build Coastguard Worker     // repeated.structs
1681*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x04,
1682*61c4878aSAndroid Build Coastguard Worker     // repeated.structs.one v=16
1683*61c4878aSAndroid Build Coastguard Worker     0x08, 0x10,
1684*61c4878aSAndroid Build Coastguard Worker     // repeated.structs.two v=32
1685*61c4878aSAndroid Build Coastguard Worker     0x10, 0x20,
1686*61c4878aSAndroid Build Coastguard Worker     // repeated.structs
1687*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x04,
1688*61c4878aSAndroid Build Coastguard Worker     // repeated.structs.one v=48
1689*61c4878aSAndroid Build Coastguard Worker     0x08, 0x30,
1690*61c4878aSAndroid Build Coastguard Worker     // repeated.structs.two v=64
1691*61c4878aSAndroid Build Coastguard Worker     0x10, 0x40,
1692*61c4878aSAndroid Build Coastguard Worker   };
1693*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1694*61c4878aSAndroid Build Coastguard Worker 
1695*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1696*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1697*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1698*61c4878aSAndroid Build Coastguard Worker             0);
1699*61c4878aSAndroid Build Coastguard Worker }
1700*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WriteNestedForcedCallback)1701*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WriteNestedForcedCallback) {
1702*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message message{};
1703*61c4878aSAndroid Build Coastguard Worker   // pigweed.device_info has use_callback=true to force the use of a callback.
1704*61c4878aSAndroid Build Coastguard Worker   message.device_info.SetEncoder([](Pigweed::StreamEncoder& encoder) {
1705*61c4878aSAndroid Build Coastguard Worker     DeviceInfo::Message device_info{};
1706*61c4878aSAndroid Build Coastguard Worker     device_info.device_name = "pixel";
1707*61c4878aSAndroid Build Coastguard Worker     device_info.device_id = 0x08080808u;
1708*61c4878aSAndroid Build Coastguard Worker     device_info.status = DeviceInfo::DeviceStatus::OK;
1709*61c4878aSAndroid Build Coastguard Worker 
1710*61c4878aSAndroid Build Coastguard Worker     // Use the callback to set nested callbacks.
1711*61c4878aSAndroid Build Coastguard Worker     device_info.attributes.SetEncoder(
1712*61c4878aSAndroid Build Coastguard Worker         [](DeviceInfo::StreamEncoder& device_info_encoder) {
1713*61c4878aSAndroid Build Coastguard Worker           KeyValuePair::Message attribute{};
1714*61c4878aSAndroid Build Coastguard Worker 
1715*61c4878aSAndroid Build Coastguard Worker           attribute.key = "version";
1716*61c4878aSAndroid Build Coastguard Worker           attribute.value = "5.3.1";
1717*61c4878aSAndroid Build Coastguard Worker           PW_TRY(device_info_encoder.GetAttributesEncoder().Write(attribute));
1718*61c4878aSAndroid Build Coastguard Worker 
1719*61c4878aSAndroid Build Coastguard Worker           attribute.key = "chip";
1720*61c4878aSAndroid Build Coastguard Worker           attribute.value = "left-soc";
1721*61c4878aSAndroid Build Coastguard Worker           PW_TRY(device_info_encoder.GetAttributesEncoder().Write(attribute));
1722*61c4878aSAndroid Build Coastguard Worker 
1723*61c4878aSAndroid Build Coastguard Worker           return OkStatus();
1724*61c4878aSAndroid Build Coastguard Worker         });
1725*61c4878aSAndroid Build Coastguard Worker 
1726*61c4878aSAndroid Build Coastguard Worker     return encoder.GetDeviceInfoEncoder().Write(device_info);
1727*61c4878aSAndroid Build Coastguard Worker   });
1728*61c4878aSAndroid Build Coastguard Worker 
1729*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[Pigweed::kMaxEncodedSizeBytes +
1730*61c4878aSAndroid Build Coastguard Worker                           DeviceInfo::kMaxEncodedSizeBytes];
1731*61c4878aSAndroid Build Coastguard Worker   std::byte temp_buffer[Pigweed::kScratchBufferSizeBytes +
1732*61c4878aSAndroid Build Coastguard Worker                         DeviceInfo::kMaxEncodedSizeBytes];
1733*61c4878aSAndroid Build Coastguard Worker 
1734*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1735*61c4878aSAndroid Build Coastguard Worker   Pigweed::StreamEncoder pigweed(writer, temp_buffer);
1736*61c4878aSAndroid Build Coastguard Worker 
1737*61c4878aSAndroid Build Coastguard Worker   const auto status = pigweed.Write(message);
1738*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1739*61c4878aSAndroid Build Coastguard Worker 
1740*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1741*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1742*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info
1743*61c4878aSAndroid Build Coastguard Worker     0x32, 0x30,
1744*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.device_name
1745*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'p', 'i', 'x', 'e', 'l',
1746*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.device_id
1747*61c4878aSAndroid Build Coastguard Worker     0x15, 0x08, 0x08, 0x08, 0x08,
1748*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.attributes[0]
1749*61c4878aSAndroid Build Coastguard Worker     0x22, 0x10,
1750*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.attributes[0].key
1751*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
1752*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.attributes[0].value
1753*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05, '5', '.', '3', '.', '1',
1754*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.attributes[1]
1755*61c4878aSAndroid Build Coastguard Worker     0x22, 0x10,
1756*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.attributes[1].key
1757*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x04, 'c', 'h', 'i', 'p',
1758*61c4878aSAndroid Build Coastguard Worker     // pigweed.device_info.attributes[1].value
1759*61c4878aSAndroid Build Coastguard Worker     0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
1760*61c4878aSAndroid Build Coastguard Worker   };
1761*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1762*61c4878aSAndroid Build Coastguard Worker 
1763*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1764*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1765*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1766*61c4878aSAndroid Build Coastguard Worker             0);
1767*61c4878aSAndroid Build Coastguard Worker }
1768*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,EnumAliases)1769*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, EnumAliases) {
1770*61c4878aSAndroid Build Coastguard Worker   // Unprefixed enum.
1771*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Bool::kTrue, Bool::TRUE);
1772*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Bool::kFalse, Bool::FALSE);
1773*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Bool::kFileNotFound, Bool::FILE_NOT_FOUND);
1774*61c4878aSAndroid Build Coastguard Worker 
1775*61c4878aSAndroid Build Coastguard Worker   // Prefixed enum has the prefix removed.
1776*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Error::kNone, Error::ERROR_NONE);
1777*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Error::kNotFound, Error::ERROR_NOT_FOUND);
1778*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(Error::kUnknown, Error::ERROR_UNKNOWN);
1779*61c4878aSAndroid Build Coastguard Worker 
1780*61c4878aSAndroid Build Coastguard Worker   // Single-value enum.
1781*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(AlwaysBlue::kBlue, AlwaysBlue::BLUE);
1782*61c4878aSAndroid Build Coastguard Worker }
1783*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WriteOptionalPresent)1784*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WriteOptionalPresent) {
1785*61c4878aSAndroid Build Coastguard Worker   OptionalTest::Message message{};
1786*61c4878aSAndroid Build Coastguard Worker   message.sometimes_present_fixed = 0x2a;
1787*61c4878aSAndroid Build Coastguard Worker   message.sometimes_present_varint = 0x2a;
1788*61c4878aSAndroid Build Coastguard Worker   message.explicitly_present_fixed = 0x45;
1789*61c4878aSAndroid Build Coastguard Worker   message.explicitly_present_varint = 0x45;
1790*61c4878aSAndroid Build Coastguard Worker   message.sometimes_empty_fixed.push_back(0x63);
1791*61c4878aSAndroid Build Coastguard Worker   message.sometimes_empty_varint.push_back(0x63);
1792*61c4878aSAndroid Build Coastguard Worker 
1793*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[512];
1794*61c4878aSAndroid Build Coastguard Worker 
1795*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1796*61c4878aSAndroid Build Coastguard Worker   OptionalTest::StreamEncoder optional_test(writer, ByteSpan());
1797*61c4878aSAndroid Build Coastguard Worker 
1798*61c4878aSAndroid Build Coastguard Worker   const auto status = optional_test.Write(message);
1799*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1800*61c4878aSAndroid Build Coastguard Worker 
1801*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1802*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1803*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_present_fixed
1804*61c4878aSAndroid Build Coastguard Worker     0x0d, 0x2a, 0x00, 0x00, 0x00,
1805*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_present_varint
1806*61c4878aSAndroid Build Coastguard Worker     0x10, 0x2a,
1807*61c4878aSAndroid Build Coastguard Worker     // optional.explicitly_present_fixed
1808*61c4878aSAndroid Build Coastguard Worker     0x1d, 0x45, 0x00, 0x00, 0x00,
1809*61c4878aSAndroid Build Coastguard Worker     // optional.explicitly_present_varint
1810*61c4878aSAndroid Build Coastguard Worker     0x20, 0x45,
1811*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_empty_fixed
1812*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x04, 0x63, 0x00, 0x00, 0x00,
1813*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_empty_varint
1814*61c4878aSAndroid Build Coastguard Worker     0x32, 0x01, 0x63,
1815*61c4878aSAndroid Build Coastguard Worker   };
1816*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1817*61c4878aSAndroid Build Coastguard Worker 
1818*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1819*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1820*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1821*61c4878aSAndroid Build Coastguard Worker             0);
1822*61c4878aSAndroid Build Coastguard Worker }
1823*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WriteOptionalNotPresent)1824*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WriteOptionalNotPresent) {
1825*61c4878aSAndroid Build Coastguard Worker   OptionalTest::Message message{};
1826*61c4878aSAndroid Build Coastguard Worker 
1827*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[512];
1828*61c4878aSAndroid Build Coastguard Worker 
1829*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1830*61c4878aSAndroid Build Coastguard Worker   OptionalTest::StreamEncoder optional_test(writer, ByteSpan());
1831*61c4878aSAndroid Build Coastguard Worker 
1832*61c4878aSAndroid Build Coastguard Worker   const auto status = optional_test.Write(message);
1833*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1834*61c4878aSAndroid Build Coastguard Worker 
1835*61c4878aSAndroid Build Coastguard Worker   // The expected proto is empty; no bytes should be written.
1836*61c4878aSAndroid Build Coastguard Worker 
1837*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1838*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(result.empty());
1839*61c4878aSAndroid Build Coastguard Worker }
1840*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,WriteOptionalPresentDefaults)1841*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, WriteOptionalPresentDefaults) {
1842*61c4878aSAndroid Build Coastguard Worker   OptionalTest::Message message{};
1843*61c4878aSAndroid Build Coastguard Worker   // Non-optional fields with a default value are not explicitly encoded, so
1844*61c4878aSAndroid Build Coastguard Worker   // aren't meaningfully different from one that's just ommitted.
1845*61c4878aSAndroid Build Coastguard Worker   message.sometimes_present_fixed = 0x00;
1846*61c4878aSAndroid Build Coastguard Worker   message.sometimes_present_varint = 0x00;
1847*61c4878aSAndroid Build Coastguard Worker   // Optional fields, even with a default value, are explicitly encoded.
1848*61c4878aSAndroid Build Coastguard Worker   message.explicitly_present_fixed = 0x00;
1849*61c4878aSAndroid Build Coastguard Worker   message.explicitly_present_varint = 0x00;
1850*61c4878aSAndroid Build Coastguard Worker   // Repeated fields with a default value are meaningfully non-empty.
1851*61c4878aSAndroid Build Coastguard Worker   message.sometimes_empty_fixed.push_back(0x00);
1852*61c4878aSAndroid Build Coastguard Worker   message.sometimes_empty_varint.push_back(0x00);
1853*61c4878aSAndroid Build Coastguard Worker 
1854*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[512];
1855*61c4878aSAndroid Build Coastguard Worker 
1856*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer(encode_buffer);
1857*61c4878aSAndroid Build Coastguard Worker   OptionalTest::StreamEncoder optional_test(writer, ByteSpan());
1858*61c4878aSAndroid Build Coastguard Worker 
1859*61c4878aSAndroid Build Coastguard Worker   const auto status = optional_test.Write(message);
1860*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1861*61c4878aSAndroid Build Coastguard Worker 
1862*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1863*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
1864*61c4878aSAndroid Build Coastguard Worker     // optional.explicitly_present_fixed
1865*61c4878aSAndroid Build Coastguard Worker     0x1d, 0x00, 0x00, 0x00, 0x00,
1866*61c4878aSAndroid Build Coastguard Worker     // optional.explicitly_present_varint
1867*61c4878aSAndroid Build Coastguard Worker     0x20, 0x00,
1868*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_empty_fixed
1869*61c4878aSAndroid Build Coastguard Worker     0x2a, 0x04, 0x00, 0x00, 0x00, 0x00,
1870*61c4878aSAndroid Build Coastguard Worker     // optional.sometimes_empty_varint
1871*61c4878aSAndroid Build Coastguard Worker     0x32, 0x01, 0x00,
1872*61c4878aSAndroid Build Coastguard Worker   };
1873*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1874*61c4878aSAndroid Build Coastguard Worker 
1875*61c4878aSAndroid Build Coastguard Worker   ConstByteSpan result = writer.WrittenData();
1876*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.size(), sizeof(expected_proto));
1877*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(result.data(), expected_proto, sizeof(expected_proto)),
1878*61c4878aSAndroid Build Coastguard Worker             0);
1879*61c4878aSAndroid Build Coastguard Worker }
1880*61c4878aSAndroid Build Coastguard Worker 
1881*61c4878aSAndroid Build Coastguard Worker class BreakableEncoder : public KeyValuePair::MemoryEncoder {
1882*61c4878aSAndroid Build Coastguard Worker  public:
BreakableEncoder(ByteSpan buffer)1883*61c4878aSAndroid Build Coastguard Worker   constexpr BreakableEncoder(ByteSpan buffer)
1884*61c4878aSAndroid Build Coastguard Worker       : KeyValuePair::MemoryEncoder(buffer) {}
1885*61c4878aSAndroid Build Coastguard Worker 
Write(const KeyValuePair::Message & message,span<const internal::MessageField> table)1886*61c4878aSAndroid Build Coastguard Worker   Status Write(const KeyValuePair::Message& message,
1887*61c4878aSAndroid Build Coastguard Worker                span<const internal::MessageField> table) {
1888*61c4878aSAndroid Build Coastguard Worker     return ::pw::protobuf::StreamEncoder::Write(as_bytes(span(&message, 1)),
1889*61c4878aSAndroid Build Coastguard Worker                                                 table);
1890*61c4878aSAndroid Build Coastguard Worker   }
1891*61c4878aSAndroid Build Coastguard Worker };
1892*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,DISABLED_WriteDoesNotOverrun)1893*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, DISABLED_WriteDoesNotOverrun) {
1894*61c4878aSAndroid Build Coastguard Worker   // Deliberately construct a message table that attempts to violate the bounds
1895*61c4878aSAndroid Build Coastguard Worker   // of the structure. We're not testing that a developer can't do this, rather
1896*61c4878aSAndroid Build Coastguard Worker   // that the protobuf encoder can't be exploited in this way.
1897*61c4878aSAndroid Build Coastguard Worker   constexpr internal::MessageField kMessageFields[] = {
1898*61c4878aSAndroid Build Coastguard Worker       {1,
1899*61c4878aSAndroid Build Coastguard Worker        WireType::kDelimited,
1900*61c4878aSAndroid Build Coastguard Worker        sizeof(std::byte),
1901*61c4878aSAndroid Build Coastguard Worker        static_cast<internal::VarintType>(0),
1902*61c4878aSAndroid Build Coastguard Worker        false,
1903*61c4878aSAndroid Build Coastguard Worker        false,
1904*61c4878aSAndroid Build Coastguard Worker        false,
1905*61c4878aSAndroid Build Coastguard Worker        false,
1906*61c4878aSAndroid Build Coastguard Worker        internal::CallbackType::kNone,
1907*61c4878aSAndroid Build Coastguard Worker        0,
1908*61c4878aSAndroid Build Coastguard Worker        sizeof(KeyValuePair::Message) * 2,
1909*61c4878aSAndroid Build Coastguard Worker        {}},
1910*61c4878aSAndroid Build Coastguard Worker   };
1911*61c4878aSAndroid Build Coastguard Worker 
1912*61c4878aSAndroid Build Coastguard Worker   std::byte encode_buffer[64];
1913*61c4878aSAndroid Build Coastguard Worker 
1914*61c4878aSAndroid Build Coastguard Worker   BreakableEncoder encoder(encode_buffer);
1915*61c4878aSAndroid Build Coastguard Worker   KeyValuePair::Message message{};
1916*61c4878aSAndroid Build Coastguard Worker   // ASSERT_CRASH
1917*61c4878aSAndroid Build Coastguard Worker   std::ignore = encoder.Write(message, kMessageFields);
1918*61c4878aSAndroid Build Coastguard Worker }
1919*61c4878aSAndroid Build Coastguard Worker 
1920*61c4878aSAndroid Build Coastguard Worker // The following tests cover using the codegen struct Message and callbacks in
1921*61c4878aSAndroid Build Coastguard Worker // different ways.
1922*61c4878aSAndroid Build Coastguard Worker 
1923*61c4878aSAndroid Build Coastguard Worker // Check that the callback function object is large enough to implement a
1924*61c4878aSAndroid Build Coastguard Worker // "call a function on this" lambda.
1925*61c4878aSAndroid Build Coastguard Worker class StringChecker {
1926*61c4878aSAndroid Build Coastguard Worker  public:
1927*61c4878aSAndroid Build Coastguard Worker   StringChecker() = default;
1928*61c4878aSAndroid Build Coastguard Worker   ~StringChecker() = default;
1929*61c4878aSAndroid Build Coastguard Worker 
Check(RepeatedTest::StreamDecoder & repeated_test)1930*61c4878aSAndroid Build Coastguard Worker   Status Check(RepeatedTest::StreamDecoder& repeated_test) {
1931*61c4878aSAndroid Build Coastguard Worker     RepeatedTest::Message message{};
1932*61c4878aSAndroid Build Coastguard Worker     message.strings.SetDecoder([this](RepeatedTest::StreamDecoder& decoder) {
1933*61c4878aSAndroid Build Coastguard Worker       return this->CheckOne(decoder);
1934*61c4878aSAndroid Build Coastguard Worker     });
1935*61c4878aSAndroid Build Coastguard Worker     return repeated_test.Read(message);
1936*61c4878aSAndroid Build Coastguard Worker   }
1937*61c4878aSAndroid Build Coastguard Worker 
1938*61c4878aSAndroid Build Coastguard Worker  private:
CheckOne(RepeatedTest::StreamDecoder & decoder)1939*61c4878aSAndroid Build Coastguard Worker   Status CheckOne(RepeatedTest::StreamDecoder& decoder) {
1940*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(decoder.Field().value(), RepeatedTest::Fields::kStrings);
1941*61c4878aSAndroid Build Coastguard Worker 
1942*61c4878aSAndroid Build Coastguard Worker     std::array<char, 40> strings{};
1943*61c4878aSAndroid Build Coastguard Worker     const StatusWithSize sws = decoder.ReadStrings(strings);
1944*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sws.status(), OkStatus());
1945*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(sws.size(), kExpectedStrings[i_].size());
1946*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(std::memcmp(strings.data(),
1947*61c4878aSAndroid Build Coastguard Worker                           kExpectedStrings[i_].data(),
1948*61c4878aSAndroid Build Coastguard Worker                           kExpectedStrings[i_].size()),
1949*61c4878aSAndroid Build Coastguard Worker               0);
1950*61c4878aSAndroid Build Coastguard Worker 
1951*61c4878aSAndroid Build Coastguard Worker     ++i_;
1952*61c4878aSAndroid Build Coastguard Worker     return sws.status();
1953*61c4878aSAndroid Build Coastguard Worker   }
1954*61c4878aSAndroid Build Coastguard Worker 
1955*61c4878aSAndroid Build Coastguard Worker   int i_ = 0;
1956*61c4878aSAndroid Build Coastguard Worker   constexpr static std::string_view kExpectedStrings[] = {
1957*61c4878aSAndroid Build Coastguard Worker       {"if music be the food of love, play on"},
1958*61c4878aSAndroid Build Coastguard Worker       {"give me excess of it, that, surfeiting"},
1959*61c4878aSAndroid Build Coastguard Worker       {"the appetite may sicken, and so die"}};
1960*61c4878aSAndroid Build Coastguard Worker };
1961*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,CallbackInClass)1962*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, CallbackInClass) {
1963*61c4878aSAndroid Build Coastguard Worker   // clang-format off
1964*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
1965*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
1966*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x25, 'i', 'f', ' ', 'm', 'u', 's', 'i', 'c', ' ', 'b', 'e', ' ',
1967*61c4878aSAndroid Build Coastguard Worker     't', 'h', 'e', ' ', 'f', 'o', 'o', 'd', ' ', 'o', 'f', ' ',
1968*61c4878aSAndroid Build Coastguard Worker     'l', 'o', 'v', 'e', ',', ' ', 'p', 'l', 'a', 'y', ' ', 'o', 'n',
1969*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
1970*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x26, 'g', 'i', 'v', 'e', ' ', 'm', 'e', ' ', 'e', 'x', 'c', 'e',
1971*61c4878aSAndroid Build Coastguard Worker     's', 's', ' ', 'o', 'f', ' ', 'i', 't', ',', ' ', 't', 'h', 'a', 't', ',',
1972*61c4878aSAndroid Build Coastguard Worker     ' ', 's', 'u', 'r', 'f', 'e', 'i', 't', 'i', 'n', 'g',
1973*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
1974*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x23, 't', 'h', 'e', ' ', 'a', 'p', 'p', 'e', 't', 'i', 't', 'e', ' ',
1975*61c4878aSAndroid Build Coastguard Worker     'm', 'a', 'y', ' ', 's', 'i', 'c', 'k', 'e', 'n', ',', ' ', 'a', 'n', 'd',
1976*61c4878aSAndroid Build Coastguard Worker     ' ', 's', 'o', ' ', 'd', 'i', 'e',
1977*61c4878aSAndroid Build Coastguard Worker   };
1978*61c4878aSAndroid Build Coastguard Worker   // clang-format on
1979*61c4878aSAndroid Build Coastguard Worker 
1980*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
1981*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
1982*61c4878aSAndroid Build Coastguard Worker 
1983*61c4878aSAndroid Build Coastguard Worker   StringChecker checker{};
1984*61c4878aSAndroid Build Coastguard Worker   const auto status = checker.Check(repeated_test);
1985*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
1986*61c4878aSAndroid Build Coastguard Worker }
1987*61c4878aSAndroid Build Coastguard Worker 
1988*61c4878aSAndroid Build Coastguard Worker // Check that we can create a custom subclass of the message struct that sets
1989*61c4878aSAndroid Build Coastguard Worker // its own callbacks to member functions that populate fields added in the
1990*61c4878aSAndroid Build Coastguard Worker // subclass.
1991*61c4878aSAndroid Build Coastguard Worker struct CustomMessage : RepeatedTest::Message {
CustomMessagepw::protobuf::__anon3b63cbad0111::CustomMessage1992*61c4878aSAndroid Build Coastguard Worker   CustomMessage() : RepeatedTest::Message() {
1993*61c4878aSAndroid Build Coastguard Worker     strings.SetDecoder([this](RepeatedTest::StreamDecoder& decoder) {
1994*61c4878aSAndroid Build Coastguard Worker       return this->ParseStrings(decoder);
1995*61c4878aSAndroid Build Coastguard Worker     });
1996*61c4878aSAndroid Build Coastguard Worker   }
1997*61c4878aSAndroid Build Coastguard Worker 
1998*61c4878aSAndroid Build Coastguard Worker   pw::Vector<std::array<char, 40>, 8> all_strings{};
1999*61c4878aSAndroid Build Coastguard Worker 
2000*61c4878aSAndroid Build Coastguard Worker  private:
ParseStringspw::protobuf::__anon3b63cbad0111::CustomMessage2001*61c4878aSAndroid Build Coastguard Worker   Status ParseStrings(RepeatedTest::StreamDecoder& decoder) {
2002*61c4878aSAndroid Build Coastguard Worker     PW_ASSERT(decoder.Field().value() == RepeatedTest::Fields::kStrings);
2003*61c4878aSAndroid Build Coastguard Worker 
2004*61c4878aSAndroid Build Coastguard Worker     std::array<char, 40> one_strings{};
2005*61c4878aSAndroid Build Coastguard Worker     const auto sws = decoder.ReadStrings(one_strings);
2006*61c4878aSAndroid Build Coastguard Worker     if (!sws.ok()) {
2007*61c4878aSAndroid Build Coastguard Worker       return sws.status();
2008*61c4878aSAndroid Build Coastguard Worker     }
2009*61c4878aSAndroid Build Coastguard Worker 
2010*61c4878aSAndroid Build Coastguard Worker     one_strings[sws.size()] = '\0';
2011*61c4878aSAndroid Build Coastguard Worker     all_strings.push_back(one_strings);
2012*61c4878aSAndroid Build Coastguard Worker 
2013*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
2014*61c4878aSAndroid Build Coastguard Worker   }
2015*61c4878aSAndroid Build Coastguard Worker };
2016*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,CallbackInSubclass)2017*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, CallbackInSubclass) {
2018*61c4878aSAndroid Build Coastguard Worker   // clang-format off
2019*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
2020*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
2021*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x25, 'i', 'f', ' ', 'm', 'u', 's', 'i', 'c', ' ', 'b', 'e', ' ',
2022*61c4878aSAndroid Build Coastguard Worker     't', 'h', 'e', ' ', 'f', 'o', 'o', 'd', ' ', 'o', 'f', ' ',
2023*61c4878aSAndroid Build Coastguard Worker     'l', 'o', 'v', 'e', ',', ' ', 'p', 'l', 'a', 'y', ' ', 'o', 'n',
2024*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
2025*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x26, 'g', 'i', 'v', 'e', ' ', 'm', 'e', ' ', 'e', 'x', 'c', 'e',
2026*61c4878aSAndroid Build Coastguard Worker     's', 's', ' ', 'o', 'f', ' ', 'i', 't', ',', ' ', 't', 'h', 'a', 't', ',',
2027*61c4878aSAndroid Build Coastguard Worker     ' ', 's', 'u', 'r', 'f', 'e', 'i', 't', 'i', 'n', 'g',
2028*61c4878aSAndroid Build Coastguard Worker     // repeated.strings
2029*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x23, 't', 'h', 'e', ' ', 'a', 'p', 'p', 'e', 't', 'i', 't', 'e', ' ',
2030*61c4878aSAndroid Build Coastguard Worker     'm', 'a', 'y', ' ', 's', 'i', 'c', 'k', 'e', 'n', ',', ' ', 'a', 'n', 'd',
2031*61c4878aSAndroid Build Coastguard Worker     ' ', 's', 'o', ' ', 'd', 'i', 'e',
2032*61c4878aSAndroid Build Coastguard Worker   };
2033*61c4878aSAndroid Build Coastguard Worker   // clang-format on
2034*61c4878aSAndroid Build Coastguard Worker 
2035*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
2036*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::StreamDecoder repeated_test(reader);
2037*61c4878aSAndroid Build Coastguard Worker 
2038*61c4878aSAndroid Build Coastguard Worker   CustomMessage message{};
2039*61c4878aSAndroid Build Coastguard Worker   const auto status = repeated_test.Read(message);
2040*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(status, OkStatus());
2041*61c4878aSAndroid Build Coastguard Worker 
2042*61c4878aSAndroid Build Coastguard Worker   constexpr static std::string_view kExpectedStrings[] = {
2043*61c4878aSAndroid Build Coastguard Worker       {"if music be the food of love, play on"},
2044*61c4878aSAndroid Build Coastguard Worker       {"give me excess of it, that, surfeiting"},
2045*61c4878aSAndroid Build Coastguard Worker       {"the appetite may sicken, and so die"}};
2046*61c4878aSAndroid Build Coastguard Worker 
2047*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(message.all_strings.size(), 3u);
2048*61c4878aSAndroid Build Coastguard Worker   for (unsigned short i = 0; i < 3; ++i) {
2049*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(std::memcmp(message.all_strings[i].data(),
2050*61c4878aSAndroid Build Coastguard Worker                           kExpectedStrings[i].data(),
2051*61c4878aSAndroid Build Coastguard Worker                           kExpectedStrings[i].size()),
2052*61c4878aSAndroid Build Coastguard Worker               0);
2053*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(message.all_strings[i].data()[kExpectedStrings[i].size()], '\0');
2054*61c4878aSAndroid Build Coastguard Worker   }
2055*61c4878aSAndroid Build Coastguard Worker }
2056*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,MaxSize)2057*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, MaxSize) {
2058*61c4878aSAndroid Build Coastguard Worker   // Verify constants generated from max_size options in full_test.pwpb_options
2059*61c4878aSAndroid Build Coastguard Worker   static_assert(Pigweed::kErrorMessageMaxSize == 64);
2060*61c4878aSAndroid Build Coastguard Worker   static_assert(Pigweed::kDataMaxSize == 8);
2061*61c4878aSAndroid Build Coastguard Worker 
2062*61c4878aSAndroid Build Coastguard Worker   Pigweed::Message size_message;
2063*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(size_message.error_message.max_size(),
2064*61c4878aSAndroid Build Coastguard Worker             Pigweed::kErrorMessageMaxSize);
2065*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(size_message.data.max_size(), Pigweed::kDataMaxSize);
2066*61c4878aSAndroid Build Coastguard Worker 
2067*61c4878aSAndroid Build Coastguard Worker   // Verify constants generated from max_count options in repeated.pwpb_options
2068*61c4878aSAndroid Build Coastguard Worker   static_assert(RepeatedTest::kUint32sMaxSize == 8);
2069*61c4878aSAndroid Build Coastguard Worker   static_assert(RepeatedTest::kFixed32sMaxSize == 8);
2070*61c4878aSAndroid Build Coastguard Worker   static_assert(RepeatedTest::kDoublesMaxSize == 2);
2071*61c4878aSAndroid Build Coastguard Worker   static_assert(RepeatedTest::kUint64sMaxSize == 4);
2072*61c4878aSAndroid Build Coastguard Worker   static_assert(RepeatedTest::kEnumsMaxSize == 4);
2073*61c4878aSAndroid Build Coastguard Worker 
2074*61c4878aSAndroid Build Coastguard Worker   RepeatedTest::Message count_message;
2075*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(count_message.uint32s.max_size(), RepeatedTest::kUint32sMaxSize);
2076*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(count_message.fixed32s.max_size(), RepeatedTest::kFixed32sMaxSize);
2077*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(count_message.doubles.max_size(), RepeatedTest::kDoublesMaxSize);
2078*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(count_message.uint64s.max_size(), RepeatedTest::kUint64sMaxSize);
2079*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(count_message.enums.max_size(), RepeatedTest::kEnumsMaxSize);
2080*61c4878aSAndroid Build Coastguard Worker }
2081*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,OneOf_Encode)2082*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, OneOf_Encode) {
2083*61c4878aSAndroid Build Coastguard Worker   OneOfTest::Message message;
2084*61c4878aSAndroid Build Coastguard Worker 
2085*61c4878aSAndroid Build Coastguard Worker   int invocations = 0;
2086*61c4878aSAndroid Build Coastguard Worker   message.type.SetEncoder([&invocations](OneOfTest::StreamEncoder& encoder) {
2087*61c4878aSAndroid Build Coastguard Worker     invocations++;
2088*61c4878aSAndroid Build Coastguard Worker     return encoder.WriteAnInt(32);
2089*61c4878aSAndroid Build Coastguard Worker   });
2090*61c4878aSAndroid Build Coastguard Worker 
2091*61c4878aSAndroid Build Coastguard Worker   // clang-format off
2092*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
2093*61c4878aSAndroid Build Coastguard Worker     // type.an_int
2094*61c4878aSAndroid Build Coastguard Worker     0x08, 0x20,
2095*61c4878aSAndroid Build Coastguard Worker   };
2096*61c4878aSAndroid Build Coastguard Worker   // clang-format on
2097*61c4878aSAndroid Build Coastguard Worker 
2098*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 8> buffer;
2099*61c4878aSAndroid Build Coastguard Worker   OneOfTest::MemoryEncoder oneof_test(buffer);
2100*61c4878aSAndroid Build Coastguard Worker 
2101*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(oneof_test.Write(message), OkStatus());
2102*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(invocations, 1);
2103*61c4878aSAndroid Build Coastguard Worker 
2104*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(oneof_test.size(), sizeof(expected_proto));
2105*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
2106*61c4878aSAndroid Build Coastguard Worker       std::memcmp(oneof_test.data(), expected_proto, sizeof(expected_proto)),
2107*61c4878aSAndroid Build Coastguard Worker       0);
2108*61c4878aSAndroid Build Coastguard Worker }
2109*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,OneOf_Encode_MultipleTimes)2110*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, OneOf_Encode_MultipleTimes) {
2111*61c4878aSAndroid Build Coastguard Worker   OneOfTest::Message message;
2112*61c4878aSAndroid Build Coastguard Worker 
2113*61c4878aSAndroid Build Coastguard Worker   int invocations = 0;
2114*61c4878aSAndroid Build Coastguard Worker   message.type.SetEncoder([&invocations](OneOfTest::StreamEncoder& encoder) {
2115*61c4878aSAndroid Build Coastguard Worker     invocations++;
2116*61c4878aSAndroid Build Coastguard Worker     return encoder.WriteAString("oneof");
2117*61c4878aSAndroid Build Coastguard Worker   });
2118*61c4878aSAndroid Build Coastguard Worker 
2119*61c4878aSAndroid Build Coastguard Worker   // clang-format off
2120*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t expected_proto[] = {
2121*61c4878aSAndroid Build Coastguard Worker     // type.a_string
2122*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05, 'o', 'n', 'e', 'o', 'f'
2123*61c4878aSAndroid Build Coastguard Worker   };
2124*61c4878aSAndroid Build Coastguard Worker   // clang-format on
2125*61c4878aSAndroid Build Coastguard Worker 
2126*61c4878aSAndroid Build Coastguard Worker   // Write the same message struct to two different buffers. Even though its
2127*61c4878aSAndroid Build Coastguard Worker   // internal state is modified during the write, it should be logically const
2128*61c4878aSAndroid Build Coastguard Worker   // with both writes successfully producing the same output.
2129*61c4878aSAndroid Build Coastguard Worker 
2130*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 8> buffer_1;
2131*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 8> buffer_2;
2132*61c4878aSAndroid Build Coastguard Worker   OneOfTest::MemoryEncoder oneof_test_1(buffer_1);
2133*61c4878aSAndroid Build Coastguard Worker   OneOfTest::MemoryEncoder oneof_test_2(buffer_2);
2134*61c4878aSAndroid Build Coastguard Worker 
2135*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(oneof_test_1.Write(message), OkStatus());
2136*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(invocations, 1);
2137*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(oneof_test_1.size(), sizeof(expected_proto));
2138*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
2139*61c4878aSAndroid Build Coastguard Worker       std::memcmp(oneof_test_1.data(), expected_proto, sizeof(expected_proto)),
2140*61c4878aSAndroid Build Coastguard Worker       0);
2141*61c4878aSAndroid Build Coastguard Worker 
2142*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(oneof_test_2.Write(message), OkStatus());
2143*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(invocations, 2);
2144*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(oneof_test_2.size(), sizeof(expected_proto));
2145*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
2146*61c4878aSAndroid Build Coastguard Worker       std::memcmp(oneof_test_2.data(), expected_proto, sizeof(expected_proto)),
2147*61c4878aSAndroid Build Coastguard Worker       0);
2148*61c4878aSAndroid Build Coastguard Worker }
2149*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,OneOf_Encode_UnsetEncoderIsIgnored)2150*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, OneOf_Encode_UnsetEncoderIsIgnored) {
2151*61c4878aSAndroid Build Coastguard Worker   OneOfTest::Message message;
2152*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 8> buffer;
2153*61c4878aSAndroid Build Coastguard Worker   OneOfTest::MemoryEncoder oneof_test(buffer);
2154*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(oneof_test.Write(message), OkStatus());
2155*61c4878aSAndroid Build Coastguard Worker }
2156*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,OneOf_Decode)2157*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, OneOf_Decode) {
2158*61c4878aSAndroid Build Coastguard Worker   // clang-format off
2159*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
2160*61c4878aSAndroid Build Coastguard Worker     // type.a_message
2161*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x02, 0x08, 0x01,
2162*61c4878aSAndroid Build Coastguard Worker   };
2163*61c4878aSAndroid Build Coastguard Worker   // clang-format on
2164*61c4878aSAndroid Build Coastguard Worker 
2165*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
2166*61c4878aSAndroid Build Coastguard Worker   OneOfTest::StreamDecoder stream_decoder(reader);
2167*61c4878aSAndroid Build Coastguard Worker 
2168*61c4878aSAndroid Build Coastguard Worker   struct {
2169*61c4878aSAndroid Build Coastguard Worker     OneOfTest::Fields field;
2170*61c4878aSAndroid Build Coastguard Worker     OneOfTest::AMessage::Message submessage;
2171*61c4878aSAndroid Build Coastguard Worker     int invocations = 0;
2172*61c4878aSAndroid Build Coastguard Worker   } result;
2173*61c4878aSAndroid Build Coastguard Worker 
2174*61c4878aSAndroid Build Coastguard Worker   OneOfTest::Message message;
2175*61c4878aSAndroid Build Coastguard Worker   message.type.SetDecoder(
2176*61c4878aSAndroid Build Coastguard Worker       [&result](OneOfTest::Fields field, OneOfTest::StreamDecoder& decoder) {
2177*61c4878aSAndroid Build Coastguard Worker         result.field = field;
2178*61c4878aSAndroid Build Coastguard Worker         result.invocations++;
2179*61c4878aSAndroid Build Coastguard Worker         if (field == OneOfTest::Fields::kAMessage) {
2180*61c4878aSAndroid Build Coastguard Worker           return decoder.GetAMessageDecoder().Read(result.submessage);
2181*61c4878aSAndroid Build Coastguard Worker         }
2182*61c4878aSAndroid Build Coastguard Worker         return Status::InvalidArgument();
2183*61c4878aSAndroid Build Coastguard Worker       });
2184*61c4878aSAndroid Build Coastguard Worker 
2185*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(stream_decoder.Read(message), OkStatus());
2186*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.field, OneOfTest::Fields::kAMessage);
2187*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.invocations, 1);
2188*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(result.submessage.a_bool, true);
2189*61c4878aSAndroid Build Coastguard Worker }
2190*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,OneOf_Decode_MultipleOneOfFieldsFails)2191*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, OneOf_Decode_MultipleOneOfFieldsFails) {
2192*61c4878aSAndroid Build Coastguard Worker   // clang-format off
2193*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
2194*61c4878aSAndroid Build Coastguard Worker     // type.an_int
2195*61c4878aSAndroid Build Coastguard Worker     0x08, 0x20,
2196*61c4878aSAndroid Build Coastguard Worker     // type.a_message
2197*61c4878aSAndroid Build Coastguard Worker     0x1a, 0x02, 0x08, 0x01,
2198*61c4878aSAndroid Build Coastguard Worker   };
2199*61c4878aSAndroid Build Coastguard Worker   // clang-format on
2200*61c4878aSAndroid Build Coastguard Worker 
2201*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
2202*61c4878aSAndroid Build Coastguard Worker   OneOfTest::StreamDecoder stream_decoder(reader);
2203*61c4878aSAndroid Build Coastguard Worker 
2204*61c4878aSAndroid Build Coastguard Worker   OneOfTest::Message message;
2205*61c4878aSAndroid Build Coastguard Worker   message.type.SetDecoder(
2206*61c4878aSAndroid Build Coastguard Worker       [](OneOfTest::Fields, OneOfTest::StreamDecoder&) { return OkStatus(); });
2207*61c4878aSAndroid Build Coastguard Worker 
2208*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(stream_decoder.Read(message), Status::DataLoss());
2209*61c4878aSAndroid Build Coastguard Worker }
2210*61c4878aSAndroid Build Coastguard Worker 
TEST(CodegenMessage,OneOf_Decode_UnsetDecoderIsIgnored)2211*61c4878aSAndroid Build Coastguard Worker TEST(CodegenMessage, OneOf_Decode_UnsetDecoderIsIgnored) {
2212*61c4878aSAndroid Build Coastguard Worker   // clang-format off
2213*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t proto_data[] = {
2214*61c4878aSAndroid Build Coastguard Worker     // type.an_int
2215*61c4878aSAndroid Build Coastguard Worker     0x08, 0x20,
2216*61c4878aSAndroid Build Coastguard Worker   };
2217*61c4878aSAndroid Build Coastguard Worker   // clang-format on
2218*61c4878aSAndroid Build Coastguard Worker 
2219*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(proto_data)));
2220*61c4878aSAndroid Build Coastguard Worker   OneOfTest::StreamDecoder stream_decoder(reader);
2221*61c4878aSAndroid Build Coastguard Worker   OneOfTest::Message message;
2222*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(stream_decoder.Read(message), OkStatus());
2223*61c4878aSAndroid Build Coastguard Worker }
2224*61c4878aSAndroid Build Coastguard Worker 
2225*61c4878aSAndroid Build Coastguard Worker }  // namespace
2226*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::protobuf
2227