937 lines
30 KiB
C++
937 lines
30 KiB
C++
// Copyright 2022 The Pigweed Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
#include <array>
|
|
#include <span>
|
|
#include <stdexcept>
|
|
#include <string_view>
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "pw_bytes/span.h"
|
|
#include "pw_containers/vector.h"
|
|
#include "pw_status/status.h"
|
|
#include "pw_status/status_with_size.h"
|
|
#include "pw_stream/memory_stream.h"
|
|
|
|
// These header files contain the code generated by the pw_protobuf plugin.
|
|
// They are re-generated every time the tests are built and are used by the
|
|
// tests to ensure that the interface remains consistent.
|
|
//
|
|
// The purpose of the tests in this file is primarily to verify that the
|
|
// generated C++ interface is valid rather than the correctness of the
|
|
// low-level encoder.
|
|
#include "pw_protobuf_test_protos/full_test.pwpb.h"
|
|
#include "pw_protobuf_test_protos/importer.pwpb.h"
|
|
#include "pw_protobuf_test_protos/non_pw_package.pwpb.h"
|
|
#include "pw_protobuf_test_protos/proto2.pwpb.h"
|
|
#include "pw_protobuf_test_protos/repeated.pwpb.h"
|
|
|
|
namespace pw::protobuf {
|
|
namespace {
|
|
|
|
using namespace pw::protobuf::test;
|
|
|
|
TEST(Codegen, StreamDecoder) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// pigweed.magic_number
|
|
0x08, 0x49,
|
|
// pigweed.ziggy
|
|
0x10, 0xdd, 0x01,
|
|
// pigweed.error_message
|
|
0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
|
|
't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
|
|
// pigweed.bin
|
|
0x40, 0x01,
|
|
// pigweed.pigweed
|
|
0x3a, 0x02,
|
|
// pigweed.pigweed.status
|
|
0x08, 0x02,
|
|
// pigweed.proto
|
|
0x4a, 0x56,
|
|
// pigweed.proto.bin
|
|
0x10, 0x00,
|
|
// pigweed.proto.pigweed_pigweed_bin
|
|
0x18, 0x00,
|
|
// pigweed.proto.pigweed_protobuf_bin
|
|
0x20, 0x01,
|
|
// pigweed.proto.meta
|
|
0x2a, 0x0f,
|
|
// pigweed.proto.meta.file_name
|
|
0x0a, 0x0b, '/', 'e', 't', 'c', '/', 'p', 'a', 's', 's', 'w', 'd',
|
|
// pigweed.proto.meta.status
|
|
0x10, 0x02,
|
|
// pigweed.proto.nested_pigweed
|
|
0x0a, 0x3d,
|
|
// pigweed.proto.nested_pigweed.error_message
|
|
0x2a, 0x10, 'h', 'e', 'r', 'e', ' ', 'w', 'e', ' ',
|
|
'g', 'o', ' ', 'a', 'g', 'a', 'i', 'n',
|
|
// pigweed.proto.nested_pigweed.magic_number
|
|
0x08, 0xe8, 0x04,
|
|
// pigweed.proto.nested_pigweed.device_info
|
|
0x32, 0x26,
|
|
// pigweed.proto.nested_pigweed.device_info.attributes[0]
|
|
0x22, 0x10,
|
|
// pigweed.proto.nested_pigweed.device_info.attributes[0].key
|
|
0x0a, 0x07, 'v', 'e', 'r', 's', 'i', 'o', 'n',
|
|
// pigweed.proto.nested_pigweed.device_info.attributes[0].value
|
|
0x12, 0x05, '5', '.', '3', '.', '1',
|
|
// pigweed.proto.nested_pigweed.device_info.attributes[1]
|
|
0x22, 0x10,
|
|
// pigweed.proto.nested_pigweed.device_info.attributes[1].key
|
|
0x0a, 0x04, 'c', 'h', 'i', 'p',
|
|
// pigweed.proto.nested_pigweed.device_info.attributes[1].value
|
|
0x12, 0x08, 'l', 'e', 'f', 't', '-', 's', 'o', 'c',
|
|
// pigweed.proto.nested_pigweed.device_info.status
|
|
0x18, 0x03,
|
|
// pigweed.id[0]
|
|
0x52, 0x02,
|
|
// pigweed.id[0].id
|
|
0x08, 0x31,
|
|
// pigweed.id[1]
|
|
0x52, 0x02,
|
|
// pigweed.id[1].id
|
|
0x08, 0x39,
|
|
// pigweed.id[2]
|
|
0x52, 0x02,
|
|
// pigweed.id[2].id
|
|
0x08, 0x4b,
|
|
// pigweed.id[3]
|
|
0x52, 0x02,
|
|
// pigweed.id[3].id
|
|
0x08, 0x67,
|
|
// pigweed.id[4]
|
|
0x52, 0x03,
|
|
// pigweed.id[4].id
|
|
0x08, 0x8d, 0x01
|
|
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
Pigweed::StreamDecoder pigweed(reader);
|
|
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::MAGIC_NUMBER);
|
|
Result<uint32_t> magic_number = pigweed.ReadMagicNumber();
|
|
EXPECT_EQ(magic_number.status(), OkStatus());
|
|
EXPECT_EQ(magic_number.value(), 0x49u);
|
|
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ZIGGY);
|
|
Result<int32_t> ziggy = pigweed.ReadZiggy();
|
|
EXPECT_EQ(ziggy.status(), OkStatus());
|
|
EXPECT_EQ(ziggy.value(), -111);
|
|
|
|
constexpr std::string_view kExpectedErrorMessage{"not a typewriter"};
|
|
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
|
|
std::array<char, 32> error_message{};
|
|
StatusWithSize error_message_status = pigweed.ReadErrorMessage(error_message);
|
|
EXPECT_EQ(error_message_status.status(), OkStatus());
|
|
EXPECT_EQ(error_message_status.size(), kExpectedErrorMessage.size());
|
|
EXPECT_EQ(std::memcmp(error_message.data(),
|
|
kExpectedErrorMessage.data(),
|
|
kExpectedErrorMessage.size()),
|
|
0);
|
|
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::BIN);
|
|
Result<Pigweed::Protobuf::Binary> bin = pigweed.ReadBin();
|
|
EXPECT_EQ(bin.status(), OkStatus());
|
|
EXPECT_EQ(bin.value(), Pigweed::Protobuf::Binary::ZERO);
|
|
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::PIGWEED);
|
|
{
|
|
Pigweed::Pigweed::StreamDecoder pigweed_pigweed =
|
|
pigweed.GetPigweedDecoder();
|
|
|
|
EXPECT_EQ(pigweed_pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed_pigweed.Field().value(),
|
|
Pigweed::Pigweed::Fields::STATUS);
|
|
Result<Bool> pigweed_status = pigweed_pigweed.ReadStatus();
|
|
EXPECT_EQ(pigweed_status.status(), OkStatus());
|
|
EXPECT_EQ(pigweed_status.value(), Bool::FILE_NOT_FOUND);
|
|
|
|
EXPECT_EQ(pigweed_pigweed.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::PROTO);
|
|
{
|
|
Proto::StreamDecoder proto = pigweed.GetProtoDecoder();
|
|
|
|
EXPECT_EQ(proto.Next(), OkStatus());
|
|
EXPECT_EQ(proto.Field().value(), Proto::Fields::BIN);
|
|
Result<Proto::Binary> proto_bin = proto.ReadBin();
|
|
EXPECT_EQ(proto_bin.status(), OkStatus());
|
|
EXPECT_EQ(proto_bin.value(), Proto::Binary::OFF);
|
|
|
|
EXPECT_EQ(proto.Next(), OkStatus());
|
|
EXPECT_EQ(proto.Field().value(), Proto::Fields::PIGWEED_PIGWEED_BIN);
|
|
Result<Pigweed::Pigweed::Binary> proto_pigweed_bin =
|
|
proto.ReadPigweedPigweedBin();
|
|
EXPECT_EQ(proto_pigweed_bin.status(), OkStatus());
|
|
EXPECT_EQ(proto_pigweed_bin.value(), Pigweed::Pigweed::Binary::ZERO);
|
|
|
|
EXPECT_EQ(proto.Next(), OkStatus());
|
|
EXPECT_EQ(proto.Field().value(), Proto::Fields::PIGWEED_PROTOBUF_BIN);
|
|
Result<Pigweed::Protobuf::Binary> proto_protobuf_bin =
|
|
proto.ReadPigweedProtobufBin();
|
|
EXPECT_EQ(proto_protobuf_bin.status(), OkStatus());
|
|
EXPECT_EQ(proto_protobuf_bin.value(), Pigweed::Protobuf::Binary::ZERO);
|
|
|
|
EXPECT_EQ(proto.Next(), OkStatus());
|
|
EXPECT_EQ(proto.Field().value(), Proto::Fields::META);
|
|
{
|
|
Pigweed::Protobuf::Compiler::StreamDecoder meta = proto.GetMetaDecoder();
|
|
|
|
constexpr std::string_view kExpectedFileName{"/etc/passwd"};
|
|
|
|
EXPECT_EQ(meta.Next(), OkStatus());
|
|
EXPECT_EQ(meta.Field().value(),
|
|
Pigweed::Protobuf::Compiler::Fields::FILE_NAME);
|
|
std::array<char, 32> meta_file_name{};
|
|
StatusWithSize meta_file_name_status = meta.ReadFileName(meta_file_name);
|
|
EXPECT_EQ(meta_file_name_status.status(), OkStatus());
|
|
EXPECT_EQ(meta_file_name_status.size(), kExpectedFileName.size());
|
|
EXPECT_EQ(std::memcmp(meta_file_name.data(),
|
|
kExpectedFileName.data(),
|
|
kExpectedFileName.size()),
|
|
0);
|
|
|
|
EXPECT_EQ(meta.Next(), OkStatus());
|
|
EXPECT_EQ(meta.Field().value(),
|
|
Pigweed::Protobuf::Compiler::Fields::STATUS);
|
|
Result<Pigweed::Protobuf::Compiler::Status> meta_status =
|
|
meta.ReadStatus();
|
|
EXPECT_EQ(meta_status.status(), OkStatus());
|
|
EXPECT_EQ(meta_status.value(),
|
|
Pigweed::Protobuf::Compiler::Status::FUBAR);
|
|
|
|
EXPECT_EQ(meta.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
EXPECT_EQ(proto.Next(), OkStatus());
|
|
EXPECT_EQ(proto.Field().value(), Proto::Fields::PIGWEED);
|
|
{
|
|
Pigweed::StreamDecoder proto_pigweed = proto.GetPigweedDecoder();
|
|
|
|
constexpr std::string_view kExpectedProtoErrorMessage{"here we go again"};
|
|
|
|
EXPECT_EQ(proto_pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
|
|
std::array<char, 32> proto_pigweed_error_message{};
|
|
StatusWithSize proto_pigweed_error_message_status =
|
|
proto_pigweed.ReadErrorMessage(proto_pigweed_error_message);
|
|
EXPECT_EQ(proto_pigweed_error_message_status.status(), OkStatus());
|
|
EXPECT_EQ(proto_pigweed_error_message_status.size(),
|
|
kExpectedProtoErrorMessage.size());
|
|
EXPECT_EQ(std::memcmp(proto_pigweed_error_message.data(),
|
|
kExpectedProtoErrorMessage.data(),
|
|
kExpectedProtoErrorMessage.size()),
|
|
0);
|
|
|
|
EXPECT_EQ(proto_pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::MAGIC_NUMBER);
|
|
Result<uint32_t> proto_pigweed_magic_number =
|
|
proto_pigweed.ReadMagicNumber();
|
|
EXPECT_EQ(proto_pigweed_magic_number.status(), OkStatus());
|
|
EXPECT_EQ(proto_pigweed_magic_number.value(), 616u);
|
|
|
|
EXPECT_EQ(proto_pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(proto_pigweed.Field().value(), Pigweed::Fields::DEVICE_INFO);
|
|
{
|
|
DeviceInfo::StreamDecoder device_info =
|
|
proto_pigweed.GetDeviceInfoDecoder();
|
|
|
|
EXPECT_EQ(device_info.Next(), OkStatus());
|
|
EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::ATTRIBUTES);
|
|
{
|
|
KeyValuePair::StreamDecoder key_value_pair =
|
|
device_info.GetAttributesDecoder();
|
|
|
|
constexpr std::string_view kExpectedKey{"version"};
|
|
constexpr std::string_view kExpectedValue{"5.3.1"};
|
|
|
|
EXPECT_EQ(key_value_pair.Next(), OkStatus());
|
|
EXPECT_EQ(key_value_pair.Field().value(), KeyValuePair::Fields::KEY);
|
|
std::array<char, 32> key{};
|
|
StatusWithSize key_status = key_value_pair.ReadKey(key);
|
|
EXPECT_EQ(key_status.status(), OkStatus());
|
|
EXPECT_EQ(key_status.size(), kExpectedKey.size());
|
|
EXPECT_EQ(
|
|
std::memcmp(key.data(), kExpectedKey.data(), kExpectedKey.size()),
|
|
0);
|
|
|
|
EXPECT_EQ(key_value_pair.Next(), OkStatus());
|
|
EXPECT_EQ(key_value_pair.Field().value(),
|
|
KeyValuePair::Fields::VALUE);
|
|
std::array<char, 32> value{};
|
|
StatusWithSize value_status = key_value_pair.ReadValue(value);
|
|
EXPECT_EQ(value_status.status(), OkStatus());
|
|
EXPECT_EQ(value_status.size(), kExpectedValue.size());
|
|
EXPECT_EQ(
|
|
std::memcmp(
|
|
value.data(), kExpectedValue.data(), kExpectedValue.size()),
|
|
0);
|
|
|
|
EXPECT_EQ(key_value_pair.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
EXPECT_EQ(device_info.Next(), OkStatus());
|
|
EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::ATTRIBUTES);
|
|
{
|
|
KeyValuePair::StreamDecoder key_value_pair =
|
|
device_info.GetAttributesDecoder();
|
|
|
|
constexpr std::string_view kExpectedKey{"chip"};
|
|
constexpr std::string_view kExpectedValue{"left-soc"};
|
|
|
|
EXPECT_EQ(key_value_pair.Next(), OkStatus());
|
|
EXPECT_EQ(key_value_pair.Field().value(), KeyValuePair::Fields::KEY);
|
|
std::array<char, 32> key{};
|
|
StatusWithSize key_status = key_value_pair.ReadKey(key);
|
|
EXPECT_EQ(key_status.status(), OkStatus());
|
|
EXPECT_EQ(key_status.size(), kExpectedKey.size());
|
|
EXPECT_EQ(
|
|
std::memcmp(key.data(), kExpectedKey.data(), kExpectedKey.size()),
|
|
0);
|
|
|
|
EXPECT_EQ(key_value_pair.Next(), OkStatus());
|
|
EXPECT_EQ(key_value_pair.Field().value(),
|
|
KeyValuePair::Fields::VALUE);
|
|
std::array<char, 32> value{};
|
|
StatusWithSize value_status = key_value_pair.ReadValue(value);
|
|
EXPECT_EQ(value_status.status(), OkStatus());
|
|
EXPECT_EQ(value_status.size(), kExpectedValue.size());
|
|
EXPECT_EQ(
|
|
std::memcmp(
|
|
value.data(), kExpectedValue.data(), kExpectedValue.size()),
|
|
0);
|
|
|
|
EXPECT_EQ(key_value_pair.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
EXPECT_EQ(device_info.Next(), OkStatus());
|
|
EXPECT_EQ(device_info.Field().value(), DeviceInfo::Fields::STATUS);
|
|
Result<DeviceInfo::DeviceStatus> device_info_status =
|
|
device_info.ReadStatus();
|
|
EXPECT_EQ(device_info_status.status(), OkStatus());
|
|
EXPECT_EQ(device_info_status.value(), DeviceInfo::DeviceStatus::PANIC);
|
|
|
|
EXPECT_EQ(device_info.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
EXPECT_EQ(proto_pigweed.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
EXPECT_EQ(proto.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ID);
|
|
|
|
Proto::ID::StreamDecoder id = pigweed.GetIdDecoder();
|
|
|
|
EXPECT_EQ(id.Next(), OkStatus());
|
|
EXPECT_EQ(id.Field().value(), Proto::ID::Fields::ID);
|
|
Result<uint32_t> id_id = id.ReadId();
|
|
EXPECT_EQ(id_id.status(), OkStatus());
|
|
EXPECT_EQ(id_id.value(), 5u * i * i + 3 * i + 49);
|
|
|
|
EXPECT_EQ(id.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
TEST(Codegen, ResourceExhausted) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// pigweed.error_message
|
|
0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
|
|
't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
Pigweed::StreamDecoder pigweed(reader);
|
|
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
|
|
std::array<char, 8> error_message{};
|
|
StatusWithSize error_message_status = pigweed.ReadErrorMessage(error_message);
|
|
EXPECT_EQ(error_message_status.status(), Status::ResourceExhausted());
|
|
EXPECT_EQ(error_message_status.size(), 0u);
|
|
|
|
EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
TEST(Codegen, BytesReader) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// pigweed.error_message
|
|
0x2a, 0x10, 'n', 'o', 't', ' ', 'a', ' ',
|
|
't', 'y', 'p', 'e', 'w', 'r', 'i', 't', 'e', 'r',
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
Pigweed::StreamDecoder pigweed(reader);
|
|
|
|
constexpr std::string_view kExpectedErrorMessage{"not a typewriter"};
|
|
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::ERROR_MESSAGE);
|
|
{
|
|
StreamDecoder::BytesReader bytes_reader = pigweed.GetErrorMessageReader();
|
|
EXPECT_EQ(bytes_reader.field_size(), kExpectedErrorMessage.size());
|
|
|
|
std::array<std::byte, 32> error_message{};
|
|
Result<ByteSpan> result = bytes_reader.Read(error_message);
|
|
EXPECT_EQ(result.status(), OkStatus());
|
|
EXPECT_EQ(result.value().size(), kExpectedErrorMessage.size());
|
|
EXPECT_EQ(std::memcmp(result.value().data(),
|
|
kExpectedErrorMessage.data(),
|
|
kExpectedErrorMessage.size()),
|
|
0);
|
|
|
|
result = bytes_reader.Read(error_message);
|
|
EXPECT_EQ(result.status(), Status::OutOfRange());
|
|
}
|
|
|
|
EXPECT_EQ(pigweed.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
TEST(Codegen, Enum) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// pigweed.bin (value value)
|
|
0x40, 0x01,
|
|
// pigweed.bin (invalid value)
|
|
0x40, 0xff,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
Pigweed::StreamDecoder pigweed(reader);
|
|
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::BIN);
|
|
Result<Pigweed::Protobuf::Binary> bin = pigweed.ReadBin();
|
|
EXPECT_EQ(bin.status(), OkStatus());
|
|
EXPECT_EQ(bin.value(), Pigweed::Protobuf::Binary::ZERO);
|
|
|
|
EXPECT_EQ(pigweed.Next(), OkStatus());
|
|
EXPECT_EQ(pigweed.Field().value(), Pigweed::Fields::BIN);
|
|
bin = pigweed.ReadBin();
|
|
EXPECT_EQ(bin.status(), Status::DataLoss());
|
|
}
|
|
|
|
TEST(Codegen, ImportedEnum) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// result.status (value value)
|
|
0x08, 0x01,
|
|
// result.status (invalid value)
|
|
0x08, 0xff,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
TestResult::StreamDecoder test_result(reader);
|
|
|
|
EXPECT_EQ(test_result.Next(), OkStatus());
|
|
EXPECT_EQ(test_result.Field().value(), TestResult::Fields::STATUS);
|
|
Result<imported::Status> status = test_result.ReadStatus();
|
|
EXPECT_EQ(status.status(), OkStatus());
|
|
EXPECT_EQ(status.value(), imported::Status::NOT_OK);
|
|
|
|
EXPECT_EQ(test_result.Next(), OkStatus());
|
|
EXPECT_EQ(test_result.Field().value(), TestResult::Fields::STATUS);
|
|
status = test_result.ReadStatus();
|
|
EXPECT_EQ(status.status(), Status::DataLoss());
|
|
}
|
|
|
|
TEST(CodegenRepeated, NonPackedScalar) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// uint32s[], v={0, 16, 32, 48}
|
|
0x08, 0x00,
|
|
0x08, 0x10,
|
|
0x08, 0x20,
|
|
0x08, 0x30,
|
|
// fixed32s[]. v={0, 16, 32, 48}
|
|
0x35, 0x00, 0x00, 0x00, 0x00,
|
|
0x35, 0x10, 0x00, 0x00, 0x00,
|
|
0x35, 0x20, 0x00, 0x00, 0x00,
|
|
0x35, 0x30, 0x00, 0x00, 0x00,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
|
|
Result<uint32_t> result = repeated_test.ReadUint32s();
|
|
EXPECT_EQ(result.status(), OkStatus());
|
|
EXPECT_EQ(result.value(), i * 16u);
|
|
}
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
|
|
Result<uint32_t> result = repeated_test.ReadFixed32s();
|
|
EXPECT_EQ(result.status(), OkStatus());
|
|
EXPECT_EQ(result.value(), i * 16u);
|
|
}
|
|
|
|
EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
TEST(CodegenRepeated, NonPackedScalarVector) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// uint32s[], v={0, 16, 32, 48}
|
|
0x08, 0x00,
|
|
0x08, 0x10,
|
|
0x08, 0x20,
|
|
0x08, 0x30,
|
|
// fixed32s[]. v={0, 16, 32, 48}
|
|
0x35, 0x00, 0x00, 0x00, 0x00,
|
|
0x35, 0x10, 0x00, 0x00, 0x00,
|
|
0x35, 0x20, 0x00, 0x00, 0x00,
|
|
0x35, 0x30, 0x00, 0x00, 0x00,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
pw::Vector<uint32_t, 8> uint32s{};
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
|
|
Status status = repeated_test.ReadUint32s(uint32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(uint32s.size(), i + 1u);
|
|
}
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(uint32s[i], i * 16u);
|
|
}
|
|
|
|
pw::Vector<uint32_t, 8> fixed32s{};
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
|
|
Status status = repeated_test.ReadFixed32s(fixed32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(fixed32s.size(), i + 1u);
|
|
}
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(fixed32s[i], i * 16u);
|
|
}
|
|
|
|
EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
TEST(CodegenRepeated, NonPackedVarintScalarVectorFull) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// uint32s[], v={0, 16, 32, 48}
|
|
0x08, 0x00,
|
|
0x08, 0x10,
|
|
0x08, 0x20,
|
|
0x08, 0x30,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
pw::Vector<uint32_t, 2> uint32s{};
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
Status status = repeated_test.ReadUint32s(uint32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(uint32s.size(), 1u);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
status = repeated_test.ReadUint32s(uint32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(uint32s.size(), 2u);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
status = repeated_test.ReadUint32s(uint32s);
|
|
EXPECT_EQ(status, Status::ResourceExhausted());
|
|
EXPECT_EQ(uint32s.size(), 2u);
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
EXPECT_EQ(uint32s[i], i * 16u);
|
|
}
|
|
}
|
|
|
|
TEST(CodegenRepeated, NonPackedFixedScalarVectorFull) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// fixed32s[]. v={0, 16, 32, 48}
|
|
0x35, 0x00, 0x00, 0x00, 0x00,
|
|
0x35, 0x10, 0x00, 0x00, 0x00,
|
|
0x35, 0x20, 0x00, 0x00, 0x00,
|
|
0x35, 0x30, 0x00, 0x00, 0x00,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
pw::Vector<uint32_t, 2> fixed32s{};
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
Status status = repeated_test.ReadFixed32s(fixed32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(fixed32s.size(), 1u);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
status = repeated_test.ReadFixed32s(fixed32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(fixed32s.size(), 2u);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
status = repeated_test.ReadFixed32s(fixed32s);
|
|
EXPECT_EQ(status, Status::ResourceExhausted());
|
|
EXPECT_EQ(fixed32s.size(), 2u);
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
EXPECT_EQ(fixed32s[i], i * 16u);
|
|
}
|
|
}
|
|
|
|
TEST(CodegenRepeated, PackedScalar) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// uint32s[], v={0, 16, 32, 48}
|
|
0x0a, 0x04,
|
|
0x00,
|
|
0x10,
|
|
0x20,
|
|
0x30,
|
|
// fixed32s[]. v={0, 16, 32, 48}
|
|
0x32, 0x10,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x10, 0x00, 0x00, 0x00,
|
|
0x20, 0x00, 0x00, 0x00,
|
|
0x30, 0x00, 0x00, 0x00,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
std::array<uint32_t, 8> uint32s{};
|
|
StatusWithSize sws = repeated_test.ReadUint32s(uint32s);
|
|
EXPECT_EQ(sws.status(), OkStatus());
|
|
EXPECT_EQ(sws.size(), 4u);
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(uint32s[i], i * 16u);
|
|
}
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
std::array<uint32_t, 8> fixed32s{};
|
|
sws = repeated_test.ReadFixed32s(fixed32s);
|
|
EXPECT_EQ(sws.status(), OkStatus());
|
|
EXPECT_EQ(sws.size(), 4u);
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(fixed32s[i], i * 16u);
|
|
}
|
|
|
|
EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
TEST(CodegenRepeated, PackedVarintScalarExhausted) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// uint32s[], v={0, 16, 32, 48}
|
|
0x0a, 0x04,
|
|
0x00,
|
|
0x10,
|
|
0x20,
|
|
0x30,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
std::array<uint32_t, 2> uint32s{};
|
|
StatusWithSize sws = repeated_test.ReadUint32s(uint32s);
|
|
EXPECT_EQ(sws.status(), Status::ResourceExhausted());
|
|
EXPECT_EQ(sws.size(), 2u);
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
EXPECT_EQ(uint32s[i], i * 16u);
|
|
}
|
|
}
|
|
|
|
TEST(CodegenRepeated, PackedFixedScalarExhausted) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// fixed32s[]. v={0, 16, 32, 48}
|
|
0x32, 0x10,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x10, 0x00, 0x00, 0x00,
|
|
0x20, 0x00, 0x00, 0x00,
|
|
0x30, 0x00, 0x00, 0x00,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
std::array<uint32_t, 2> fixed32s{};
|
|
StatusWithSize sws = repeated_test.ReadFixed32s(fixed32s);
|
|
EXPECT_EQ(sws.status(), Status::ResourceExhausted());
|
|
EXPECT_EQ(sws.size(), 0u);
|
|
}
|
|
|
|
TEST(CodegenRepeated, PackedScalarVector) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// uint32s[], v={0, 16, 32, 48}
|
|
0x0a, 0x04,
|
|
0x00,
|
|
0x10,
|
|
0x20,
|
|
0x30,
|
|
// fixed32s[]. v={0, 16, 32, 48}
|
|
0x32, 0x10,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x10, 0x00, 0x00, 0x00,
|
|
0x20, 0x00, 0x00, 0x00,
|
|
0x30, 0x00, 0x00, 0x00,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
pw::Vector<uint32_t, 8> uint32s{};
|
|
Status status = repeated_test.ReadUint32s(uint32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(uint32s.size(), 4u);
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(uint32s[i], i * 16u);
|
|
}
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
pw::Vector<uint32_t, 8> fixed32s{};
|
|
status = repeated_test.ReadFixed32s(fixed32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(fixed32s.size(), 4u);
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(fixed32s[i], i * 16u);
|
|
}
|
|
|
|
EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
TEST(CodegenRepeated, PackedVarintScalarVectorFull) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// uint32s[], v={0, 16, 32, 48}
|
|
0x0a, 0x04,
|
|
0x00,
|
|
0x10,
|
|
0x20,
|
|
0x30,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
pw::Vector<uint32_t, 2> uint32s{};
|
|
Status status = repeated_test.ReadUint32s(uint32s);
|
|
EXPECT_EQ(status, Status::ResourceExhausted());
|
|
EXPECT_EQ(uint32s.size(), 2u);
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
EXPECT_EQ(uint32s[i], i * 16u);
|
|
}
|
|
}
|
|
|
|
TEST(CodegenRepeated, PackedFixedScalarVectorFull) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// fixed32s[]. v={0, 16, 32, 48}
|
|
0x32, 0x10,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x10, 0x00, 0x00, 0x00,
|
|
0x20, 0x00, 0x00, 0x00,
|
|
0x30, 0x00, 0x00, 0x00,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
pw::Vector<uint32_t, 2> fixed32s{};
|
|
Status status = repeated_test.ReadFixed32s(fixed32s);
|
|
EXPECT_EQ(status, Status::ResourceExhausted());
|
|
EXPECT_EQ(fixed32s.size(), 0u);
|
|
}
|
|
|
|
TEST(CodegenRepeated, PackedScalarVectorRepeated) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// uint32s[], v={0, 16, 32, 48}
|
|
0x0a, 0x04,
|
|
0x00,
|
|
0x10,
|
|
0x20,
|
|
0x30,
|
|
// uint32s[], v={64, 80, 96, 112}
|
|
0x0a, 0x04,
|
|
0x40,
|
|
0x50,
|
|
0x60,
|
|
0x70,
|
|
// fixed32s[]. v={0, 16, 32, 48}
|
|
0x32, 0x10,
|
|
0x00, 0x00, 0x00, 0x00,
|
|
0x10, 0x00, 0x00, 0x00,
|
|
0x20, 0x00, 0x00, 0x00,
|
|
0x30, 0x00, 0x00, 0x00,
|
|
// fixed32s[]. v={64, 80, 96, 112}
|
|
0x32, 0x10,
|
|
0x40, 0x00, 0x00, 0x00,
|
|
0x50, 0x00, 0x00, 0x00,
|
|
0x60, 0x00, 0x00, 0x00,
|
|
0x70, 0x00, 0x00, 0x00,
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
pw::Vector<uint32_t, 8> uint32s{};
|
|
Status status = repeated_test.ReadUint32s(uint32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(uint32s.size(), 4u);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::UINT32S);
|
|
status = repeated_test.ReadUint32s(uint32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(uint32s.size(), 8u);
|
|
|
|
for (int i = 0; i < 8; ++i) {
|
|
EXPECT_EQ(uint32s[i], i * 16u);
|
|
}
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
pw::Vector<uint32_t, 8> fixed32s{};
|
|
status = repeated_test.ReadFixed32s(fixed32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(fixed32s.size(), 4u);
|
|
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::FIXED32S);
|
|
status = repeated_test.ReadFixed32s(fixed32s);
|
|
EXPECT_EQ(status, OkStatus());
|
|
EXPECT_EQ(fixed32s.size(), 8u);
|
|
|
|
for (int i = 0; i < 8; ++i) {
|
|
EXPECT_EQ(fixed32s[i], i * 16u);
|
|
}
|
|
|
|
EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
TEST(CodegenRepeated, NonScalar) {
|
|
// clang-format off
|
|
constexpr uint8_t proto_data[] = {
|
|
// strings[], v={"the", "quick", "brown", "fox"}
|
|
0x1a, 0x03, 't', 'h', 'e',
|
|
0x1a, 0x5, 'q', 'u', 'i', 'c', 'k',
|
|
0x1a, 0x5, 'b', 'r', 'o', 'w', 'n',
|
|
0x1a, 0x3, 'f', 'o', 'x'
|
|
};
|
|
// clang-format on
|
|
|
|
stream::MemoryReader reader(std::as_bytes(std::span(proto_data)));
|
|
RepeatedTest::StreamDecoder repeated_test(reader);
|
|
|
|
constexpr std::array<std::string_view, 4> kExpectedString{
|
|
{{"the"}, {"quick"}, {"brown"}, {"fox"}}};
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
EXPECT_EQ(repeated_test.Next(), OkStatus());
|
|
EXPECT_EQ(repeated_test.Field().value(), RepeatedTest::Fields::STRINGS);
|
|
std::array<char, 32> string{};
|
|
StatusWithSize sws = repeated_test.ReadStrings(string);
|
|
EXPECT_EQ(sws.status(), OkStatus());
|
|
EXPECT_EQ(sws.size(), kExpectedString[i].size());
|
|
EXPECT_EQ(std::memcmp(string.data(),
|
|
kExpectedString[i].data(),
|
|
kExpectedString[i].size()),
|
|
0);
|
|
}
|
|
|
|
EXPECT_EQ(repeated_test.Next(), Status::OutOfRange());
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace pw::protobuf
|