2#include <unordered_map>
5#include <gtest/gtest.h>
7#include <userver/formats/json/value_builder.hpp>
8#include <userver/formats/parse/common_containers.hpp>
9#include <userver/formats/serialize/common_containers.hpp>
10#include <userver/proto-structs/convert.hpp>
11#include <userver/proto-structs/type_mapping.hpp>
13#include <simple/base/base.pb.h>
14#include <simple/base/base.structs.usrv.pb.hpp>
16namespace ss = simple::base::structs;
18USERVER_NAMESPACE_BEGIN
20TEST(SingleFile, SimpleStruct) {
21 static_assert(std::is_aggregate_v<ss::SimpleStruct>);
22 [[maybe_unused]] ss::SimpleStruct message;
23 message.some_integer = 5;
24 message.some_text = std::optional<std::string>(
"foo");
25 message.is_condition =
true;
26 message.some_bytes = {
"foo",
"bar"};
27 message.something.set_bar(
"bar_val");
28 message.inner_enum = ss::SimpleStruct::InnerEnum2::kFooVal;
29 message.nested.swag =
"foo";
30 message.optional_nested = std::optional<ss::SimpleStruct::NestedStruct>{{.swag =
"foo"}};
32 auto vanilla = ::proto_structs::StructToMessage(std::move(message));
34 EXPECT_EQ(vanilla.some_integer(), 5);
35 EXPECT_EQ(vanilla.some_text(),
"foo");
36 EXPECT_EQ(vanilla.is_condition(),
true);
37 EXPECT_EQ(vanilla.some_bytes().Get(0),
"foo");
38 EXPECT_EQ(vanilla.some_bytes().Get(1),
"bar");
39 EXPECT_EQ(vanilla.bar(),
"bar_val");
40 EXPECT_EQ(vanilla.inner_enum(), ss::SimpleStruct::ProtobufMessage::FOO_VAL);
41 EXPECT_EQ(vanilla.nested().swag(),
"foo");
42 EXPECT_EQ(vanilla.optional_nested().swag(),
"foo");
45 ::proto_structs::MessageToStruct(vanilla, to);
47 ASSERT_EQ(to.some_integer, 5);
48 ASSERT_EQ(to.some_text, std::optional<std::string>(
"foo"));
49 ASSERT_TRUE(to.is_condition);
50 std::vector<std::string> exp = {
"foo",
"bar"};
51 ASSERT_EQ(to.some_bytes, exp);
52 ASSERT_EQ(to.something.bar(),
"bar_val");
53 ASSERT_THROW([[maybe_unused]]
auto foo = to.something.foo(), proto_structs::OneofAccessError);
56TEST(SingleFile, NestedStruct) {
57 static_assert(std::is_aggregate_v<ss::SimpleStruct::NestedStruct>);
58 [[maybe_unused]] ss::SimpleStruct::NestedStruct nested;
61 static_assert(std::is_aggregate_v<ss::SimpleStruct::NestedStruct::NestedStruct2>);
62 [[maybe_unused]] ss::SimpleStruct::NestedStruct::NestedStruct2 nested2;
63 nested2.swag2 =
"bar";
66TEST(SingleFile, InnerEnum1) {
67 static_assert(std::is_enum_v<ss::SimpleStruct::NestedStruct::NestedStruct2::InnerEnum1>);
68 [[maybe_unused]]
const auto inner_enum1 = ss::SimpleStruct::NestedStruct::NestedStruct2::InnerEnum1::kBarVal;
71TEST(SingleFile, InnerEnum2) {
72 static_assert(std::is_enum_v<ss::SimpleStruct::InnerEnum2>);
73 [[maybe_unused]]
const auto inner_enum2 = ss::SimpleStruct::InnerEnum2::kFooVal;
76TEST(SingleFile, SecondStruct) {
77 static_assert(std::is_aggregate_v<ss::SecondStruct>);
78 [[maybe_unused]] ss::SecondStruct message;
81TEST(SingleFile, GlobalEnum) {
82 static_assert(std::is_enum_v<ss::GlobalEnum>);
83 [[maybe_unused]] ss::GlobalEnum message{};
87 const ss::SimpleStruct::Something none;
89 EXPECT_FALSE(none.has_foo());
90 EXPECT_FALSE(none.has_bar());
91 EXPECT_THROW([[maybe_unused]]
const auto& not_found1 = none.foo(), proto_structs::OneofAccessError);
92 EXPECT_THROW([[maybe_unused]]
const auto& not_found2 = none.bar(), proto_structs::OneofAccessError);
96 ss::SimpleStruct::Something foo;
99 EXPECT_TRUE(foo.has_foo());
100 EXPECT_NO_THROW(EXPECT_EQ(foo.foo(), 42));
101 EXPECT_FALSE(foo.has_bar());
102 EXPECT_THROW([[maybe_unused]]
const auto& not_found = foo.bar(), proto_structs::OneofAccessError);
105TEST(Oneof, MakeBar) {
106 ss::SimpleStruct::Something bar;
109 EXPECT_FALSE(bar.has_foo());
110 EXPECT_THROW([[maybe_unused]]
const auto& not_found = bar.foo(), proto_structs::OneofAccessError);
111 EXPECT_TRUE(bar.has_bar());
112 EXPECT_NO_THROW(EXPECT_EQ(bar.bar(),
"bar"));
115TEST(Oneof, OneofInStruct) {
116 [[maybe_unused]] ss::SimpleStruct message;
117 message.something.set_bar(
"bar");
118 EXPECT_EQ(message.something.bar(),
"bar");
121TEST(Oneof, WellKnownTypes) {
122 const std::chrono::seconds seconds{1};
123 const std::chrono::nanoseconds nanoseconds{1};
124 const std::chrono::year year{2025};
125 const std::chrono::month month{10};
126 const std::chrono::day day{30};
127 const std::chrono::hours hours{20};
128 const std::chrono::minutes minutes{10};
129 const std::string string_value{
"swag"};
130 const formats::json::
Value json_bool = formats::json::ValueBuilder{
true}.ExtractValue();
131 const formats::json::Array json_array{formats::json::ValueBuilder{std::vector<
double>{-1.5, 1.5}}.ExtractValue()};
132 const formats::json::Object json_object{
133 formats::json::ValueBuilder(std::unordered_map<std::string, std::string>{{
"a",
"1"}, {
"b",
"2"}}).ExtractValue()
136 ss::WellKnownUsrv message;
138 message.f1 = proto_structs::Timestamp(seconds, nanoseconds);
139 message.f2 = proto_structs::Duration(seconds, nanoseconds);
140 message.f3 = proto_structs::Date(year, month, day);
141 message.f4 = proto_structs::TimeOfDay(hours, minutes, seconds);
143 google::protobuf::Any pbuf_any;
144 proto_structs::traits::CompatibleMessageType<ss::ForAny> for_any;
145 for_any.set_f1(string_value);
147 ASSERT_TRUE(pbuf_any.PackFrom(for_any));
149 message.f5 = proto_structs::Any{pbuf_any};
150 message.f6 = json_bool;
151 message.f7 = json_array;
152 message.f8 = json_object;
154 const auto vanilla = proto_structs::StructToMessage(std::move(message));
156 ss::WellKnownUsrv parsed;
157 proto_structs::MessageToStruct(vanilla, parsed);
159 ASSERT_EQ(parsed.f1.Seconds(), seconds);
160 ASSERT_EQ(parsed.f1.Nanos(), nanoseconds);
162 ASSERT_EQ(parsed.f2.Seconds(), seconds);
163 ASSERT_EQ(parsed.f2.Nanos(), nanoseconds);
165 ASSERT_TRUE(parsed.f3.Year().has_value());
166 ASSERT_TRUE(parsed.f3.Month().has_value());
167 ASSERT_TRUE(parsed.f3.Day().has_value());
169 ASSERT_EQ(parsed.f3.Year(), year);
170 ASSERT_EQ(parsed.f3.Month(), month);
171 ASSERT_EQ(parsed.f3.Day(), day);
173 ASSERT_EQ(parsed.f4.Hours(), hours);
174 ASSERT_EQ(parsed.f4.Minutes(), minutes);
175 ASSERT_EQ(parsed.f4.Seconds(), seconds);
176 ASSERT_EQ(parsed.f4.Nanos(), std::chrono::nanoseconds{0});
178 ASSERT_TRUE(parsed.f5.Is<proto_structs::traits::CompatibleMessageType<ss::ForAny>>());
180 const auto parsed_any = parsed.f5.Unpack<ss::ForAny>();
181 ASSERT_EQ(parsed_any.f1, string_value);
183 ASSERT_EQ(parsed.f6, json_bool);
184 ASSERT_EQ(parsed.f7, json_array);
185 ASSERT_EQ(parsed.f8, json_object);