xref: /aosp_15_r20/external/pigweed/pw_protobuf/find_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_protobuf/find.h"
16 
17 #include <string_view>
18 
19 #include "pw_bytes/array.h"
20 #include "pw_status/status.h"
21 #include "pw_stream/memory_stream.h"
22 #include "pw_string/string.h"
23 #include "pw_unit_test/framework.h"
24 
25 namespace pw::protobuf {
26 namespace {
27 
28 constexpr auto kEncodedProto = bytes::Array<  // clang-format off
29     // type=int32, k=1, v=42
30     0x08, 0x2a,  // 0-1
31     // type=sint32, k=2, v=-13
32     0x10, 0x19,  // 2-3
33     // type=bool, k=3, v=false
34     0x18, 0x00,  // 4-5
35     // type=double, k=4, v=3.14159
36     0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40, // 6-14
37     // type=fixed32, k=5, v=0xdeadbeef
38     0x2d, 0xef, 0xbe, 0xad, 0xde,  // 15-19
39     // type=string, k=6, v="Hello world"
40     0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',  // 20-32
41 
42     // type=message, k=7, len=2
43     0x3a, 0x02,  // 33-34
44     // (nested) type=uint32, k=1, v=3
45     0x08, 0x03   // 35-36
46 >();  // clang-format on
47 
48 static_assert(kEncodedProto.size() == 37);
49 
TEST(Find,PresentField)50 TEST(Find, PresentField) {
51   EXPECT_EQ(FindInt32(kEncodedProto, 1).value(), 42);
52   EXPECT_EQ(FindSint32(kEncodedProto, 2).value(), -13);
53   EXPECT_EQ(FindBool(kEncodedProto, 3).value(), false);
54   EXPECT_EQ(FindDouble(kEncodedProto, 4).value(), 3.14159);
55   EXPECT_EQ(FindFixed32(kEncodedProto, 5).value(), 0xdeadbeef);
56 
57   Result<std::string_view> result = FindString(kEncodedProto, 6);
58   ASSERT_EQ(result.status(), OkStatus());
59   InlineString<32> str(*result);
60   EXPECT_STREQ(str.c_str(), "Hello world");
61 }
62 
TEST(Find,MissingField)63 TEST(Find, MissingField) {
64   EXPECT_EQ(FindUint32(kEncodedProto, 8).status(), Status::NotFound());
65   EXPECT_EQ(FindUint32(kEncodedProto, 66).status(), Status::NotFound());
66   EXPECT_EQ(FindUint32(kEncodedProto, 123456789).status(), Status::NotFound());
67   EXPECT_EQ(FindRaw(kEncodedProto, 123456789).status(), Status::NotFound());
68 }
69 
TEST(Find,InvalidFieldNumber)70 TEST(Find, InvalidFieldNumber) {
71   EXPECT_EQ(FindUint32(kEncodedProto, 0).status(), Status::InvalidArgument());
72   EXPECT_EQ(FindUint32(kEncodedProto, uint32_t(-1)).status(),
73             Status::InvalidArgument());
74 }
75 
TEST(Find,WrongWireType)76 TEST(Find, WrongWireType) {
77   // Field 5 is a fixed32, but we request a uint32 (varint).
78   EXPECT_EQ(FindUint32(kEncodedProto, 5).status(),
79             Status::FailedPrecondition());
80 }
81 
TEST(Find,MultiLevel)82 TEST(Find, MultiLevel) {
83   Result<ConstByteSpan> submessage = FindSubmessage(kEncodedProto, 7);
84   ASSERT_EQ(submessage.status(), OkStatus());
85   EXPECT_EQ(submessage->size(), 2u);
86 
87   // Read a field from the submessage.
88   EXPECT_EQ(FindUint32(*submessage, 1).value(), 3u);
89 }
90 
TEST(FindStream,PresentField)91 TEST(FindStream, PresentField) {
92   stream::MemoryReader reader(kEncodedProto);
93 
94   EXPECT_EQ(FindInt32(reader, 1).value(), 42);
95   EXPECT_EQ(FindSint32(reader, 2).value(), -13);
96   EXPECT_EQ(FindBool(reader, 3).value(), false);
97   EXPECT_EQ(FindDouble(kEncodedProto, 4).value(), 3.14159);
98 
99   EXPECT_EQ(FindFixed32(reader, 5).value(), 0xdeadbeef);
100 
101   char str[32];
102   StatusWithSize sws = FindString(reader, 6, str);
103   ASSERT_EQ(sws.status(), OkStatus());
104   ASSERT_EQ(sws.size(), 11u);
105   str[sws.size()] = '\0';
106   EXPECT_STREQ(str, "Hello world");
107 }
108 
TEST(FindStream,MissingField)109 TEST(FindStream, MissingField) {
110   stream::MemoryReader reader(kEncodedProto);
111   EXPECT_EQ(FindUint32(reader, 8).status(), Status::NotFound());
112 
113   reader = stream::MemoryReader(kEncodedProto);
114   EXPECT_EQ(FindUint32(reader, 66).status(), Status::NotFound());
115 
116   reader = stream::MemoryReader(kEncodedProto);
117   EXPECT_EQ(FindUint32(reader, 123456789).status(), Status::NotFound());
118 }
119 
TEST(FindStream,InvalidFieldNumber)120 TEST(FindStream, InvalidFieldNumber) {
121   stream::MemoryReader reader(kEncodedProto);
122   EXPECT_EQ(FindUint32(reader, 0).status(), Status::InvalidArgument());
123 
124   reader = stream::MemoryReader(kEncodedProto);
125   EXPECT_EQ(FindUint32(reader, uint32_t(-1)).status(),
126             Status::InvalidArgument());
127 }
128 
TEST(FindStream,WrongWireType)129 TEST(FindStream, WrongWireType) {
130   stream::MemoryReader reader(kEncodedProto);
131 
132   // Field 5 is a fixed32, but we request a uint32 (varint).
133   EXPECT_EQ(FindUint32(reader, 5).status(), Status::FailedPrecondition());
134 }
135 
136 enum class Fields : uint32_t {
137   kField1 = 1,
138   kField2 = 2,
139   kField3 = 3,
140   kField4 = 4,
141   kField5 = 5,
142   kField6 = 6,
143   kField7 = 7,
144 };
145 
TEST(FindEnum,PresentField)146 TEST(FindEnum, PresentField) {
147   EXPECT_EQ(FindInt32(kEncodedProto, Fields::kField1).value(), 42);
148   EXPECT_EQ(FindSint32(kEncodedProto, Fields::kField2).value(), -13);
149   EXPECT_EQ(FindBool(kEncodedProto, Fields::kField3).value(), false);
150   EXPECT_EQ(FindDouble(kEncodedProto, Fields::kField4).value(), 3.14159);
151   EXPECT_EQ(FindFixed32(kEncodedProto, Fields::kField5).value(), 0xdeadbeef);
152 
153   stream::MemoryReader reader(kEncodedProto);
154   InlineString<32> str;
155   StatusWithSize result = FindString(reader, Fields::kField6, str);
156   ASSERT_EQ(result.status(), OkStatus());
157   EXPECT_STREQ(str.c_str(), "Hello world");
158 }
159 
TEST(FindRaw,PresentField)160 TEST(FindRaw, PresentField) {
161   ConstByteSpan field1 = FindRaw(kEncodedProto, Fields::kField1).value();
162   EXPECT_EQ(field1.data(), kEncodedProto.data() + 1);
163   EXPECT_EQ(field1.size(), 1u);
164 
165   ConstByteSpan field2 = FindRaw(kEncodedProto, Fields::kField2).value();
166   EXPECT_EQ(field2.data(), kEncodedProto.data() + 3);
167   EXPECT_EQ(field2.size(), 1u);
168 
169   ConstByteSpan field3 = FindRaw(kEncodedProto, Fields::kField3).value();
170   EXPECT_EQ(field3.data(), kEncodedProto.data() + 5);
171   EXPECT_EQ(field3.size(), 1u);
172 
173   ConstByteSpan field4 = FindRaw(kEncodedProto, Fields::kField4).value();
174   EXPECT_EQ(field4.data(), kEncodedProto.data() + 7);
175   EXPECT_EQ(field4.size(), sizeof(double));
176 
177   ConstByteSpan field5 = FindRaw(kEncodedProto, Fields::kField5).value();
178   EXPECT_EQ(field5.data(), kEncodedProto.data() + 16);
179   EXPECT_EQ(field5.size(), sizeof(uint32_t));
180 
181   ConstByteSpan field6 = FindRaw(kEncodedProto, Fields::kField6).value();
182   EXPECT_EQ(field6.data(), kEncodedProto.data() + 22);
183   EXPECT_EQ(field6.size(), sizeof("Hello world") - 1 /* null */);
184 
185   ConstByteSpan field7 = FindRaw(kEncodedProto, Fields::kField7).value();
186   EXPECT_EQ(field7.data(), kEncodedProto.data() + 35);
187   EXPECT_EQ(field7.size(), 2u);
188 }
189 
190 enum class Boolean {
191   kTrue = 0,
192   kFalse = 1,
193   kFileNotFound = 2,
194 };
195 
196 constexpr auto kEncodedRepeatedProto = bytes::Array<  // clang-format off
197     // type=int32, k=1, v=42
198     0x08, 0x2a,
199     // type=int32, k=1, v=32
200     0x08, 0x20,
201     // type=int32, k=1, v=16
202     0x08, 0x10,
203     // type=int32, k=1, v=0
204     0x08, 0x00,
205     // type=uint32, k=2, v=1
206     0x10, 0x1,
207     // type=uint32, k=2, v=2
208     0x10, 0x2,
209     // type=string, k=6, v="Hello, "
210     0x32, 0x07, 'H', 'e', 'l', 'l', 'o', ',', ' ',
211     // type=string, k=6, v="world"
212     0x32, 0x05, 'w', 'o', 'r', 'l', 'd',
213     // type=string, k=6, v="!"
214     0x32, 0x01, '!'
215 >();  // clang-format on
216 
TEST(Finder,RepeatedField)217 TEST(Finder, RepeatedField) {
218   StringFinder finder(kEncodedRepeatedProto, 6);
219   Result<std::string_view> result = finder.Next();
220   EXPECT_EQ(result.status(), OkStatus());
221   EXPECT_EQ(result.value(), std::string_view("Hello, "));
222   result = finder.Next();
223   EXPECT_EQ(result.status(), OkStatus());
224   EXPECT_EQ(result.value(), std::string_view("world"));
225   result = finder.Next();
226   EXPECT_EQ(result.status(), OkStatus());
227   EXPECT_EQ(result.value(), std::string_view("!"));
228   result = finder.Next();
229   EXPECT_EQ(result.status(), Status::NotFound());
230 }
231 
TEST(StreamFinder,RepeatedField)232 TEST(StreamFinder, RepeatedField) {
233   stream::MemoryReader reader(kEncodedRepeatedProto);
234   Int32StreamFinder finder(reader, 1);
235   Result<int32_t> result = finder.Next();
236   EXPECT_EQ(result.status(), OkStatus());
237   EXPECT_EQ(result.value(), 42);
238   result = finder.Next();
239   EXPECT_EQ(result.status(), OkStatus());
240   EXPECT_EQ(result.value(), 32);
241   result = finder.Next();
242   EXPECT_EQ(result.status(), OkStatus());
243   EXPECT_EQ(result.value(), 16);
244   result = finder.Next();
245   EXPECT_EQ(result.status(), OkStatus());
246   EXPECT_EQ(result.value(), 0);
247   result = finder.Next();
248   EXPECT_EQ(result.status(), Status::NotFound());
249 }
250 
TEST(EnumFinder,RepeatedField)251 TEST(EnumFinder, RepeatedField) {
252   EnumFinder<Boolean> finder(kEncodedRepeatedProto, 2);
253   Result<Boolean> result = finder.Next();
254   EXPECT_EQ(result.status(), OkStatus());
255   EXPECT_EQ(result.value(), Boolean::kFalse);
256   result = finder.Next();
257   EXPECT_EQ(result.status(), OkStatus());
258   EXPECT_EQ(result.value(), Boolean::kFileNotFound);
259   result = finder.Next();
260   EXPECT_EQ(result.status(), Status::NotFound());
261 }
262 
263 }  // namespace
264 }  // namespace pw::protobuf
265