blob: 657e6e9d02c5dfad95e1ef340049c3b8652de10c [file] [log] [blame]
Scott James Remnant354a6982022-03-03 16:45:48 -08001// Copyright 2022 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.
Scott James Remnant001f9532022-03-04 17:51:54 -080014#include <array>
Scott James Remnant354a6982022-03-03 16:45:48 -080015#include <span>
Scott James Remnant001f9532022-03-04 17:51:54 -080016#include <stdexcept>
17#include <string_view>
Scott James Remnant354a6982022-03-03 16:45:48 -080018
19#include "gtest/gtest.h"
Scott James Remnant001f9532022-03-04 17:51:54 -080020#include "pw_bytes/span.h"
Scott James Remnant75c76842022-03-17 16:51:33 -070021#include "pw_containers/vector.h"
Scott James Remnant354a6982022-03-03 16:45:48 -080022#include "pw_status/status.h"
Scott James Remnant001f9532022-03-04 17:51:54 -080023#include "pw_status/status_with_size.h"
Scott James Remnant354a6982022-03-03 16:45:48 -080024#include "pw_stream/memory_stream.h"
25
26// These header files contain the code generated by the pw_protobuf plugin.
27// They are re-generated every time the tests are built and are used by the
28// tests to ensure that the interface remains consistent.
29//
30// The purpose of the tests in this file is primarily to verify that the
31// generated C++ interface is valid rather than the correctness of the
32// low-level encoder.
33#include "pw_protobuf_test_protos/full_test.pwpb.h"
34#include "pw_protobuf_test_protos/importer.pwpb.h"
35#include "pw_protobuf_test_protos/non_pw_package.pwpb.h"
36#include "pw_protobuf_test_protos/proto2.pwpb.h"
37#include "pw_protobuf_test_protos/repeated.pwpb.h"
38
39namespace pw::protobuf {
40namespace {
41
42using namespace pw::protobuf::test;
43
44TEST(Codegen, StreamDecoder) {
45 // clang-format off
46 constexpr uint8_t proto_data[] = {
47 // pigweed.magic_number
48 0x08, 0x49,
Scott James Remnant001f9532022-03-04 17:51:54 -080049 // pigweed.ziggy
50 0x10, 0xdd, 0x01,
51 // pigweed.error_message
52 0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
53 't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
54 // pigweed.bin
55 0x40, 0x01,
Scott James Remnant354a6982022-03-03 16:45:48 -080056 // pigweed.pigweed
57 0x3a, 0x02,
58 // pigweed.pigweed.status
59 0x08, 0x02,
Scott James Remnant001f9532022-03-04 17:51:54 -080060 // pigweed.proto
61 0x4a, 0x56,
62 // pigweed.proto.bin
63 0x10, 0x00,
64 // pigweed.proto.pigweed_pigweed_bin
65 0x18, 0x00,
66 // pigweed.proto.pigweed_protobuf_bin
67 0x20, 0x01,
68 // pigweed.proto.meta
69 0x2a, 0x0f,
70 // pigweed.proto.meta.file_name
71 0x0a, 0x0b, '/', 'e', 't', 'c', '/', 'p', 'a', 's', 's', 'w', 'd',
72 // pigweed.proto.meta.status
73 0x10, 0x02,
74 // pigweed.proto.nested_pigweed
75 0x0a, 0x3d,
76 // pigweed.proto.nested_pigweed.error_message
77 0x2a, 0x10, 'h', 'e', 'r', 'e', ' ', 'w', 'e', ' ',
78 'g', 'o', ' ', 'a', 'g', 'a', 'i', 'n',
79 // pigweed.proto.nested_pigweed.magic_number
80 0x08, 0xe8, 0x04,
81 // pigweed.proto.nested_pigweed.device_info
82 0x32, 0x26,
83 // pigweed.proto.nested_pigweed.device_info.attributes[0]
84 0x22, 0x10,
85 // pigweed.proto.nested_pigweed.device_info.attributes[0].key
86 0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
87 // pigweed.proto.nested_pigweed.device_info.attributes[0].value
88 0x12, 0x05, '5', '.', '3', '.', '1',
89 // pigweed.proto.nested_pigweed.device_info.attributes[1]
90 0x22, 0x10,
91 // pigweed.proto.nested_pigweed.device_info.attributes[1].key
92 0x0a, 0x04, 'c', 'h', 'i', 'p',
93 // pigweed.proto.nested_pigweed.device_info.attributes[1].value
94 0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
95 // pigweed.proto.nested_pigweed.device_info.status
96 0x18, 0x03,
97 // pigweed.id[0]
98 0x52, 0x02,
99 // pigweed.id[0].id
100 0x08, 0x31,
101 // pigweed.id[1]
102 0x52, 0x02,
103 // pigweed.id[1].id
104 0x08, 0x39,
105 // pigweed.id[2]
106 0x52, 0x02,
107 // pigweed.id[2].id
108 0x08, 0x4b,
109 // pigweed.id[3]
110 0x52, 0x02,
111 // pigweed.id[3].id
112 0x08, 0x67,
113 // pigweed.id[4]
114 0x52, 0x03,
115 // pigweed.id[4].id
116 0x08, 0x8d, 0x01
117
Scott James Remnant354a6982022-03-03 16:45:48 -0800118 };
119 // clang-format on
120
121 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
122 Pigweed::StreamDecoder pigweed(reader);
123
124 EXPECT_EQ(pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700125 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::MAGIC_NUMBER);
Scott James Remnant001f9532022-03-04 17:51:54 -0800126 Result<uint32_t> magic_number = pigweed.ReadMagicNumber();
Scott James Remnant354a6982022-03-03 16:45:48 -0800127 EXPECT_EQ(magic_number.status(), OkStatus());
128 EXPECT_EQ(magic_number.value(), 0x49u);
129
130 EXPECT_EQ(pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700131 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ZIGGY);
Scott James Remnant001f9532022-03-04 17:51:54 -0800132 Result<int32_t> ziggy = pigweed.ReadZiggy();
133 EXPECT_EQ(ziggy.status(), OkStatus());
134 EXPECT_EQ(ziggy.value(), -111);
135
136 constexpr std::string_view kExpectedErrorMessage{"not a typewriter"};
137
138 EXPECT_EQ(pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700139 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
Scott James Remnant001f9532022-03-04 17:51:54 -0800140 std::array<char, 32> error_message{};
141 StatusWithSize error_message_status = pigweed.ReadErrorMessage(error_message);
142 EXPECT_EQ(error_message_status.status(), OkStatus());
143 EXPECT_EQ(error_message_status.size(), kExpectedErrorMessage.size());
144 EXPECT_EQ(std::memcmp(error_message.data(),
145 kExpectedErrorMessage.data(),
146 kExpectedErrorMessage.size()),
147 0);
148
149 EXPECT_EQ(pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700150 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::BIN);
Scott James Remnant001f9532022-03-04 17:51:54 -0800151 Result<Pigweed::Protobuf::Binary> bin = pigweed.ReadBin();
152 EXPECT_EQ(bin.status(), OkStatus());
153 EXPECT_EQ(bin.value(), Pigweed::Protobuf::Binary::ZERO);
154
155 EXPECT_EQ(pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700156 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::PIGWEED);
Scott James Remnant354a6982022-03-03 16:45:48 -0800157 {
158 Pigweed::Pigweed::StreamDecoder pigweed_pigweed =
159 pigweed.GetPigweedDecoder();
160
161 EXPECT_EQ(pigweed_pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700162 EXPECT_EQ(pigweed_pigweed.Field().value(),
163 Pigweed::Pigweed::Fields::STATUS);
Scott James Remnant001f9532022-03-04 17:51:54 -0800164 Result<Bool> pigweed_status = pigweed_pigweed.ReadStatus();
Scott James Remnant354a6982022-03-03 16:45:48 -0800165 EXPECT_EQ(pigweed_status.status(), OkStatus());
Scott James Remnant001f9532022-03-04 17:51:54 -0800166 EXPECT_EQ(pigweed_status.value(), Bool::FILE_NOT_FOUND);
Scott James Remnant354a6982022-03-03 16:45:48 -0800167
168 EXPECT_EQ(pigweed_pigweed.Next(), Status::OutOfRange());
169 }
170
Scott James Remnant001f9532022-03-04 17:51:54 -0800171 EXPECT_EQ(pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700172 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::PROTO);
Scott James Remnant001f9532022-03-04 17:51:54 -0800173 {
174 Proto::StreamDecoder proto = pigweed.GetProtoDecoder();
175
176 EXPECT_EQ(proto.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700177 EXPECT_EQ(proto.Field().value(), Proto::Fields::BIN);
Scott James Remnant001f9532022-03-04 17:51:54 -0800178 Result<Proto::Binary> proto_bin = proto.ReadBin();
179 EXPECT_EQ(proto_bin.status(), OkStatus());
180 EXPECT_EQ(proto_bin.value(), Proto::Binary::OFF);
181
182 EXPECT_EQ(proto.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700183 EXPECT_EQ(proto.Field().value(), Proto::Fields::PIGWEED_PIGWEED_BIN);
Scott James Remnant001f9532022-03-04 17:51:54 -0800184 Result<Pigweed::Pigweed::Binary> proto_pigweed_bin =
185 proto.ReadPigweedPigweedBin();
186 EXPECT_EQ(proto_pigweed_bin.status(), OkStatus());
187 EXPECT_EQ(proto_pigweed_bin.value(), Pigweed::Pigweed::Binary::ZERO);
188
189 EXPECT_EQ(proto.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700190 EXPECT_EQ(proto.Field().value(), Proto::Fields::PIGWEED_PROTOBUF_BIN);
Scott James Remnant001f9532022-03-04 17:51:54 -0800191 Result<Pigweed::Protobuf::Binary> proto_protobuf_bin =
192 proto.ReadPigweedProtobufBin();
193 EXPECT_EQ(proto_protobuf_bin.status(), OkStatus());
194 EXPECT_EQ(proto_protobuf_bin.value(), Pigweed::Protobuf::Binary::ZERO);
195
196 EXPECT_EQ(proto.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700197 EXPECT_EQ(proto.Field().value(), Proto::Fields::META);
Scott James Remnant001f9532022-03-04 17:51:54 -0800198 {
199 Pigweed::Protobuf::Compiler::StreamDecoder meta = proto.GetMetaDecoder();
200
201 constexpr std::string_view kExpectedFileName{"/etc/passwd"};
202
203 EXPECT_EQ(meta.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700204 EXPECT_EQ(meta.Field().value(),
205 Pigweed::Protobuf::Compiler::Fields::FILE_NAME);
Scott James Remnant001f9532022-03-04 17:51:54 -0800206 std::array<char, 32> meta_file_name{};
207 StatusWithSize meta_file_name_status = meta.ReadFileName(meta_file_name);
208 EXPECT_EQ(meta_file_name_status.status(), OkStatus());
209 EXPECT_EQ(meta_file_name_status.size(), kExpectedFileName.size());
210 EXPECT_EQ(std::memcmp(meta_file_name.data(),
211 kExpectedFileName.data(),
212 kExpectedFileName.size()),
213 0);
214
215 EXPECT_EQ(meta.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700216 EXPECT_EQ(meta.Field().value(),
217 Pigweed::Protobuf::Compiler::Fields::STATUS);
Scott James Remnant001f9532022-03-04 17:51:54 -0800218 Result<Pigweed::Protobuf::Compiler::Status> meta_status =
219 meta.ReadStatus();
220 EXPECT_EQ(meta_status.status(), OkStatus());
221 EXPECT_EQ(meta_status.value(),
222 Pigweed::Protobuf::Compiler::Status::FUBAR);
223
224 EXPECT_EQ(meta.Next(), Status::OutOfRange());
225 }
226
227 EXPECT_EQ(proto.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700228 EXPECT_EQ(proto.Field().value(), Proto::Fields::PIGWEED);
Scott James Remnant001f9532022-03-04 17:51:54 -0800229 {
230 Pigweed::StreamDecoder proto_pigweed = proto.GetPigweedDecoder();
231
232 constexpr std::string_view kExpectedProtoErrorMessage{"here we go again"};
233
234 EXPECT_EQ(proto_pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700235 EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
Scott James Remnant001f9532022-03-04 17:51:54 -0800236 std::array<char, 32> proto_pigweed_error_message{};
237 StatusWithSize proto_pigweed_error_message_status =
238 proto_pigweed.ReadErrorMessage(proto_pigweed_error_message);
239 EXPECT_EQ(proto_pigweed_error_message_status.status(), OkStatus());
240 EXPECT_EQ(proto_pigweed_error_message_status.size(),
241 kExpectedProtoErrorMessage.size());
242 EXPECT_EQ(std::memcmp(proto_pigweed_error_message.data(),
243 kExpectedProtoErrorMessage.data(),
244 kExpectedProtoErrorMessage.size()),
245 0);
246
247 EXPECT_EQ(proto_pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700248 EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::MAGIC_NUMBER);
Scott James Remnant001f9532022-03-04 17:51:54 -0800249 Result<uint32_t> proto_pigweed_magic_number =
250 proto_pigweed.ReadMagicNumber();
251 EXPECT_EQ(proto_pigweed_magic_number.status(), OkStatus());
252 EXPECT_EQ(proto_pigweed_magic_number.value(), 616u);
253
254 EXPECT_EQ(proto_pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700255 EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::DEVICE_INFO);
Scott James Remnant001f9532022-03-04 17:51:54 -0800256 {
257 DeviceInfo::StreamDecoder device_info =
258 proto_pigweed.GetDeviceInfoDecoder();
259
260 EXPECT_EQ(device_info.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700261 EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::ATTRIBUTES);
Scott James Remnant001f9532022-03-04 17:51:54 -0800262 {
263 KeyValuePair::StreamDecoder key_value_pair =
264 device_info.GetAttributesDecoder();
265
266 constexpr std::string_view kExpectedKey{"version"};
267 constexpr std::string_view kExpectedValue{"5.3.1"};
268
269 EXPECT_EQ(key_value_pair.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700270 EXPECT_EQ(key_value_pair.Field().value(), KeyValuePair::Fields::KEY);
Scott James Remnant001f9532022-03-04 17:51:54 -0800271 std::array<char, 32> key{};
272 StatusWithSize key_status = key_value_pair.ReadKey(key);
273 EXPECT_EQ(key_status.status(), OkStatus());
274 EXPECT_EQ(key_status.size(), kExpectedKey.size());
275 EXPECT_EQ(
276 std::memcmp(key.data(), kExpectedKey.data(), kExpectedKey.size()),
277 0);
278
279 EXPECT_EQ(key_value_pair.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700280 EXPECT_EQ(key_value_pair.Field().value(),
281 KeyValuePair::Fields::VALUE);
Scott James Remnant001f9532022-03-04 17:51:54 -0800282 std::array<char, 32> value{};
283 StatusWithSize value_status = key_value_pair.ReadValue(value);
284 EXPECT_EQ(value_status.status(), OkStatus());
285 EXPECT_EQ(value_status.size(), kExpectedValue.size());
286 EXPECT_EQ(
287 std::memcmp(
288 value.data(), kExpectedValue.data(), kExpectedValue.size()),
289 0);
290
291 EXPECT_EQ(key_value_pair.Next(), Status::OutOfRange());
292 }
293
294 EXPECT_EQ(device_info.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700295 EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::ATTRIBUTES);
Scott James Remnant001f9532022-03-04 17:51:54 -0800296 {
297 KeyValuePair::StreamDecoder key_value_pair =
298 device_info.GetAttributesDecoder();
299
300 constexpr std::string_view kExpectedKey{"chip"};
301 constexpr std::string_view kExpectedValue{"left-soc"};
302
303 EXPECT_EQ(key_value_pair.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700304 EXPECT_EQ(key_value_pair.Field().value(), KeyValuePair::Fields::KEY);
Scott James Remnant001f9532022-03-04 17:51:54 -0800305 std::array<char, 32> key{};
306 StatusWithSize key_status = key_value_pair.ReadKey(key);
307 EXPECT_EQ(key_status.status(), OkStatus());
308 EXPECT_EQ(key_status.size(), kExpectedKey.size());
309 EXPECT_EQ(
310 std::memcmp(key.data(), kExpectedKey.data(), kExpectedKey.size()),
311 0);
312
313 EXPECT_EQ(key_value_pair.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700314 EXPECT_EQ(key_value_pair.Field().value(),
315 KeyValuePair::Fields::VALUE);
Scott James Remnant001f9532022-03-04 17:51:54 -0800316 std::array<char, 32> value{};
317 StatusWithSize value_status = key_value_pair.ReadValue(value);
318 EXPECT_EQ(value_status.status(), OkStatus());
319 EXPECT_EQ(value_status.size(), kExpectedValue.size());
320 EXPECT_EQ(
321 std::memcmp(
322 value.data(), kExpectedValue.data(), kExpectedValue.size()),
323 0);
324
325 EXPECT_EQ(key_value_pair.Next(), Status::OutOfRange());
326 }
327
328 EXPECT_EQ(device_info.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700329 EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::STATUS);
Scott James Remnant001f9532022-03-04 17:51:54 -0800330 Result<DeviceInfo::DeviceStatus> device_info_status =
331 device_info.ReadStatus();
332 EXPECT_EQ(device_info_status.status(), OkStatus());
333 EXPECT_EQ(device_info_status.value(), DeviceInfo::DeviceStatus::PANIC);
334
335 EXPECT_EQ(device_info.Next(), Status::OutOfRange());
336 }
337
338 EXPECT_EQ(proto_pigweed.Next(), Status::OutOfRange());
339 }
340
341 EXPECT_EQ(proto.Next(), Status::OutOfRange());
342 }
343
344 for (int i = 0; i < 5; ++i) {
345 EXPECT_EQ(pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700346 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ID);
Scott James Remnant001f9532022-03-04 17:51:54 -0800347
348 Proto::ID::StreamDecoder id = pigweed.GetIdDecoder();
349
350 EXPECT_EQ(id.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700351 EXPECT_EQ(id.Field().value(), Proto::ID::Fields::ID);
Scott James Remnant001f9532022-03-04 17:51:54 -0800352 Result<uint32_t> id_id = id.ReadId();
353 EXPECT_EQ(id_id.status(), OkStatus());
354 EXPECT_EQ(id_id.value(), 5u * i * i + 3 * i + 49);
355
356 EXPECT_EQ(id.Next(), Status::OutOfRange());
357 }
358
359 EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
360}
361
362TEST(Codegen, ResourceExhausted) {
363 // clang-format off
364 constexpr uint8_t proto_data[] = {
365 // pigweed.error_message
366 0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
367 't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
368 };
369 // clang-format on
370
371 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
372 Pigweed::StreamDecoder pigweed(reader);
373
374 EXPECT_EQ(pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700375 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
Scott James Remnant001f9532022-03-04 17:51:54 -0800376 std::array<char, 8> error_message{};
377 StatusWithSize error_message_status = pigweed.ReadErrorMessage(error_message);
378 EXPECT_EQ(error_message_status.status(), Status::ResourceExhausted());
379 EXPECT_EQ(error_message_status.size(), 0u);
380
381 EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
382}
383
384TEST(Codegen, BytesReader) {
385 // clang-format off
386 constexpr uint8_t proto_data[] = {
387 // pigweed.error_message
388 0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
389 't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
390 };
391 // clang-format on
392
393 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
394 Pigweed::StreamDecoder pigweed(reader);
395
396 constexpr std::string_view kExpectedErrorMessage{"not a typewriter"};
397
398 EXPECT_EQ(pigweed.Next(), OkStatus());
Scott James Remnant7660d682022-03-16 19:27:57 -0700399 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
Scott James Remnant001f9532022-03-04 17:51:54 -0800400 {
401 StreamDecoder::BytesReader bytes_reader = pigweed.GetErrorMessageReader();
402 EXPECT_EQ(bytes_reader.field_size(), kExpectedErrorMessage.size());
403
404 std::array<std::byte, 32> error_message{};
405 Result<ByteSpan> result = bytes_reader.Read(error_message);
406 EXPECT_EQ(result.status(), OkStatus());
407 EXPECT_EQ(result.value().size(), kExpectedErrorMessage.size());
408 EXPECT_EQ(std::memcmp(result.value().data(),
409 kExpectedErrorMessage.data(),
410 kExpectedErrorMessage.size()),
411 0);
412
413 result = bytes_reader.Read(error_message);
414 EXPECT_EQ(result.status(), Status::OutOfRange());
415 }
416
Scott James Remnant354a6982022-03-03 16:45:48 -0800417 EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
418}
419
Scott James Remnant67506a12022-03-21 11:55:35 -0700420TEST(Codegen, Enum) {
421 // clang-format off
422 constexpr uint8_t proto_data[] = {
423 // pigweed.bin (value value)
424 0x40, 0x01,
425 // pigweed.bin (invalid value)
426 0x40, 0xff,
427 };
428 // clang-format on
429
430 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
431 Pigweed::StreamDecoder pigweed(reader);
432
433 EXPECT_EQ(pigweed.Next(), OkStatus());
434 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::BIN);
435 Result<Pigweed::Protobuf::Binary> bin = pigweed.ReadBin();
436 EXPECT_EQ(bin.status(), OkStatus());
437 EXPECT_EQ(bin.value(), Pigweed::Protobuf::Binary::ZERO);
438
439 EXPECT_EQ(pigweed.Next(), OkStatus());
440 EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::BIN);
441 bin = pigweed.ReadBin();
442 EXPECT_EQ(bin.status(), Status::DataLoss());
443}
444
445TEST(Codegen, ImportedEnum) {
446 // clang-format off
447 constexpr uint8_t proto_data[] = {
448 // result.status (value value)
449 0x08, 0x01,
450 // result.status (invalid value)
451 0x08, 0xff,
452 };
453 // clang-format on
454
455 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
456 TestResult::StreamDecoder test_result(reader);
457
458 EXPECT_EQ(test_result.Next(), OkStatus());
459 EXPECT_EQ(test_result.Field().value(), TestResult::Fields::STATUS);
460 Result<imported::Status> status = test_result.ReadStatus();
461 EXPECT_EQ(status.status(), OkStatus());
462 EXPECT_EQ(status.value(), imported::Status::NOT_OK);
463
464 EXPECT_EQ(test_result.Next(), OkStatus());
465 EXPECT_EQ(test_result.Field().value(), TestResult::Fields::STATUS);
466 status = test_result.ReadStatus();
467 EXPECT_EQ(status.status(), Status::DataLoss());
468}
469
Scott James Remnant55790d42022-03-08 11:58:00 -0800470TEST(CodegenRepeated, NonPackedScalar) {
471 // clang-format off
472 constexpr uint8_t proto_data[] = {
473 // uint32s[], v={0, 16, 32, 48}
474 0x08, 0x00,
475 0x08, 0x10,
476 0x08, 0x20,
477 0x08, 0x30,
478 // fixed32s[]. v={0, 16, 32, 48}
479 0x35, 0x00, 0x00, 0x00, 0x00,
480 0x35, 0x10, 0x00, 0x00, 0x00,
481 0x35, 0x20, 0x00, 0x00, 0x00,
482 0x35, 0x30, 0x00, 0x00, 0x00,
483 };
484 // clang-format on
485
486 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
487 RepeatedTest::StreamDecoder repeated_test(reader);
488
489 for (int i = 0; i < 4; ++i) {
490 EXPECT_EQ(repeated_test.Next(), OkStatus());
491 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
492
493 Result<uint32_t> result = repeated_test.ReadUint32s();
494 EXPECT_EQ(result.status(), OkStatus());
495 EXPECT_EQ(result.value(), i * 16u);
496 }
497
498 for (int i = 0; i < 4; ++i) {
499 EXPECT_EQ(repeated_test.Next(), OkStatus());
500 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
501
502 Result<uint32_t> result = repeated_test.ReadFixed32s();
503 EXPECT_EQ(result.status(), OkStatus());
504 EXPECT_EQ(result.value(), i * 16u);
505 }
506
507 EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
508}
509
Scott James Remnant75c76842022-03-17 16:51:33 -0700510TEST(CodegenRepeated, NonPackedScalarVector) {
511 // clang-format off
512 constexpr uint8_t proto_data[] = {
513 // uint32s[], v={0, 16, 32, 48}
514 0x08, 0x00,
515 0x08, 0x10,
516 0x08, 0x20,
517 0x08, 0x30,
518 // fixed32s[]. v={0, 16, 32, 48}
519 0x35, 0x00, 0x00, 0x00, 0x00,
520 0x35, 0x10, 0x00, 0x00, 0x00,
521 0x35, 0x20, 0x00, 0x00, 0x00,
522 0x35, 0x30, 0x00, 0x00, 0x00,
523 };
524 // clang-format on
525
526 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
527 RepeatedTest::StreamDecoder repeated_test(reader);
528
529 pw::Vector<uint32_t, 8> uint32s{};
530
531 for (int i = 0; i < 4; ++i) {
532 EXPECT_EQ(repeated_test.Next(), OkStatus());
533 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
534
535 Status status = repeated_test.ReadUint32s(uint32s);
536 EXPECT_EQ(status, OkStatus());
537 EXPECT_EQ(uint32s.size(), i + 1u);
538 }
539
540 for (int i = 0; i < 4; ++i) {
541 EXPECT_EQ(uint32s[i], i * 16u);
542 }
543
544 pw::Vector<uint32_t, 8> fixed32s{};
545
546 for (int i = 0; i < 4; ++i) {
547 EXPECT_EQ(repeated_test.Next(), OkStatus());
548 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
549
550 Status status = repeated_test.ReadFixed32s(fixed32s);
551 EXPECT_EQ(status, OkStatus());
552 EXPECT_EQ(fixed32s.size(), i + 1u);
553 }
554
555 for (int i = 0; i < 4; ++i) {
556 EXPECT_EQ(fixed32s[i], i * 16u);
557 }
558
559 EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
560}
561
562TEST(CodegenRepeated, NonPackedVarintScalarVectorFull) {
563 // clang-format off
564 constexpr uint8_t proto_data[] = {
565 // uint32s[], v={0, 16, 32, 48}
566 0x08, 0x00,
567 0x08, 0x10,
568 0x08, 0x20,
569 0x08, 0x30,
570 };
571 // clang-format on
572
573 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
574 RepeatedTest::StreamDecoder repeated_test(reader);
575
576 pw::Vector<uint32_t, 2> uint32s{};
577
578 EXPECT_EQ(repeated_test.Next(), OkStatus());
579 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
580 Status status = repeated_test.ReadUint32s(uint32s);
581 EXPECT_EQ(status, OkStatus());
582 EXPECT_EQ(uint32s.size(), 1u);
583
584 EXPECT_EQ(repeated_test.Next(), OkStatus());
585 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
586 status = repeated_test.ReadUint32s(uint32s);
587 EXPECT_EQ(status, OkStatus());
588 EXPECT_EQ(uint32s.size(), 2u);
589
590 EXPECT_EQ(repeated_test.Next(), OkStatus());
591 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
592 status = repeated_test.ReadUint32s(uint32s);
593 EXPECT_EQ(status, Status::ResourceExhausted());
594 EXPECT_EQ(uint32s.size(), 2u);
595
596 for (int i = 0; i < 2; ++i) {
597 EXPECT_EQ(uint32s[i], i * 16u);
598 }
599}
600
601TEST(CodegenRepeated, NonPackedFixedScalarVectorFull) {
602 // clang-format off
603 constexpr uint8_t proto_data[] = {
604 // fixed32s[]. v={0, 16, 32, 48}
605 0x35, 0x00, 0x00, 0x00, 0x00,
606 0x35, 0x10, 0x00, 0x00, 0x00,
607 0x35, 0x20, 0x00, 0x00, 0x00,
608 0x35, 0x30, 0x00, 0x00, 0x00,
609 };
610 // clang-format on
611
612 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
613 RepeatedTest::StreamDecoder repeated_test(reader);
614
615 pw::Vector<uint32_t, 2> fixed32s{};
616
617 EXPECT_EQ(repeated_test.Next(), OkStatus());
618 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
619 Status status = repeated_test.ReadFixed32s(fixed32s);
620 EXPECT_EQ(status, OkStatus());
621 EXPECT_EQ(fixed32s.size(), 1u);
622
623 EXPECT_EQ(repeated_test.Next(), OkStatus());
624 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
625 status = repeated_test.ReadFixed32s(fixed32s);
626 EXPECT_EQ(status, OkStatus());
627 EXPECT_EQ(fixed32s.size(), 2u);
628
629 EXPECT_EQ(repeated_test.Next(), OkStatus());
630 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
631 status = repeated_test.ReadFixed32s(fixed32s);
632 EXPECT_EQ(status, Status::ResourceExhausted());
633 EXPECT_EQ(fixed32s.size(), 2u);
634
635 for (int i = 0; i < 2; ++i) {
636 EXPECT_EQ(fixed32s[i], i * 16u);
637 }
638}
639
Scott James Remnant55790d42022-03-08 11:58:00 -0800640TEST(CodegenRepeated, PackedScalar) {
641 // clang-format off
642 constexpr uint8_t proto_data[] = {
643 // uint32s[], v={0, 16, 32, 48}
644 0x0a, 0x04,
645 0x00,
646 0x10,
647 0x20,
648 0x30,
649 // fixed32s[]. v={0, 16, 32, 48}
650 0x32, 0x10,
651 0x00, 0x00, 0x00, 0x00,
652 0x10, 0x00, 0x00, 0x00,
653 0x20, 0x00, 0x00, 0x00,
654 0x30, 0x00, 0x00, 0x00,
655 };
656 // clang-format on
657
658 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
659 RepeatedTest::StreamDecoder repeated_test(reader);
660
661 EXPECT_EQ(repeated_test.Next(), OkStatus());
662 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
663 std::array<uint32_t, 8> uint32s{};
664 StatusWithSize sws = repeated_test.ReadUint32s(uint32s);
665 EXPECT_EQ(sws.status(), OkStatus());
666 EXPECT_EQ(sws.size(), 4u);
667
668 for (int i = 0; i < 4; ++i) {
669 EXPECT_EQ(uint32s[i], i * 16u);
670 }
671
672 EXPECT_EQ(repeated_test.Next(), OkStatus());
673 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
674 std::array<uint32_t, 8> fixed32s{};
675 sws = repeated_test.ReadFixed32s(fixed32s);
676 EXPECT_EQ(sws.status(), OkStatus());
677 EXPECT_EQ(sws.size(), 4u);
678
679 for (int i = 0; i < 4; ++i) {
680 EXPECT_EQ(fixed32s[i], i * 16u);
681 }
682
683 EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
684}
685
686TEST(CodegenRepeated, PackedVarintScalarExhausted) {
687 // clang-format off
688 constexpr uint8_t proto_data[] = {
689 // uint32s[], v={0, 16, 32, 48}
690 0x0a, 0x04,
691 0x00,
692 0x10,
693 0x20,
694 0x30,
695 };
696 // clang-format on
697
698 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
699 RepeatedTest::StreamDecoder repeated_test(reader);
700
701 EXPECT_EQ(repeated_test.Next(), OkStatus());
702 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
703 std::array<uint32_t, 2> uint32s{};
704 StatusWithSize sws = repeated_test.ReadUint32s(uint32s);
705 EXPECT_EQ(sws.status(), Status::ResourceExhausted());
706 EXPECT_EQ(sws.size(), 2u);
707
708 for (int i = 0; i < 2; ++i) {
709 EXPECT_EQ(uint32s[i], i * 16u);
710 }
711}
712
713TEST(CodegenRepeated, PackedFixedScalarExhausted) {
714 // clang-format off
715 constexpr uint8_t proto_data[] = {
716 // fixed32s[]. v={0, 16, 32, 48}
717 0x32, 0x10,
718 0x00, 0x00, 0x00, 0x00,
719 0x10, 0x00, 0x00, 0x00,
720 0x20, 0x00, 0x00, 0x00,
721 0x30, 0x00, 0x00, 0x00,
722 };
723 // clang-format on
724
725 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
726 RepeatedTest::StreamDecoder repeated_test(reader);
727
728 EXPECT_EQ(repeated_test.Next(), OkStatus());
729 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
730 std::array<uint32_t, 2> fixed32s{};
731 StatusWithSize sws = repeated_test.ReadFixed32s(fixed32s);
732 EXPECT_EQ(sws.status(), Status::ResourceExhausted());
733 EXPECT_EQ(sws.size(), 0u);
734}
735
Scott James Remnant75c76842022-03-17 16:51:33 -0700736TEST(CodegenRepeated, PackedScalarVector) {
737 // clang-format off
738 constexpr uint8_t proto_data[] = {
739 // uint32s[], v={0, 16, 32, 48}
740 0x0a, 0x04,
741 0x00,
742 0x10,
743 0x20,
744 0x30,
745 // fixed32s[]. v={0, 16, 32, 48}
746 0x32, 0x10,
747 0x00, 0x00, 0x00, 0x00,
748 0x10, 0x00, 0x00, 0x00,
749 0x20, 0x00, 0x00, 0x00,
750 0x30, 0x00, 0x00, 0x00,
751 };
752 // clang-format on
753
754 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
755 RepeatedTest::StreamDecoder repeated_test(reader);
756
757 EXPECT_EQ(repeated_test.Next(), OkStatus());
758 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
759 pw::Vector<uint32_t, 8> uint32s{};
760 Status status = repeated_test.ReadUint32s(uint32s);
761 EXPECT_EQ(status, OkStatus());
762 EXPECT_EQ(uint32s.size(), 4u);
763
764 for (int i = 0; i < 4; ++i) {
765 EXPECT_EQ(uint32s[i], i * 16u);
766 }
767
768 EXPECT_EQ(repeated_test.Next(), OkStatus());
769 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
770 pw::Vector<uint32_t, 8> fixed32s{};
771 status = repeated_test.ReadFixed32s(fixed32s);
772 EXPECT_EQ(status, OkStatus());
773 EXPECT_EQ(fixed32s.size(), 4u);
774
775 for (int i = 0; i < 4; ++i) {
776 EXPECT_EQ(fixed32s[i], i * 16u);
777 }
778
779 EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
780}
781
782TEST(CodegenRepeated, PackedVarintScalarVectorFull) {
783 // clang-format off
784 constexpr uint8_t proto_data[] = {
785 // uint32s[], v={0, 16, 32, 48}
786 0x0a, 0x04,
787 0x00,
788 0x10,
789 0x20,
790 0x30,
791 };
792 // clang-format on
793
794 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
795 RepeatedTest::StreamDecoder repeated_test(reader);
796
797 EXPECT_EQ(repeated_test.Next(), OkStatus());
798 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
799 pw::Vector<uint32_t, 2> uint32s{};
800 Status status = repeated_test.ReadUint32s(uint32s);
801 EXPECT_EQ(status, Status::ResourceExhausted());
802 EXPECT_EQ(uint32s.size(), 2u);
803
804 for (int i = 0; i < 2; ++i) {
805 EXPECT_EQ(uint32s[i], i * 16u);
806 }
807}
808
809TEST(CodegenRepeated, PackedFixedScalarVectorFull) {
810 // clang-format off
811 constexpr uint8_t proto_data[] = {
812 // fixed32s[]. v={0, 16, 32, 48}
813 0x32, 0x10,
814 0x00, 0x00, 0x00, 0x00,
815 0x10, 0x00, 0x00, 0x00,
816 0x20, 0x00, 0x00, 0x00,
817 0x30, 0x00, 0x00, 0x00,
818 };
819 // clang-format on
820
821 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
822 RepeatedTest::StreamDecoder repeated_test(reader);
823
824 EXPECT_EQ(repeated_test.Next(), OkStatus());
825 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
826 pw::Vector<uint32_t, 2> fixed32s{};
827 Status status = repeated_test.ReadFixed32s(fixed32s);
828 EXPECT_EQ(status, Status::ResourceExhausted());
829 EXPECT_EQ(fixed32s.size(), 0u);
830}
831
832TEST(CodegenRepeated, PackedScalarVectorRepeated) {
833 // clang-format off
834 constexpr uint8_t proto_data[] = {
835 // uint32s[], v={0, 16, 32, 48}
836 0x0a, 0x04,
837 0x00,
838 0x10,
839 0x20,
840 0x30,
841 // uint32s[], v={64, 80, 96, 112}
842 0x0a, 0x04,
843 0x40,
844 0x50,
845 0x60,
846 0x70,
847 // fixed32s[]. v={0, 16, 32, 48}
848 0x32, 0x10,
849 0x00, 0x00, 0x00, 0x00,
850 0x10, 0x00, 0x00, 0x00,
851 0x20, 0x00, 0x00, 0x00,
852 0x30, 0x00, 0x00, 0x00,
853 // fixed32s[]. v={64, 80, 96, 112}
854 0x32, 0x10,
855 0x40, 0x00, 0x00, 0x00,
856 0x50, 0x00, 0x00, 0x00,
857 0x60, 0x00, 0x00, 0x00,
858 0x70, 0x00, 0x00, 0x00,
859 };
860 // clang-format on
861
862 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
863 RepeatedTest::StreamDecoder repeated_test(reader);
864
865 EXPECT_EQ(repeated_test.Next(), OkStatus());
866 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
867 pw::Vector<uint32_t, 8> uint32s{};
868 Status status = repeated_test.ReadUint32s(uint32s);
869 EXPECT_EQ(status, OkStatus());
870 EXPECT_EQ(uint32s.size(), 4u);
871
872 EXPECT_EQ(repeated_test.Next(), OkStatus());
873 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
874 status = repeated_test.ReadUint32s(uint32s);
875 EXPECT_EQ(status, OkStatus());
876 EXPECT_EQ(uint32s.size(), 8u);
877
878 for (int i = 0; i < 8; ++i) {
879 EXPECT_EQ(uint32s[i], i * 16u);
880 }
881
882 EXPECT_EQ(repeated_test.Next(), OkStatus());
883 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
884 pw::Vector<uint32_t, 8> fixed32s{};
885 status = repeated_test.ReadFixed32s(fixed32s);
886 EXPECT_EQ(status, OkStatus());
887 EXPECT_EQ(fixed32s.size(), 4u);
888
889 EXPECT_EQ(repeated_test.Next(), OkStatus());
890 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
891 status = repeated_test.ReadFixed32s(fixed32s);
892 EXPECT_EQ(status, OkStatus());
893 EXPECT_EQ(fixed32s.size(), 8u);
894
895 for (int i = 0; i < 8; ++i) {
896 EXPECT_EQ(fixed32s[i], i * 16u);
897 }
898
899 EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
900}
901
Scott James Remnant55790d42022-03-08 11:58:00 -0800902TEST(CodegenRepeated, NonScalar) {
903 // clang-format off
904 constexpr uint8_t proto_data[] = {
905 // strings[], v={"the", "quick", "brown", "fox"}
906 0x1a, 0x03, 't', 'h', 'e',
907 0x1a, 0x5, 'q', 'u', 'i', 'c', 'k',
908 0x1a, 0x5, 'b', 'r', 'o', 'w', 'n',
909 0x1a, 0x3, 'f', 'o', 'x'
910 };
911 // clang-format on
912
913 stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
914 RepeatedTest::StreamDecoder repeated_test(reader);
915
916 constexpr std::array<std::string_view, 4> kExpectedString{
917 {{"the"}, {"quick"}, {"brown"}, {"fox"}}};
918
919 for (int i = 0; i < 4; ++i) {
920 EXPECT_EQ(repeated_test.Next(), OkStatus());
921 EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::STRINGS);
922 std::array<char, 32> string{};
923 StatusWithSize sws = repeated_test.ReadStrings(string);
924 EXPECT_EQ(sws.status(), OkStatus());
925 EXPECT_EQ(sws.size(), kExpectedString[i].size());
926 EXPECT_EQ(std::memcmp(string.data(),
927 kExpectedString[i].data(),
928 kExpectedString[i].size()),
929 0);
930 }
931
932 EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
933}
934
Scott James Remnant354a6982022-03-03 16:45:48 -0800935} // namespace
936} // namespace pw::protobuf