• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "pw_bytes/array.h"
18 #include "pw_stream/memory_stream.h"
19 #include "pw_string/string.h"
20 #include "pw_unit_test/framework.h"
21 
22 namespace pw::protobuf {
23 namespace {
24 
25 constexpr auto kEncodedProto = bytes::Array<  // clang-format off
26     // type=int32, k=1, v=42
27     0x08, 0x2a,  // 0-1
28     // type=sint32, k=2, v=-13
29     0x10, 0x19,  // 2-3
30     // type=bool, k=3, v=false
31     0x18, 0x00,  // 4-5
32     // type=double, k=4, v=3.14159
33     0x21, 0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40, // 6-14
34     // type=fixed32, k=5, v=0xdeadbeef
35     0x2d, 0xef, 0xbe, 0xad, 0xde,  // 15-19
36     // type=string, k=6, v="Hello world"
37     0x32, 0x0b, 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd',  // 20-32
38 
39     // type=message, k=7, len=2
40     0x3a, 0x02,  // 33-34
41     // (nested) type=uint32, k=1, v=3
42     0x08, 0x03   // 35-36
43 >();  // clang-format on
44 
45 static_assert(kEncodedProto.size() == 37);
46 
TEST(Find,PresentField)47 TEST(Find, PresentField) {
48   EXPECT_EQ(FindInt32(kEncodedProto, 1).value(), 42);
49   EXPECT_EQ(FindSint32(kEncodedProto, 2).value(), -13);
50   EXPECT_EQ(FindBool(kEncodedProto, 3).value(), false);
51   EXPECT_EQ(FindDouble(kEncodedProto, 4).value(), 3.14159);
52   EXPECT_EQ(FindFixed32(kEncodedProto, 5).value(), 0xdeadbeef);
53 
54   Result<std::string_view> result = FindString(kEncodedProto, 6);
55   ASSERT_EQ(result.status(), OkStatus());
56   InlineString<32> str(*result);
57   EXPECT_STREQ(str.c_str(), "Hello world");
58 }
59 
TEST(Find,MissingField)60 TEST(Find, MissingField) {
61   EXPECT_EQ(FindUint32(kEncodedProto, 8).status(), Status::NotFound());
62   EXPECT_EQ(FindUint32(kEncodedProto, 66).status(), Status::NotFound());
63   EXPECT_EQ(FindUint32(kEncodedProto, 123456789).status(), Status::NotFound());
64   EXPECT_EQ(FindRaw(kEncodedProto, 123456789).status(), Status::NotFound());
65 }
66 
TEST(Find,InvalidFieldNumber)67 TEST(Find, InvalidFieldNumber) {
68   EXPECT_EQ(FindUint32(kEncodedProto, 0).status(), Status::InvalidArgument());
69   EXPECT_EQ(FindUint32(kEncodedProto, uint32_t(-1)).status(),
70             Status::InvalidArgument());
71 }
72 
TEST(Find,WrongWireType)73 TEST(Find, WrongWireType) {
74   // Field 5 is a fixed32, but we request a uint32 (varint).
75   EXPECT_EQ(FindUint32(kEncodedProto, 5).status(),
76             Status::FailedPrecondition());
77 }
78 
TEST(Find,MultiLevel)79 TEST(Find, MultiLevel) {
80   Result<ConstByteSpan> submessage = FindSubmessage(kEncodedProto, 7);
81   ASSERT_EQ(submessage.status(), OkStatus());
82   EXPECT_EQ(submessage->size(), 2u);
83 
84   // Read a field from the submessage.
85   EXPECT_EQ(FindUint32(*submessage, 1).value(), 3u);
86 }
87 
TEST(FindStream,PresentField)88 TEST(FindStream, PresentField) {
89   stream::MemoryReader reader(kEncodedProto);
90 
91   EXPECT_EQ(FindInt32(reader, 1).value(), 42);
92   EXPECT_EQ(FindSint32(reader, 2).value(), -13);
93   EXPECT_EQ(FindBool(reader, 3).value(), false);
94   EXPECT_EQ(FindDouble(kEncodedProto, 4).value(), 3.14159);
95 
96   EXPECT_EQ(FindFixed32(reader, 5).value(), 0xdeadbeef);
97 
98   char str[32];
99   StatusWithSize sws = FindString(reader, 6, str);
100   ASSERT_EQ(sws.status(), OkStatus());
101   ASSERT_EQ(sws.size(), 11u);
102   str[sws.size()] = '\0';
103   EXPECT_STREQ(str, "Hello world");
104 }
105 
TEST(FindStream,MissingField)106 TEST(FindStream, MissingField) {
107   stream::MemoryReader reader(kEncodedProto);
108   EXPECT_EQ(FindUint32(reader, 8).status(), Status::NotFound());
109 
110   reader = stream::MemoryReader(kEncodedProto);
111   EXPECT_EQ(FindUint32(reader, 66).status(), Status::NotFound());
112 
113   reader = stream::MemoryReader(kEncodedProto);
114   EXPECT_EQ(FindUint32(reader, 123456789).status(), Status::NotFound());
115 }
116 
TEST(FindStream,InvalidFieldNumber)117 TEST(FindStream, InvalidFieldNumber) {
118   stream::MemoryReader reader(kEncodedProto);
119   EXPECT_EQ(FindUint32(reader, 0).status(), Status::InvalidArgument());
120 
121   reader = stream::MemoryReader(kEncodedProto);
122   EXPECT_EQ(FindUint32(reader, uint32_t(-1)).status(),
123             Status::InvalidArgument());
124 }
125 
TEST(FindStream,WrongWireType)126 TEST(FindStream, WrongWireType) {
127   stream::MemoryReader reader(kEncodedProto);
128 
129   // Field 5 is a fixed32, but we request a uint32 (varint).
130   EXPECT_EQ(FindUint32(reader, 5).status(), Status::FailedPrecondition());
131 }
132 
133 enum class Fields : uint32_t {
134   kField1 = 1,
135   kField2 = 2,
136   kField3 = 3,
137   kField4 = 4,
138   kField5 = 5,
139   kField6 = 6,
140   kField7 = 7,
141 };
142 
TEST(FindEnum,PresentField)143 TEST(FindEnum, PresentField) {
144   EXPECT_EQ(FindInt32(kEncodedProto, Fields::kField1).value(), 42);
145   EXPECT_EQ(FindSint32(kEncodedProto, Fields::kField2).value(), -13);
146   EXPECT_EQ(FindBool(kEncodedProto, Fields::kField3).value(), false);
147   EXPECT_EQ(FindDouble(kEncodedProto, Fields::kField4).value(), 3.14159);
148   EXPECT_EQ(FindFixed32(kEncodedProto, Fields::kField5).value(), 0xdeadbeef);
149 
150   stream::MemoryReader reader(kEncodedProto);
151   InlineString<32> str;
152   StatusWithSize result = FindString(reader, Fields::kField6, str);
153   ASSERT_EQ(result.status(), OkStatus());
154   EXPECT_STREQ(str.c_str(), "Hello world");
155 }
156 
TEST(FindRaw,PresentField)157 TEST(FindRaw, PresentField) {
158   ConstByteSpan field1 = FindRaw(kEncodedProto, Fields::kField1).value();
159   EXPECT_EQ(field1.data(), kEncodedProto.data() + 1);
160   EXPECT_EQ(field1.size(), 1u);
161 
162   ConstByteSpan field2 = FindRaw(kEncodedProto, Fields::kField2).value();
163   EXPECT_EQ(field2.data(), kEncodedProto.data() + 3);
164   EXPECT_EQ(field2.size(), 1u);
165 
166   ConstByteSpan field3 = FindRaw(kEncodedProto, Fields::kField3).value();
167   EXPECT_EQ(field3.data(), kEncodedProto.data() + 5);
168   EXPECT_EQ(field3.size(), 1u);
169 
170   ConstByteSpan field4 = FindRaw(kEncodedProto, Fields::kField4).value();
171   EXPECT_EQ(field4.data(), kEncodedProto.data() + 7);
172   EXPECT_EQ(field4.size(), sizeof(double));
173 
174   ConstByteSpan field5 = FindRaw(kEncodedProto, Fields::kField5).value();
175   EXPECT_EQ(field5.data(), kEncodedProto.data() + 16);
176   EXPECT_EQ(field5.size(), sizeof(uint32_t));
177 
178   ConstByteSpan field6 = FindRaw(kEncodedProto, Fields::kField6).value();
179   EXPECT_EQ(field6.data(), kEncodedProto.data() + 22);
180   EXPECT_EQ(field6.size(), sizeof("Hello world") - 1 /* null */);
181 
182   ConstByteSpan field7 = FindRaw(kEncodedProto, Fields::kField7).value();
183   EXPECT_EQ(field7.data(), kEncodedProto.data() + 35);
184   EXPECT_EQ(field7.size(), 2u);
185 }
186 
187 }  // namespace
188 }  // namespace pw::protobuf
189