blob: c1d5164e72ec22ee20efac52cc14afb4f6d94182 [file] [log] [blame]
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "hpb/extension.h"
#include <cstdint>
#include <type_traits>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/status/status_matchers.h"
#include "absl/strings/string_view.h"
#include "hpb_generator/tests/child_model.hpb.h"
#include "hpb_generator/tests/test_extension.hpb.h"
#include "hpb_generator/tests/test_model.hpb.h"
#include "hpb/arena.h"
#include "hpb/backend/upb/interop.h"
#include "hpb/hpb.h"
#include "hpb/options.h"
#include "hpb/requires.h"
#include "hpb/status.h"
#include "upb/mem/arena.h"
namespace {
using ::hpb::internal::Requires;
using ::hpb_unittest::protos::container_ext;
using ::hpb_unittest::protos::ContainerExtension;
using ::hpb_unittest::protos::TestModel;
using ::hpb_unittest::protos::theme;
using ::hpb_unittest::protos::ThemeExtension;
using ::hpb_unittest::someotherpackage::protos::bool_ext;
using ::hpb_unittest::someotherpackage::protos::double_ext;
using ::hpb_unittest::someotherpackage::protos::float_ext;
using ::hpb_unittest::someotherpackage::protos::int32_ext;
using ::hpb_unittest::someotherpackage::protos::int64_ext;
using ::hpb_unittest::someotherpackage::protos::repeated_int32_ext;
using ::hpb_unittest::someotherpackage::protos::repeated_int64_ext;
using ::hpb_unittest::someotherpackage::protos::repeated_string_ext;
using ::hpb_unittest::someotherpackage::protos::string_escape_ext;
using ::hpb_unittest::someotherpackage::protos::string_ext;
using ::hpb_unittest::someotherpackage::protos::uint32_ext;
using ::hpb_unittest::someotherpackage::protos::uint64_ext;
using absl_testing::IsOkAndHolds;
TEST(CppGeneratedCode, HasExtension) {
TestModel model;
EXPECT_EQ(false, ::hpb::HasExtension(&model, theme));
}
TEST(CppGeneratedCode, HasExtensionPtr) {
TestModel model;
EXPECT_EQ(false, ::hpb::HasExtension(model.recursive_child(), theme));
}
TEST(CppGeneratedCode, ClearExtensionWithEmptyExtension) {
TestModel model;
EXPECT_EQ(false, ::hpb::HasExtension(&model, theme));
::hpb::ClearExtension(&model, theme);
EXPECT_EQ(false, ::hpb::HasExtension(&model, theme));
}
TEST(CppGeneratedCode, ClearExtensionWithEmptyExtensionPtr) {
TestModel model;
::hpb::Ptr<TestModel> recursive_child = model.mutable_recursive_child();
::hpb::ClearExtension(recursive_child, theme);
EXPECT_EQ(false, ::hpb::HasExtension(recursive_child, theme));
}
TEST(CppGeneratedCode, GetSetExtensionInt32) {
TestModel model;
EXPECT_EQ(false, hpb::HasExtension(&model, int32_ext));
int32_t val = 55;
auto x = hpb::SetExtension(&model, int32_ext, val);
EXPECT_EQ(true, hpb::HasExtension(&model, int32_ext));
EXPECT_THAT(hpb::GetExtension(&model, int32_ext), IsOkAndHolds(val));
}
TEST(CppGeneratedCode, GetSetExtensionInt64) {
TestModel model;
EXPECT_EQ(false, hpb::HasExtension(&model, int64_ext));
int64_t val = std::numeric_limits<int32_t>::max() + int64_t{1};
auto x = hpb::SetExtension(&model, int64_ext, val);
EXPECT_EQ(true, hpb::HasExtension(&model, int64_ext));
EXPECT_THAT(hpb::GetExtension(&model, int64_ext), IsOkAndHolds(val));
}
TEST(CppGeneratedCode, GetSetExtensionUInt32) {
TestModel model;
EXPECT_EQ(false, hpb::HasExtension(&model, uint32_ext));
uint32_t val = std::numeric_limits<int32_t>::max() + uint32_t{5};
auto x = hpb::SetExtension(&model, uint32_ext, val);
EXPECT_EQ(true, hpb::HasExtension(&model, uint32_ext));
EXPECT_THAT(hpb::GetExtension(&model, uint32_ext), IsOkAndHolds(val));
}
TEST(CppGeneratedCode, GetSetExtensionUInt64) {
TestModel model;
EXPECT_EQ(false, hpb::HasExtension(&model, uint64_ext));
uint64_t val = std::numeric_limits<int64_t>::max() + uint64_t{5};
auto x = hpb::SetExtension(&model, uint64_ext, val);
EXPECT_EQ(true, hpb::HasExtension(&model, uint64_ext));
EXPECT_THAT(hpb::GetExtension(&model, uint64_ext), IsOkAndHolds(val));
}
TEST(CppGeneratedCode, GetSetExtensionFloat) {
TestModel model;
EXPECT_EQ(false, hpb::HasExtension(&model, float_ext));
float val = 2.78;
auto x = hpb::SetExtension(&model, float_ext, val);
EXPECT_EQ(true, hpb::HasExtension(&model, float_ext));
EXPECT_THAT(hpb::GetExtension(&model, float_ext), IsOkAndHolds(val));
}
TEST(CppGeneratedCode, GetSetExtensionDouble) {
TestModel model;
EXPECT_EQ(false, hpb::HasExtension(&model, double_ext));
double val = std::numeric_limits<float>::max() + 1.23;
auto x = hpb::SetExtension(&model, double_ext, val);
EXPECT_EQ(true, hpb::HasExtension(&model, double_ext));
EXPECT_THAT(hpb::GetExtension(&model, double_ext), IsOkAndHolds(val));
}
TEST(CppGeneratedCode, GetSetExtensionBool) {
TestModel model;
EXPECT_EQ(false, hpb::HasExtension(&model, bool_ext));
auto x = hpb::SetExtension(&model, bool_ext, true);
EXPECT_EQ(true, hpb::HasExtension(&model, bool_ext));
EXPECT_THAT(hpb::GetExtension(&model, bool_ext), IsOkAndHolds(true));
}
TEST(CppGeneratedCode, GetSetExtensionString) {
TestModel model;
EXPECT_EQ(false, hpb::HasExtension(&model, string_ext));
absl::string_view val = "Hello World";
auto x = hpb::SetExtension(&model, string_ext, val);
EXPECT_EQ(true, hpb::HasExtension(&model, string_ext));
EXPECT_THAT(hpb::GetExtension(&model, string_ext), IsOkAndHolds(val));
}
TEST(CppGeneratedCode, SetExtension) {
TestModel model;
void* prior_message;
{
// Use a nested scope to make sure the arenas are fused correctly.
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
prior_message = hpb::interop::upb::GetMessage(&extension1);
EXPECT_EQ(false, ::hpb::HasExtension(&model, theme));
EXPECT_EQ(true,
::hpb::SetExtension(&model, theme, std::move(extension1)).ok());
}
EXPECT_EQ(true, ::hpb::HasExtension(&model, theme));
auto ext = hpb::GetExtension(&model, theme);
EXPECT_TRUE(ext.ok());
EXPECT_EQ(hpb::interop::upb::GetMessage(*ext), prior_message);
}
TEST(CppGeneratedCode, SetExtensionWithPtr) {
::hpb::Arena arena_model;
::hpb::Ptr<TestModel> model = ::hpb::CreateMessage<TestModel>(arena_model);
void* prior_message;
{
// Use a nested scope to make sure the arenas are fused correctly.
::hpb::Arena arena;
::hpb::Ptr<ThemeExtension> extension1 =
::hpb::CreateMessage<ThemeExtension>(arena);
extension1->set_ext_name("Hello World");
prior_message = hpb::interop::upb::GetMessage(extension1);
EXPECT_EQ(false, ::hpb::HasExtension(model, theme));
auto res = ::hpb::SetExtension(model, theme, extension1);
EXPECT_EQ(true, res.ok());
}
EXPECT_EQ(true, ::hpb::HasExtension(model, theme));
auto ext = hpb::GetExtension(model, theme);
EXPECT_TRUE(ext.ok());
EXPECT_NE(hpb::interop::upb::GetMessage(*ext), prior_message);
}
#ifndef _MSC_VER
TEST(CppGeneratedCode, SetExtensionShouldNotCompileForWrongType) {
::hpb::Arena arena;
::hpb::Ptr<TestModel> model = ::hpb::CreateMessage<TestModel>(arena);
ThemeExtension extension1;
ContainerExtension extension2;
const auto canSetExtension = [&](auto l) {
return Requires<decltype(model)>(l);
};
EXPECT_TRUE(canSetExtension(
[](auto p) -> decltype(::hpb::SetExtension(p, theme, extension1)) {}));
// Wrong extension value type should fail to compile.
EXPECT_TRUE(!canSetExtension(
[](auto p) -> decltype(::hpb::SetExtension(p, theme, extension2)) {}));
// Wrong extension id with correct extension type should fail to compile.
EXPECT_TRUE(
!canSetExtension([](auto p) -> decltype(::hpb::SetExtension(
p, container_ext, extension1)) {}));
}
#endif
TEST(CppGeneratedCode, SetExtensionWithPtrSameArena) {
::hpb::Arena arena;
::hpb::Ptr<TestModel> model = ::hpb::CreateMessage<TestModel>(arena);
void* prior_message;
{
// Use a nested scope to make sure the arenas are fused correctly.
::hpb::Ptr<ThemeExtension> extension1 =
::hpb::CreateMessage<ThemeExtension>(arena);
extension1->set_ext_name("Hello World");
prior_message = hpb::interop::upb::GetMessage(extension1);
EXPECT_EQ(false, ::hpb::HasExtension(model, theme));
auto res = ::hpb::SetExtension(model, theme, extension1);
EXPECT_EQ(true, res.ok());
}
EXPECT_EQ(true, ::hpb::HasExtension(model, theme));
auto ext = hpb::GetExtension(model, theme);
EXPECT_TRUE(ext.ok());
EXPECT_NE(hpb::interop::upb::GetMessage(*ext), prior_message);
}
TEST(CppGeneratedCode, SetExtensionFusingFailureShouldCopy) {
// Use an initial block to disallow fusing.
char initial_block[1000];
hpb::Arena arena(initial_block, sizeof(initial_block));
hpb::Ptr<TestModel> model = ::hpb::CreateMessage<TestModel>(arena);
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
ASSERT_FALSE(upb_Arena_Fuse(hpb::interop::upb::UnwrapArena(arena),
hpb::interop::upb::GetArena(&extension1)));
EXPECT_FALSE(::hpb::HasExtension(model, theme));
auto status = ::hpb::SetExtension(model, theme, std::move(extension1));
EXPECT_TRUE(status.ok());
EXPECT_TRUE(::hpb::HasExtension(model, theme));
EXPECT_TRUE(hpb::GetExtension(model, theme).ok());
}
TEST(CppGeneratedCode, SetExtensionShouldClone) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(false, ::hpb::HasExtension(&model, theme));
EXPECT_EQ(true, ::hpb::SetExtension(&model, theme, extension1).ok());
extension1.set_ext_name("Goodbye");
EXPECT_EQ(true, ::hpb::HasExtension(&model, theme));
auto ext = hpb::GetExtension(&model, theme);
EXPECT_TRUE(ext.ok());
EXPECT_EQ((*ext)->ext_name(), "Hello World");
}
TEST(CppGeneratedCode, SetExtensionShouldCloneConst) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(false, ::hpb::HasExtension(&model, theme));
EXPECT_EQ(true,
::hpb::SetExtension(&model, theme, std::as_const(extension1)).ok());
extension1.set_ext_name("Goodbye");
EXPECT_EQ(true, ::hpb::HasExtension(&model, theme));
auto ext = hpb::GetExtension(&model, theme);
EXPECT_TRUE(ext.ok());
EXPECT_EQ((*ext)->ext_name(), "Hello World");
}
TEST(CppGeneratedCode, SetExtensionOnMutableChild) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(false, ::hpb::HasExtension(model.mutable_recursive_child(), theme));
EXPECT_EQ(true, ::hpb::SetExtension(model.mutable_recursive_child(), theme,
extension1)
.ok());
EXPECT_EQ(true, ::hpb::HasExtension(model.mutable_recursive_child(), theme));
}
TEST(CppGeneratedCode, SetAliasExtensionOnMutableChild) {
hpb::Arena arena;
hpb::Ptr<TestModel> model = hpb::CreateMessage<TestModel>(arena);
hpb::Ptr<ThemeExtension> extension1 =
hpb::CreateMessage<ThemeExtension>(arena);
extension1->set_ext_name("Hello World");
EXPECT_EQ(false,
::hpb::HasExtension(model->mutable_recursive_child(), theme));
::hpb::SetAliasExtension(model->mutable_recursive_child(), theme, extension1);
EXPECT_EQ(true, ::hpb::HasExtension(model->mutable_recursive_child(), theme));
}
TEST(CppGeneratedCode, SetAliasExtensionOnTwoParents) {
hpb::Arena arena;
hpb::Ptr<TestModel> model1 = hpb::CreateMessage<TestModel>(arena);
hpb::Ptr<TestModel> model2 = hpb::CreateMessage<TestModel>(arena);
hpb::Ptr<ThemeExtension> extension1 =
hpb::CreateMessage<ThemeExtension>(arena);
extension1->set_ext_name("Hello World");
::hpb::SetAliasExtension(model1->mutable_recursive_child(), theme,
extension1);
::hpb::SetAliasExtension(model2->mutable_recursive_child(), theme,
extension1);
extension1->set_ext_name("Goodbye");
EXPECT_EQ("Goodbye",
hpb::GetExtension(model1->mutable_recursive_child(), theme)
.value()
->ext_name());
EXPECT_EQ("Goodbye",
hpb::GetExtension(model2->mutable_recursive_child(), theme)
.value()
->ext_name());
}
#ifndef NDEBUG
TEST(CppGeneratedCode, SetAliasExtensionOnDifferentArenaShouldCrash) {
hpb::Arena arena1;
hpb::Arena arena2;
hpb::Ptr<TestModel> model = hpb::CreateMessage<TestModel>(arena1);
hpb::Ptr<ThemeExtension> extension1 =
hpb::CreateMessage<ThemeExtension>(arena2);
extension1->set_ext_name("Hello World");
EXPECT_DEATH(::hpb::SetAliasExtension(model->mutable_recursive_child(), theme,
extension1),
"");
}
#endif // NDEBUG
TEST(CppGeneratedCode, GetExtension) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(false, ::hpb::HasExtension(&model, theme));
EXPECT_EQ(true, ::hpb::SetExtension(&model, theme, extension1).ok());
EXPECT_EQ("Hello World",
hpb::GetExtension(&model, theme).value()->ext_name());
}
TEST(CppGeneratedCode, GetExtensionInt32WithDefault) {
TestModel model;
auto res = hpb::GetExtension(&model, int32_ext);
EXPECT_TRUE(res.ok());
EXPECT_EQ(*res, 644);
}
TEST(CppGeneratedCode, GetExtensionInt64WithDefault) {
TestModel model;
auto res = hpb::GetExtension(&model, int64_ext);
EXPECT_TRUE(res.ok());
int64_t expected = std::numeric_limits<int32_t>::max() + int64_t{1};
EXPECT_EQ(*res, expected);
}
TEST(CppGeneratedCode, GetExtensionUInt32WithDefault) {
TestModel model;
auto res = hpb::GetExtension(&model, uint32_ext);
EXPECT_THAT(res, IsOkAndHolds(12));
}
TEST(CppGeneratedCode, GetExtensionUInt64WithDefault) {
TestModel model;
auto res = hpb::GetExtension(&model, uint64_ext);
EXPECT_THAT(res, IsOkAndHolds(4294967296));
}
TEST(CppGeneratedCode, GetExtensionFloatWithDefault) {
TestModel model;
auto res = hpb::GetExtension(&model, float_ext);
static_assert(std::is_same_v<decltype(res), absl::StatusOr<float>>);
EXPECT_THAT(res, IsOkAndHolds(3.14f));
}
TEST(CppGeneratedCode, GetExtensionDoubleWithDefault) {
TestModel model;
auto res = hpb::GetExtension(&model, double_ext);
static_assert(std::is_same_v<decltype(res), absl::StatusOr<double>>);
EXPECT_THAT(res, IsOkAndHolds(340282000000000000000000000000000000001.23));
}
TEST(CppGeneratedCode, GetExtensionBoolWithDefault) {
TestModel model;
auto res = hpb::GetExtension(&model, bool_ext);
EXPECT_THAT(res, IsOkAndHolds(true));
}
TEST(CppGeneratedCode, GetExtensionStringWithDefault) {
TestModel model;
auto res = hpb::GetExtension(&model, string_ext);
EXPECT_TRUE(res.ok());
EXPECT_THAT(res, IsOkAndHolds("mishpacha"));
}
TEST(CppGeneratedCode, GetExtensionStringWithDefaultAndTestEscaping) {
TestModel model;
auto res = hpb::GetExtension(&model, string_escape_ext);
EXPECT_TRUE(res.ok());
EXPECT_THAT(res, IsOkAndHolds("bseder\"bseder"));
}
TEST(CppGeneratedCode, GetExtensionOnMutableChild) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
::hpb::Ptr<TestModel> mutable_recursive_child =
model.mutable_recursive_child();
EXPECT_EQ(false, ::hpb::HasExtension(mutable_recursive_child, theme));
EXPECT_EQ(
true,
::hpb::SetExtension(mutable_recursive_child, theme, extension1).ok());
EXPECT_EQ(
"Hello World",
hpb::GetExtension(mutable_recursive_child, theme).value()->ext_name());
}
TEST(CppGeneratedCode, GetExtensionOnImmutableChild) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
::hpb::Ptr<TestModel> mutable_recursive_child =
model.mutable_recursive_child();
EXPECT_EQ(false, ::hpb::HasExtension(mutable_recursive_child, theme));
EXPECT_EQ(
true,
::hpb::SetExtension(mutable_recursive_child, theme, extension1).ok());
::hpb::Ptr<const TestModel> recursive_child = model.recursive_child();
EXPECT_EQ("Hello World",
hpb::GetExtension(recursive_child, theme).value()->ext_name());
}
TEST(CppGeneratedCode, Parse) {
TestModel model;
model.set_str1("Test123");
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(true, ::hpb::SetExtension(&model, theme, extension1).ok());
hpb::Arena arena;
auto bytes = hpb::Serialize(&model, arena);
EXPECT_EQ(true, bytes.ok());
TestModel parsed_model = ::hpb::Parse<TestModel>(bytes.value()).value();
EXPECT_EQ("Test123", parsed_model.str1());
EXPECT_EQ(true, hpb::GetExtension(&parsed_model, theme).ok());
}
TEST(CppGeneratedCode, ParseIntoPtrToModel) {
TestModel model;
model.set_str1("Test123");
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(true, ::hpb::SetExtension(&model, theme, extension1).ok());
hpb::Arena arena;
auto bytes = ::hpb::Serialize(&model, arena);
EXPECT_EQ(true, bytes.ok());
::hpb::Ptr<TestModel> parsed_model = ::hpb::CreateMessage<TestModel>(arena);
EXPECT_TRUE(::hpb::Parse(parsed_model, bytes.value()));
EXPECT_EQ("Test123", parsed_model->str1());
// Should return an extension even if we don't pass ExtensionRegistry
// by promoting unknown.
EXPECT_EQ(true, hpb::GetExtension(parsed_model, theme).ok());
}
TEST(CppGeneratedCode, ParseWithExtensionRegistry) {
TestModel model;
model.set_str1("Test123");
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(true, ::hpb::SetExtension(&model, theme, extension1).ok());
EXPECT_EQ(true, ::hpb::SetExtension(&model, ThemeExtension::theme_extension,
extension1)
.ok());
hpb::Arena arena;
auto bytes = ::hpb::Serialize(&model, arena);
EXPECT_EQ(true, bytes.ok());
TestModel parsed_model =
::hpb::Parse<TestModel>(bytes.value(),
hpb::ExtensionRegistry::generated_registry())
.value();
EXPECT_EQ("Test123", parsed_model.str1());
EXPECT_EQ(true, hpb::GetExtension(&parsed_model, theme).ok());
EXPECT_EQ(
true,
hpb::GetExtension(&parsed_model, ThemeExtension::theme_extension).ok());
EXPECT_EQ("Hello World",
hpb::GetExtension(&parsed_model, ThemeExtension::theme_extension)
.value()
->ext_name());
}
TEST(CppGeneratedCode, HpbStatusGeneratedRegistry) {
TestModel model;
ThemeExtension extension1;
extension1.set_ext_name("Hello World");
EXPECT_EQ(true, ::hpb::SetExtension(&model, ThemeExtension::theme_extension,
extension1)
.ok());
hpb::Arena arena;
auto bytes = ::hpb::Serialize(&model, arena);
EXPECT_EQ(true, bytes.ok());
// By default, hpb::ParseOptionsDefault uses the generated registry.
hpb::StatusOr<TestModel> parsed_model =
::hpb::Parse<TestModel>(bytes.value(), hpb::ParseOptionsDefault());
EXPECT_EQ(true, parsed_model.ok());
EXPECT_EQ(true, hpb::GetExtension(&parsed_model.value(),
ThemeExtension::theme_extension)
.ok());
EXPECT_EQ("Hello World", hpb::GetExtension(&parsed_model.value(),
ThemeExtension::theme_extension)
.value()
->ext_name());
}
TEST(CppGeneratedCode, ClearSubMessage) {
// Fill model.
TestModel model;
model.set_int64(5);
auto new_child = model.mutable_child_model_1();
new_child->set_child_str1("text in child");
ThemeExtension extension1;
extension1.set_ext_name("name in extension");
EXPECT_TRUE(::hpb::SetExtension(&model, theme, extension1).ok());
EXPECT_TRUE(model.mutable_child_model_1()->has_child_str1());
// Clear using Ptr<T>
::hpb::ClearMessage(model.mutable_child_model_1());
EXPECT_FALSE(model.mutable_child_model_1()->has_child_str1());
}
TEST(CppGeneratedCode, ClearMessage) {
// Fill model.
TestModel model;
model.set_int64(5);
model.set_str2("Hello");
auto new_child = model.add_child_models();
ASSERT_TRUE(new_child.ok());
new_child.value()->set_child_str1("text in child");
ThemeExtension extension1;
extension1.set_ext_name("name in extension");
EXPECT_TRUE(::hpb::SetExtension(&model, theme, extension1).ok());
// Clear using T*
::hpb::ClearMessage(&model);
// Verify that scalars, repeated fields and extensions are cleared.
EXPECT_FALSE(model.has_int64());
EXPECT_FALSE(model.has_str2());
EXPECT_TRUE(model.child_models().empty());
EXPECT_FALSE(::hpb::HasExtension(&model, theme));
}
TEST(CppGeneratedCode, DeepCopy) {
// Fill model.
TestModel model;
model.set_int64(5);
model.set_str2("Hello");
auto new_child = model.add_child_models();
ASSERT_TRUE(new_child.ok());
new_child.value()->set_child_str1("text in child");
ThemeExtension extension1;
extension1.set_ext_name("name in extension");
EXPECT_TRUE(::hpb::SetExtension(&model, theme, extension1).ok());
TestModel target;
target.set_b1(true);
::hpb::DeepCopy(&model, &target);
EXPECT_FALSE(target.b1()) << "Target was not cleared before copying content ";
EXPECT_EQ(target.str2(), "Hello");
EXPECT_TRUE(::hpb::HasExtension(&target, theme));
}
TEST(CppGeneratedCode, HasExtensionAndRegistry) {
// Fill model.
TestModel source;
source.set_int64(5);
source.set_str2("Hello");
auto new_child = source.add_child_models();
ASSERT_TRUE(new_child.ok());
new_child.value()->set_child_str1("text in child");
ThemeExtension extension1;
extension1.set_ext_name("name in extension");
ASSERT_TRUE(::hpb::SetExtension(&source, theme, extension1).ok());
// Now that we have a source model with extension data, serialize.
::hpb::Arena arena;
std::string data = std::string(::hpb::Serialize(&source, arena).value());
// Test with ExtensionRegistry
TestModel parsed_model =
::hpb::Parse<TestModel>(data,
hpb::ExtensionRegistry::generated_registry())
.value();
EXPECT_TRUE(::hpb::HasExtension(&parsed_model, theme));
}
TEST(CppGeneratedCode, ExtensionFieldNumberConstant) {
EXPECT_EQ(12003, ::hpb::ExtensionNumber(ThemeExtension::theme_extension));
}
TEST(CppGeneratedCode, GetExtensionRepeatedi32) {
TestModel model;
hpb::Arena arena;
hpb::ExtensionRegistry extensions(arena);
extensions.AddExtension(repeated_int32_ext);
// These bytes are the serialized form of a repeated int32 field
// with two elements: [2, 3] @index 13004
auto bytes = "\342\254\006\002\002\003";
auto parsed_model = hpb::Parse<TestModel>(bytes, extensions).value();
auto res = hpb::GetExtension(&parsed_model, repeated_int32_ext);
EXPECT_EQ(true, res.ok());
EXPECT_EQ(res->size(), 2);
EXPECT_EQ((*res)[0], 2);
EXPECT_EQ((*res)[1], 3);
}
TEST(CppGeneratedCode, GetExtensionRepeatedi64) {
TestModel model;
hpb::Arena arena;
hpb::ExtensionRegistry extensions(arena);
extensions.AddExtension(repeated_int64_ext);
// These bytes represent a repeated int64 field with one element: [322].
auto bytes = "\352\254\006\002\302\002";
auto parsed_model = hpb::Parse<TestModel>(bytes, extensions).value();
auto res = hpb::GetExtension(&parsed_model, repeated_int64_ext);
EXPECT_EQ(true, res.ok());
EXPECT_EQ(res->size(), 1);
EXPECT_EQ((*res)[0], 322);
}
TEST(CppGeneratedCode, GetExtensionSingularString) {
TestModel model;
hpb::Arena arena;
hpb::ExtensionRegistry extensions(arena);
extensions.AddExtension(string_ext);
// These bytes represent a singular string field: "todaraba" @index 13012.
auto bytes = "\242\255\006\010todaraba";
auto parsed_model = hpb::Parse<TestModel>(bytes, extensions).value();
auto res = hpb::GetExtension(&parsed_model, string_ext);
EXPECT_THAT(res, IsOkAndHolds("todaraba"));
}
TEST(CppGeneratedCode, GetExtensionRepeatedString) {
TestModel model;
hpb::Arena arena;
hpb::ExtensionRegistry extensions(arena);
extensions.AddExtension(repeated_string_ext);
// These bytes represent a repeated string field with two elements:
// ["hello", "world"] @index 13006.
auto bytes = "\362\254\006\005hello\362\254\006\005world";
auto parsed_model = hpb::Parse<TestModel>(bytes, extensions).value();
auto res = hpb::GetExtension(&parsed_model, repeated_string_ext);
EXPECT_EQ(true, res.ok());
EXPECT_EQ(res->size(), 2);
EXPECT_EQ((*res)[0], "hello");
EXPECT_EQ((*res)[1], "world");
}
TEST(CppGeneratedCode, ConstExprExtensionNumber) {
constexpr auto ext_num = hpb::ExtensionNumber(int32_ext);
EXPECT_EQ(ext_num, 13002);
}
} // namespace