blob: 1779716bcd1a8200dbcaebfcd6ca8bf475957c00 [file]
// Copyright 2026 Google LLC
//
// 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 <memory>
#include <utility>
#include "absl/status/status.h"
#include "absl/status/status_macros.h" // IWYU pragma: keep
#include "absl/status/status_matchers.h"
#include "cbor/cbor.h"
#include "cbor/options.h"
#include "cbor/test/external.pb.h"
#include "cbor/test/migrated.cbor.h" // IWYU pragma: keep
#include "cbor/test/test.cbor.h"
#include "cbor/test/test.pb.h"
#include "cppbor/cppbor.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace cbor_test {
namespace {
using ::testing::Eq;
TEST(CborGeneratorTest, RoundTrip) {
TestMessage msg;
msg.set_name("hello");
msg.set_version(1);
// Serialize to CBOR map
auto map_or = cbor::FromProto(msg);
ABSL_ASSERT_OK(map_or);
auto map = std::move(map_or.value());
ASSERT_NE(map, nullptr);
// Deserialize from CBOR map
TestMessage parsed_msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &parsed_msg);
ABSL_ASSERT_OK(status);
EXPECT_EQ(parsed_msg.name(), "hello");
EXPECT_EQ(parsed_msg.version(), 1);
}
TEST(CborGeneratorTest, ComplexRoundTrip) {
ComplexMessage msg;
msg.set_int32_field(10);
msg.set_int64_field(20);
msg.set_uint32_field(30);
msg.set_uint64_field(40);
msg.set_string_field("test_string");
msg.set_bytes_field("test_bytes");
msg.set_bool_field(true);
msg.set_float_field(1.5f);
msg.set_double_field(2.5);
msg.add_repeated_int32(100);
msg.add_repeated_int32(200);
msg.add_repeated_string("item1");
msg.add_repeated_string("item2");
msg.mutable_nested()->set_value("nested_val");
msg.add_repeated_nested()->set_value("rn1");
msg.add_repeated_nested()->set_value("rn2");
msg.add_repeated_bytes("b1");
msg.add_repeated_bytes("b2");
msg.add_repeated_string_array("s1");
msg.add_repeated_string_array("s2");
msg.add_repeated_int64(2000000000L);
msg.add_repeated_int64(3000000000L);
msg.add_repeated_uint32(300);
msg.add_repeated_uint32(400);
msg.add_repeated_uint64(4000000000L);
msg.add_repeated_uint64(5000000000L);
msg.add_repeated_bool(true);
msg.add_repeated_bool(false);
msg.add_repeated_float(1.5f);
msg.add_repeated_float(2.5f);
msg.add_repeated_double(3.5);
msg.add_repeated_double(4.5);
msg.set_read_only_field("ro");
msg.set_write_only_field("wo");
msg.set_skip_field("skip");
msg.mutable_external_field()->set_external_value("ext_val");
// Serialize to CBOR map
auto map_or = cbor::FromProto(msg);
ABSL_ASSERT_OK(map_or);
auto map = std::move(map_or.value());
ASSERT_NE(map, nullptr);
// Deserialize from CBOR map
ComplexMessage parsed_msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &parsed_msg);
ABSL_ASSERT_OK(status);
EXPECT_EQ(parsed_msg.int32_field(), 10);
EXPECT_EQ(parsed_msg.int64_field(), 20);
EXPECT_EQ(parsed_msg.uint32_field(), 30);
EXPECT_EQ(parsed_msg.uint64_field(), 40);
EXPECT_EQ(parsed_msg.string_field(), "test_string");
EXPECT_EQ(parsed_msg.bytes_field(), "test_bytes");
EXPECT_EQ(parsed_msg.bool_field(), true);
EXPECT_FLOAT_EQ(parsed_msg.float_field(), 1.5f);
EXPECT_DOUBLE_EQ(parsed_msg.double_field(), 2.5);
ASSERT_EQ(parsed_msg.repeated_int32_size(), 2);
EXPECT_EQ(parsed_msg.repeated_int32(0), 100);
EXPECT_EQ(parsed_msg.repeated_int32(1), 200);
ASSERT_EQ(parsed_msg.repeated_string_size(), 2);
EXPECT_EQ(parsed_msg.repeated_string(0), "item1");
EXPECT_EQ(parsed_msg.repeated_string(1), "item2");
EXPECT_EQ(parsed_msg.nested().value(), "nested_val");
ASSERT_EQ(parsed_msg.repeated_nested_size(), 2);
EXPECT_EQ(parsed_msg.repeated_nested(0).value(), "rn1");
EXPECT_EQ(parsed_msg.repeated_nested(1).value(), "rn2");
ASSERT_EQ(parsed_msg.repeated_bytes_size(), 2);
EXPECT_EQ(parsed_msg.repeated_bytes(0), "b1");
EXPECT_EQ(parsed_msg.repeated_bytes(1), "b2");
ASSERT_EQ(parsed_msg.repeated_string_array_size(), 2);
EXPECT_EQ(parsed_msg.repeated_string_array(0), "s1");
EXPECT_EQ(parsed_msg.repeated_string_array(1), "s2");
ASSERT_EQ(parsed_msg.repeated_int64_size(), 2);
EXPECT_EQ(parsed_msg.repeated_int64(0), 2000000000L);
EXPECT_EQ(parsed_msg.repeated_int64(1), 3000000000L);
ASSERT_EQ(parsed_msg.repeated_uint32_size(), 2);
EXPECT_EQ(parsed_msg.repeated_uint32(0), 300);
EXPECT_EQ(parsed_msg.repeated_uint32(1), 400);
ASSERT_EQ(parsed_msg.repeated_uint64_size(), 2);
EXPECT_EQ(parsed_msg.repeated_uint64(0), 4000000000L);
EXPECT_EQ(parsed_msg.repeated_uint64(1), 5000000000L);
ASSERT_EQ(parsed_msg.repeated_bool_size(), 2);
EXPECT_EQ(parsed_msg.repeated_bool(0), true);
EXPECT_EQ(parsed_msg.repeated_bool(1), false);
ASSERT_EQ(parsed_msg.repeated_float_size(), 2);
EXPECT_FLOAT_EQ(parsed_msg.repeated_float(0), 1.5f);
EXPECT_FLOAT_EQ(parsed_msg.repeated_float(1), 2.5f);
ASSERT_EQ(parsed_msg.repeated_double_size(), 2);
EXPECT_DOUBLE_EQ(parsed_msg.repeated_double(0), 3.5);
EXPECT_DOUBLE_EQ(parsed_msg.repeated_double(1), 4.5);
EXPECT_EQ(parsed_msg.read_only_field(), "");
EXPECT_EQ(parsed_msg.write_only_field(), "");
EXPECT_EQ(parsed_msg.skip_field(), "");
EXPECT_EQ(parsed_msg.external_field().external_value(), "ext_val");
}
TEST(CborGeneratorTest, RequiredFieldMissing) {
auto map = std::make_unique<cppbor::Map>();
RequiredMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
EXPECT_THAT(status.code(), Eq(absl::StatusCode::kInvalidArgument));
}
TEST(CborGeneratorTest, RequiredFieldPresent) {
auto map = std::make_unique<cppbor::Map>();
map->add("RequiredField", cppbor::Tstr("value"));
RequiredMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
ABSL_EXPECT_OK(status);
EXPECT_EQ(msg.required_field(), "value");
}
TEST(CborGeneratorTest, RequiredRepeatedFieldEmpty) {
RequiredRepeatedMessage msg;
auto map_or = cbor::FromProto(msg);
ABSL_ASSERT_OK(map_or);
auto map = std::move(map_or.value());
ASSERT_NE(map, nullptr);
cbor::MapView map_view(map.get());
auto array_view = map_view.GetOptionalArray("RequiredRepeatedField");
ASSERT_TRUE(array_view.has_value());
EXPECT_EQ(array_view->size(), 0);
}
TEST(CborGeneratorTest, RequiredDisallowEmptyPresent) {
auto map = std::make_unique<cppbor::Map>();
auto array = std::make_unique<cppbor::Array>();
array->add(cppbor::Tstr("item"));
map->add("RequiredNonEmptyList", std::move(array));
RequiredDisallowEmptyMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
ABSL_EXPECT_OK(status);
ASSERT_EQ(msg.required_non_empty_list_size(), 1);
EXPECT_EQ(msg.required_non_empty_list(0), "item");
}
TEST(CborGeneratorTest, RequiredDisallowEmptyEmpty) {
auto map = std::make_unique<cppbor::Map>();
auto array = std::make_unique<cppbor::Array>();
map->add("RequiredNonEmptyList", std::move(array));
RequiredDisallowEmptyMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
EXPECT_THAT(status.code(), Eq(absl::StatusCode::kInvalidArgument));
}
TEST(CborGeneratorTest, RequiredDisallowEmptyMissing) {
auto map = std::make_unique<cppbor::Map>();
RequiredDisallowEmptyMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
EXPECT_THAT(status.code(), Eq(absl::StatusCode::kInvalidArgument));
}
TEST(CborGeneratorTest, OptionalDisallowEmptyPresent) {
auto map = std::make_unique<cppbor::Map>();
auto array = std::make_unique<cppbor::Array>();
array->add(cppbor::Tstr("item"));
map->add("OptionalNonEmptyList", std::move(array));
OptionalDisallowEmptyMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
ABSL_EXPECT_OK(status);
ASSERT_EQ(msg.optional_non_empty_list_size(), 1);
EXPECT_EQ(msg.optional_non_empty_list(0), "item");
}
TEST(CborGeneratorTest, OptionalDisallowEmptyEmpty) {
auto map = std::make_unique<cppbor::Map>();
auto array = std::make_unique<cppbor::Array>();
map->add("OptionalNonEmptyList", std::move(array));
OptionalDisallowEmptyMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
EXPECT_THAT(status.code(), Eq(absl::StatusCode::kInvalidArgument));
}
TEST(CborGeneratorTest, OptionalDisallowEmptyMissing) {
auto map = std::make_unique<cppbor::Map>();
OptionalDisallowEmptyMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
ABSL_EXPECT_OK(status);
// Proto2 does not distinguish between empty and missing, so this is 0.
EXPECT_EQ(msg.optional_non_empty_list_size(), 0);
}
TEST(CborGeneratorTest, TypeOverrideTextString) {
auto map = std::make_unique<cppbor::Map>();
map->add("TextAsBytes", cppbor::Tstr("text_value"));
TypeOverrideMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
ABSL_EXPECT_OK(status);
EXPECT_EQ(msg.text_as_bytes(), "text_value");
}
TEST(CborGeneratorTest, TypeOverrideByteString) {
auto map = std::make_unique<cppbor::Map>();
map->add("BytesAsText", cppbor::Bstr("byte_value"));
TypeOverrideMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
ABSL_EXPECT_OK(status);
EXPECT_EQ(msg.bytes_as_text(), "byte_value");
}
TEST(CborGeneratorTest, TypeOverrideUint) {
auto map = std::make_unique<cppbor::Map>();
map->add("UintAsInt", cppbor::Uint(42));
TypeOverrideMessage msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &msg);
ABSL_EXPECT_OK(status);
EXPECT_EQ(msg.uint_as_int(), 42);
}
TEST(CborGeneratorTest, SkipValidationMissingRequired) {
RequiredMessage msg;
cbor::FromProtoOptions options;
options.skip_validation = true;
auto map_or = cbor::FromProto(msg, options);
ABSL_EXPECT_OK(map_or);
}
TEST(CborGeneratorTest, SkipValidationEmptyRequiredDisallowEmpty) {
RequiredDisallowEmptyMessage msg;
cbor::FromProtoOptions options;
options.skip_validation = true;
auto map_or = cbor::FromProto(msg, options);
ABSL_EXPECT_OK(map_or);
}
TEST(CborGeneratorTest, SkipValidationEmptyOptionalDisallowEmpty) {
// Proto2 does not distinguish between empty and missing, so an empty list in
// the proto should be considered "not present" when converting to cbor.
OptionalDisallowEmptyMessage msg;
cbor::FromProtoOptions options;
options.skip_validation = true;
auto map_or = cbor::FromProto(msg, options);
ABSL_ASSERT_OK(map_or);
auto map = std::move(map_or.value());
cbor::MapView map_view(map.get());
EXPECT_FALSE(map_view.GetOptionalArray("OptionalNonEmptyList").has_value());
}
TEST(CborGeneratorTest, FromProtoMissingRequired) {
RequiredMessage msg;
auto map_or = cbor::FromProto(msg);
EXPECT_FALSE(map_or.ok());
EXPECT_EQ(map_or.status().code(), absl::StatusCode::kInvalidArgument);
}
TEST(CborGeneratorTest, FromProtoEmptyRequiredDisallowEmpty) {
RequiredDisallowEmptyMessage msg;
auto map_or = cbor::FromProto(msg);
EXPECT_FALSE(map_or.ok());
EXPECT_EQ(map_or.status().code(), absl::StatusCode::kInvalidArgument);
}
TEST(CborGeneratorTest, FromProtoEmptyOptionalDisallowEmpty) {
OptionalDisallowEmptyMessage msg;
auto map_or = cbor::FromProto(msg);
ABSL_ASSERT_OK(map_or);
auto map = std::move(map_or.value());
cbor::MapView map_view(map.get());
EXPECT_FALSE(map_view.GetOptionalArray("OptionalNonEmptyList").has_value());
}
TEST(CborGeneratorTest, FromProtoNonEmptyOptionalDisallowEmpty) {
OptionalDisallowEmptyMessage msg;
msg.add_optional_non_empty_list("item");
auto map_or = cbor::FromProto(msg);
ABSL_ASSERT_OK(map_or);
auto map = std::move(map_or.value());
cbor::MapView map_view(map.get());
auto list_opt = map_view.GetOptionalArray("OptionalNonEmptyList");
ASSERT_TRUE(list_opt.has_value());
EXPECT_EQ(list_opt->size(), 1);
auto first_item_or = list_opt->GetString(0);
ABSL_ASSERT_OK(first_item_or);
EXPECT_EQ(first_item_or.value(), "item");
}
TEST(CborGeneratorTest, ImportedPublicRoundTrip) {
ImportedPublicMessage msg;
msg.set_public_value("imported_val");
auto map_or = cbor::FromProto(msg);
ABSL_ASSERT_OK(map_or);
auto map = std::move(map_or.value());
ASSERT_NE(map, nullptr);
ImportedPublicMessage parsed_msg;
cbor::MapView map_view(map.get());
auto status = cbor::ToProto(map_view, &parsed_msg);
ABSL_ASSERT_OK(status);
EXPECT_EQ(parsed_msg.public_value(), "imported_val");
}
} // namespace
} // namespace cbor_test