xref: /aosp_15_r20/external/perfetto/src/protozero/proto_decoder_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/protozero/proto_decoder.h"
18*6dbdd20aSAndroid Build Coastguard Worker 
19*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/utils.h"
20*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/protozero/message.h"
21*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/protozero/proto_utils.h"
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/protozero/scattered_heap_buffer.h"
23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/protozero/static_buffer.h"
24*6dbdd20aSAndroid Build Coastguard Worker #include "test/gtest_and_gmock.h"
25*6dbdd20aSAndroid Build Coastguard Worker 
26*6dbdd20aSAndroid Build Coastguard Worker #include "src/protozero/test/example_proto/test_messages.pb.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "src/protozero/test/example_proto/test_messages.pbzero.h"
28*6dbdd20aSAndroid Build Coastguard Worker 
29*6dbdd20aSAndroid Build Coastguard Worker // Generated by the protozero plugin.
30*6dbdd20aSAndroid Build Coastguard Worker namespace pbtest = protozero::test::protos::pbzero;
31*6dbdd20aSAndroid Build Coastguard Worker 
32*6dbdd20aSAndroid Build Coastguard Worker // Generated by the official protobuf compiler.
33*6dbdd20aSAndroid Build Coastguard Worker namespace pbgold = protozero::test::protos;
34*6dbdd20aSAndroid Build Coastguard Worker 
35*6dbdd20aSAndroid Build Coastguard Worker namespace protozero {
36*6dbdd20aSAndroid Build Coastguard Worker namespace {
37*6dbdd20aSAndroid Build Coastguard Worker 
38*6dbdd20aSAndroid Build Coastguard Worker using ::testing::_;
39*6dbdd20aSAndroid Build Coastguard Worker using ::testing::ElementsAre;
40*6dbdd20aSAndroid Build Coastguard Worker using ::testing::InSequence;
41*6dbdd20aSAndroid Build Coastguard Worker using ::testing::Invoke;
42*6dbdd20aSAndroid Build Coastguard Worker using namespace proto_utils;
43*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,ReadString)44*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, ReadString) {
45*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<Message> message;
46*6dbdd20aSAndroid Build Coastguard Worker 
47*6dbdd20aSAndroid Build Coastguard Worker   static constexpr char kTestString[] = "test";
48*6dbdd20aSAndroid Build Coastguard Worker   message->AppendString(1, kTestString);
49*6dbdd20aSAndroid Build Coastguard Worker   std::vector<uint8_t> proto = message.SerializeAsArray();
50*6dbdd20aSAndroid Build Coastguard Worker   TypedProtoDecoder<32, false> decoder(proto.data(), proto.size());
51*6dbdd20aSAndroid Build Coastguard Worker 
52*6dbdd20aSAndroid Build Coastguard Worker   const auto& field = decoder.Get(1);
53*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(field.type(), ProtoWireType::kLengthDelimited);
54*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(field.size(), sizeof(kTestString) - 1);
55*6dbdd20aSAndroid Build Coastguard Worker   for (size_t i = 0; i < sizeof(kTestString) - 1; i++) {
56*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(field.data()[i], kTestString[i]);
57*6dbdd20aSAndroid Build Coastguard Worker   }
58*6dbdd20aSAndroid Build Coastguard Worker }
59*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,SkipVeryLargeFields)60*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, SkipVeryLargeFields) {
61*6dbdd20aSAndroid Build Coastguard Worker   const size_t kPayloadSize = 257 * 1024 * 1024;
62*6dbdd20aSAndroid Build Coastguard Worker   const uint64_t data_size = 4096 + kPayloadSize;
63*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<uint8_t, perfetto::base::FreeDeleter> data(
64*6dbdd20aSAndroid Build Coastguard Worker       static_cast<uint8_t*>(malloc(data_size)));
65*6dbdd20aSAndroid Build Coastguard Worker   StaticBuffered<Message> message(data.get(), data_size);
66*6dbdd20aSAndroid Build Coastguard Worker 
67*6dbdd20aSAndroid Build Coastguard Worker   // Append a valid field.
68*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/1, 11);
69*6dbdd20aSAndroid Build Coastguard Worker 
70*6dbdd20aSAndroid Build Coastguard Worker   // Append a very large field that will be skipped.
71*6dbdd20aSAndroid Build Coastguard Worker   uint8_t raw[10];
72*6dbdd20aSAndroid Build Coastguard Worker   uint8_t* wptr = raw;
73*6dbdd20aSAndroid Build Coastguard Worker   wptr = WriteVarInt(MakeTagLengthDelimited(2), wptr);
74*6dbdd20aSAndroid Build Coastguard Worker   wptr = WriteVarInt(kPayloadSize, wptr);
75*6dbdd20aSAndroid Build Coastguard Worker   message->AppendRawProtoBytes(raw, static_cast<size_t>(wptr - raw));
76*6dbdd20aSAndroid Build Coastguard Worker   const size_t kPaddingSize = 1024 * 128;
77*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<uint8_t[]> padding(new uint8_t[kPaddingSize]());
78*6dbdd20aSAndroid Build Coastguard Worker   for (size_t i = 0; i < kPayloadSize / kPaddingSize; i++)
79*6dbdd20aSAndroid Build Coastguard Worker     message->AppendRawProtoBytes(padding.get(), kPaddingSize);
80*6dbdd20aSAndroid Build Coastguard Worker 
81*6dbdd20aSAndroid Build Coastguard Worker   // Append another valid field.
82*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/3, 13);
83*6dbdd20aSAndroid Build Coastguard Worker 
84*6dbdd20aSAndroid Build Coastguard Worker   ProtoDecoder decoder(data.get(), message.Finalize());
85*6dbdd20aSAndroid Build Coastguard Worker   Field field = decoder.ReadField();
86*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(1u, field.id());
87*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(11, field.as_int32());
88*6dbdd20aSAndroid Build Coastguard Worker 
89*6dbdd20aSAndroid Build Coastguard Worker   field = decoder.ReadField();
90*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(3u, field.id());
91*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(13, field.as_int32());
92*6dbdd20aSAndroid Build Coastguard Worker 
93*6dbdd20aSAndroid Build Coastguard Worker   field = decoder.ReadField();
94*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(field.valid());
95*6dbdd20aSAndroid Build Coastguard Worker }
96*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,SingleRepeatedField)97*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, SingleRepeatedField) {
98*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<Message> message;
99*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/2, 10);
100*6dbdd20aSAndroid Build Coastguard Worker   auto data = message.SerializeAsArray();
101*6dbdd20aSAndroid Build Coastguard Worker   TypedProtoDecoder<2, true> tpd(data.data(), data.size());
102*6dbdd20aSAndroid Build Coastguard Worker   auto it = tpd.GetRepeated<int32_t>(/*field_id=*/2);
103*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_TRUE(it);
104*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(it.field().as_int32(), 10);
105*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(*it, 10);
106*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FALSE(++it);
107*6dbdd20aSAndroid Build Coastguard Worker }
108*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,RepeatedVariableLengthField)109*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, RepeatedVariableLengthField) {
110*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<Message> message;
111*6dbdd20aSAndroid Build Coastguard Worker 
112*6dbdd20aSAndroid Build Coastguard Worker   static constexpr char kTestString[] = "test";
113*6dbdd20aSAndroid Build Coastguard Worker   static constexpr char kTestString2[] = "honk honk";
114*6dbdd20aSAndroid Build Coastguard Worker   message->AppendString(1, kTestString);
115*6dbdd20aSAndroid Build Coastguard Worker   message->AppendString(1, kTestString2);
116*6dbdd20aSAndroid Build Coastguard Worker   std::vector<uint8_t> proto = message.SerializeAsArray();
117*6dbdd20aSAndroid Build Coastguard Worker   TypedProtoDecoder<32, false> decoder(proto.data(), proto.size());
118*6dbdd20aSAndroid Build Coastguard Worker 
119*6dbdd20aSAndroid Build Coastguard Worker   auto it = decoder.GetRepeated<ConstChars>(1);
120*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(it->type(), ProtoWireType::kLengthDelimited);
121*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(it->size(), sizeof(kTestString) - 1);
122*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(it->as_std_string(), std::string(kTestString));
123*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ((*it).ToStdString(), std::string(kTestString));
124*6dbdd20aSAndroid Build Coastguard Worker   ++it;
125*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(it->type(), ProtoWireType::kLengthDelimited);
126*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(it->size(), sizeof(kTestString2) - 1);
127*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ(it->as_std_string(), std::string(kTestString2));
128*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_EQ((*it).ToStdString(), std::string(kTestString2));
129*6dbdd20aSAndroid Build Coastguard Worker }
130*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,SingleRepeatedFieldWithExpansion)131*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, SingleRepeatedFieldWithExpansion) {
132*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<Message> message;
133*6dbdd20aSAndroid Build Coastguard Worker   for (int i = 0; i < 2000; i++) {
134*6dbdd20aSAndroid Build Coastguard Worker     message->AppendVarInt(/*field_id=*/2, i);
135*6dbdd20aSAndroid Build Coastguard Worker   }
136*6dbdd20aSAndroid Build Coastguard Worker   auto data = message.SerializeAsArray();
137*6dbdd20aSAndroid Build Coastguard Worker   TypedProtoDecoder<2, true> tpd(data.data(), data.size());
138*6dbdd20aSAndroid Build Coastguard Worker   auto it = tpd.GetRepeated<int32_t>(/*field_id=*/2);
139*6dbdd20aSAndroid Build Coastguard Worker   for (int i = 0; i < 2000; i++) {
140*6dbdd20aSAndroid Build Coastguard Worker     EXPECT_TRUE(it);
141*6dbdd20aSAndroid Build Coastguard Worker     EXPECT_EQ(*it, i);
142*6dbdd20aSAndroid Build Coastguard Worker     ++it;
143*6dbdd20aSAndroid Build Coastguard Worker   }
144*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FALSE(it);
145*6dbdd20aSAndroid Build Coastguard Worker }
146*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,NoRepeatedField)147*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, NoRepeatedField) {
148*6dbdd20aSAndroid Build Coastguard Worker   uint8_t buf[] = {0x01};
149*6dbdd20aSAndroid Build Coastguard Worker   TypedProtoDecoder<2, true> tpd(buf, 1);
150*6dbdd20aSAndroid Build Coastguard Worker   auto it = tpd.GetRepeated<int32_t>(/*field_id=*/1);
151*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FALSE(it);
152*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FALSE(tpd.Get(2).valid());
153*6dbdd20aSAndroid Build Coastguard Worker }
154*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,RepeatedFields)155*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, RepeatedFields) {
156*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<Message> message;
157*6dbdd20aSAndroid Build Coastguard Worker 
158*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(1, 10);
159*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(2, 20);
160*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(3, 30);
161*6dbdd20aSAndroid Build Coastguard Worker 
162*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(1, 11);
163*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(2, 21);
164*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(2, 22);
165*6dbdd20aSAndroid Build Coastguard Worker 
166*6dbdd20aSAndroid Build Coastguard Worker   // When iterating with the simple decoder we should just see fields in parsing
167*6dbdd20aSAndroid Build Coastguard Worker   // order.
168*6dbdd20aSAndroid Build Coastguard Worker   auto data = message.SerializeAsArray();
169*6dbdd20aSAndroid Build Coastguard Worker   ProtoDecoder decoder(data.data(), data.size());
170*6dbdd20aSAndroid Build Coastguard Worker   std::string fields_seen;
171*6dbdd20aSAndroid Build Coastguard Worker   for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
172*6dbdd20aSAndroid Build Coastguard Worker     fields_seen +=
173*6dbdd20aSAndroid Build Coastguard Worker         std::to_string(fld.id()) + ":" + std::to_string(fld.as_int32()) + ";";
174*6dbdd20aSAndroid Build Coastguard Worker   }
175*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(fields_seen, "1:10;2:20;3:30;1:11;2:21;2:22;");
176*6dbdd20aSAndroid Build Coastguard Worker 
177*6dbdd20aSAndroid Build Coastguard Worker   TypedProtoDecoder<4, true> tpd(data.data(), data.size());
178*6dbdd20aSAndroid Build Coastguard Worker 
179*6dbdd20aSAndroid Build Coastguard Worker   // When parsing with the one-shot decoder and querying the single field id, we
180*6dbdd20aSAndroid Build Coastguard Worker   // should see the last value for each of them, not the first one. This is the
181*6dbdd20aSAndroid Build Coastguard Worker   // current behavior of Google protobuf's parser.
182*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(tpd.Get(1).as_int32(), 11);
183*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(tpd.Get(2).as_int32(), 22);
184*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(tpd.Get(3).as_int32(), 30);
185*6dbdd20aSAndroid Build Coastguard Worker 
186*6dbdd20aSAndroid Build Coastguard Worker   // But when iterating we should see values in the original order.
187*6dbdd20aSAndroid Build Coastguard Worker   auto it = tpd.GetRepeated<int32_t>(1);
188*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(*it, 10);
189*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(*++it, 11);
190*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FALSE(++it);
191*6dbdd20aSAndroid Build Coastguard Worker 
192*6dbdd20aSAndroid Build Coastguard Worker   it = tpd.GetRepeated<int32_t>(2);
193*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(*it++, 20);
194*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(*it++, 21);
195*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(*it++, 22);
196*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FALSE(it);
197*6dbdd20aSAndroid Build Coastguard Worker 
198*6dbdd20aSAndroid Build Coastguard Worker   it = tpd.GetRepeated<int32_t>(3);
199*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(*it, 30);
200*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FALSE(++it);
201*6dbdd20aSAndroid Build Coastguard Worker }
202*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,FixedData)203*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, FixedData) {
204*6dbdd20aSAndroid Build Coastguard Worker   struct FieldExpectation {
205*6dbdd20aSAndroid Build Coastguard Worker     const char* encoded;
206*6dbdd20aSAndroid Build Coastguard Worker     size_t encoded_size;
207*6dbdd20aSAndroid Build Coastguard Worker     uint32_t id;
208*6dbdd20aSAndroid Build Coastguard Worker     ProtoWireType type;
209*6dbdd20aSAndroid Build Coastguard Worker     uint64_t int_value;
210*6dbdd20aSAndroid Build Coastguard Worker   };
211*6dbdd20aSAndroid Build Coastguard Worker 
212*6dbdd20aSAndroid Build Coastguard Worker   const FieldExpectation kFieldExpectations[] = {
213*6dbdd20aSAndroid Build Coastguard Worker       {"\x08\x00", 2, 1, ProtoWireType::kVarInt, 0},
214*6dbdd20aSAndroid Build Coastguard Worker       {"\x08\x01", 2, 1, ProtoWireType::kVarInt, 1},
215*6dbdd20aSAndroid Build Coastguard Worker       {"\x08\x42", 2, 1, ProtoWireType::kVarInt, 0x42},
216*6dbdd20aSAndroid Build Coastguard Worker       {"\xF8\x07\x42", 3, 127, ProtoWireType::kVarInt, 0x42},
217*6dbdd20aSAndroid Build Coastguard Worker       {"\xB8\x3E\xFF\xFF\xFF\xFF\x0F", 7, 999, ProtoWireType::kVarInt,
218*6dbdd20aSAndroid Build Coastguard Worker        0xFFFFFFFF},
219*6dbdd20aSAndroid Build Coastguard Worker       {"\x7D\x42\x00\x00\x00", 5, 15, ProtoWireType::kFixed32, 0x42},
220*6dbdd20aSAndroid Build Coastguard Worker       {"\xBD\x3E\x78\x56\x34\x12", 6, 999, ProtoWireType::kFixed32, 0x12345678},
221*6dbdd20aSAndroid Build Coastguard Worker       {"\x79\x42\x00\x00\x00\x00\x00\x00\x00", 9, 15, ProtoWireType::kFixed64,
222*6dbdd20aSAndroid Build Coastguard Worker        0x42},
223*6dbdd20aSAndroid Build Coastguard Worker       {"\xB9\x3E\x08\x07\x06\x05\x04\x03\x02\x01", 10, 999,
224*6dbdd20aSAndroid Build Coastguard Worker        ProtoWireType::kFixed64, 0x0102030405060708},
225*6dbdd20aSAndroid Build Coastguard Worker       {"\x0A\x00", 2, 1, ProtoWireType::kLengthDelimited, 0},
226*6dbdd20aSAndroid Build Coastguard Worker       {"\x0A\x04|abc", 6, 1, ProtoWireType::kLengthDelimited, 4},
227*6dbdd20aSAndroid Build Coastguard Worker       {"\xBA\x3E\x04|abc", 7, 999, ProtoWireType::kLengthDelimited, 4},
228*6dbdd20aSAndroid Build Coastguard Worker       {"\xBA\x3E\x83\x01|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab"
229*6dbdd20aSAndroid Build Coastguard Worker        "cdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu"
230*6dbdd20aSAndroid Build Coastguard Worker        "vwx",
231*6dbdd20aSAndroid Build Coastguard Worker        135, 999, ProtoWireType::kLengthDelimited, 131},
232*6dbdd20aSAndroid Build Coastguard Worker   };
233*6dbdd20aSAndroid Build Coastguard Worker 
234*6dbdd20aSAndroid Build Coastguard Worker   for (size_t i = 0; i < perfetto::base::ArraySize(kFieldExpectations); ++i) {
235*6dbdd20aSAndroid Build Coastguard Worker     const FieldExpectation& exp = kFieldExpectations[i];
236*6dbdd20aSAndroid Build Coastguard Worker     TypedProtoDecoder<999, 0> decoder(
237*6dbdd20aSAndroid Build Coastguard Worker         reinterpret_cast<const uint8_t*>(exp.encoded), exp.encoded_size);
238*6dbdd20aSAndroid Build Coastguard Worker 
239*6dbdd20aSAndroid Build Coastguard Worker     auto& field = decoder.Get(exp.id);
240*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(exp.type, field.type());
241*6dbdd20aSAndroid Build Coastguard Worker 
242*6dbdd20aSAndroid Build Coastguard Worker     if (field.type() == ProtoWireType::kLengthDelimited) {
243*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(exp.int_value, field.size());
244*6dbdd20aSAndroid Build Coastguard Worker     } else {
245*6dbdd20aSAndroid Build Coastguard Worker       ASSERT_EQ(int64_t(exp.int_value), field.as_int64());
246*6dbdd20aSAndroid Build Coastguard Worker       // Proto encodes booleans as varints of 0 or 1.
247*6dbdd20aSAndroid Build Coastguard Worker       if (exp.int_value == 0 || exp.int_value == 1) {
248*6dbdd20aSAndroid Build Coastguard Worker         ASSERT_EQ(int64_t(exp.int_value), field.as_bool());
249*6dbdd20aSAndroid Build Coastguard Worker       }
250*6dbdd20aSAndroid Build Coastguard Worker     }
251*6dbdd20aSAndroid Build Coastguard Worker   }
252*6dbdd20aSAndroid Build Coastguard Worker 
253*6dbdd20aSAndroid Build Coastguard Worker   // Test float and doubles decoding.
254*6dbdd20aSAndroid Build Coastguard Worker   const char buf[] = "\x0d\x00\x00\xa0\x3f\x11\x00\x00\x00\x00\x00\x42\x8f\xc0";
255*6dbdd20aSAndroid Build Coastguard Worker   TypedProtoDecoder<2, false> decoder(reinterpret_cast<const uint8_t*>(buf),
256*6dbdd20aSAndroid Build Coastguard Worker                                       sizeof(buf));
257*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(decoder.Get(1).as_float(), 1.25f);
258*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_DOUBLE_EQ(decoder.Get(2).as_double(), -1000.25);
259*6dbdd20aSAndroid Build Coastguard Worker }
260*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,FindField)261*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, FindField) {
262*6dbdd20aSAndroid Build Coastguard Worker   uint8_t buf[] = {0x08, 0x00};  // field_id 1, varint value 0.
263*6dbdd20aSAndroid Build Coastguard Worker   ProtoDecoder pd(buf, 2);
264*6dbdd20aSAndroid Build Coastguard Worker 
265*6dbdd20aSAndroid Build Coastguard Worker   auto field = pd.FindField(1);
266*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(field);
267*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(field.as_int64(), 0);
268*6dbdd20aSAndroid Build Coastguard Worker 
269*6dbdd20aSAndroid Build Coastguard Worker   auto field2 = pd.FindField(2);
270*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FALSE(field2);
271*6dbdd20aSAndroid Build Coastguard Worker }
272*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,MoveTypedDecoder)273*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, MoveTypedDecoder) {
274*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<Message> message;
275*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/1, 10);
276*6dbdd20aSAndroid Build Coastguard Worker   std::vector<uint8_t> proto = message.SerializeAsArray();
277*6dbdd20aSAndroid Build Coastguard Worker 
278*6dbdd20aSAndroid Build Coastguard Worker   // Construct a decoder that uses inline storage (i.e., the fields are stored
279*6dbdd20aSAndroid Build Coastguard Worker   // within the object itself).
280*6dbdd20aSAndroid Build Coastguard Worker   using Decoder = TypedProtoDecoder<32, false>;
281*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<Decoder> decoder(new Decoder(proto.data(), proto.size()));
282*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_GE(reinterpret_cast<uintptr_t>(&decoder->at<1>()),
283*6dbdd20aSAndroid Build Coastguard Worker             reinterpret_cast<uintptr_t>(decoder.get()));
284*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_LT(reinterpret_cast<uintptr_t>(&decoder->at<1>()),
285*6dbdd20aSAndroid Build Coastguard Worker             reinterpret_cast<uintptr_t>(decoder.get()) + sizeof(Decoder));
286*6dbdd20aSAndroid Build Coastguard Worker 
287*6dbdd20aSAndroid Build Coastguard Worker   // Move the decoder into another object and deallocate the original object.
288*6dbdd20aSAndroid Build Coastguard Worker   Decoder decoder2(std::move(*decoder));
289*6dbdd20aSAndroid Build Coastguard Worker   decoder.reset();
290*6dbdd20aSAndroid Build Coastguard Worker 
291*6dbdd20aSAndroid Build Coastguard Worker   // Check that the contents got moved correctly.
292*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(decoder2.Get(1).as_int32(), 10);
293*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_GE(reinterpret_cast<uintptr_t>(&decoder2.at<1>()),
294*6dbdd20aSAndroid Build Coastguard Worker             reinterpret_cast<uintptr_t>(&decoder2));
295*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_LT(reinterpret_cast<uintptr_t>(&decoder2.at<1>()),
296*6dbdd20aSAndroid Build Coastguard Worker             reinterpret_cast<uintptr_t>(&decoder2) + sizeof(Decoder));
297*6dbdd20aSAndroid Build Coastguard Worker }
298*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,PackedRepeatedVarint)299*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, PackedRepeatedVarint) {
300*6dbdd20aSAndroid Build Coastguard Worker   std::vector<int32_t> values = {42, 255, 0, -1};
301*6dbdd20aSAndroid Build Coastguard Worker 
302*6dbdd20aSAndroid Build Coastguard Worker   // serialize using protobuf library
303*6dbdd20aSAndroid Build Coastguard Worker   pbgold::PackedRepeatedFields msg;
304*6dbdd20aSAndroid Build Coastguard Worker   for (auto v : values)
305*6dbdd20aSAndroid Build Coastguard Worker     msg.add_field_int32(v);
306*6dbdd20aSAndroid Build Coastguard Worker   std::string serialized = msg.SerializeAsString();
307*6dbdd20aSAndroid Build Coastguard Worker 
308*6dbdd20aSAndroid Build Coastguard Worker   // decode using TypedProtoDecoder directly
309*6dbdd20aSAndroid Build Coastguard Worker   {
310*6dbdd20aSAndroid Build Coastguard Worker     constexpr int kFieldId =
311*6dbdd20aSAndroid Build Coastguard Worker         pbtest::PackedRepeatedFields::kFieldInt32FieldNumber;
312*6dbdd20aSAndroid Build Coastguard Worker     TypedProtoDecoder<kFieldId, false> decoder(
313*6dbdd20aSAndroid Build Coastguard Worker         reinterpret_cast<const uint8_t*>(serialized.data()), serialized.size());
314*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_TRUE(decoder.at<kFieldId>().valid());
315*6dbdd20aSAndroid Build Coastguard Worker     bool parse_error = false;
316*6dbdd20aSAndroid Build Coastguard Worker     auto packed_it =
317*6dbdd20aSAndroid Build Coastguard Worker         decoder.GetPackedRepeated<proto_utils::ProtoWireType::kVarInt, int32_t>(
318*6dbdd20aSAndroid Build Coastguard Worker             kFieldId, &parse_error);
319*6dbdd20aSAndroid Build Coastguard Worker 
320*6dbdd20aSAndroid Build Coastguard Worker     std::vector<int32_t> decoded_values;
321*6dbdd20aSAndroid Build Coastguard Worker     for (; packed_it; ++packed_it) {
322*6dbdd20aSAndroid Build Coastguard Worker       auto v = *packed_it;
323*6dbdd20aSAndroid Build Coastguard Worker       decoded_values.push_back(v);
324*6dbdd20aSAndroid Build Coastguard Worker     }
325*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(values, decoded_values);
326*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_FALSE(parse_error);
327*6dbdd20aSAndroid Build Coastguard Worker   }
328*6dbdd20aSAndroid Build Coastguard Worker 
329*6dbdd20aSAndroid Build Coastguard Worker   // decode using plugin-generated accessor
330*6dbdd20aSAndroid Build Coastguard Worker   {
331*6dbdd20aSAndroid Build Coastguard Worker     auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
332*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_TRUE(decoder.has_field_int32());
333*6dbdd20aSAndroid Build Coastguard Worker 
334*6dbdd20aSAndroid Build Coastguard Worker     bool parse_error = false;
335*6dbdd20aSAndroid Build Coastguard Worker     std::vector<int32_t> decoded_values;
336*6dbdd20aSAndroid Build Coastguard Worker     for (auto packed_it = decoder.field_int32(&parse_error); packed_it;
337*6dbdd20aSAndroid Build Coastguard Worker          ++packed_it) {
338*6dbdd20aSAndroid Build Coastguard Worker       auto v = *packed_it;
339*6dbdd20aSAndroid Build Coastguard Worker       decoded_values.push_back(v);
340*6dbdd20aSAndroid Build Coastguard Worker     }
341*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(values, decoded_values);
342*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_FALSE(parse_error);
343*6dbdd20aSAndroid Build Coastguard Worker   }
344*6dbdd20aSAndroid Build Coastguard Worker 
345*6dbdd20aSAndroid Build Coastguard Worker   // unset field case
346*6dbdd20aSAndroid Build Coastguard Worker   pbgold::PackedRepeatedFields empty_msg;
347*6dbdd20aSAndroid Build Coastguard Worker   std::string empty_serialized = empty_msg.SerializeAsString();
348*6dbdd20aSAndroid Build Coastguard Worker   auto decoder = pbtest::PackedRepeatedFields::Decoder(empty_serialized);
349*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(decoder.has_field_int32());
350*6dbdd20aSAndroid Build Coastguard Worker   bool parse_error = false;
351*6dbdd20aSAndroid Build Coastguard Worker   auto packed_it = decoder.field_int32(&parse_error);
352*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(bool(packed_it));
353*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(parse_error);
354*6dbdd20aSAndroid Build Coastguard Worker }
355*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,PackedRepeatedFixed32)356*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, PackedRepeatedFixed32) {
357*6dbdd20aSAndroid Build Coastguard Worker   std::vector<uint32_t> values = {42, 255, 0, 1};
358*6dbdd20aSAndroid Build Coastguard Worker 
359*6dbdd20aSAndroid Build Coastguard Worker   // serialize using protobuf library
360*6dbdd20aSAndroid Build Coastguard Worker   pbgold::PackedRepeatedFields msg;
361*6dbdd20aSAndroid Build Coastguard Worker   for (auto v : values)
362*6dbdd20aSAndroid Build Coastguard Worker     msg.add_field_fixed32(v);
363*6dbdd20aSAndroid Build Coastguard Worker   std::string serialized = msg.SerializeAsString();
364*6dbdd20aSAndroid Build Coastguard Worker 
365*6dbdd20aSAndroid Build Coastguard Worker   // decode using TypedProtoDecoder directly
366*6dbdd20aSAndroid Build Coastguard Worker   {
367*6dbdd20aSAndroid Build Coastguard Worker     constexpr int kFieldId =
368*6dbdd20aSAndroid Build Coastguard Worker         pbtest::PackedRepeatedFields::kFieldFixed32FieldNumber;
369*6dbdd20aSAndroid Build Coastguard Worker     TypedProtoDecoder<kFieldId, false> decoder(
370*6dbdd20aSAndroid Build Coastguard Worker         reinterpret_cast<const uint8_t*>(serialized.data()), serialized.size());
371*6dbdd20aSAndroid Build Coastguard Worker     bool parse_error = false;
372*6dbdd20aSAndroid Build Coastguard Worker     auto packed_it =
373*6dbdd20aSAndroid Build Coastguard Worker         decoder
374*6dbdd20aSAndroid Build Coastguard Worker             .GetPackedRepeated<proto_utils::ProtoWireType::kFixed32, uint32_t>(
375*6dbdd20aSAndroid Build Coastguard Worker                 kFieldId, &parse_error);
376*6dbdd20aSAndroid Build Coastguard Worker 
377*6dbdd20aSAndroid Build Coastguard Worker     std::vector<uint32_t> decoded_values;
378*6dbdd20aSAndroid Build Coastguard Worker     for (; packed_it; ++packed_it) {
379*6dbdd20aSAndroid Build Coastguard Worker       auto v = *packed_it;
380*6dbdd20aSAndroid Build Coastguard Worker       decoded_values.push_back(v);
381*6dbdd20aSAndroid Build Coastguard Worker     }
382*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(values, decoded_values);
383*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_FALSE(parse_error);
384*6dbdd20aSAndroid Build Coastguard Worker   }
385*6dbdd20aSAndroid Build Coastguard Worker 
386*6dbdd20aSAndroid Build Coastguard Worker   // decode using plugin-generated accessor
387*6dbdd20aSAndroid Build Coastguard Worker   {
388*6dbdd20aSAndroid Build Coastguard Worker     auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
389*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_TRUE(decoder.has_field_fixed32());
390*6dbdd20aSAndroid Build Coastguard Worker 
391*6dbdd20aSAndroid Build Coastguard Worker     bool parse_error = false;
392*6dbdd20aSAndroid Build Coastguard Worker     std::vector<uint32_t> decoded_values;
393*6dbdd20aSAndroid Build Coastguard Worker     for (auto packed_it = decoder.field_fixed32(&parse_error); packed_it;
394*6dbdd20aSAndroid Build Coastguard Worker          packed_it++) {
395*6dbdd20aSAndroid Build Coastguard Worker       auto v = *packed_it;
396*6dbdd20aSAndroid Build Coastguard Worker       decoded_values.push_back(v);
397*6dbdd20aSAndroid Build Coastguard Worker     }
398*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(values, decoded_values);
399*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_FALSE(parse_error);
400*6dbdd20aSAndroid Build Coastguard Worker   }
401*6dbdd20aSAndroid Build Coastguard Worker 
402*6dbdd20aSAndroid Build Coastguard Worker   // unset field case
403*6dbdd20aSAndroid Build Coastguard Worker   pbgold::PackedRepeatedFields empty_msg;
404*6dbdd20aSAndroid Build Coastguard Worker   std::string empty_serialized = empty_msg.SerializeAsString();
405*6dbdd20aSAndroid Build Coastguard Worker   auto decoder = pbtest::PackedRepeatedFields::Decoder(empty_serialized);
406*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(decoder.has_field_fixed32());
407*6dbdd20aSAndroid Build Coastguard Worker   bool parse_error = false;
408*6dbdd20aSAndroid Build Coastguard Worker   auto packed_it = decoder.field_fixed32(&parse_error);
409*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(bool(packed_it));
410*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(parse_error);
411*6dbdd20aSAndroid Build Coastguard Worker }
412*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,PackedRepeatedFixed64)413*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, PackedRepeatedFixed64) {
414*6dbdd20aSAndroid Build Coastguard Worker   std::vector<int64_t> values = {42, 255, 0, -1};
415*6dbdd20aSAndroid Build Coastguard Worker 
416*6dbdd20aSAndroid Build Coastguard Worker   // serialize using protobuf library
417*6dbdd20aSAndroid Build Coastguard Worker   pbgold::PackedRepeatedFields msg;
418*6dbdd20aSAndroid Build Coastguard Worker   for (auto v : values)
419*6dbdd20aSAndroid Build Coastguard Worker     msg.add_field_sfixed64(v);
420*6dbdd20aSAndroid Build Coastguard Worker   std::string serialized = msg.SerializeAsString();
421*6dbdd20aSAndroid Build Coastguard Worker 
422*6dbdd20aSAndroid Build Coastguard Worker   // decode using TypedProtoDecoder directly
423*6dbdd20aSAndroid Build Coastguard Worker   {
424*6dbdd20aSAndroid Build Coastguard Worker     constexpr int kFieldId =
425*6dbdd20aSAndroid Build Coastguard Worker         pbtest::PackedRepeatedFields::kFieldSfixed64FieldNumber;
426*6dbdd20aSAndroid Build Coastguard Worker     TypedProtoDecoder<kFieldId, false> decoder(
427*6dbdd20aSAndroid Build Coastguard Worker         reinterpret_cast<const uint8_t*>(serialized.data()), serialized.size());
428*6dbdd20aSAndroid Build Coastguard Worker     bool parse_error = false;
429*6dbdd20aSAndroid Build Coastguard Worker     auto packed_it =
430*6dbdd20aSAndroid Build Coastguard Worker         decoder
431*6dbdd20aSAndroid Build Coastguard Worker             .GetPackedRepeated<proto_utils::ProtoWireType::kFixed64, int64_t>(
432*6dbdd20aSAndroid Build Coastguard Worker                 kFieldId, &parse_error);
433*6dbdd20aSAndroid Build Coastguard Worker 
434*6dbdd20aSAndroid Build Coastguard Worker     std::vector<int64_t> decoded_values;
435*6dbdd20aSAndroid Build Coastguard Worker     for (; packed_it; ++packed_it) {
436*6dbdd20aSAndroid Build Coastguard Worker       auto v = *packed_it;
437*6dbdd20aSAndroid Build Coastguard Worker       decoded_values.push_back(v);
438*6dbdd20aSAndroid Build Coastguard Worker     }
439*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(values, decoded_values);
440*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_FALSE(parse_error);
441*6dbdd20aSAndroid Build Coastguard Worker   }
442*6dbdd20aSAndroid Build Coastguard Worker 
443*6dbdd20aSAndroid Build Coastguard Worker   // decode using plugin-generated accessor
444*6dbdd20aSAndroid Build Coastguard Worker   {
445*6dbdd20aSAndroid Build Coastguard Worker     auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
446*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_TRUE(decoder.has_field_sfixed64());
447*6dbdd20aSAndroid Build Coastguard Worker 
448*6dbdd20aSAndroid Build Coastguard Worker     bool parse_error = false;
449*6dbdd20aSAndroid Build Coastguard Worker     std::vector<int64_t> decoded_values;
450*6dbdd20aSAndroid Build Coastguard Worker     for (auto packed_it = decoder.field_sfixed64(&parse_error); packed_it;
451*6dbdd20aSAndroid Build Coastguard Worker          packed_it++) {
452*6dbdd20aSAndroid Build Coastguard Worker       auto v = *packed_it;
453*6dbdd20aSAndroid Build Coastguard Worker       decoded_values.push_back(v);
454*6dbdd20aSAndroid Build Coastguard Worker     }
455*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(values, decoded_values);
456*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_FALSE(parse_error);
457*6dbdd20aSAndroid Build Coastguard Worker   }
458*6dbdd20aSAndroid Build Coastguard Worker 
459*6dbdd20aSAndroid Build Coastguard Worker   // unset field case
460*6dbdd20aSAndroid Build Coastguard Worker   pbgold::PackedRepeatedFields empty_msg;
461*6dbdd20aSAndroid Build Coastguard Worker   std::string empty_serialized = empty_msg.SerializeAsString();
462*6dbdd20aSAndroid Build Coastguard Worker   auto decoder = pbtest::PackedRepeatedFields::Decoder(empty_serialized);
463*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(decoder.has_field_sfixed64());
464*6dbdd20aSAndroid Build Coastguard Worker   bool parse_error = false;
465*6dbdd20aSAndroid Build Coastguard Worker   auto packed_it = decoder.field_sfixed64(&parse_error);
466*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(bool(packed_it));
467*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(parse_error);
468*6dbdd20aSAndroid Build Coastguard Worker }
469*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,ZeroLengthPackedRepeatedField)470*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, ZeroLengthPackedRepeatedField) {
471*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<pbtest::PackedRepeatedFields> msg;
472*6dbdd20aSAndroid Build Coastguard Worker   PackedVarInt buf;
473*6dbdd20aSAndroid Build Coastguard Worker   msg->set_field_int32(buf);
474*6dbdd20aSAndroid Build Coastguard Worker   std::string serialized = msg.SerializeAsString();
475*6dbdd20aSAndroid Build Coastguard Worker 
476*6dbdd20aSAndroid Build Coastguard Worker   // Encoded as 2 bytes: tag/field, and a length of zero.
477*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_EQ(2u, serialized.size());
478*6dbdd20aSAndroid Build Coastguard Worker 
479*6dbdd20aSAndroid Build Coastguard Worker   // Appears empty when decoded.
480*6dbdd20aSAndroid Build Coastguard Worker   auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
481*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(decoder.has_field_int32());
482*6dbdd20aSAndroid Build Coastguard Worker   bool parse_error = false;
483*6dbdd20aSAndroid Build Coastguard Worker   auto packed_it = decoder.field_int32(&parse_error);
484*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(bool(packed_it));
485*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(parse_error);
486*6dbdd20aSAndroid Build Coastguard Worker }
487*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,MalformedPackedFixedBuffer)488*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, MalformedPackedFixedBuffer) {
489*6dbdd20aSAndroid Build Coastguard Worker   // Encode a fixed32 field where the length is not a multiple of 4 bytes.
490*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<pbtest::PackedRepeatedFields> msg;
491*6dbdd20aSAndroid Build Coastguard Worker   PackedFixedSizeInt<uint32_t> buf;
492*6dbdd20aSAndroid Build Coastguard Worker   buf.Append(1);
493*6dbdd20aSAndroid Build Coastguard Worker   buf.Append(2);
494*6dbdd20aSAndroid Build Coastguard Worker   buf.Append(3);
495*6dbdd20aSAndroid Build Coastguard Worker   const uint8_t* data = buf.data();
496*6dbdd20aSAndroid Build Coastguard Worker   size_t size = buf.size();
497*6dbdd20aSAndroid Build Coastguard Worker   size_t invalid_size = size - 2;
498*6dbdd20aSAndroid Build Coastguard Worker   constexpr int kFieldId =
499*6dbdd20aSAndroid Build Coastguard Worker       pbtest::PackedRepeatedFields::kFieldFixed32FieldNumber;
500*6dbdd20aSAndroid Build Coastguard Worker   msg->AppendBytes(kFieldId, data, invalid_size);
501*6dbdd20aSAndroid Build Coastguard Worker   std::string serialized = msg.SerializeAsString();
502*6dbdd20aSAndroid Build Coastguard Worker 
503*6dbdd20aSAndroid Build Coastguard Worker   // Iterator indicates parse error.
504*6dbdd20aSAndroid Build Coastguard Worker   auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
505*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(decoder.has_field_fixed32());
506*6dbdd20aSAndroid Build Coastguard Worker   bool parse_error = false;
507*6dbdd20aSAndroid Build Coastguard Worker   for (auto packed_it = decoder.field_fixed32(&parse_error); packed_it;
508*6dbdd20aSAndroid Build Coastguard Worker        packed_it++) {
509*6dbdd20aSAndroid Build Coastguard Worker   }
510*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(parse_error);
511*6dbdd20aSAndroid Build Coastguard Worker }
512*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,MalformedPackedVarIntBuffer)513*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, MalformedPackedVarIntBuffer) {
514*6dbdd20aSAndroid Build Coastguard Worker   // Encode a varint field with the last varint chopped off partway.
515*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<pbtest::PackedRepeatedFields> msg;
516*6dbdd20aSAndroid Build Coastguard Worker   PackedVarInt buf;
517*6dbdd20aSAndroid Build Coastguard Worker   buf.Append(1024);
518*6dbdd20aSAndroid Build Coastguard Worker   buf.Append(2048);
519*6dbdd20aSAndroid Build Coastguard Worker   buf.Append(4096);
520*6dbdd20aSAndroid Build Coastguard Worker   const uint8_t* data = buf.data();
521*6dbdd20aSAndroid Build Coastguard Worker   size_t size = buf.size();
522*6dbdd20aSAndroid Build Coastguard Worker   size_t invalid_size = size - 1;
523*6dbdd20aSAndroid Build Coastguard Worker   constexpr int kFieldId = pbtest::PackedRepeatedFields::kFieldInt32FieldNumber;
524*6dbdd20aSAndroid Build Coastguard Worker   msg->AppendBytes(kFieldId, data, invalid_size);
525*6dbdd20aSAndroid Build Coastguard Worker   std::string serialized = msg.SerializeAsString();
526*6dbdd20aSAndroid Build Coastguard Worker 
527*6dbdd20aSAndroid Build Coastguard Worker   // Iterator indicates parse error.
528*6dbdd20aSAndroid Build Coastguard Worker   auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
529*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(decoder.has_field_int32());
530*6dbdd20aSAndroid Build Coastguard Worker   bool parse_error = false;
531*6dbdd20aSAndroid Build Coastguard Worker   for (auto packed_it = decoder.field_int32(&parse_error); packed_it;
532*6dbdd20aSAndroid Build Coastguard Worker        packed_it++) {
533*6dbdd20aSAndroid Build Coastguard Worker   }
534*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_TRUE(parse_error);
535*6dbdd20aSAndroid Build Coastguard Worker }
536*6dbdd20aSAndroid Build Coastguard Worker 
537*6dbdd20aSAndroid Build Coastguard Worker // Tests that:
538*6dbdd20aSAndroid Build Coastguard Worker // 1. Very big field ids (>= 2**24) are just skipped but don't fail parsing.
539*6dbdd20aSAndroid Build Coastguard Worker //    This is a regression test for b/145339282 (DataSourceConfig.for_testing
540*6dbdd20aSAndroid Build Coastguard Worker //    having a very large ID == 268435455 until Android R).
541*6dbdd20aSAndroid Build Coastguard Worker // 2. Moderately big" field ids can be parsed correctly. See also
542*6dbdd20aSAndroid Build Coastguard Worker //    https://github.com/google/perfetto/issues/510 .
TEST(ProtoDecoderTest,BigFieldIds)543*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, BigFieldIds) {
544*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<Message> message;
545*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/1, 11);
546*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/1 << 24, 0);  // Will be skipped
547*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/65535, 99);
548*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/(1 << 24) + 1023,
549*6dbdd20aSAndroid Build Coastguard Worker                         0);  // Will be skipped
550*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/2, 12);
551*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/1 << 28, 0);  // Will be skipped
552*6dbdd20aSAndroid Build Coastguard Worker 
553*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/(1 << 24) - 1, 13);
554*6dbdd20aSAndroid Build Coastguard Worker   auto data = message.SerializeAsArray();
555*6dbdd20aSAndroid Build Coastguard Worker 
556*6dbdd20aSAndroid Build Coastguard Worker   // Check the iterator-based ProtoDecoder.
557*6dbdd20aSAndroid Build Coastguard Worker   {
558*6dbdd20aSAndroid Build Coastguard Worker     ProtoDecoder decoder(data.data(), data.size());
559*6dbdd20aSAndroid Build Coastguard Worker     Field field = decoder.ReadField();
560*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_TRUE(field.valid());
561*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(field.id(), 1u);
562*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(field.as_int32(), 11);
563*6dbdd20aSAndroid Build Coastguard Worker 
564*6dbdd20aSAndroid Build Coastguard Worker     field = decoder.ReadField();
565*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_TRUE(field.valid());
566*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(field.id(), 65535u);
567*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(field.as_int32(), 99);
568*6dbdd20aSAndroid Build Coastguard Worker 
569*6dbdd20aSAndroid Build Coastguard Worker     field = decoder.ReadField();
570*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_TRUE(field.valid());
571*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(field.id(), 2u);
572*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(field.as_int32(), 12);
573*6dbdd20aSAndroid Build Coastguard Worker 
574*6dbdd20aSAndroid Build Coastguard Worker     field = decoder.ReadField();
575*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_TRUE(field.valid());
576*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(field.id(), (1u << 24) - 1u);
577*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_EQ(field.as_int32(), 13);
578*6dbdd20aSAndroid Build Coastguard Worker 
579*6dbdd20aSAndroid Build Coastguard Worker     field = decoder.ReadField();
580*6dbdd20aSAndroid Build Coastguard Worker     ASSERT_FALSE(field.valid());
581*6dbdd20aSAndroid Build Coastguard Worker   }
582*6dbdd20aSAndroid Build Coastguard Worker 
583*6dbdd20aSAndroid Build Coastguard Worker   // Test the one-shot-read TypedProtoDecoder.
584*6dbdd20aSAndroid Build Coastguard Worker   // Note: field 65535 will be also skipped because this TypedProtoDecoder has
585*6dbdd20aSAndroid Build Coastguard Worker   // a cap on MAX_FIELD_ID = 3.
586*6dbdd20aSAndroid Build Coastguard Worker   {
587*6dbdd20aSAndroid Build Coastguard Worker     TypedProtoDecoder<3, true> tpd(data.data(), data.size());
588*6dbdd20aSAndroid Build Coastguard Worker     EXPECT_EQ(tpd.Get(1).as_int32(), 11);
589*6dbdd20aSAndroid Build Coastguard Worker     EXPECT_EQ(tpd.Get(2).as_int32(), 12);
590*6dbdd20aSAndroid Build Coastguard Worker   }
591*6dbdd20aSAndroid Build Coastguard Worker }
592*6dbdd20aSAndroid Build Coastguard Worker 
593*6dbdd20aSAndroid Build Coastguard Worker // Edge case for SkipBigFieldIds, the message contains only one field with a
594*6dbdd20aSAndroid Build Coastguard Worker // very big id. Test that we skip it and return an invalid field, instead of
595*6dbdd20aSAndroid Build Coastguard Worker // geetting stuck in some loop.
TEST(ProtoDecoderTest,OneBigFieldIdOnly)596*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, OneBigFieldIdOnly) {
597*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<Message> message;
598*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(/*field_id=*/268435455, 0);
599*6dbdd20aSAndroid Build Coastguard Worker   auto data = message.SerializeAsArray();
600*6dbdd20aSAndroid Build Coastguard Worker 
601*6dbdd20aSAndroid Build Coastguard Worker   // Check the iterator-based ProtoDecoder.
602*6dbdd20aSAndroid Build Coastguard Worker   ProtoDecoder decoder(data.data(), data.size());
603*6dbdd20aSAndroid Build Coastguard Worker   Field field = decoder.ReadField();
604*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(field.valid());
605*6dbdd20aSAndroid Build Coastguard Worker }
606*6dbdd20aSAndroid Build Coastguard Worker 
607*6dbdd20aSAndroid Build Coastguard Worker // Check what happens when trying to parse packed repeated field and finding a
608*6dbdd20aSAndroid Build Coastguard Worker // mismatching wire type instead. A compliant protobuf decoder should accept it,
609*6dbdd20aSAndroid Build Coastguard Worker // but protozero doesn't handle that. At least it shouldn't crash.
TEST(ProtoDecoderTest,PacketRepeatedWireTypeMismatch)610*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, PacketRepeatedWireTypeMismatch) {
611*6dbdd20aSAndroid Build Coastguard Worker   protozero::HeapBuffered<pbtest::PackedRepeatedFields> message;
612*6dbdd20aSAndroid Build Coastguard Worker   // A proper packed encoding should have a length delimited wire type. Use a
613*6dbdd20aSAndroid Build Coastguard Worker   // var int wire type instead.
614*6dbdd20aSAndroid Build Coastguard Worker   constexpr int kFieldId = pbtest::PackedRepeatedFields::kFieldInt32FieldNumber;
615*6dbdd20aSAndroid Build Coastguard Worker   message->AppendTinyVarInt(kFieldId, 5);
616*6dbdd20aSAndroid Build Coastguard Worker   auto data = message.SerializeAsArray();
617*6dbdd20aSAndroid Build Coastguard Worker 
618*6dbdd20aSAndroid Build Coastguard Worker   pbtest::PackedRepeatedFields::Decoder decoder(data.data(), data.size());
619*6dbdd20aSAndroid Build Coastguard Worker   bool parse_error = false;
620*6dbdd20aSAndroid Build Coastguard Worker   auto it = decoder.field_int32(&parse_error);
621*6dbdd20aSAndroid Build Coastguard Worker   // The decoder doesn't return a parse error (maybe it should, but that has
622*6dbdd20aSAndroid Build Coastguard Worker   // been the behavior since the beginning).
623*6dbdd20aSAndroid Build Coastguard Worker   ASSERT_FALSE(parse_error);
624*6dbdd20aSAndroid Build Coastguard Worker   // But the iterator returns 0 elements.
625*6dbdd20aSAndroid Build Coastguard Worker   EXPECT_FALSE(it);
626*6dbdd20aSAndroid Build Coastguard Worker }
627*6dbdd20aSAndroid Build Coastguard Worker 
TEST(ProtoDecoderTest,RepeatedMaxFieldIdStack)628*6dbdd20aSAndroid Build Coastguard Worker TEST(ProtoDecoderTest, RepeatedMaxFieldIdStack) {
629*6dbdd20aSAndroid Build Coastguard Worker   HeapBuffered<Message> message;
630*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(15, 1);
631*6dbdd20aSAndroid Build Coastguard Worker   message->AppendVarInt(15, 2);
632*6dbdd20aSAndroid Build Coastguard Worker   std::vector<uint8_t> proto = message.SerializeAsArray();
633*6dbdd20aSAndroid Build Coastguard Worker 
634*6dbdd20aSAndroid Build Coastguard Worker   // Make sure that even with a max field id close to the stack capacity,
635*6dbdd20aSAndroid Build Coastguard Worker   // TypedProtoDecoder behaves correctly w.r.t. repeated fields.
636*6dbdd20aSAndroid Build Coastguard Worker   const int kMaxFieldId = PROTOZERO_DECODER_INITIAL_STACK_CAPACITY;
637*6dbdd20aSAndroid Build Coastguard Worker 
638*6dbdd20aSAndroid Build Coastguard Worker   {
639*6dbdd20aSAndroid Build Coastguard Worker     protozero::TypedProtoDecoder<kMaxFieldId,
640*6dbdd20aSAndroid Build Coastguard Worker                                  /*HAS_NONPACKED_REPEATED_FIELDS=*/true>
641*6dbdd20aSAndroid Build Coastguard Worker         decoder(proto.data(), proto.size());
642*6dbdd20aSAndroid Build Coastguard Worker     std::vector<uint64_t> res;
643*6dbdd20aSAndroid Build Coastguard Worker     for (auto it = decoder.GetRepeated<uint64_t>(15); it; it++) {
644*6dbdd20aSAndroid Build Coastguard Worker       res.push_back(*it);
645*6dbdd20aSAndroid Build Coastguard Worker     }
646*6dbdd20aSAndroid Build Coastguard Worker     EXPECT_THAT(res, ElementsAre(1, 2));
647*6dbdd20aSAndroid Build Coastguard Worker   }
648*6dbdd20aSAndroid Build Coastguard Worker }
649*6dbdd20aSAndroid Build Coastguard Worker 
650*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
651*6dbdd20aSAndroid Build Coastguard Worker }  // namespace protozero
652