1*61c4878aSAndroid Build Coastguard Worker // Copyright 2020 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 "pw_protobuf/decoder.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include <cstring>
18*61c4878aSAndroid Build Coastguard Worker
19*61c4878aSAndroid Build Coastguard Worker #include "pw_preprocessor/util.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Worker namespace pw::protobuf {
23*61c4878aSAndroid Build Coastguard Worker namespace {
24*61c4878aSAndroid Build Coastguard Worker
25*61c4878aSAndroid Build Coastguard Worker class TestDecodeHandler : public DecodeHandler {
26*61c4878aSAndroid Build Coastguard Worker public:
ProcessField(CallbackDecoder & decoder,uint32_t field_number)27*61c4878aSAndroid Build Coastguard Worker Status ProcessField(CallbackDecoder& decoder,
28*61c4878aSAndroid Build Coastguard Worker uint32_t field_number) override {
29*61c4878aSAndroid Build Coastguard Worker std::string_view str;
30*61c4878aSAndroid Build Coastguard Worker
31*61c4878aSAndroid Build Coastguard Worker switch (field_number) {
32*61c4878aSAndroid Build Coastguard Worker case 1:
33*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(OkStatus(), decoder.ReadInt32(&test_int32));
34*61c4878aSAndroid Build Coastguard Worker break;
35*61c4878aSAndroid Build Coastguard Worker case 2:
36*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(OkStatus(), decoder.ReadSint32(&test_sint32));
37*61c4878aSAndroid Build Coastguard Worker break;
38*61c4878aSAndroid Build Coastguard Worker case 3:
39*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(OkStatus(), decoder.ReadBool(&test_bool));
40*61c4878aSAndroid Build Coastguard Worker break;
41*61c4878aSAndroid Build Coastguard Worker case 4:
42*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(OkStatus(), decoder.ReadDouble(&test_double));
43*61c4878aSAndroid Build Coastguard Worker break;
44*61c4878aSAndroid Build Coastguard Worker case 5:
45*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(OkStatus(), decoder.ReadFixed32(&test_fixed32));
46*61c4878aSAndroid Build Coastguard Worker break;
47*61c4878aSAndroid Build Coastguard Worker case 6:
48*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(OkStatus(), decoder.ReadString(&str));
49*61c4878aSAndroid Build Coastguard Worker std::memcpy(test_string, str.data(), str.size());
50*61c4878aSAndroid Build Coastguard Worker test_string[str.size()] = '\0';
51*61c4878aSAndroid Build Coastguard Worker break;
52*61c4878aSAndroid Build Coastguard Worker }
53*61c4878aSAndroid Build Coastguard Worker
54*61c4878aSAndroid Build Coastguard Worker called = true;
55*61c4878aSAndroid Build Coastguard Worker return OkStatus();
56*61c4878aSAndroid Build Coastguard Worker }
57*61c4878aSAndroid Build Coastguard Worker
58*61c4878aSAndroid Build Coastguard Worker bool called = false;
59*61c4878aSAndroid Build Coastguard Worker int32_t test_int32 = 0;
60*61c4878aSAndroid Build Coastguard Worker int32_t test_sint32 = 0;
61*61c4878aSAndroid Build Coastguard Worker bool test_bool = true;
62*61c4878aSAndroid Build Coastguard Worker double test_double = 0;
63*61c4878aSAndroid Build Coastguard Worker uint32_t test_fixed32 = 0;
64*61c4878aSAndroid Build Coastguard Worker char test_string[16];
65*61c4878aSAndroid Build Coastguard Worker };
66*61c4878aSAndroid Build Coastguard Worker
TEST(Decoder,Decode)67*61c4878aSAndroid Build Coastguard Worker TEST(Decoder, Decode) {
68*61c4878aSAndroid Build Coastguard Worker // clang-format off
69*61c4878aSAndroid Build Coastguard Worker uint8_t encoded_proto[] = {
70*61c4878aSAndroid Build Coastguard Worker // type=int32, k=1, v=42
71*61c4878aSAndroid Build Coastguard Worker 0x08, 0x2a,
72*61c4878aSAndroid Build Coastguard Worker // type=sint32, k=2, v=-13
73*61c4878aSAndroid Build Coastguard Worker 0x10, 0x19,
74*61c4878aSAndroid Build Coastguard Worker // type=bool, k=3, v=false
75*61c4878aSAndroid Build Coastguard Worker 0x18, 0x00,
76*61c4878aSAndroid Build Coastguard Worker // type=double, k=4, v=3.14159
77*61c4878aSAndroid Build Coastguard Worker 0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
78*61c4878aSAndroid Build Coastguard Worker // type=fixed32, k=5, v=0xdeadbeef
79*61c4878aSAndroid Build Coastguard Worker 0x2d, 0xef, 0xbe, 0xad, 0xde,
80*61c4878aSAndroid Build Coastguard Worker // type=string, k=6, v="Hello world"
81*61c4878aSAndroid Build Coastguard Worker 0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
82*61c4878aSAndroid Build Coastguard Worker };
83*61c4878aSAndroid Build Coastguard Worker // clang-format on
84*61c4878aSAndroid Build Coastguard Worker
85*61c4878aSAndroid Build Coastguard Worker Decoder decoder(as_bytes(span(encoded_proto)));
86*61c4878aSAndroid Build Coastguard Worker
87*61c4878aSAndroid Build Coastguard Worker int32_t v1 = 0;
88*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
89*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(decoder.FieldNumber(), 1u);
90*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadInt32(&v1), OkStatus());
91*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(v1, 42);
92*61c4878aSAndroid Build Coastguard Worker
93*61c4878aSAndroid Build Coastguard Worker int32_t v2 = 0;
94*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
95*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(decoder.FieldNumber(), 2u);
96*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadSint32(&v2), OkStatus());
97*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(v2, -13);
98*61c4878aSAndroid Build Coastguard Worker
99*61c4878aSAndroid Build Coastguard Worker bool v3 = true;
100*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
101*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(decoder.FieldNumber(), 3u);
102*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadBool(&v3), OkStatus());
103*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(v3);
104*61c4878aSAndroid Build Coastguard Worker
105*61c4878aSAndroid Build Coastguard Worker double v4 = 0;
106*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
107*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(decoder.FieldNumber(), 4u);
108*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadDouble(&v4), OkStatus());
109*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(v4, 3.14159);
110*61c4878aSAndroid Build Coastguard Worker
111*61c4878aSAndroid Build Coastguard Worker uint32_t v5 = 0;
112*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
113*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(decoder.FieldNumber(), 5u);
114*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadFixed32(&v5), OkStatus());
115*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(v5, 0xdeadbeef);
116*61c4878aSAndroid Build Coastguard Worker
117*61c4878aSAndroid Build Coastguard Worker std::string_view v6;
118*61c4878aSAndroid Build Coastguard Worker char buffer[16];
119*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
120*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(decoder.FieldNumber(), 6u);
121*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadString(&v6), OkStatus());
122*61c4878aSAndroid Build Coastguard Worker std::memcpy(buffer, v6.data(), v6.size());
123*61c4878aSAndroid Build Coastguard Worker buffer[v6.size()] = '\0';
124*61c4878aSAndroid Build Coastguard Worker EXPECT_STREQ(buffer, "Hello world");
125*61c4878aSAndroid Build Coastguard Worker
126*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), Status::OutOfRange());
127*61c4878aSAndroid Build Coastguard Worker }
128*61c4878aSAndroid Build Coastguard Worker
TEST(Decoder,Decode_SkipsUnusedFields)129*61c4878aSAndroid Build Coastguard Worker TEST(Decoder, Decode_SkipsUnusedFields) {
130*61c4878aSAndroid Build Coastguard Worker // clang-format off
131*61c4878aSAndroid Build Coastguard Worker uint8_t encoded_proto[] = {
132*61c4878aSAndroid Build Coastguard Worker // type=int32, k=1, v=42
133*61c4878aSAndroid Build Coastguard Worker 0x08, 0x2a,
134*61c4878aSAndroid Build Coastguard Worker // type=sint32, k=2, v=-13
135*61c4878aSAndroid Build Coastguard Worker 0x10, 0x19,
136*61c4878aSAndroid Build Coastguard Worker // type=bool, k=3, v=false
137*61c4878aSAndroid Build Coastguard Worker 0x18, 0x00,
138*61c4878aSAndroid Build Coastguard Worker // type=double, k=4, v=3.14159
139*61c4878aSAndroid Build Coastguard Worker 0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
140*61c4878aSAndroid Build Coastguard Worker // type=fixed32, k=5, v=0xdeadbeef
141*61c4878aSAndroid Build Coastguard Worker 0x2d, 0xef, 0xbe, 0xad, 0xde,
142*61c4878aSAndroid Build Coastguard Worker // type=string, k=6, v="Hello world"
143*61c4878aSAndroid Build Coastguard Worker 0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
144*61c4878aSAndroid Build Coastguard Worker };
145*61c4878aSAndroid Build Coastguard Worker // clang-format on
146*61c4878aSAndroid Build Coastguard Worker
147*61c4878aSAndroid Build Coastguard Worker Decoder decoder(as_bytes(span(encoded_proto)));
148*61c4878aSAndroid Build Coastguard Worker
149*61c4878aSAndroid Build Coastguard Worker // Don't process any fields except for the fourth. Next should still iterate
150*61c4878aSAndroid Build Coastguard Worker // correctly despite field values not being consumed.
151*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
152*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
153*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
154*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
155*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(decoder.FieldNumber(), 4u);
156*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
157*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
158*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), Status::OutOfRange());
159*61c4878aSAndroid Build Coastguard Worker }
160*61c4878aSAndroid Build Coastguard Worker
TEST(Decoder,Decode_BadFieldNumber)161*61c4878aSAndroid Build Coastguard Worker TEST(Decoder, Decode_BadFieldNumber) {
162*61c4878aSAndroid Build Coastguard Worker // clang-format off
163*61c4878aSAndroid Build Coastguard Worker constexpr uint8_t encoded_proto[] = {
164*61c4878aSAndroid Build Coastguard Worker // type=int32, k=1, v=42
165*61c4878aSAndroid Build Coastguard Worker 0x08, 0x2a,
166*61c4878aSAndroid Build Coastguard Worker // type=int32, k=19001, v=42 (invalid field number)
167*61c4878aSAndroid Build Coastguard Worker 0xc8, 0xa3, 0x09, 0x2a,
168*61c4878aSAndroid Build Coastguard Worker // type=bool, k=3, v=false
169*61c4878aSAndroid Build Coastguard Worker 0x18, 0x00,
170*61c4878aSAndroid Build Coastguard Worker };
171*61c4878aSAndroid Build Coastguard Worker // clang-format on
172*61c4878aSAndroid Build Coastguard Worker
173*61c4878aSAndroid Build Coastguard Worker Decoder decoder(as_bytes(span(encoded_proto)));
174*61c4878aSAndroid Build Coastguard Worker int32_t value;
175*61c4878aSAndroid Build Coastguard Worker
176*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), OkStatus());
177*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.FieldNumber(), 1u);
178*61c4878aSAndroid Build Coastguard Worker ASSERT_EQ(decoder.ReadInt32(&value), OkStatus());
179*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(value, 42);
180*61c4878aSAndroid Build Coastguard Worker
181*61c4878aSAndroid Build Coastguard Worker // Bad field.
182*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Next(), Status::DataLoss());
183*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.FieldNumber(), 0u);
184*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadInt32(&value), Status::DataLoss());
185*61c4878aSAndroid Build Coastguard Worker }
186*61c4878aSAndroid Build Coastguard Worker
TEST(CallbackDecoder,Decode)187*61c4878aSAndroid Build Coastguard Worker TEST(CallbackDecoder, Decode) {
188*61c4878aSAndroid Build Coastguard Worker CallbackDecoder decoder;
189*61c4878aSAndroid Build Coastguard Worker TestDecodeHandler handler;
190*61c4878aSAndroid Build Coastguard Worker
191*61c4878aSAndroid Build Coastguard Worker // clang-format off
192*61c4878aSAndroid Build Coastguard Worker uint8_t encoded_proto[] = {
193*61c4878aSAndroid Build Coastguard Worker // type=int32, k=1, v=42
194*61c4878aSAndroid Build Coastguard Worker 0x08, 0x2a,
195*61c4878aSAndroid Build Coastguard Worker // type=sint32, k=2, v=-13
196*61c4878aSAndroid Build Coastguard Worker 0x10, 0x19,
197*61c4878aSAndroid Build Coastguard Worker // type=bool, k=3, v=false
198*61c4878aSAndroid Build Coastguard Worker 0x18, 0x00,
199*61c4878aSAndroid Build Coastguard Worker // type=double, k=4, v=3.14159
200*61c4878aSAndroid Build Coastguard Worker 0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40,
201*61c4878aSAndroid Build Coastguard Worker // type=fixed32, k=5, v=0xdeadbeef
202*61c4878aSAndroid Build Coastguard Worker 0x2d, 0xef, 0xbe, 0xad, 0xde,
203*61c4878aSAndroid Build Coastguard Worker // type=string, k=6, v="Hello world"
204*61c4878aSAndroid Build Coastguard Worker 0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',
205*61c4878aSAndroid Build Coastguard Worker };
206*61c4878aSAndroid Build Coastguard Worker // clang-format on
207*61c4878aSAndroid Build Coastguard Worker
208*61c4878aSAndroid Build Coastguard Worker decoder.set_handler(&handler);
209*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), OkStatus());
210*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(handler.called);
211*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.test_int32, 42);
212*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.test_sint32, -13);
213*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(handler.test_bool);
214*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.test_double, 3.14159);
215*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.test_fixed32, 0xdeadbeef);
216*61c4878aSAndroid Build Coastguard Worker EXPECT_STREQ(handler.test_string, "Hello world");
217*61c4878aSAndroid Build Coastguard Worker }
218*61c4878aSAndroid Build Coastguard Worker
TEST(CallbackDecoder,Decode_OverridesDuplicateFields)219*61c4878aSAndroid Build Coastguard Worker TEST(CallbackDecoder, Decode_OverridesDuplicateFields) {
220*61c4878aSAndroid Build Coastguard Worker CallbackDecoder decoder;
221*61c4878aSAndroid Build Coastguard Worker TestDecodeHandler handler;
222*61c4878aSAndroid Build Coastguard Worker
223*61c4878aSAndroid Build Coastguard Worker // clang-format off
224*61c4878aSAndroid Build Coastguard Worker uint8_t encoded_proto[] = {
225*61c4878aSAndroid Build Coastguard Worker // type=int32, k=1, v=42
226*61c4878aSAndroid Build Coastguard Worker 0x08, 0x2a,
227*61c4878aSAndroid Build Coastguard Worker // type=int32, k=1, v=43
228*61c4878aSAndroid Build Coastguard Worker 0x08, 0x2b,
229*61c4878aSAndroid Build Coastguard Worker // type=int32, k=1, v=44
230*61c4878aSAndroid Build Coastguard Worker 0x08, 0x2c,
231*61c4878aSAndroid Build Coastguard Worker };
232*61c4878aSAndroid Build Coastguard Worker // clang-format on
233*61c4878aSAndroid Build Coastguard Worker
234*61c4878aSAndroid Build Coastguard Worker decoder.set_handler(&handler);
235*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), OkStatus());
236*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(handler.called);
237*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.test_int32, 44);
238*61c4878aSAndroid Build Coastguard Worker }
239*61c4878aSAndroid Build Coastguard Worker
TEST(CallbackDecoder,Decode_Empty)240*61c4878aSAndroid Build Coastguard Worker TEST(CallbackDecoder, Decode_Empty) {
241*61c4878aSAndroid Build Coastguard Worker CallbackDecoder decoder;
242*61c4878aSAndroid Build Coastguard Worker TestDecodeHandler handler;
243*61c4878aSAndroid Build Coastguard Worker
244*61c4878aSAndroid Build Coastguard Worker decoder.set_handler(&handler);
245*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Decode(span<std::byte>()), OkStatus());
246*61c4878aSAndroid Build Coastguard Worker EXPECT_FALSE(handler.called);
247*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.test_int32, 0);
248*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.test_sint32, 0);
249*61c4878aSAndroid Build Coastguard Worker }
250*61c4878aSAndroid Build Coastguard Worker
TEST(CallbackDecoder,Decode_BadData)251*61c4878aSAndroid Build Coastguard Worker TEST(CallbackDecoder, Decode_BadData) {
252*61c4878aSAndroid Build Coastguard Worker CallbackDecoder decoder;
253*61c4878aSAndroid Build Coastguard Worker TestDecodeHandler handler;
254*61c4878aSAndroid Build Coastguard Worker
255*61c4878aSAndroid Build Coastguard Worker // Field key without a value.
256*61c4878aSAndroid Build Coastguard Worker uint8_t encoded_proto[] = {0x08};
257*61c4878aSAndroid Build Coastguard Worker
258*61c4878aSAndroid Build Coastguard Worker decoder.set_handler(&handler);
259*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), Status::DataLoss());
260*61c4878aSAndroid Build Coastguard Worker }
261*61c4878aSAndroid Build Coastguard Worker
262*61c4878aSAndroid Build Coastguard Worker // Only processes fields numbered 1 or 3.
263*61c4878aSAndroid Build Coastguard Worker class OneThreeDecodeHandler : public DecodeHandler {
264*61c4878aSAndroid Build Coastguard Worker public:
ProcessField(CallbackDecoder & decoder,uint32_t field_number)265*61c4878aSAndroid Build Coastguard Worker Status ProcessField(CallbackDecoder& decoder,
266*61c4878aSAndroid Build Coastguard Worker uint32_t field_number) override {
267*61c4878aSAndroid Build Coastguard Worker switch (field_number) {
268*61c4878aSAndroid Build Coastguard Worker case 1:
269*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadInt32(&field_one), OkStatus());
270*61c4878aSAndroid Build Coastguard Worker break;
271*61c4878aSAndroid Build Coastguard Worker case 3:
272*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadInt32(&field_three), OkStatus());
273*61c4878aSAndroid Build Coastguard Worker break;
274*61c4878aSAndroid Build Coastguard Worker default:
275*61c4878aSAndroid Build Coastguard Worker // Do nothing.
276*61c4878aSAndroid Build Coastguard Worker break;
277*61c4878aSAndroid Build Coastguard Worker }
278*61c4878aSAndroid Build Coastguard Worker
279*61c4878aSAndroid Build Coastguard Worker called = true;
280*61c4878aSAndroid Build Coastguard Worker return OkStatus();
281*61c4878aSAndroid Build Coastguard Worker }
282*61c4878aSAndroid Build Coastguard Worker
283*61c4878aSAndroid Build Coastguard Worker bool called = false;
284*61c4878aSAndroid Build Coastguard Worker int32_t field_one = 0;
285*61c4878aSAndroid Build Coastguard Worker int32_t field_three = 0;
286*61c4878aSAndroid Build Coastguard Worker };
287*61c4878aSAndroid Build Coastguard Worker
TEST(CallbackDecoder,Decode_SkipsUnprocessedFields)288*61c4878aSAndroid Build Coastguard Worker TEST(CallbackDecoder, Decode_SkipsUnprocessedFields) {
289*61c4878aSAndroid Build Coastguard Worker CallbackDecoder decoder;
290*61c4878aSAndroid Build Coastguard Worker OneThreeDecodeHandler handler;
291*61c4878aSAndroid Build Coastguard Worker
292*61c4878aSAndroid Build Coastguard Worker // clang-format off
293*61c4878aSAndroid Build Coastguard Worker uint8_t encoded_proto[] = {
294*61c4878aSAndroid Build Coastguard Worker // type=int32, k=1, v=42
295*61c4878aSAndroid Build Coastguard Worker // Should be read.
296*61c4878aSAndroid Build Coastguard Worker 0x08, 0x2a,
297*61c4878aSAndroid Build Coastguard Worker // type=sint32, k=2, v=-13
298*61c4878aSAndroid Build Coastguard Worker // Should be ignored.
299*61c4878aSAndroid Build Coastguard Worker 0x10, 0x19,
300*61c4878aSAndroid Build Coastguard Worker // type=int32, k=2, v=3
301*61c4878aSAndroid Build Coastguard Worker // Should be ignored.
302*61c4878aSAndroid Build Coastguard Worker 0x10, 0x03,
303*61c4878aSAndroid Build Coastguard Worker // type=int32, k=3, v=99
304*61c4878aSAndroid Build Coastguard Worker // Should be read.
305*61c4878aSAndroid Build Coastguard Worker 0x18, 0x63,
306*61c4878aSAndroid Build Coastguard Worker // type=int32, k=4, v=16
307*61c4878aSAndroid Build Coastguard Worker // Should be ignored.
308*61c4878aSAndroid Build Coastguard Worker 0x20, 0x10,
309*61c4878aSAndroid Build Coastguard Worker };
310*61c4878aSAndroid Build Coastguard Worker // clang-format on
311*61c4878aSAndroid Build Coastguard Worker
312*61c4878aSAndroid Build Coastguard Worker decoder.set_handler(&handler);
313*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), OkStatus());
314*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(handler.called);
315*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.field_one, 42);
316*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.field_three, 99);
317*61c4878aSAndroid Build Coastguard Worker }
318*61c4878aSAndroid Build Coastguard Worker
319*61c4878aSAndroid Build Coastguard Worker // Only processes fields numbered 1 or 3, and stops the decode after hitting 1.
320*61c4878aSAndroid Build Coastguard Worker class ExitOnOneDecoder : public DecodeHandler {
321*61c4878aSAndroid Build Coastguard Worker public:
ProcessField(CallbackDecoder & decoder,uint32_t field_number)322*61c4878aSAndroid Build Coastguard Worker Status ProcessField(CallbackDecoder& decoder,
323*61c4878aSAndroid Build Coastguard Worker uint32_t field_number) override {
324*61c4878aSAndroid Build Coastguard Worker switch (field_number) {
325*61c4878aSAndroid Build Coastguard Worker case 1:
326*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadInt32(&field_one), OkStatus());
327*61c4878aSAndroid Build Coastguard Worker return Status::Cancelled();
328*61c4878aSAndroid Build Coastguard Worker case 3:
329*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.ReadInt32(&field_three), OkStatus());
330*61c4878aSAndroid Build Coastguard Worker break;
331*61c4878aSAndroid Build Coastguard Worker default:
332*61c4878aSAndroid Build Coastguard Worker // Do nothing.
333*61c4878aSAndroid Build Coastguard Worker break;
334*61c4878aSAndroid Build Coastguard Worker }
335*61c4878aSAndroid Build Coastguard Worker
336*61c4878aSAndroid Build Coastguard Worker return OkStatus();
337*61c4878aSAndroid Build Coastguard Worker }
338*61c4878aSAndroid Build Coastguard Worker
339*61c4878aSAndroid Build Coastguard Worker int32_t field_one = 0;
340*61c4878aSAndroid Build Coastguard Worker int32_t field_three = 1111;
341*61c4878aSAndroid Build Coastguard Worker };
342*61c4878aSAndroid Build Coastguard Worker
TEST(CallbackDecoder,Decode_StopsOnNonOkStatus)343*61c4878aSAndroid Build Coastguard Worker TEST(CallbackDecoder, Decode_StopsOnNonOkStatus) {
344*61c4878aSAndroid Build Coastguard Worker CallbackDecoder decoder;
345*61c4878aSAndroid Build Coastguard Worker ExitOnOneDecoder handler;
346*61c4878aSAndroid Build Coastguard Worker
347*61c4878aSAndroid Build Coastguard Worker // clang-format off
348*61c4878aSAndroid Build Coastguard Worker uint8_t encoded_proto[] = {
349*61c4878aSAndroid Build Coastguard Worker // type=int32, k=1, v=42
350*61c4878aSAndroid Build Coastguard Worker // Should be read.
351*61c4878aSAndroid Build Coastguard Worker 0x08, 0x2a,
352*61c4878aSAndroid Build Coastguard Worker // type=int32, k=3, v=99
353*61c4878aSAndroid Build Coastguard Worker // Should be skipped.
354*61c4878aSAndroid Build Coastguard Worker 0x18, 0x63,
355*61c4878aSAndroid Build Coastguard Worker // type=int32, k=2, v=16
356*61c4878aSAndroid Build Coastguard Worker // Should be skipped.
357*61c4878aSAndroid Build Coastguard Worker 0x08, 0x10,
358*61c4878aSAndroid Build Coastguard Worker };
359*61c4878aSAndroid Build Coastguard Worker // clang-format on
360*61c4878aSAndroid Build Coastguard Worker
361*61c4878aSAndroid Build Coastguard Worker decoder.set_handler(&handler);
362*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(decoder.Decode(as_bytes(span(encoded_proto))), Status::Cancelled());
363*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.field_one, 42);
364*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(handler.field_three, 1111);
365*61c4878aSAndroid Build Coastguard Worker }
366*61c4878aSAndroid Build Coastguard Worker
367*61c4878aSAndroid Build Coastguard Worker } // namespace
368*61c4878aSAndroid Build Coastguard Worker } // namespace pw::protobuf
369