xref: /aosp_15_r20/external/pigweed/pw_protobuf/message_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/message.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/memory_stream.h"
18*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
19*61c4878aSAndroid Build Coastguard Worker 
20*61c4878aSAndroid Build Coastguard Worker namespace pw::protobuf {
21*61c4878aSAndroid Build Coastguard Worker namespace {
22*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,IterateMessage)23*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, IterateMessage) {
24*61c4878aSAndroid Build Coastguard Worker   // clang-format off
25*61c4878aSAndroid Build Coastguard Worker   constexpr uint8_t encoded_proto[] = {
26*61c4878aSAndroid Build Coastguard Worker     // type=uint32, k=1, v=1
27*61c4878aSAndroid Build Coastguard Worker     0x08, 0x01,
28*61c4878aSAndroid Build Coastguard Worker     // type=uint32, k=2, v=2
29*61c4878aSAndroid Build Coastguard Worker     0x10, 0x02,
30*61c4878aSAndroid Build Coastguard Worker     // type=uint32, k=3, v=3
31*61c4878aSAndroid Build Coastguard Worker     0x18, 0x03,
32*61c4878aSAndroid Build Coastguard Worker   };
33*61c4878aSAndroid Build Coastguard Worker   // clang-format on
34*61c4878aSAndroid Build Coastguard Worker 
35*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
36*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
37*61c4878aSAndroid Build Coastguard Worker 
38*61c4878aSAndroid Build Coastguard Worker   uint32_t count = 0;
39*61c4878aSAndroid Build Coastguard Worker   for (Message::Field field : parser) {
40*61c4878aSAndroid Build Coastguard Worker     ++count;
41*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(field.field_number(), count);
42*61c4878aSAndroid Build Coastguard Worker     Uint32 value = field.As<Uint32>();
43*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
44*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(value.value(), count);
45*61c4878aSAndroid Build Coastguard Worker   }
46*61c4878aSAndroid Build Coastguard Worker 
47*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(count, static_cast<uint32_t>(3));
48*61c4878aSAndroid Build Coastguard Worker }
49*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,MessageIterator)50*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, MessageIterator) {
51*61c4878aSAndroid Build Coastguard Worker   // clang-format off
52*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
53*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "foo 1"
54*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'f', 'o', 'o', ' ', '1',
55*61c4878aSAndroid Build Coastguard Worker     // type=uint32, k=2, v=2
56*61c4878aSAndroid Build Coastguard Worker     0x10, 0x02,
57*61c4878aSAndroid Build Coastguard Worker   };
58*61c4878aSAndroid Build Coastguard Worker   // clang-format on
59*61c4878aSAndroid Build Coastguard Worker 
60*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
61*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
62*61c4878aSAndroid Build Coastguard Worker 
63*61c4878aSAndroid Build Coastguard Worker   Message::iterator iter = parser.begin();
64*61c4878aSAndroid Build Coastguard Worker 
65*61c4878aSAndroid Build Coastguard Worker   Message::iterator first = iter++;
66*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(first, first);
67*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(first->field_number(), static_cast<uint32_t>(1));
68*61c4878aSAndroid Build Coastguard Worker   String str = first->As<String>();
69*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(str.status());
70*61c4878aSAndroid Build Coastguard Worker   Result<bool> cmp = str.Equal("foo 1");
71*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(cmp.status());
72*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(cmp.value());
73*61c4878aSAndroid Build Coastguard Worker 
74*61c4878aSAndroid Build Coastguard Worker   Message::iterator second = iter++;
75*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(second, second);
76*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(second->field_number(), static_cast<uint32_t>(2));
77*61c4878aSAndroid Build Coastguard Worker   Uint32 uint32_val = second->As<Uint32>();
78*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(uint32_val.status());
79*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(uint32_val.value(), static_cast<uint32_t>(2));
80*61c4878aSAndroid Build Coastguard Worker 
81*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(first, second);
82*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(first, iter);
83*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(second, iter);
84*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(iter, parser.end());
85*61c4878aSAndroid Build Coastguard Worker }
86*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,MessageIteratorMalformedProto)87*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, MessageIteratorMalformedProto) {
88*61c4878aSAndroid Build Coastguard Worker   // clang-format off
89*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
90*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "foo 1"
91*61c4878aSAndroid Build Coastguard Worker     0x0a,0x05,'f','o','o',' ','1',
92*61c4878aSAndroid Build Coastguard Worker     // key = 0, str = "foo 2" (invalid)
93*61c4878aSAndroid Build Coastguard Worker     0x02,0x05,'f','o','o',' ','2',
94*61c4878aSAndroid Build Coastguard Worker     // key = 3, str = "bar 1"
95*61c4878aSAndroid Build Coastguard Worker     0x1a,0x05,'b','a','r',' ','1',
96*61c4878aSAndroid Build Coastguard Worker   };
97*61c4878aSAndroid Build Coastguard Worker   // clang-format on
98*61c4878aSAndroid Build Coastguard Worker 
99*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
100*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
101*61c4878aSAndroid Build Coastguard Worker 
102*61c4878aSAndroid Build Coastguard Worker   Message::iterator iter = parser.begin();
103*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(iter.status());
104*61c4878aSAndroid Build Coastguard Worker 
105*61c4878aSAndroid Build Coastguard Worker   // Second field has invalid field number
106*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE((++iter).ok());
107*61c4878aSAndroid Build Coastguard Worker 
108*61c4878aSAndroid Build Coastguard Worker   // Attempting to increment an invalid iterator result in it being end()
109*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ((++iter), parser.end());
110*61c4878aSAndroid Build Coastguard Worker 
111*61c4878aSAndroid Build Coastguard Worker   // Test the c++ std loop behavior.
112*61c4878aSAndroid Build Coastguard Worker   bool expected_ok_status[] = {true, false};
113*61c4878aSAndroid Build Coastguard Worker   size_t count = 0;
114*61c4878aSAndroid Build Coastguard Worker   for (Message::Field field : parser) {
115*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(field.ok(), expected_ok_status[count++]);
116*61c4878aSAndroid Build Coastguard Worker   }
117*61c4878aSAndroid Build Coastguard Worker   // First element ok. Second element invalid. Iteration ends in the next
118*61c4878aSAndroid Build Coastguard Worker   // iteration.
119*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(count, 2ULL);
120*61c4878aSAndroid Build Coastguard Worker }
121*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,InvalidMessageBeginIterator)122*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, InvalidMessageBeginIterator) {
123*61c4878aSAndroid Build Coastguard Worker   Message parser(Status::Internal());
124*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(parser.begin().ok());
125*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(parser.begin(), parser.end());
126*61c4878aSAndroid Build Coastguard Worker }
127*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,AsProtoInteger)128*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, AsProtoInteger) {
129*61c4878aSAndroid Build Coastguard Worker   // clang-format off
130*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
131*61c4878aSAndroid Build Coastguard Worker       // type: int32, k = 1, val = -123
132*61c4878aSAndroid Build Coastguard Worker       0x08, 0x85, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
133*61c4878aSAndroid Build Coastguard Worker       // type: uint32, k = 2, val = 123
134*61c4878aSAndroid Build Coastguard Worker       0x10, 0x7b,
135*61c4878aSAndroid Build Coastguard Worker       // type: sint32, k = 3, val = -456
136*61c4878aSAndroid Build Coastguard Worker       0x18, 0x8f, 0x07,
137*61c4878aSAndroid Build Coastguard Worker       // type: fixed32, k = 4, val = 268435457
138*61c4878aSAndroid Build Coastguard Worker       0x25, 0x01, 0x00, 0x00, 0x10,
139*61c4878aSAndroid Build Coastguard Worker       // type: sfixed32, k = 5, val = -268435457
140*61c4878aSAndroid Build Coastguard Worker       0x2d, 0xff, 0xff, 0xff, 0xef,
141*61c4878aSAndroid Build Coastguard Worker       // type: int64, k = 6, val = -1099511627776
142*61c4878aSAndroid Build Coastguard Worker       0x30, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe0, 0xff, 0xff, 0xff, 0x01,
143*61c4878aSAndroid Build Coastguard Worker       // type: uint64, k = 7, val = 1099511627776
144*61c4878aSAndroid Build Coastguard Worker       0x38, 0x80, 0x80, 0x80, 0x80, 0x80, 0x20,
145*61c4878aSAndroid Build Coastguard Worker       // type: sint64, k = 8, val = -2199023255552
146*61c4878aSAndroid Build Coastguard Worker       0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
147*61c4878aSAndroid Build Coastguard Worker       // type: fixed64, k = 9, val = 72057594037927937
148*61c4878aSAndroid Build Coastguard Worker       0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
149*61c4878aSAndroid Build Coastguard Worker       // type: sfixed64, k = 10, val = -72057594037927937
150*61c4878aSAndroid Build Coastguard Worker       0x51, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
151*61c4878aSAndroid Build Coastguard Worker       // type: float, k = 11, val = 123456.00
152*61c4878aSAndroid Build Coastguard Worker       0x5d, 0x00, 0x20, 0xf1, 0x47,
153*61c4878aSAndroid Build Coastguard Worker       // type: double, k = 12, val = -123456.789
154*61c4878aSAndroid Build Coastguard Worker       0x61, 0xc9, 0x76, 0xbe, 0x9f, 0x0c, 0x24, 0xfe, 0xc0,
155*61c4878aSAndroid Build Coastguard Worker       // type: bool, k = 13, val = true
156*61c4878aSAndroid Build Coastguard Worker       0x68, 0x01,
157*61c4878aSAndroid Build Coastguard Worker       // type: bool, k = 14, val = false
158*61c4878aSAndroid Build Coastguard Worker       0x70, 0x00
159*61c4878aSAndroid Build Coastguard Worker   };
160*61c4878aSAndroid Build Coastguard Worker   // clang-format on
161*61c4878aSAndroid Build Coastguard Worker 
162*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
163*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
164*61c4878aSAndroid Build Coastguard Worker 
165*61c4878aSAndroid Build Coastguard Worker   {
166*61c4878aSAndroid Build Coastguard Worker     Int32 value = parser.AsInt32(1);
167*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
168*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<int32_t>(-123));
169*61c4878aSAndroid Build Coastguard Worker   }
170*61c4878aSAndroid Build Coastguard Worker 
171*61c4878aSAndroid Build Coastguard Worker   {
172*61c4878aSAndroid Build Coastguard Worker     Uint32 value = parser.AsUint32(2);
173*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
174*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<uint32_t>(123));
175*61c4878aSAndroid Build Coastguard Worker   }
176*61c4878aSAndroid Build Coastguard Worker 
177*61c4878aSAndroid Build Coastguard Worker   {
178*61c4878aSAndroid Build Coastguard Worker     Sint32 value = parser.AsSint32(3);
179*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
180*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<int32_t>(-456));
181*61c4878aSAndroid Build Coastguard Worker   }
182*61c4878aSAndroid Build Coastguard Worker 
183*61c4878aSAndroid Build Coastguard Worker   {
184*61c4878aSAndroid Build Coastguard Worker     Fixed32 value = parser.AsFixed32(4);
185*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
186*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<uint32_t>(268435457));
187*61c4878aSAndroid Build Coastguard Worker   }
188*61c4878aSAndroid Build Coastguard Worker 
189*61c4878aSAndroid Build Coastguard Worker   {
190*61c4878aSAndroid Build Coastguard Worker     Sfixed32 value = parser.AsSfixed32(5);
191*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
192*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<int32_t>(-268435457));
193*61c4878aSAndroid Build Coastguard Worker   }
194*61c4878aSAndroid Build Coastguard Worker 
195*61c4878aSAndroid Build Coastguard Worker   {
196*61c4878aSAndroid Build Coastguard Worker     Int64 value = parser.AsInt64(6);
197*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
198*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<int64_t>(-1099511627776));
199*61c4878aSAndroid Build Coastguard Worker   }
200*61c4878aSAndroid Build Coastguard Worker 
201*61c4878aSAndroid Build Coastguard Worker   {
202*61c4878aSAndroid Build Coastguard Worker     Uint64 value = parser.AsUint64(7);
203*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
204*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<uint64_t>(1099511627776));
205*61c4878aSAndroid Build Coastguard Worker   }
206*61c4878aSAndroid Build Coastguard Worker 
207*61c4878aSAndroid Build Coastguard Worker   {
208*61c4878aSAndroid Build Coastguard Worker     Sint64 value = parser.AsSint64(8);
209*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
210*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<int64_t>(-2199023255552));
211*61c4878aSAndroid Build Coastguard Worker   }
212*61c4878aSAndroid Build Coastguard Worker 
213*61c4878aSAndroid Build Coastguard Worker   {
214*61c4878aSAndroid Build Coastguard Worker     Fixed64 value = parser.AsFixed64(9);
215*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
216*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<uint64_t>(72057594037927937));
217*61c4878aSAndroid Build Coastguard Worker   }
218*61c4878aSAndroid Build Coastguard Worker 
219*61c4878aSAndroid Build Coastguard Worker   {
220*61c4878aSAndroid Build Coastguard Worker     Sfixed64 value = parser.AsSfixed64(10);
221*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
222*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<int64_t>(-72057594037927937));
223*61c4878aSAndroid Build Coastguard Worker   }
224*61c4878aSAndroid Build Coastguard Worker 
225*61c4878aSAndroid Build Coastguard Worker   {
226*61c4878aSAndroid Build Coastguard Worker     Float value = parser.AsFloat(11);
227*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
228*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<float>(123456.00));
229*61c4878aSAndroid Build Coastguard Worker   }
230*61c4878aSAndroid Build Coastguard Worker 
231*61c4878aSAndroid Build Coastguard Worker   {
232*61c4878aSAndroid Build Coastguard Worker     Double value = parser.AsDouble(12);
233*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
234*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<double>(-123456.789));
235*61c4878aSAndroid Build Coastguard Worker   }
236*61c4878aSAndroid Build Coastguard Worker 
237*61c4878aSAndroid Build Coastguard Worker   {
238*61c4878aSAndroid Build Coastguard Worker     Bool value = parser.AsBool(13);
239*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
240*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<bool>(true));
241*61c4878aSAndroid Build Coastguard Worker   }
242*61c4878aSAndroid Build Coastguard Worker 
243*61c4878aSAndroid Build Coastguard Worker   {
244*61c4878aSAndroid Build Coastguard Worker     Bool value = parser.AsBool(14);
245*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
246*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.value(), static_cast<bool>(false));
247*61c4878aSAndroid Build Coastguard Worker   }
248*61c4878aSAndroid Build Coastguard Worker }
249*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,AsString)250*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, AsString) {
251*61c4878aSAndroid Build Coastguard Worker   // message {
252*61c4878aSAndroid Build Coastguard Worker   //   string str = 1;
253*61c4878aSAndroid Build Coastguard Worker   // }
254*61c4878aSAndroid Build Coastguard Worker   // clang-format off
255*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
256*61c4878aSAndroid Build Coastguard Worker     // `str`, k = 1, "string"
257*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x06, 's', 't', 'r', 'i', 'n', 'g',
258*61c4878aSAndroid Build Coastguard Worker   };
259*61c4878aSAndroid Build Coastguard Worker   // clang-format on
260*61c4878aSAndroid Build Coastguard Worker 
261*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
262*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
263*61c4878aSAndroid Build Coastguard Worker 
264*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kFieldNumber = 1;
265*61c4878aSAndroid Build Coastguard Worker   String value = parser.AsString(kFieldNumber);
266*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(value.status());
267*61c4878aSAndroid Build Coastguard Worker   Result<bool> cmp = value.Equal("string");
268*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(cmp.status());
269*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(cmp.value());
270*61c4878aSAndroid Build Coastguard Worker 
271*61c4878aSAndroid Build Coastguard Worker   cmp = value.Equal("other");
272*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(cmp.status());
273*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(cmp.value());
274*61c4878aSAndroid Build Coastguard Worker 
275*61c4878aSAndroid Build Coastguard Worker   // The string is a prefix of the target string to compare.
276*61c4878aSAndroid Build Coastguard Worker   cmp = value.Equal("string and more");
277*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(cmp.status());
278*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(cmp.value());
279*61c4878aSAndroid Build Coastguard Worker 
280*61c4878aSAndroid Build Coastguard Worker   // The target string to compare is a sub prefix of this string
281*61c4878aSAndroid Build Coastguard Worker   cmp = value.Equal("str");
282*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(cmp.status());
283*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(cmp.value());
284*61c4878aSAndroid Build Coastguard Worker }
285*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,AsRepeatedStrings)286*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, AsRepeatedStrings) {
287*61c4878aSAndroid Build Coastguard Worker   // Repeated field of string i.e.
288*61c4878aSAndroid Build Coastguard Worker   //
289*61c4878aSAndroid Build Coastguard Worker   // message RepeatedString {
290*61c4878aSAndroid Build Coastguard Worker   //   repeated string msg_a = 1;
291*61c4878aSAndroid Build Coastguard Worker   //   repeated string msg_b = 2;
292*61c4878aSAndroid Build Coastguard Worker   // }
293*61c4878aSAndroid Build Coastguard Worker   // clang-format off
294*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
295*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "foo 1"
296*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'f', 'o', 'o', ' ', '1',
297*61c4878aSAndroid Build Coastguard Worker     // key = 2, str = "foo 2"
298*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05, 'f', 'o', 'o', ' ', '2',
299*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "bar 1"
300*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'b', 'a', 'r', ' ', '1',
301*61c4878aSAndroid Build Coastguard Worker     // key = 2, str = "bar 2"
302*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05, 'b', 'a', 'r', ' ', '2',
303*61c4878aSAndroid Build Coastguard Worker   };
304*61c4878aSAndroid Build Coastguard Worker   // clang-format on
305*61c4878aSAndroid Build Coastguard Worker 
306*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kMsgAFieldNumber = 1;
307*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kMsgBFieldNumber = 2;
308*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kNonExistFieldNumber = 3;
309*61c4878aSAndroid Build Coastguard Worker 
310*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
311*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
312*61c4878aSAndroid Build Coastguard Worker 
313*61c4878aSAndroid Build Coastguard Worker   // Field 'msg_a'
314*61c4878aSAndroid Build Coastguard Worker   {
315*61c4878aSAndroid Build Coastguard Worker     RepeatedStrings msg = parser.AsRepeatedStrings(kMsgAFieldNumber);
316*61c4878aSAndroid Build Coastguard Worker     std::string_view expected[] = {
317*61c4878aSAndroid Build Coastguard Worker         "foo 1",
318*61c4878aSAndroid Build Coastguard Worker         "bar 1",
319*61c4878aSAndroid Build Coastguard Worker     };
320*61c4878aSAndroid Build Coastguard Worker 
321*61c4878aSAndroid Build Coastguard Worker     size_t count = 0;
322*61c4878aSAndroid Build Coastguard Worker     for (String ele : msg) {
323*61c4878aSAndroid Build Coastguard Worker       PW_TEST_ASSERT_OK(ele.status());
324*61c4878aSAndroid Build Coastguard Worker       Result<bool> res = ele.Equal(expected[count++]);
325*61c4878aSAndroid Build Coastguard Worker       PW_TEST_ASSERT_OK(res.status());
326*61c4878aSAndroid Build Coastguard Worker       ASSERT_TRUE(res.value());
327*61c4878aSAndroid Build Coastguard Worker     }
328*61c4878aSAndroid Build Coastguard Worker 
329*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(count, static_cast<size_t>(2));
330*61c4878aSAndroid Build Coastguard Worker   }
331*61c4878aSAndroid Build Coastguard Worker 
332*61c4878aSAndroid Build Coastguard Worker   // Field `msg_b`
333*61c4878aSAndroid Build Coastguard Worker   {
334*61c4878aSAndroid Build Coastguard Worker     RepeatedStrings msg = parser.AsRepeatedStrings(kMsgBFieldNumber);
335*61c4878aSAndroid Build Coastguard Worker     std::string_view expected[] = {
336*61c4878aSAndroid Build Coastguard Worker         "foo 2",
337*61c4878aSAndroid Build Coastguard Worker         "bar 2",
338*61c4878aSAndroid Build Coastguard Worker     };
339*61c4878aSAndroid Build Coastguard Worker 
340*61c4878aSAndroid Build Coastguard Worker     size_t count = 0;
341*61c4878aSAndroid Build Coastguard Worker     for (String ele : msg) {
342*61c4878aSAndroid Build Coastguard Worker       PW_TEST_ASSERT_OK(ele.status());
343*61c4878aSAndroid Build Coastguard Worker       Result<bool> res = ele.Equal(expected[count++]);
344*61c4878aSAndroid Build Coastguard Worker       PW_TEST_ASSERT_OK(res.status());
345*61c4878aSAndroid Build Coastguard Worker       ASSERT_TRUE(res.value());
346*61c4878aSAndroid Build Coastguard Worker     }
347*61c4878aSAndroid Build Coastguard Worker 
348*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(count, static_cast<size_t>(2));
349*61c4878aSAndroid Build Coastguard Worker   }
350*61c4878aSAndroid Build Coastguard Worker 
351*61c4878aSAndroid Build Coastguard Worker   // non-existing field
352*61c4878aSAndroid Build Coastguard Worker   {
353*61c4878aSAndroid Build Coastguard Worker     RepeatedStrings msg = parser.AsRepeatedStrings(kNonExistFieldNumber);
354*61c4878aSAndroid Build Coastguard Worker     size_t count = 0;
355*61c4878aSAndroid Build Coastguard Worker     for ([[maybe_unused]] String ele : msg) {
356*61c4878aSAndroid Build Coastguard Worker       count++;
357*61c4878aSAndroid Build Coastguard Worker     }
358*61c4878aSAndroid Build Coastguard Worker 
359*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(count, static_cast<size_t>(0));
360*61c4878aSAndroid Build Coastguard Worker   }
361*61c4878aSAndroid Build Coastguard Worker }
362*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,RepeatedFieldIterator)363*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, RepeatedFieldIterator) {
364*61c4878aSAndroid Build Coastguard Worker   // Repeated field of string i.e.
365*61c4878aSAndroid Build Coastguard Worker   //
366*61c4878aSAndroid Build Coastguard Worker   // message RepeatedString {
367*61c4878aSAndroid Build Coastguard Worker   //   repeated string msg = 1;
368*61c4878aSAndroid Build Coastguard Worker   // }
369*61c4878aSAndroid Build Coastguard Worker   // clang-format off
370*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
371*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "foo 1"
372*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'f', 'o', 'o', ' ', '1',
373*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "bar 1"
374*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'b', 'a', 'r', ' ', '1',
375*61c4878aSAndroid Build Coastguard Worker   };
376*61c4878aSAndroid Build Coastguard Worker   // clang-format on
377*61c4878aSAndroid Build Coastguard Worker 
378*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kFieldNumber = 1;
379*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
380*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
381*61c4878aSAndroid Build Coastguard Worker   RepeatedStrings repeated_str = parser.AsRepeatedStrings(kFieldNumber);
382*61c4878aSAndroid Build Coastguard Worker 
383*61c4878aSAndroid Build Coastguard Worker   RepeatedStrings::iterator iter = repeated_str.begin();
384*61c4878aSAndroid Build Coastguard Worker 
385*61c4878aSAndroid Build Coastguard Worker   RepeatedStrings::iterator first = iter++;
386*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(first, first);
387*61c4878aSAndroid Build Coastguard Worker   Result<bool> cmp = first->Equal("foo 1");
388*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(cmp.status());
389*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(cmp.value());
390*61c4878aSAndroid Build Coastguard Worker 
391*61c4878aSAndroid Build Coastguard Worker   RepeatedStrings::iterator second = iter++;
392*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(second, second);
393*61c4878aSAndroid Build Coastguard Worker   cmp = second->Equal("bar 1");
394*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(cmp.status());
395*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(cmp.value());
396*61c4878aSAndroid Build Coastguard Worker 
397*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(first, second);
398*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(first, iter);
399*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(second, iter);
400*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(iter, repeated_str.end());
401*61c4878aSAndroid Build Coastguard Worker }
402*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,RepeatedFieldIteratorMalformedFieldID)403*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, RepeatedFieldIteratorMalformedFieldID) {
404*61c4878aSAndroid Build Coastguard Worker   // Repeated field of string i.e.
405*61c4878aSAndroid Build Coastguard Worker   //
406*61c4878aSAndroid Build Coastguard Worker   // message RepeatedString {
407*61c4878aSAndroid Build Coastguard Worker   //   repeated string msg = 1;
408*61c4878aSAndroid Build Coastguard Worker   // }
409*61c4878aSAndroid Build Coastguard Worker   // clang-format off
410*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
411*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "foo 1"
412*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'f', 'o', 'o', ' ', '1',
413*61c4878aSAndroid Build Coastguard Worker     // key = 0, str = "foo 1" (invalid)
414*61c4878aSAndroid Build Coastguard Worker     0x02, 0x05, 'f', 'o', 'o', ' ', '1',
415*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "foo 1"
416*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'f', 'o', 'o', ' ', '1',
417*61c4878aSAndroid Build Coastguard Worker   };
418*61c4878aSAndroid Build Coastguard Worker   // clang-format on
419*61c4878aSAndroid Build Coastguard Worker 
420*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
421*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
422*61c4878aSAndroid Build Coastguard Worker   RepeatedStrings repeated_str = parser.AsRepeatedStrings(1);
423*61c4878aSAndroid Build Coastguard Worker 
424*61c4878aSAndroid Build Coastguard Worker   bool expected_ok[] = {true, false};
425*61c4878aSAndroid Build Coastguard Worker   size_t count = 0;
426*61c4878aSAndroid Build Coastguard Worker   for (String s : repeated_str) {
427*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(s.ok(), expected_ok[count++]);
428*61c4878aSAndroid Build Coastguard Worker   }
429*61c4878aSAndroid Build Coastguard Worker   // Iterator becomes invalid in the second iteration. Attempting to increment
430*61c4878aSAndroid Build Coastguard Worker   // causes it to become end(); Therefore, count should be incremented twice.
431*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(count, 2ULL);
432*61c4878aSAndroid Build Coastguard Worker }
433*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,RepeatedFieldIteratorMalformedFieldIDBeginning)434*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, RepeatedFieldIteratorMalformedFieldIDBeginning) {
435*61c4878aSAndroid Build Coastguard Worker   // Repeated field of string i.e.
436*61c4878aSAndroid Build Coastguard Worker   //
437*61c4878aSAndroid Build Coastguard Worker   // message RepeatedString {
438*61c4878aSAndroid Build Coastguard Worker   //   repeated string msg = 1;
439*61c4878aSAndroid Build Coastguard Worker   // }
440*61c4878aSAndroid Build Coastguard Worker   // clang-format off
441*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
442*61c4878aSAndroid Build Coastguard Worker     // key = 0, str = "foo 1" (invalid)
443*61c4878aSAndroid Build Coastguard Worker     0x02, 0x05, 'f', 'o', 'o', ' ', '1',
444*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "foo 1"
445*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'f', 'o', 'o', ' ', '1',
446*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "foo 1"
447*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'f', 'o', 'o', ' ', '1',
448*61c4878aSAndroid Build Coastguard Worker   };
449*61c4878aSAndroid Build Coastguard Worker   // clang-format on
450*61c4878aSAndroid Build Coastguard Worker 
451*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
452*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
453*61c4878aSAndroid Build Coastguard Worker   RepeatedStrings repeated_str = parser.AsRepeatedStrings(1);
454*61c4878aSAndroid Build Coastguard Worker 
455*61c4878aSAndroid Build Coastguard Worker   bool expected_ok[] = {false};
456*61c4878aSAndroid Build Coastguard Worker   size_t count = 0;
457*61c4878aSAndroid Build Coastguard Worker   for (String s : repeated_str) {
458*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(s.ok(), expected_ok[count++]);
459*61c4878aSAndroid Build Coastguard Worker   }
460*61c4878aSAndroid Build Coastguard Worker   // Iterator becomes invalid in the second iteration. Attempting to increment
461*61c4878aSAndroid Build Coastguard Worker   // causes it to become end(); Therefore, count should be incremented twice.
462*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(count, 1ULL);
463*61c4878aSAndroid Build Coastguard Worker }
464*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,RepeatedFieldIteratorMalformedDataLoss)465*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, RepeatedFieldIteratorMalformedDataLoss) {
466*61c4878aSAndroid Build Coastguard Worker   // Repeated field of string i.e.
467*61c4878aSAndroid Build Coastguard Worker   //
468*61c4878aSAndroid Build Coastguard Worker   // message RepeatedString {
469*61c4878aSAndroid Build Coastguard Worker   //   repeated string msg = 1;
470*61c4878aSAndroid Build Coastguard Worker   // }
471*61c4878aSAndroid Build Coastguard Worker   // clang-format off
472*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
473*61c4878aSAndroid Build Coastguard Worker     // key = 1, str = "foo 1"
474*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, 'f', 'o', 'o', ' ', '1',
475*61c4878aSAndroid Build Coastguard Worker     // key = 0, str = "foo 1" (invalid)
476*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x10, 'f', 'o', 'o', ' ', '1',
477*61c4878aSAndroid Build Coastguard Worker   };
478*61c4878aSAndroid Build Coastguard Worker   // clang-format on
479*61c4878aSAndroid Build Coastguard Worker 
480*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
481*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
482*61c4878aSAndroid Build Coastguard Worker   RepeatedStrings repeated_str = parser.AsRepeatedStrings(1);
483*61c4878aSAndroid Build Coastguard Worker 
484*61c4878aSAndroid Build Coastguard Worker   bool expected_ok[] = {true, false};
485*61c4878aSAndroid Build Coastguard Worker   size_t count = 0;
486*61c4878aSAndroid Build Coastguard Worker   for (String s : repeated_str) {
487*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(s.ok(), expected_ok[count++]);
488*61c4878aSAndroid Build Coastguard Worker   }
489*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(count, 2ULL);
490*61c4878aSAndroid Build Coastguard Worker }
491*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,AsMessage)492*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, AsMessage) {
493*61c4878aSAndroid Build Coastguard Worker   // A nested message:
494*61c4878aSAndroid Build Coastguard Worker   //
495*61c4878aSAndroid Build Coastguard Worker   // message Contact {
496*61c4878aSAndroid Build Coastguard Worker   //   string number = 1;
497*61c4878aSAndroid Build Coastguard Worker   //   string email = 2;
498*61c4878aSAndroid Build Coastguard Worker   // }
499*61c4878aSAndroid Build Coastguard Worker   //
500*61c4878aSAndroid Build Coastguard Worker   // message Person {
501*61c4878aSAndroid Build Coastguard Worker   //  Contact info = 2;
502*61c4878aSAndroid Build Coastguard Worker   // }
503*61c4878aSAndroid Build Coastguard Worker   // clang-format off
504*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
505*61c4878aSAndroid Build Coastguard Worker     // Person.info.number = "123456", .email = "[email protected]"
506*61c4878aSAndroid Build Coastguard Worker     0x12, 0x17,
507*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x06, '1', '2', '3', '4', '5', '6',
508*61c4878aSAndroid Build Coastguard Worker     0x12, 0x0d, 'f', 'o', 'o', '@', 'e', 'm', 'a', 'i', 'l', '.', 'c', 'o', 'm',
509*61c4878aSAndroid Build Coastguard Worker   };
510*61c4878aSAndroid Build Coastguard Worker   // clang-format on
511*61c4878aSAndroid Build Coastguard Worker 
512*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kInfoFieldNumber = 2;
513*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kNumberFieldNumber = 1;
514*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kEmailFieldNumber = 2;
515*61c4878aSAndroid Build Coastguard Worker 
516*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
517*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
518*61c4878aSAndroid Build Coastguard Worker 
519*61c4878aSAndroid Build Coastguard Worker   Message info = parser.AsMessage(kInfoFieldNumber);
520*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(info.status());
521*61c4878aSAndroid Build Coastguard Worker 
522*61c4878aSAndroid Build Coastguard Worker   String number = info.AsString(kNumberFieldNumber);
523*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(number.status());
524*61c4878aSAndroid Build Coastguard Worker   Result<bool> cmp = number.Equal("123456");
525*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(cmp.status());
526*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(cmp.value());
527*61c4878aSAndroid Build Coastguard Worker 
528*61c4878aSAndroid Build Coastguard Worker   String email = info.AsString(kEmailFieldNumber);
529*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(email.status());
530*61c4878aSAndroid Build Coastguard Worker   cmp = email.Equal("[email protected]");
531*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(cmp.status());
532*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(cmp.value());
533*61c4878aSAndroid Build Coastguard Worker }
534*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,AsRepeatedMessages)535*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, AsRepeatedMessages) {
536*61c4878aSAndroid Build Coastguard Worker   // message Contact {
537*61c4878aSAndroid Build Coastguard Worker   //   string number = 1;
538*61c4878aSAndroid Build Coastguard Worker   //   string email = 2;
539*61c4878aSAndroid Build Coastguard Worker   // }
540*61c4878aSAndroid Build Coastguard Worker   //
541*61c4878aSAndroid Build Coastguard Worker   // message Person {
542*61c4878aSAndroid Build Coastguard Worker   //  repeated Contact info = 1;
543*61c4878aSAndroid Build Coastguard Worker   // }
544*61c4878aSAndroid Build Coastguard Worker   // clang-format off
545*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
546*61c4878aSAndroid Build Coastguard Worker     // Person.Contact.number = "12345", .email = "[email protected]"
547*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x16,
548*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, '1', '2', '3', '4', '5',
549*61c4878aSAndroid Build Coastguard Worker     0x12, 0x0d, 'f', 'o', 'o', '@', 'e', 'm', 'a', 'i', 'l', '.', 'c', 'o', 'm',
550*61c4878aSAndroid Build Coastguard Worker 
551*61c4878aSAndroid Build Coastguard Worker     // Person.Contact.number = "67890", .email = "[email protected]"
552*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x16,
553*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x05, '6', '7', '8', '9', '0',
554*61c4878aSAndroid Build Coastguard Worker     0x12, 0x0d, 'b', 'a', 'r', '@', 'e', 'm', 'a', 'i', 'l', '.', 'c', 'o', 'm',
555*61c4878aSAndroid Build Coastguard Worker   };
556*61c4878aSAndroid Build Coastguard Worker   // clang-format on
557*61c4878aSAndroid Build Coastguard Worker 
558*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kInfoFieldNumber = 1;
559*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kNumberFieldNumber = 1;
560*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kEmailFieldNumber = 2;
561*61c4878aSAndroid Build Coastguard Worker 
562*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
563*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
564*61c4878aSAndroid Build Coastguard Worker 
565*61c4878aSAndroid Build Coastguard Worker   RepeatedMessages messages = parser.AsRepeatedMessages(kInfoFieldNumber);
566*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(messages.status());
567*61c4878aSAndroid Build Coastguard Worker 
568*61c4878aSAndroid Build Coastguard Worker   struct {
569*61c4878aSAndroid Build Coastguard Worker     std::string_view number;
570*61c4878aSAndroid Build Coastguard Worker     std::string_view email;
571*61c4878aSAndroid Build Coastguard Worker   } expected[] = {
572*61c4878aSAndroid Build Coastguard Worker       {"12345", "[email protected]"},
573*61c4878aSAndroid Build Coastguard Worker       {"67890", "[email protected]"},
574*61c4878aSAndroid Build Coastguard Worker   };
575*61c4878aSAndroid Build Coastguard Worker 
576*61c4878aSAndroid Build Coastguard Worker   size_t count = 0;
577*61c4878aSAndroid Build Coastguard Worker   for (Message message : messages) {
578*61c4878aSAndroid Build Coastguard Worker     String number = message.AsString(kNumberFieldNumber);
579*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(number.status());
580*61c4878aSAndroid Build Coastguard Worker     Result<bool> cmp = number.Equal(expected[count].number);
581*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(cmp.status());
582*61c4878aSAndroid Build Coastguard Worker     ASSERT_TRUE(cmp.value());
583*61c4878aSAndroid Build Coastguard Worker 
584*61c4878aSAndroid Build Coastguard Worker     String email = message.AsString(kEmailFieldNumber);
585*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(email.status());
586*61c4878aSAndroid Build Coastguard Worker     cmp = email.Equal(expected[count].email);
587*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(cmp.status());
588*61c4878aSAndroid Build Coastguard Worker     ASSERT_TRUE(cmp.value());
589*61c4878aSAndroid Build Coastguard Worker 
590*61c4878aSAndroid Build Coastguard Worker     count++;
591*61c4878aSAndroid Build Coastguard Worker   }
592*61c4878aSAndroid Build Coastguard Worker 
593*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(count, static_cast<size_t>(2));
594*61c4878aSAndroid Build Coastguard Worker }
595*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,AsStringToBytesMap)596*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, AsStringToBytesMap) {
597*61c4878aSAndroid Build Coastguard Worker   // message Maps {
598*61c4878aSAndroid Build Coastguard Worker   //   map<string, string> map_a = 1;
599*61c4878aSAndroid Build Coastguard Worker   //   map<string, string> map_b = 2;
600*61c4878aSAndroid Build Coastguard Worker   // }
601*61c4878aSAndroid Build Coastguard Worker   // clang-format off
602*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
603*61c4878aSAndroid Build Coastguard Worker     // map_a["key_bar"] = "bar_a", key = 1
604*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x10,
605*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x07, 'k', 'e', 'y', '_', 'b', 'a', 'r', // map key
606*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05, 'b', 'a', 'r', '_', 'a', // map value
607*61c4878aSAndroid Build Coastguard Worker 
608*61c4878aSAndroid Build Coastguard Worker     // map_a["key_foo"] = "foo_a", key = 1
609*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x10,
610*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x07, 'k', 'e', 'y', '_', 'f', 'o', 'o',
611*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05, 'f', 'o', 'o', '_', 'a',
612*61c4878aSAndroid Build Coastguard Worker 
613*61c4878aSAndroid Build Coastguard Worker     // map_b["key_foo"] = "foo_b", key = 2
614*61c4878aSAndroid Build Coastguard Worker     0x12, 0x10,
615*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x07, 'k', 'e', 'y', '_', 'f', 'o', 'o',
616*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05, 'f', 'o', 'o', 0x5f, 0x62,
617*61c4878aSAndroid Build Coastguard Worker 
618*61c4878aSAndroid Build Coastguard Worker     // map_b["key_bar"] = "bar_b", key = 2
619*61c4878aSAndroid Build Coastguard Worker     0x12, 0x10,
620*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x07, 'k', 'e', 'y', '_', 'b', 'a', 'r',
621*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05, 'b', 'a', 'r', 0x5f, 0x62,
622*61c4878aSAndroid Build Coastguard Worker   };
623*61c4878aSAndroid Build Coastguard Worker   // clang-format on
624*61c4878aSAndroid Build Coastguard Worker 
625*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
626*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
627*61c4878aSAndroid Build Coastguard Worker 
628*61c4878aSAndroid Build Coastguard Worker   {
629*61c4878aSAndroid Build Coastguard Worker     // Parse field 'map_a'
630*61c4878aSAndroid Build Coastguard Worker     constexpr uint32_t kFieldNumber = 1;
631*61c4878aSAndroid Build Coastguard Worker     StringMapParser<String> string_map =
632*61c4878aSAndroid Build Coastguard Worker         parser.AsStringToStringMap(kFieldNumber);
633*61c4878aSAndroid Build Coastguard Worker 
634*61c4878aSAndroid Build Coastguard Worker     String value = string_map["key_foo"];
635*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
636*61c4878aSAndroid Build Coastguard Worker     Result<bool> cmp = value.Equal("foo_a");
637*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(cmp.status());
638*61c4878aSAndroid Build Coastguard Worker     ASSERT_TRUE(cmp.value());
639*61c4878aSAndroid Build Coastguard Worker 
640*61c4878aSAndroid Build Coastguard Worker     value = string_map["key_bar"];
641*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
642*61c4878aSAndroid Build Coastguard Worker     cmp = value.Equal("bar_a");
643*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(cmp.status());
644*61c4878aSAndroid Build Coastguard Worker     ASSERT_TRUE(cmp.value());
645*61c4878aSAndroid Build Coastguard Worker 
646*61c4878aSAndroid Build Coastguard Worker     // Non-existing key
647*61c4878aSAndroid Build Coastguard Worker     value = string_map["non-existing"];
648*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.status(), Status::NotFound());
649*61c4878aSAndroid Build Coastguard Worker   }
650*61c4878aSAndroid Build Coastguard Worker 
651*61c4878aSAndroid Build Coastguard Worker   {
652*61c4878aSAndroid Build Coastguard Worker     // Parse field 'map_b'
653*61c4878aSAndroid Build Coastguard Worker     constexpr uint32_t kFieldNumber = 2;
654*61c4878aSAndroid Build Coastguard Worker     StringMapParser<String> string_map =
655*61c4878aSAndroid Build Coastguard Worker         parser.AsStringToStringMap(kFieldNumber);
656*61c4878aSAndroid Build Coastguard Worker 
657*61c4878aSAndroid Build Coastguard Worker     String value = string_map["key_foo"];
658*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
659*61c4878aSAndroid Build Coastguard Worker     Result<bool> cmp = value.Equal("foo_b");
660*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(cmp.status());
661*61c4878aSAndroid Build Coastguard Worker     ASSERT_TRUE(cmp.value());
662*61c4878aSAndroid Build Coastguard Worker 
663*61c4878aSAndroid Build Coastguard Worker     value = string_map["key_bar"];
664*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(value.status());
665*61c4878aSAndroid Build Coastguard Worker     cmp = value.Equal("bar_b");
666*61c4878aSAndroid Build Coastguard Worker     PW_TEST_ASSERT_OK(cmp.status());
667*61c4878aSAndroid Build Coastguard Worker     ASSERT_TRUE(cmp.value());
668*61c4878aSAndroid Build Coastguard Worker 
669*61c4878aSAndroid Build Coastguard Worker     // Non-existing key
670*61c4878aSAndroid Build Coastguard Worker     value = string_map["non-existing"];
671*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(value.status(), Status::NotFound());
672*61c4878aSAndroid Build Coastguard Worker   }
673*61c4878aSAndroid Build Coastguard Worker }
674*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,AsStringToMessageMap)675*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, AsStringToMessageMap) {
676*61c4878aSAndroid Build Coastguard Worker   // message Contact {
677*61c4878aSAndroid Build Coastguard Worker   //   string number = 1;
678*61c4878aSAndroid Build Coastguard Worker   //   string email = 2;
679*61c4878aSAndroid Build Coastguard Worker   // }
680*61c4878aSAndroid Build Coastguard Worker   //
681*61c4878aSAndroid Build Coastguard Worker   // message Contacts {
682*61c4878aSAndroid Build Coastguard Worker   //  map<string, Contact> staffs = 1;
683*61c4878aSAndroid Build Coastguard Worker   // }
684*61c4878aSAndroid Build Coastguard Worker   // clang-format off
685*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
686*61c4878aSAndroid Build Coastguard Worker     // staffs['bar'] = {.number = '456, .email = "[email protected]"}
687*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x1b,
688*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x03, 0x62, 0x61, 0x72,
689*61c4878aSAndroid Build Coastguard Worker     0x12, 0x14, 0x0a, 0x03, 0x34, 0x35, 0x36, 0x12, 0x0d, 0x62, 0x61, 0x72, 0x40, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d,
690*61c4878aSAndroid Build Coastguard Worker 
691*61c4878aSAndroid Build Coastguard Worker     // staffs['foo'] = {.number = '123', .email = "[email protected]"}
692*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x1b,
693*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x03, 0x66, 0x6f, 0x6f,
694*61c4878aSAndroid Build Coastguard Worker     0x12, 0x14, 0x0a, 0x03, 0x31, 0x32, 0x33, 0x12, 0x0d, 0x66, 0x6f, 0x6f, 0x40, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x2e, 0x63, 0x6f, 0x6d,
695*61c4878aSAndroid Build Coastguard Worker   };
696*61c4878aSAndroid Build Coastguard Worker   // clang-format on
697*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kStaffsFieldId = 1;
698*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kNumberFieldId = 1;
699*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kEmailFieldId = 2;
700*61c4878aSAndroid Build Coastguard Worker 
701*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
702*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
703*61c4878aSAndroid Build Coastguard Worker 
704*61c4878aSAndroid Build Coastguard Worker   StringMapParser<Message> staffs = parser.AsStringToMessageMap(kStaffsFieldId);
705*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(staffs.status());
706*61c4878aSAndroid Build Coastguard Worker 
707*61c4878aSAndroid Build Coastguard Worker   Message foo_staff = staffs["foo"];
708*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(foo_staff.status());
709*61c4878aSAndroid Build Coastguard Worker   String foo_number = foo_staff.AsString(kNumberFieldId);
710*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(foo_number.status());
711*61c4878aSAndroid Build Coastguard Worker   Result<bool> foo_number_cmp = foo_number.Equal("123");
712*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(foo_number_cmp.status());
713*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(foo_number_cmp.value());
714*61c4878aSAndroid Build Coastguard Worker   String foo_email = foo_staff.AsString(kEmailFieldId);
715*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(foo_email.status());
716*61c4878aSAndroid Build Coastguard Worker   Result<bool> foo_email_cmp = foo_email.Equal("[email protected]");
717*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(foo_email_cmp.status());
718*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(foo_email_cmp.value());
719*61c4878aSAndroid Build Coastguard Worker 
720*61c4878aSAndroid Build Coastguard Worker   Message bar_staff = staffs["bar"];
721*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(bar_staff.status());
722*61c4878aSAndroid Build Coastguard Worker   String bar_number = bar_staff.AsString(kNumberFieldId);
723*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(bar_number.status());
724*61c4878aSAndroid Build Coastguard Worker   Result<bool> bar_number_cmp = bar_number.Equal("456");
725*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(bar_number_cmp.status());
726*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(bar_number_cmp.value());
727*61c4878aSAndroid Build Coastguard Worker   String bar_email = bar_staff.AsString(kEmailFieldId);
728*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(bar_email.status());
729*61c4878aSAndroid Build Coastguard Worker   Result<bool> bar_email_cmp = bar_email.Equal("[email protected]");
730*61c4878aSAndroid Build Coastguard Worker   PW_TEST_ASSERT_OK(bar_email_cmp.status());
731*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(bar_email_cmp.value());
732*61c4878aSAndroid Build Coastguard Worker }
733*61c4878aSAndroid Build Coastguard Worker 
TEST(ProtoHelper,AsStringToBytesMapMalformed)734*61c4878aSAndroid Build Coastguard Worker TEST(ProtoHelper, AsStringToBytesMapMalformed) {
735*61c4878aSAndroid Build Coastguard Worker   // message Maps {
736*61c4878aSAndroid Build Coastguard Worker   //   map<string, string> map_a = 1;
737*61c4878aSAndroid Build Coastguard Worker   //   map<string, string> map_b = 2;
738*61c4878aSAndroid Build Coastguard Worker   // }
739*61c4878aSAndroid Build Coastguard Worker   // clang-format off
740*61c4878aSAndroid Build Coastguard Worker   std::uint8_t encoded_proto[] = {
741*61c4878aSAndroid Build Coastguard Worker     // map_a["key_bar"] = "bar_a", key = 1
742*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x10,
743*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x07, 'k', 'e', 'y', '_', 'b', 'a', 'r', // map key
744*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05, 'b', 'a', 'r', '_', 'a', // map value
745*61c4878aSAndroid Build Coastguard Worker 
746*61c4878aSAndroid Build Coastguard Worker     // map_a["key_foo"] = "foo_a", key = 0 (invalid)
747*61c4878aSAndroid Build Coastguard Worker     0x02, 0x10,
748*61c4878aSAndroid Build Coastguard Worker     0x0a, 0x07, 'k', 'e', 'y', '_', 'f', 'o', 'o',
749*61c4878aSAndroid Build Coastguard Worker     0x12, 0x05, 'f', 'o', 'o', '_', 'a',
750*61c4878aSAndroid Build Coastguard Worker   };
751*61c4878aSAndroid Build Coastguard Worker   // clang-format on
752*61c4878aSAndroid Build Coastguard Worker 
753*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(as_bytes(span(encoded_proto)));
754*61c4878aSAndroid Build Coastguard Worker   Message parser = Message(reader, sizeof(encoded_proto));
755*61c4878aSAndroid Build Coastguard Worker 
756*61c4878aSAndroid Build Coastguard Worker   // Parse field 'map_a'
757*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kFieldNumber = 1;
758*61c4878aSAndroid Build Coastguard Worker   StringMapParser<String> string_map = parser.AsStringToStringMap(kFieldNumber);
759*61c4878aSAndroid Build Coastguard Worker 
760*61c4878aSAndroid Build Coastguard Worker   bool expected_ok_status[] = {true, false};
761*61c4878aSAndroid Build Coastguard Worker   size_t count = 0;
762*61c4878aSAndroid Build Coastguard Worker   for (StringToStringMapEntry entry : string_map) {
763*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(entry.ok(), expected_ok_status[count]);
764*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(entry.Key().ok(), expected_ok_status[count]);
765*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(entry.Value().ok(), expected_ok_status[count]);
766*61c4878aSAndroid Build Coastguard Worker     count++;
767*61c4878aSAndroid Build Coastguard Worker   }
768*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(count, 2ULL);
769*61c4878aSAndroid Build Coastguard Worker }
770*61c4878aSAndroid Build Coastguard Worker 
771*61c4878aSAndroid Build Coastguard Worker }  // namespace
772*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::protobuf
773