1#include <gmock/gmock.h>
2#include <gtest/gtest.h>
6#include <google/protobuf/util/time_util.h>
8#include <userver/proto-structs/convert.hpp>
10#include "messages.pb.h"
13USERVER_NAMESPACE_BEGIN
15namespace proto_structs::tests {
17TEST(StructToMessage, Empty) {
21 ASSERT_NO_THROW(StructToMessage(obj, msg));
22 ASSERT_NO_THROW((msg = StructToMessage(obj)));
23 ASSERT_NO_THROW((msg = StructToMessage(structs::
Empty{obj})));
26TEST(StructToMessage, Scalar) {
30 .f2 = std::numeric_limits<int32_t>::min(),
31 .f3 = std::numeric_limits<uint32_t>::max(),
32 .f4 = std::numeric_limits<int64_t>::min(),
33 .f5 = std::numeric_limits<uint64_t>::max(),
34 .f6 =
static_cast<
float>(1.5),
38 .f10 = structs::TestEnum::kValue1,
42 auto msg = StructToMessage(obj);
43 CheckScalarEqual(obj, msg);
45 msg = StructToMessage(structs::
Scalar{obj});
46 CheckScalarEqual(obj, msg);
58 ASSERT_NO_THROW(StructToMessage(obj, msg));
59 CheckScalarEqual(obj, msg);
65 ASSERT_NO_THROW(StructToMessage(structs::
Scalar{obj}, msg));
66 CheckScalarEqual(obj, msg);
69 if (std::numeric_limits<std::size_t>::max() > std::numeric_limits<std::int32_t>::max()) {
71 obj.f11 = std::numeric_limits<std::size_t>::max();
74 auto result = StructToMessage(obj);
75 FAIL() <<
"exception should be thrown";
76 }
catch (
const ups::WriteError& e) {
77 EXPECT_THAT(e.what(), ::testing::HasSubstr(
"'messages.Scalar.f11'"));
79 FAIL() <<
"unexpected exception type";
84TEST(StructToMessage, WellKnownStd) {
85 using TimePoint = std::chrono::time_point<std::chrono::system_clock>;
86 auto create_valid = []() {
87 return structs::WellKnownStd{.f3 = {std::chrono::year{1}, std::chrono::month{1}, std::chrono::day{1}}};
92 .f1 = TimePoint{std::chrono::milliseconds{123'456'789}},
93 .f2 = std::chrono::milliseconds{987'654'321},
94 .f3 = {std::chrono::year{2025}, std::chrono::month{8}, std::chrono::day{27}},
96 std::chrono::hh_mm_ss<std::chrono::microseconds>{
97 std::chrono::minutes(65) + std::chrono::seconds{13} + std::chrono::microseconds{123'456}
101 auto msg = StructToMessage(obj);
103 CheckWellKnownStdEqual(obj, msg);
107 CheckWellKnownStdEqual(obj, msg);
112 messages::WellKnownStd msg;
114 obj.f1 = TimePoint{std::chrono::milliseconds{-987'654'321}};
115 *msg.mutable_f1() = ::google::protobuf::util::TimeUtil::NanosecondsToTimestamp(123'456'789'987'654'321LL);
116 *msg.mutable_f2() = ::google::protobuf::util::TimeUtil::NanosecondsToDuration(1001);
118 ASSERT_NO_THROW(StructToMessage(obj, msg));
119 CheckWellKnownStdEqual(obj, msg);
121 obj.f2 = std::chrono::milliseconds{-987'654'321};
122 *msg.mutable_f2() = ::google::protobuf::util::TimeUtil::NanosecondsToDuration(123'456'789'987'654'321LL);
124 ASSERT_NO_THROW(StructToMessage(structs::
WellKnownStd{obj}, msg));
125 CheckWellKnownStdEqual(obj, msg);
128 constexpr auto kMaxSecondsInStdTimePoint =
129 (TimePoint::duration::max().count() / TimePoint::duration::period::den) * TimePoint::duration::period::num;
131 if (kMaxSecondsInStdTimePoint > ::google::protobuf::util::TimeUtil::kTimestampMaxSeconds) {
133 messages::WellKnownStd msg;
135 obj.f1 = TimePoint{std::chrono::seconds{kMaxSecondsInStdTimePoint}};
138 [&obj]() {
static_cast<
void>(StructToMessage(obj)); },
139 ::testing::ThrowsMessage<WriteError>(::testing::HasSubstr(
"'messages.WellKnownStd.f1'"))
143 if ((std::chrono::milliseconds::max().count() / 1000) > ::google::protobuf::util::TimeUtil::kDurationMaxSeconds) {
145 messages::WellKnownStd msg;
147 obj.f2 = std::chrono::milliseconds::max();
150 [&obj]() {
static_cast<
void>(StructToMessage(obj)); },
151 ::testing::ThrowsMessage<WriteError>(::testing::HasSubstr(
"'messages.WellKnownStd.f2'"))
157 obj.f3 = {std::chrono::year{2025}, std::chrono::month{2}, std::chrono::day{29}};
160 [&obj]() {
static_cast<
void>(StructToMessage(obj)); },
161 ::testing::ThrowsMessage<WriteError>(::testing::HasSubstr(
"'messages.WellKnownStd.f3'"))
167 obj.f4 = std::chrono::hh_mm_ss<std::chrono::microseconds>{std::chrono::hours{25}};
170 [&obj]() {
static_cast<
void>(StructToMessage(obj)); },
171 ::testing::ThrowsMessage<WriteError>(::testing::HasSubstr(
"'messages.WellKnownStd.f4'"))
176TEST(StructToMessage, WellKnownUsrv) {
177 using TimePoint = Timestamp::TimePoint;
181 .f1 = structs::Simple{.f1 = 100},
182 .f2 = TimePoint{std::chrono::milliseconds{123'456'789}},
183 .f3 = std::chrono::milliseconds{987'654'321},
184 .f4 = std::chrono::year_month_day{std::chrono::year{2025}, std::chrono::month{8}, std::chrono::day{27}},
186 std::chrono::hh_mm_ss<std::chrono::microseconds>{
187 std::chrono::minutes(65) + std::chrono::seconds{13} + std::chrono::microseconds{123'456}
190 utils::datetime::TimeOfDay<std::chrono::microseconds>{
191 std::chrono::hours{23} + std::chrono::minutes{59} + std::chrono::seconds{59} +
192 std::chrono::microseconds{999'999}
194 .f7 = decimal64::Decimal<3>{
"123.456"}
196 messages::Simple any_payload;
198 auto msg = StructToMessage(obj);
200 CheckWellKnownUsrvEqual(obj, msg);
201 ASSERT_TRUE(msg.f1().UnpackTo(&any_payload));
202 CheckSimpleEqual(obj.f1.Unpack<structs::
Simple>(), any_payload);
206 CheckWellKnownUsrvEqual(obj, msg);
207 ASSERT_TRUE(msg.f1().UnpackTo(&any_payload));
208 CheckSimpleEqual(obj.f1.Unpack<structs::
Simple>(), any_payload);
213 messages::WellKnownUsrv msg;
215 obj.f2 = TimePoint{std::chrono::milliseconds{-987'654'321}};
216 obj.f7 = decimal64::Decimal<3>(
"1001.001");
218 messages::Scalar any_payload;
219 any_payload.set_f10(messages::TestEnum::TEST_ENUM_VALUE1);
221 ASSERT_TRUE(msg.mutable_f1()->PackFrom(any_payload));
222 *msg.mutable_f2() = ::google::protobuf::util::TimeUtil::NanosecondsToTimestamp(123'456'789'987'654'321LL);
223 *msg.mutable_f3() = ::google::protobuf::util::TimeUtil::NanosecondsToDuration(1001);
225 ASSERT_NO_THROW(StructToMessage(obj, msg));
226 CheckWellKnownUsrvEqual(obj, msg);
228 ASSERT_NO_THROW((obj.f1 = structs::
Scalar{.f2 = 5}));
229 obj.f3 = std::chrono::milliseconds{-987'654'321};
230 obj.f7 = decimal64::Decimal<3>(
"-1001.001");
231 *msg.mutable_f3() = ::google::protobuf::util::TimeUtil::NanosecondsToDuration(123'456'789'987'654'321LL);
233 ASSERT_NO_THROW(StructToMessage(structs::
WellKnownUsrv{obj}, msg));
234 CheckWellKnownUsrvEqual(obj, msg);
235 ASSERT_TRUE(msg.f1().UnpackTo(&any_payload));
236 CheckScalarEqual(obj.f1.Unpack<structs::
Scalar>(), any_payload);
240TEST(StructToMessage, Optional) {
243 {.f1 = 1001, .f2 =
"test", .f3 = structs::TestEnum::kValue1, .f4 = structs::
Simple{.f1 = 10}};
245 auto msg = StructToMessage(obj);
246 CheckOptionalEqual(obj, msg);
248 msg = StructToMessage(structs::
Optional{obj});
249 CheckOptionalEqual(obj, msg);
254 messages::Optional msg;
259 msg.set_f3(messages::TestEnum::TEST_ENUM_VALUE2);
260 msg.mutable_f4()->set_f1(5);
262 ASSERT_NO_THROW(StructToMessage(obj, msg));
263 CheckOptionalEqual(obj, msg);
267 ASSERT_NO_THROW(StructToMessage(structs::
Optional{obj}, msg));
268 CheckOptionalEqual(obj, msg);
272TEST(StructToMessage, Repeated) {
275 obj.f1 = {10, 11, 12};
276 obj.f2 = {
"test1",
"test2"};
278 structs::TestEnum::kValue1,
279 structs::TestEnum::kUnspecified,
280 structs::TestEnum::kValue2,
281 static_cast<structs::TestEnum>(1001)
283 obj.f4 = {{.f1 = 1000}, {.f1 = 1001}};
285 auto msg = StructToMessage(obj);
286 CheckRepeatedEqual(obj, msg);
288 msg = StructToMessage(structs::
Repeated{obj});
289 CheckRepeatedEqual(obj, msg);
294 messages::Repeated msg;
297 obj.f4 = {{.f1 = 13}};
302 msg.mutable_f4()->Add()->set_f1(5);
304 ASSERT_NO_THROW(StructToMessage(obj, msg));
305 CheckRepeatedEqual(obj, msg);
307 obj.f2.push_back(
"hello");
309 ASSERT_NO_THROW(StructToMessage(obj, msg));
310 CheckRepeatedEqual(obj, msg);
314TEST(StructToMessage, Map) {
317 obj.f1 = {{5, 15}, {6, 16}, {7, 17}};
318 obj.f2 = {{
"key1",
"value1"}, {
"key2",
"value2"}};
319 obj.f3 = {{
true, structs::TestEnum::kUnspecified}, {
false, structs::TestEnum::kValue2}};
320 obj.f4 = {{
"simple1", {.f1 = 1001}}, {
"simple2", {.f1 = 1002}}};
322 auto msg = StructToMessage(obj);
323 CheckMapEqual(obj, msg);
325 msg = StructToMessage(structs::
Map{obj});
326 CheckMapEqual(obj, msg);
334 obj.f4 = {{
"simple1", {.f1 = 1001}}};
335 (*msg.mutable_f1())[1] = 1;
336 (*msg.mutable_f1())[2] = 2;
337 (*msg.mutable_f1())[3] = 3;
338 (*msg.mutable_f2())[
"key1"] =
"value1";
339 (*msg.mutable_f4())[
"simple1"].set_f1(1001);
341 ASSERT_NO_THROW(StructToMessage(obj, msg));
342 CheckMapEqual(obj, msg);
344 obj.f2.emplace(
"key2",
"value2");
346 ASSERT_NO_THROW(StructToMessage(obj, msg));
347 CheckMapEqual(obj, msg);
351TEST(StructToMessage, Oneof) {
354 obj.test_oneof.Set<0>(1001);
356 auto msg = StructToMessage(obj);
357 CheckOneofEqual(obj, msg);
359 msg = StructToMessage(structs::
Oneof{obj});
360 CheckOneofEqual(obj, msg);
367 obj.test_oneof.Set<1>(
"test");
370 ASSERT_NO_THROW(StructToMessage(obj, msg));
371 CheckOneofEqual(obj, msg);
373 obj.test_oneof.Set<2>(structs::TestEnum::kUnspecified);
375 ASSERT_NO_THROW(StructToMessage(obj, msg));
376 CheckOneofEqual(obj, msg);
378 obj.test_oneof.Set<3>({.f1 = 1001});
380 ASSERT_NO_THROW(StructToMessage(obj, msg));
381 CheckOneofEqual(obj, msg);
385TEST(StructToMessage, Indirect) {
389 obj.f2 = std::chrono::nanoseconds{987'654'321'123'456'789LL};
390 obj.f3 = {structs::
Simple{.f1 = 3}, structs::
Simple{.f1 = 4}};
391 obj.f4 = {{1, structs::
Simple{.f1 = 5}}, {2, structs::
Simple{.f1 = 6}}};
392 obj.test_oneof.Set<0>(structs::
Simple{.f1 = 7});
394 obj.f8 = {structs::TestEnum::kValue1, structs::TestEnum::kValue2};
395 obj.f9 = {{
"hello", structs::
Simple{.f1 = 9}}, {
"", structs::
Simple{.f1 = 10}}};
397 auto msg = StructToMessage(obj);
398 CheckIndirectEqual(obj, msg);
400 msg = StructToMessage(structs::
Indirect{obj});
401 CheckIndirectEqual(obj, msg);
406 messages::Indirect msg;
409 obj.f4 = {{1, structs::
Simple{.f1 = 10}}};
410 obj.test_oneof.Set<1>(
"test");
411 msg.mutable_f1()->set_f1(1001);
412 msg.mutable_f3()->Add()->set_f1(1002);
413 msg.mutable_f5()->set_f1(1003);
415 ASSERT_NO_THROW(StructToMessage(obj, msg));
416 CheckIndirectEqual(obj, msg);
418 obj.test_oneof.Set<0>(structs::
Simple{.f1 = 11});
419 msg.add_f8(messages::TEST_ENUM_VALUE1);
421 ASSERT_NO_THROW(StructToMessage(obj, msg));
422 CheckIndirectEqual(obj, msg);
426TEST(StructToMessage, Strong) {
429 obj.f1 = structs::Strong::F1Strong{1};
430 obj.f2 = structs::Strong::F2Strong{
"hello"};
432 structs::Strong::F3Strong{structs::TestEnum::kValue1},
433 structs::Strong::F3Strong{structs::TestEnum::kValue2}
436 {1, structs::Strong::F4Strong(structs::Simple{.f1 = 3})},
437 {2, structs::Strong::F4Strong(structs::Simple{.f1 = 4})}
439 obj.test_oneof.Set<0>(structs::Strong::F5Strong{std::chrono::nanoseconds{-123'456'789'987'654'321}});
441 auto msg = StructToMessage(obj);
442 CheckStrongEqual(obj, msg);
444 msg = StructToMessage(structs::
Strong{obj});
445 CheckStrongEqual(obj, msg);
450 messages::Strong msg;
452 obj.f1 = structs::Strong::F1Strong{1};
454 {100, structs::Strong::F4Strong(structs::Simple{.f1 = 2})},
455 {200, structs::Strong::F4Strong(structs::Simple{.f1 = 3})}
458 msg.add_f3(messages::TestEnum::TEST_ENUM_VALUE2);
460 ASSERT_NO_THROW(StructToMessage(obj, msg));
461 CheckStrongEqual(obj, msg);
463 obj.test_oneof.Set<0>(structs::Strong::F5Strong{std::chrono::nanoseconds{123'456'789'987'654'321}});
465 ASSERT_NO_THROW(StructToMessage(obj, msg));
466 CheckStrongEqual(obj, msg);
470TEST(StructToMessage, Erroneous) {
473 messages::Erroneous msg;
475 EXPECT_NO_THROW(msg = StructToMessage(obj));
480 obj.f1 = {.error_type = structs::ConversionFailureType::kException};
483 auto result = StructToMessage(obj);
484 FAIL() <<
"exception should be thrown";
485 }
catch (
const ups::WriteError& e) {
486 EXPECT_THAT(e.what(), ::testing::HasSubstr(
"'messages.Erroneous.f1'"));
487 EXPECT_THAT(e.what(), ::testing::HasSubstr(
"conversion_failure_exception"));
489 FAIL() <<
"unexpected exception type";
495 obj.f2 = {{.error_type = structs::ConversionFailureType::kError}};
498 auto result = StructToMessage(std::move(obj));
499 FAIL() <<
"exception should be thrown";
500 }
catch (
const ups::WriteError& e) {
501 EXPECT_THAT(e.what(), ::testing::HasSubstr(
"'messages.Erroneous.f2.error_field'"));
502 EXPECT_THAT(e.what(), ::testing::HasSubstr(
"conversion_failure_error"));
504 FAIL() <<
"unexpected exception type";
510 obj.f3 = {{10, {.error_type = structs::ConversionFailureType::kErrorWithUnknownField}}};
513 auto result = StructToMessage(obj);
514 FAIL() <<
"exception should be thrown";
515 }
catch (
const ups::WriteError& e) {
516 EXPECT_THAT(e.what(), ::testing::HasSubstr(
"'messages.Erroneous.f3.<unknown_1001>'"));
517 EXPECT_THAT(e.what(), ::testing::HasSubstr(
"conversion_failure_error_with_unknown_field"));
519 FAIL() <<
"unexpected exception type";
525 obj.test_oneof.Set<0>({.error_type = structs::ConversionFailureType::kErrorWithUnknownField});
528 auto result = StructToMessage(obj);
529 FAIL() <<
"exception should be thrown";
530 }
catch (
const ups::WriteError& e) {
531 EXPECT_THAT(e.what(), ::testing::HasSubstr(
"'messages.Erroneous.f4.<unknown_1001>'"));
532 EXPECT_THAT(e.what(), ::testing::HasSubstr(
"conversion_failure_error_with_unknown_field"));
534 FAIL() <<
"unexpected exception type";