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