diff --git a/cmake/subdir.cmake b/cmake/subdir.cmake index 7c33792b6..448f46de1 100644 --- a/cmake/subdir.cmake +++ b/cmake/subdir.cmake @@ -17,6 +17,7 @@ if (NOT ENABLE_CPP_20) Set(BUILD_STRUCT_JSON ON) Set(BUILD_STRUCT_XML ON) Set(BUILD_STRUCT_YAML ON) + Set(BUILD_STRUCT_PB ON) endif() foreach(child ${children}) diff --git a/src/struct_pb/tests/CMakeLists.txt b/src/struct_pb/tests/CMakeLists.txt new file mode 100644 index 000000000..f76c19ef6 --- /dev/null +++ b/src/struct_pb/tests/CMakeLists.txt @@ -0,0 +1,37 @@ +find_package(Protobuf QUIET) +if("${yaLanTingLibs_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") + # If this is a subproject in ylt + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests) +else() + # else find installed yalantinglibs + cmake_minimum_required(VERSION 3.15) + project(struct_pb_test) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_INCLUDE_CURRENT_DIR ON) + # if you have install ylt + find_package(yalantinglibs REQUIRED) + link_libraries(yalantinglibs::yalantinglibs) + # else + # include_directories(include) + # include_directories(include/ylt/thirdparty) +endif() + +set(TEST_PROTO main.cpp) + +if (Protobuf_FOUND) + add_definitions(-DSTRUCT_PB_WITH_PROTO) + message(STATUS "Found Protobuf: ${Protobuf_VERSION}") + include_directories(${Protobuf_INCLUDE_DIRS}) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + set(PROTO_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/) + file(GLOB PROTO_FILES ${PROTO_SRC_DIR}/*.proto) + + protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_FILES}) + # message(STATUS "Proto source files: ${PROTO_SRCS}") + # message(STATUS "Proto header files: ${PROTO_HDRS}") + add_executable(struct_pb_test ${PROTO_SRCS} ${TEST_PROTO}) + target_link_libraries(struct_pb_test PRIVATE protobuf::libprotobuf) +else() + add_executable(struct_pb_test ${TEST_PROTO}) +endif() \ No newline at end of file diff --git a/src/struct_pb/tests/data_def.proto b/src/struct_pb/tests/data_def.proto new file mode 100644 index 000000000..691c964fe --- /dev/null +++ b/src/struct_pb/tests/data_def.proto @@ -0,0 +1,56 @@ +syntax = "proto3"; + +package mygame; + +option optimize_for = SPEED; +option cc_enable_arenas = true; + +message Vec3 { + float x = 1; + float y = 2; + float z = 3; +} + +message Weapon { + string name = 1; + int32 damage = 2; +} + +message Monster { + Vec3 pos = 1; + int32 mana = 2; + int32 hp = 3; + string name = 4; + bytes inventory = 5; + enum Color { + Red = 0; + Green = 1; + Blue = 2; + } + Color color = 6; + repeated Weapon weapons = 7; + Weapon equipped = 8; + repeated Vec3 path = 9; +} + +message Monsters { + repeated Monster monsters = 1; +} + +message person { + int32 id = 1; + string name = 2; + int32 age = 3; + double salary = 4; +} + +message persons { + repeated person person_list = 1; +} + +message bench_int32 { + int32 a = 1; + int32 b = 2; + int32 c = 3; + int32 d = 4; +} \ No newline at end of file diff --git a/src/struct_pb/tests/main.cpp b/src/struct_pb/tests/main.cpp new file mode 100644 index 000000000..ca06723e3 --- /dev/null +++ b/src/struct_pb/tests/main.cpp @@ -0,0 +1,1026 @@ +#define DOCTEST_CONFIG_IMPLEMENT +#include + +#include "doctest.h" +#include "unittest_proto3.h" + +#if defined(STRUCT_PB_WITH_PROTO) +TEST_CASE("test BaseTypeMsg") { + { // normal test + stpb::BaseTypeMsg se_st{0, 100, 200, 300, 400, + 31.4f, 62.8, false, "World", stpb::Enum::ZERO}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseTypeMsg se_msg; + SetBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::BaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseTypeMsg(dese_st, dese_msg); + } + + { // test min and empty str + stpb::BaseTypeMsg se_st{0, + std::numeric_limits::min(), + std::numeric_limits::min(), + std::numeric_limits::min(), + std::numeric_limits::min(), + std::numeric_limits::lowest(), + std::numeric_limits::lowest(), + false, + "", + stpb::Enum::NEG}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseTypeMsg se_msg; + SetBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::BaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseTypeMsg(dese_st, dese_msg); + } + { // test max and long str + stpb::BaseTypeMsg se_st{0, + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + true, + std::string(1000, 'x'), + stpb::Enum::BAZ}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseTypeMsg se_msg; + SetBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::BaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test person and monster") { + stpb::simple_t2 t{0, -100, 2, stpb::Color::Blue, 4}; + std::string str; + iguana::to_pb(t, str); + + stpb::simple_t2 t2; + iguana::from_pb(t2, str); + CHECK(t.c == t2.c); + + pb::Simple2 s; + s.set_a(-100); + s.set_b(2); + s.set_c(pb::Color::Blue); + s.set_d(4); + + std::string pb_str; + s.SerializeToString(&pb_str); + + CHECK(str == pb_str); +} + +TEST_CASE("test person and monster") { + auto pb_monster = protobuf_sample::create_monster(); + auto sp_monster = create_sp_monster(); + + std::string pb_str; + std::string sp_str; + + pb_monster.SerializeToString(&pb_str); + iguana::to_pb(sp_monster, sp_str); + + CHECK(pb_str == sp_str); + + mygame::Monster m; + m.ParseFromString(pb_str); + CHECK(m.name() == pb_monster.name()); + + stpb::Monster spm; + iguana::from_pb(spm, sp_str); + CHECK(spm.name == sp_monster.name); + + auto pb_person = protobuf_sample::create_person(); + auto sp_person = create_person(); + pb_person.SerializePartialToString(&pb_str); + iguana::to_pb(sp_person, sp_str); + + CHECK(pb_str == sp_str); + + mygame::person pp; + pp.ParseFromString(pb_str); + CHECK(pp.name() == pb_person.name()); + + stpb::person p; + iguana::from_pb(p, sp_str); + CHECK(p.name == sp_person.name); +} + +TEST_CASE("test IguanaTypeMsg") { + { // test normal value + stpb::IguanaTypeMsg se_st{0, {100}, {200}, {300}, {400}, {31}, {32}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg{}; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } + + { // test min value + stpb::IguanaTypeMsg se_st{0, + {std::numeric_limits::min()}, + {std::numeric_limits::min()}, + {std::numeric_limits::min()}, + {std::numeric_limits::min()}, + {std::numeric_limits::lowest()}, + {std::numeric_limits::lowest()}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg{}; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } + { // test max value + stpb::IguanaTypeMsg se_st{0, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } + { // test empty + stpb::IguanaTypeMsg se_st{}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test RepeatBaseTypeMsg") { + { + stpb::RepeatBaseTypeMsg se_st{ + 0, + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}, + {10, 11, 12}, + {13.1, 14.2, 15.3}, + {16.4, 17.5, 18.6}, + {"a", "b", "c"}, + {stpb::Enum::BAZ, stpb::Enum::ZERO, stpb::Enum::NEG}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::RepeatBaseTypeMsg se_msg; + SetRepeatBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::RepeatBaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::RepeatBaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckRepeatBaseTypeMsg(dese_st, dese_msg); + } + { // max and min vlaue + stpb::RepeatBaseTypeMsg se_st{0, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {"", "", ""}, + {stpb::Enum::NEG, stpb::Enum::FOO}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::RepeatBaseTypeMsg se_msg; + SetRepeatBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + stpb::RepeatBaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::RepeatBaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckRepeatBaseTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test RepeatIguanaTypeMsg") { + { + stpb::RepeatIguanaTypeMsg se_st{ + 0, + {{0}, {1}, {3}}, + {{4}, {5}, {6}}, + {{7}, {8}, {9}}, + {{10}, {11}, {12}}, + {{13}, {14}, {15}}, + {}, + }; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::RepeatIguanaTypeMsg se_msg; + SetRepeatIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::RepeatIguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::RepeatIguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckRepeatIguanaTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test NestedMsg") { + { + stpb::NestedMsg se_st{ + 0, + /* base_msg */ + {0, 100, 200, 300, 400, 31.4f, 62.8, false, "World", stpb::Enum::BAZ}, + /* repeat_base_msg */ + {{0, 1, 2, 3, 4, 5.5f, 6.6, true, "Hello", stpb::Enum::FOO}, + {0, 7, 8, 9, 10, 11.11f, 12.12, false, "Hi", stpb::Enum::BAR}}, + /* iguana_type_msg */ {0, {100}, {200}, {300}, {400}, {31}, {32}}, + /* repeat_iguna_msg */ + {{0, {1}, {2}, {3}}, {0, {4}, {5}, {6}}, {0, {7}, {8}, {9}}}, + /* repeat_repeat_base_msg */ + {{0, + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}, + {10, 11, 12}, + {13.1, 14.2, 15.3}, + {16.4, 17.5, 18.6}, + {"a", "b", "c"}, + {stpb::Enum::FOO, stpb::Enum::BAR, stpb::Enum::BAZ}}, + {0, + {19, 20, 21}, + {22, 23, 24}, + {25, 26, 27}, + {28, 29, 30}, + {31.1, 32.2, 33.3}, + {34.4, 35.5, 36.6}, + {"x", "y", "z"}, + {stpb::Enum::ZERO, stpb::Enum::NEG, stpb::Enum::FOO}}}}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::NestedMsg se_msg; + SetNestedMsg(se_st, se_msg); + + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + + CHECK(st_ss == pb_ss); + + stpb::NestedMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::NestedMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + + CheckNestedMsg(dese_st, dese_msg); + } + { // test empty values + stpb::NestedMsg se_st{ + 0, + /* base_msg */ {0, 0, 0, 0, 0, 0.0f, 0.0, true, "", stpb::Enum::ZERO}, + /* repeat_base_msg */ {}, + /* iguana_type_msg */ {}, + /* repeat_iguna_msg */ {}, + /* repeat_repeat_base_msg */ {}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::NestedMsg se_msg; + SetNestedMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + + CHECK(st_ss == pb_ss); + print_hex_str(st_ss); + print_hex_str(pb_ss); + stpb::NestedMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::NestedMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + + CheckNestedMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test MapMsg") { + { + stpb::MapMsg se_st{}; + + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{10}, "ten"); + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{20}, "twenty"); + + se_st.str_iguana_type_msg_map.emplace( + "first", stpb::IguanaTypeMsg{{10}, {20}, {30}, {40}, {50}, {60}}); + se_st.str_iguana_type_msg_map.emplace( + "second", stpb::IguanaTypeMsg{{11}, {21}, {31}, {41}, {51}, {61}}); + + se_st.int_repeat_base_msg_map.emplace( + 1, stpb::RepeatBaseTypeMsg{0, + {1, 2}, + {3, 4}, + {5, 6}, + {7, 8}, + {9.0f, 10.0f}, + {11.0, 12.0}, + {"one", "two"}, + {stpb::Enum::FOO, stpb::Enum::BAR}}); + se_st.int_repeat_base_msg_map.emplace( + 2, stpb::RepeatBaseTypeMsg{0, + {2, 3}, + {4, 5}, + {6, 7}, + {8, 9}, + {10.0f, 11.0f}, + {12.0, 13.0}, + {"three", "four"}, + {stpb::Enum::BAZ, stpb::Enum::NEG}}); + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::MapMsg se_msg{}; + SetMapMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + // It's okay not to satisfy this. + // CHECK(st_ss == pb_ss); + CHECK(st_ss.size() == pb_ss.size()); + stpb::MapMsg dese_st{}; + iguana::from_pb(dese_st, pb_ss); + pb::MapMsg dese_msg; + dese_msg.ParseFromString(st_ss); + CheckMapMsg(dese_st, dese_msg); + } + { + // key empty + stpb::MapMsg se_st{}; + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{30}, ""); + se_st.str_iguana_type_msg_map.emplace( + "", stpb::IguanaTypeMsg{0, {0}, {0}, {0}, {0}, {0}, {0}}); + se_st.int_repeat_base_msg_map.emplace( + 3, stpb::RepeatBaseTypeMsg{0, {}, {}, {}, {}, {}, {}, {}, {}}); + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::MapMsg se_msg{}; + SetMapMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::MapMsg dese_st{}; + iguana::from_pb(dese_st, pb_ss); + pb::MapMsg dese_msg; + dese_msg.ParseFromString(st_ss); + CheckMapMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test BaseOneofMsg") { + { // test double + stpb::BaseOneofMsg se_st{0, 123, 3.14159, 456.78}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + // print_hex_str(st_ss); + // print_hex_str(pb_ss); + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } + { // test string + stpb::BaseOneofMsg se_st{0, 123, std::string("Hello"), 456.78}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } + { // test BaseTypeMsg + stpb::BaseTypeMsg baseTypeMsg{0, 100, 200, 300, 400, + 31.4f, 62.8, false, "World", stpb::Enum::BAZ}; + stpb::BaseOneofMsg se_st{0, 123, baseTypeMsg, 456.78}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } + { // test empty variant + stpb::BaseOneofMsg se_st{0, 123, {}, 456.78}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + print_hex_str(st_ss); + print_hex_str(pb_ss); + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test NestOneofMsg ") { + { // Test BaseOneofMsg + stpb::BaseOneofMsg baseOneof{0, 123, std::string("Hello"), 456.78}; + stpb::NestOneofMsg se_st{{baseOneof}}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::NestOneofMsg se_msg; + SetNestOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + stpb::NestOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::NestOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckNestOneofMsg(dese_st, dese_msg); + } +} +#endif + +struct point_t PUBLIC { + int x; + double y; +}; +REFLECTION(point_t, x, y); + +namespace my_space { +struct inner_struct PUBLIC { + int x; + int y; + int z; +}; + +constexpr inline auto get_members_impl(inner_struct *) { + return std::make_tuple(iguana::field_t{&inner_struct::x, 7, "a"}, + iguana::field_t{&inner_struct::y, 9, "b"}, + iguana::field_t{&inner_struct::z, 12, "c"}); +} +} // namespace my_space + +struct test_pb_st1 PUBLIC { + int x; + iguana::sint32_t y; + iguana::sint64_t z; +}; +REFLECTION(test_pb_st1, x, y, z); + +struct test_pb_st2 PUBLIC { + int x; + iguana::fixed32_t y; + iguana::fixed64_t z; +}; +REFLECTION(test_pb_st2, x, y, z); + +struct test_pb_st3 PUBLIC { + int x; + iguana::sfixed32_t y; + iguana::sfixed64_t z; +}; +REFLECTION(test_pb_st3, x, y, z); + +struct test_pb_st4 PUBLIC { + int x; + std::string y; +}; +REFLECTION(test_pb_st4, x, y); + +struct test_pb_st5 PUBLIC { + int x; + std::string_view y; +}; +REFLECTION(test_pb_st5, x, y); + +struct test_pb_st6 PUBLIC { + std::optional x; + std::optional y; +}; +REFLECTION(test_pb_st6, x, y); + +struct pair_t PUBLIC { + int x; + int y; +}; +REFLECTION(pair_t, x, y); + +struct message_t PUBLIC { + int id; + pair_t t; +}; +REFLECTION(message_t, id, t); + +struct test_pb_st8 PUBLIC { + int x; + pair_t y; + message_t z; +}; +REFLECTION(test_pb_st8, x, y, z); + +struct test_pb_st9 PUBLIC { + int x; + std::vector y; + std::string z; +}; +REFLECTION(test_pb_st9, x, y, z); + +struct test_pb_st10 PUBLIC { + int x; + std::vector y; + std::string z; +}; +REFLECTION(test_pb_st10, x, y, z); + +struct test_pb_st11 PUBLIC { + int x; + std::vector> y; + std::vector z; +}; +REFLECTION(test_pb_st11, x, y, z); + +struct test_pb_st12 PUBLIC { + int x; + std::map y; + std::map z; +}; +REFLECTION(test_pb_st12, x, y, z); + +struct test_pb_st13 PUBLIC { + int x; + std::map y; + std::string z; +}; +REFLECTION(test_pb_st13, x, y, z); + +enum class colors_t { red, black }; + +enum level_t { debug, info }; + +struct test_pb_st14 PUBLIC { + int x; + colors_t y; + level_t z; +}; +REFLECTION(test_pb_st14, x, y, z); + +namespace client { +struct person PUBLIC { + std::string name; + int64_t age; +}; + +REFLECTION(person, name, age); +} // namespace client + +struct my_struct PUBLIC { + int x; + bool y; + iguana::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest1 PUBLIC { + std::string name; + my_struct value; + int var; +}; + +REFLECTION(nest1, name, value, var); + +struct numer_st PUBLIC { + bool a; + double b; + float c; +}; +REFLECTION(numer_st, a, b, c); + +TEST_CASE("test struct_pb") { + { + my_space::inner_struct inner{0, 41, 42, 43}; + + std::string str; + iguana::to_pb(inner, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(inner)); + + my_space::inner_struct inner1; + iguana::from_pb(inner1, str); + CHECK(inner.x == inner1.x); + CHECK(inner.y == inner1.y); + CHECK(inner.z == inner1.z); + } + + { + test_pb_st1 st1{0, 41, {42}, {43}}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st1 st2; + iguana::from_pb(st2, str); + CHECK(st1.x == st2.x); + CHECK(st1.y.val == st2.y.val); + CHECK(st1.z.val == st2.z.val); + } + + { + test_pb_st2 st1{0, 41, {42}, {43}}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st2 st2; + iguana::from_pb(st2, str); + CHECK(st1.y.val == st2.y.val); + } + { + test_pb_st3 st1{0, 41, {42}, {43}}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st3 st2; + iguana::from_pb(st2, str); + CHECK(st1.y.val == st2.y.val); + } + { + test_pb_st4 st1{0, 41, "it is a test"}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st4 st2; + iguana::from_pb(st2, str); + CHECK(st1.y == st2.y); + } + + { + test_pb_st5 st1{0, 41, "it is a test"}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st5 st2; + iguana::from_pb(st2, str); + CHECK(st1.y == st2.y); + } + { + // optional + test_pb_st6 st1{0, 41, "it is a test"}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st6 st2; + iguana::from_pb(st2, str); + CHECK(st1.y == st2.y); + } + { + // sub nested objects + nest1 v{0, "Hi", {0, 1, false, {3}}, 5}, v2{}; + std::string s; + iguana::to_pb(v, s); + iguana::from_pb(v2, s); + CHECK(v.var == v2.var); + CHECK(v.value.y == v2.value.y); + CHECK(v.value.z == v2.value.z); + + test_pb_st8 st1{0, 1, {0, 3, 4}, {0, 5, {0, 7, 8}}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st8 st2; + iguana::from_pb(st2, str); + CHECK(st1.z.t.y == st2.z.t.y); + } + + { + // repeated messages + test_pb_st9 st1{0, 1, {2, 4, 6}, "test"}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st9 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + test_pb_st10 st1{0, 1, {{0, 5, {7, 8}}, {0, 9, {11, 12}}}, "test"}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st10 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + message_t m{0, 1, {0, 3, 4}}; + test_pb_st11 st1{0, 1, {m}, {}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st11 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + message_t st1{}; + std::string str; + iguana::to_pb(st1, str); + + message_t st2{}; + iguana::from_pb(st2, str); + CHECK(st1.id == st2.id); + } + { + test_pb_st11 st1{0, 1, {{{0, 5, {7, 8}}}, {{0, 9, {11, 12}}}}, {"test"}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st11 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st12 st1{0, 1, {{1, "test"}, {2, "ok"}}, {{"test", 4}, {"ok", 6}}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st12 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st12 st1{0, 1, {{1, ""}, {0, "ok"}}, {{"", 4}, {"ok", 0}}}; + std::string str; + iguana::to_pb(st1, str); // error + print_hex_str(str); + test_pb_st12 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st13 st1; + st1.x = 1; + st1.y.emplace(1, message_t{0, 2, {0, 3, 4}}); + st1.y.emplace(2, message_t{0, 4, {0, 6, 8}}); + st1.z = "test"; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st13 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st13 st1; + st1.x = 1; + st1.y.emplace(2, message_t{}); + st1.y.emplace(3, message_t{}); + st1.z = "test"; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st13 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // enum + test_pb_st14 st1{0, 1, colors_t::black, level_t::info}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st14 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // bool float double + numer_st n{0, true, 10.25, 4.578}, n1; + std::string str; + iguana::to_pb(n, str); + + iguana::from_pb(n1, str); + CHECK(n1.a == n.a); + CHECK(n1.b == n.b); + CHECK(n1.c == n.c); + } +} + +TEST_CASE("test members") { + using namespace iguana; + using namespace iguana::detail; + + my_space::inner_struct inner{0, 41, 42, 43}; + const auto &map = iguana::get_members(); + std::visit( + [&inner](auto &member) mutable { + CHECK(member.field_no == 9); + CHECK(member.field_name == "b"); + CHECK(member.value(inner) == 42); + }, + map.at(9)); + + point_t pt{0, 2, 3}; + const auto &arr1 = iguana::get_members(); + auto &val = arr1.at(1); + std::visit( + [&pt](auto &member) mutable { + CHECK(member.field_no == 1); + CHECK(member.field_name == "x"); + CHECK(member.value(pt) == 2); + }, + val); +} + +struct test_variant PUBLIC { + int x; + std::variant y; + double z; +}; +REFLECTION(test_variant, x, y, z); + +TEST_CASE("test variant") { + { + constexpr auto tp = iguana::get_members_tuple(); + static_assert(std::get<0>(tp).field_no == 1); + static_assert(std::get<1>(tp).field_no == 2); + static_assert(std::get<2>(tp).field_no == 3); + static_assert(std::get<3>(tp).field_no == 4); + static_assert(std::get<4>(tp).field_no == 5); + } + { + constexpr static auto map = iguana::get_members(); + static_assert(map.find(1) != map.end()); + static_assert(map.find(2) != map.end()); + static_assert(map.find(3) != map.end()); + static_assert(map.find(4) != map.end()); + auto val1 = map.find(2); + auto val2 = map.find(3); + std::visit( + [](auto &member) mutable { + CHECK(member.field_no == 2); + CHECK(member.field_name == "y"); + }, + val1->second); + std::visit( + [](auto &member) mutable { + CHECK(member.field_no == 3); + CHECK(member.field_name == "y"); + }, + val2->second); + } + { + test_variant st1 = {0, 5, "Hello, variant!", 3.14}; + std::string str; + iguana::to_pb(st1, str); + test_variant st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + CHECK(std::get(st2.y) == "Hello, variant!"); + } + { + test_variant st1 = {0, 5, 3.88, 3.14}; + std::string str; + iguana::to_pb(st1, str); + test_variant st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + CHECK(std::get(st2.y) == 3.88); + } +} + +// doctest comments +// 'function' : must be 'attribute' - see issue #182 +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) +int main(int argc, char **argv) { return doctest::Context(argc, argv).run(); } +DOCTEST_MSVC_SUPPRESS_WARNING_POP \ No newline at end of file diff --git a/src/struct_pb/tests/unittest_proto3.h b/src/struct_pb/tests/unittest_proto3.h new file mode 100644 index 000000000..3dc104322 --- /dev/null +++ b/src/struct_pb/tests/unittest_proto3.h @@ -0,0 +1,582 @@ +#pragma once + +#include +#include "unittest_proto3.pb.h" +#include "data_def.pb.h" + +#define PUBLIC : iguana::pb_base + +// define the struct as msg in proto +namespace stpb { +enum class Enum { + ZERO = 0, + FOO = 1, + BAR = 2, + BAZ = 123456, + NEG = -1, // Intentionally negative. +}; + +struct BaseTypeMsg PUBLIC { + int32_t optional_int32; + int64_t optional_int64; + uint32_t optional_uint32; + uint64_t optional_uint64; + float optional_float; + double optional_double; + bool optional_bool; + std::string optional_string; + Enum optional_enum; + bool operator==(const BaseTypeMsg& other) const { + return optional_int32 == other.optional_int32 && + optional_int64 == other.optional_int64 && + optional_uint32 == other.optional_uint32 && + optional_uint64 == other.optional_uint64 && + optional_float == other.optional_float && + optional_double == other.optional_double && + optional_bool == other.optional_bool && + optional_string == other.optional_string && + optional_enum == other.optional_enum; + } +}; +REFLECTION(BaseTypeMsg, optional_int32, optional_int64, optional_uint32, + optional_uint64, optional_float, optional_double, optional_bool, + optional_string, optional_enum); + +struct IguanaTypeMsg PUBLIC { + iguana::sint32_t optional_sint32; + iguana::sint64_t optional_sint64; + iguana::fixed32_t optional_fixed32; + iguana::fixed64_t optional_fixed64; + iguana::sfixed32_t optional_sfixed32; + iguana::sfixed64_t optional_sfixed64; + + bool operator==(const IguanaTypeMsg& other) const { + return optional_sint32 == other.optional_sint32 && + optional_sint64 == other.optional_sint64 && + optional_fixed32 == other.optional_fixed32 && + optional_fixed64 == other.optional_fixed64 && + optional_sfixed32 == other.optional_sfixed32 && + optional_sfixed64 == other.optional_sfixed64; + } +}; +REFLECTION(IguanaTypeMsg, optional_sint32, optional_sint64, optional_fixed32, + optional_fixed64, optional_sfixed32, optional_sfixed64); + +struct RepeatBaseTypeMsg PUBLIC { + std::vector repeated_uint32; + std::vector repeated_uint64; + std::vector repeated_int32; + std::vector repeated_int64; + std::vector repeated_float; + std::vector repeated_double; + std::vector repeated_string; + std::vector repeated_enum; +}; + +REFLECTION(RepeatBaseTypeMsg, repeated_uint32, repeated_uint64, repeated_int32, + repeated_int64, repeated_float, repeated_double, repeated_string, + repeated_enum); + +struct RepeatIguanaTypeMsg PUBLIC { + std::vector repeated_sint32; + std::vector repeated_sint64; + std::vector repeated_fixed32; + std::vector repeated_fixed64; + std::vector repeated_sfixed32; + std::vector repeated_sfixed64; +}; + +REFLECTION(RepeatIguanaTypeMsg, repeated_sint32, repeated_sint64, + repeated_fixed32, repeated_fixed64, repeated_sfixed32, + repeated_sfixed64); + +struct NestedMsg PUBLIC { + BaseTypeMsg base_msg; + std::vector repeat_base_msg; + IguanaTypeMsg iguana_type_msg; + std::vector repeat_iguna_msg; + std::vector repeat_repeat_base_msg; +}; +REFLECTION(NestedMsg, base_msg, repeat_base_msg, iguana_type_msg, + repeat_iguna_msg, repeat_repeat_base_msg); + +struct MapMsg PUBLIC { + std::unordered_map sfix64_str_map{}; + std::unordered_map str_iguana_type_msg_map{}; + std::map int_repeat_base_msg_map{}; +}; +REFLECTION(MapMsg, sfix64_str_map, str_iguana_type_msg_map, + int_repeat_base_msg_map); + +struct BaseOneofMsg PUBLIC { + int32_t optional_int32; + std::variant one_of; + double optional_double; +}; +REFLECTION(BaseOneofMsg, optional_int32, one_of, optional_double); + +struct NestOneofMsg PUBLIC { + std::variant nest_one_of_msg; +}; +REFLECTION(NestOneofMsg, nest_one_of_msg); + +struct simple_t PUBLIC { + int32_t a; + int32_t b; + int64_t c; + int64_t d; + std::string_view str; +}; +REFLECTION(simple_t, a, b, c, d, str); + +struct simple_t1 PUBLIC { + int32_t a; + int32_t b; + int64_t c; + int64_t d; + std::string_view str; +}; +REFLECTION(simple_t1, a, b, c, d, str); + +enum Color : uint8_t { Red, Green, Blue }; + +struct simple_t2 PUBLIC { + int16_t a; + uint8_t b; + Color c; + int64_t d; + std::string_view str; +}; +REFLECTION(simple_t2, a, b, c, d, str); + +struct person PUBLIC { + int32_t id; + std::string name; + int age; + double salary; +}; +REFLECTION(person, id, name, age, salary); + +struct rect PUBLIC { + int32_t x = 1; + int32_t y = 0; + int32_t width = 11; + int32_t height = 1; +}; +REFLECTION(rect, x, y, width, height); + +struct Vec3 PUBLIC { + float x; + float y; + float z; + + REFLECTION(Vec3, x, y, z); +}; + +struct Weapon PUBLIC { + std::string name; + int32_t damage; +}; +REFLECTION(Weapon, name, damage); + +struct Monster PUBLIC { + Vec3 pos; + int32_t mana; + int32_t hp; + std::string name; + std::string inventory; + int32_t color; + std::vector weapons; + Weapon equipped; + std::vector path; +}; +REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, + path); + +struct bench_int32 PUBLIC { + int32_t a; + int32_t b; + int32_t c; + int32_t d; +}; +REFLECTION(bench_int32, a, b, c, d); + +} // namespace stpb + +namespace protobuf_sample { +inline mygame::person create_person() { + mygame::person p; + p.set_id(432798); + p.set_name(std::string(1024, 'A')); + p.set_age(24); + p.set_salary(65536.42); + return p; +} + +inline mygame::Monster create_monster() { + mygame::Monster m; + + auto vec = new mygame::Vec3; + vec->set_x(1); + vec->set_y(2); + vec->set_z(3); + m.set_allocated_pos(vec); + m.set_mana(16); + m.set_hp(24); + m.set_name("it is a test"); + m.set_inventory("\1\2\3\4"); + m.set_color(::mygame::Monster_Color::Monster_Color_Red); + auto w1 = m.add_weapons(); + w1->set_name("gun"); + w1->set_damage(42); + auto w2 = m.add_weapons(); + w2->set_name("shotgun"); + w2->set_damage(56); + auto w3 = new mygame::Weapon; + w3->set_name("air craft"); + w3->set_damage(67); + m.set_allocated_equipped(w3); + auto p1 = m.add_path(); + p1->set_x(7); + p1->set_y(8); + p1->set_z(9); + auto p2 = m.add_path(); + p2->set_x(71); + p2->set_y(81); + p2->set_z(91); + + return m; +} +} // namespace protobuf_sample + +inline auto create_person() { + stpb::person p{0, 432798, std::string(1024, 'A'), 24, 65536.42}; + return p; +} + +inline stpb::Monster create_sp_monster() { + stpb::Monster m = { + 0, + {0, 1, 2, 3}, + 16, + 24, + "it is a test", + "\1\2\3\4", + stpb::Color::Red, + {{0, "gun", 42}, {0, "shotgun", 56}}, + {0, "air craft", 67}, + {{0, 7, 8, 9}, {0, 71, 81, 91}}, + }; + return m; +} + +void SetBaseTypeMsg(const stpb::BaseTypeMsg& st, pb::BaseTypeMsg& msg) { + msg.set_optional_int32(st.optional_int32); + msg.set_optional_int64(st.optional_int64); + msg.set_optional_uint32(st.optional_uint32); + msg.set_optional_uint64(st.optional_uint64); + msg.set_optional_float(st.optional_float); + msg.set_optional_double(st.optional_double); + msg.set_optional_bool(st.optional_bool); + msg.set_optional_string(st.optional_string); + msg.set_optional_enum(static_cast(st.optional_enum)); +} + +void CheckBaseTypeMsg(const stpb::BaseTypeMsg& st, const pb::BaseTypeMsg& msg) { + CHECK(st.optional_int32 == msg.optional_int32()); + CHECK(st.optional_int64 == msg.optional_int64()); + CHECK(st.optional_uint32 == msg.optional_uint32()); + CHECK(st.optional_uint64 == msg.optional_uint64()); + CHECK(st.optional_float == msg.optional_float()); + CHECK(st.optional_double == msg.optional_double()); + CHECK(st.optional_bool == msg.optional_bool()); + CHECK(st.optional_string == msg.optional_string()); + CHECK(static_cast(st.optional_enum) == + static_cast(msg.optional_enum())); +} + +void SetIguanaTypeMsg(const stpb::IguanaTypeMsg& st, pb::IguanaTypeMsg& msg) { + msg.set_optional_sint32(st.optional_sint32.val); + msg.set_optional_sint64(st.optional_sint64.val); + msg.set_optional_fixed32(st.optional_fixed32.val); + msg.set_optional_fixed64(st.optional_fixed64.val); + msg.set_optional_sfixed32(st.optional_sfixed32.val); + msg.set_optional_sfixed64(st.optional_sfixed64.val); +} + +void CheckIguanaTypeMsg(const stpb::IguanaTypeMsg& st, + const pb::IguanaTypeMsg& msg) { + CHECK(st.optional_sint32.val == msg.optional_sint32()); + CHECK(st.optional_sint64.val == msg.optional_sint64()); + CHECK(st.optional_fixed32.val == msg.optional_fixed32()); + CHECK(st.optional_fixed64.val == msg.optional_fixed64()); + CHECK(st.optional_sfixed32.val == msg.optional_sfixed32()); + CHECK(st.optional_sfixed64.val == msg.optional_sfixed64()); +} + +void SetRepeatBaseTypeMsg(const stpb::RepeatBaseTypeMsg& st, + pb::RepeatBaseTypeMsg& msg) { + for (auto v : st.repeated_uint32) { + msg.add_repeated_uint32(v); + } + for (auto v : st.repeated_uint64) { + msg.add_repeated_uint64(v); + } + for (auto v : st.repeated_int32) { + msg.add_repeated_int32(v); + } + for (auto v : st.repeated_int64) { + msg.add_repeated_int64(v); + } + for (auto v : st.repeated_float) { + msg.add_repeated_float(v); + } + for (auto v : st.repeated_double) { + msg.add_repeated_double(v); + } + for (auto v : st.repeated_string) { + msg.add_repeated_string(v); + } + for (auto v : st.repeated_enum) { + msg.add_repeated_enum(static_cast(v)); + } +} + +void CheckRepeatBaseTypeMsg(const stpb::RepeatBaseTypeMsg& st, + const pb::RepeatBaseTypeMsg& msg) { + for (size_t i = 0; i < st.repeated_uint32.size(); ++i) { + CHECK(st.repeated_uint32[i] == msg.repeated_uint32(i)); + } + for (size_t i = 0; i < st.repeated_uint64.size(); ++i) { + CHECK(st.repeated_uint64[i] == msg.repeated_uint64(i)); + } + for (size_t i = 0; i < st.repeated_int32.size(); ++i) { + CHECK(st.repeated_int32[i] == msg.repeated_int32(i)); + } + for (size_t i = 0; i < st.repeated_int64.size(); ++i) { + CHECK(st.repeated_int64[i] == msg.repeated_int64(i)); + } + for (size_t i = 0; i < st.repeated_float.size(); ++i) { + CHECK(st.repeated_float[i] == msg.repeated_float(i)); + } + for (size_t i = 0; i < st.repeated_double.size(); ++i) { + CHECK(st.repeated_double[i] == msg.repeated_double(i)); + } + for (size_t i = 0; i < st.repeated_string.size(); ++i) { + CHECK(st.repeated_string[i] == msg.repeated_string(i)); + } + for (size_t i = 0; i < st.repeated_enum.size(); ++i) { + CHECK(static_cast(st.repeated_enum[i]) == + static_cast(msg.repeated_enum(i))); + } +} + +void SetRepeatIguanaTypeMsg(const stpb::RepeatIguanaTypeMsg& st, + pb::RepeatIguanaTypeMsg& msg) { + for (auto v : st.repeated_sint32) { + msg.add_repeated_sint32(v.val); + } + for (auto v : st.repeated_sint64) { + msg.add_repeated_sint64(v.val); + } + for (auto v : st.repeated_fixed32) { + msg.add_repeated_fixed32(v.val); + } + for (auto v : st.repeated_fixed64) { + msg.add_repeated_fixed64(v.val); + } + for (auto v : st.repeated_sfixed32) { + msg.add_repeated_sfixed32(v.val); + } + for (auto v : st.repeated_sfixed64) { + msg.add_repeated_sfixed64(v.val); + } +} + +void CheckRepeatIguanaTypeMsg(const stpb::RepeatIguanaTypeMsg& st, + const pb::RepeatIguanaTypeMsg& msg) { + for (size_t i = 0; i < st.repeated_sint32.size(); ++i) { + CHECK(st.repeated_sint32[i].val == msg.repeated_sint32(i)); + } + for (size_t i = 0; i < st.repeated_sint64.size(); ++i) { + CHECK(st.repeated_sint64[i].val == msg.repeated_sint64(i)); + } + for (size_t i = 0; i < st.repeated_fixed32.size(); ++i) { + CHECK(st.repeated_fixed32[i].val == msg.repeated_fixed32(i)); + } + for (size_t i = 0; i < st.repeated_fixed64.size(); ++i) { + CHECK(st.repeated_fixed64[i].val == msg.repeated_fixed64(i)); + } + for (size_t i = 0; i < st.repeated_sfixed32.size(); ++i) { + CHECK(st.repeated_sfixed32[i].val == msg.repeated_sfixed32(i)); + } + for (size_t i = 0; i < st.repeated_sfixed64.size(); ++i) { + CHECK(st.repeated_sfixed64[i].val == msg.repeated_sfixed64(i)); + } +} + +void SetNestedMsg(const stpb::NestedMsg& st, pb::NestedMsg& msg) { + SetBaseTypeMsg(st.base_msg, *msg.mutable_base_msg()); + + for (const auto& base_msg : st.repeat_base_msg) { + auto* base_msg_ptr = msg.add_repeat_base_msg(); + SetBaseTypeMsg(base_msg, *base_msg_ptr); + } + + SetIguanaTypeMsg(st.iguana_type_msg, *msg.mutable_iguana_type_msg()); + + for (const auto& iguana_type_msg : st.repeat_iguna_msg) { + auto* iguana_type_msg_ptr = msg.add_repeat_iguna_msg(); + SetIguanaTypeMsg(iguana_type_msg, *iguana_type_msg_ptr); + } + + for (const auto& repeat_base_msg : st.repeat_repeat_base_msg) { + auto* repeat_base_msg_ptr = msg.add_repeat_repeat_base_msg(); + SetRepeatBaseTypeMsg(repeat_base_msg, *repeat_base_msg_ptr); + } +} + +void CheckNestedMsg(const stpb::NestedMsg& st, const pb::NestedMsg& msg) { + CheckBaseTypeMsg(st.base_msg, msg.base_msg()); + + CHECK(st.repeat_base_msg.size() == msg.repeat_base_msg_size()); + for (size_t i = 0; i < st.repeat_base_msg.size(); ++i) { + CheckBaseTypeMsg(st.repeat_base_msg[i], msg.repeat_base_msg(i)); + } + + CheckIguanaTypeMsg(st.iguana_type_msg, msg.iguana_type_msg()); + + CHECK(st.repeat_iguna_msg.size() == msg.repeat_iguna_msg_size()); + for (size_t i = 0; i < st.repeat_iguna_msg.size(); ++i) { + CheckIguanaTypeMsg(st.repeat_iguna_msg[i], msg.repeat_iguna_msg(i)); + } + + CHECK(st.repeat_repeat_base_msg.size() == + msg.repeat_repeat_base_msg_size()); + for (size_t i = 0; i < st.repeat_repeat_base_msg.size(); ++i) { + CheckRepeatBaseTypeMsg(st.repeat_repeat_base_msg[i], + msg.repeat_repeat_base_msg(i)); + } +} + +void SetMapMsg(const stpb::MapMsg& st, pb::MapMsg& msg) { + msg.Clear(); + for (const auto& pair : st.sfix64_str_map) { + (*msg.mutable_sfix64_str_map())[pair.first.val] = pair.second; + } + for (const auto& pair : st.str_iguana_type_msg_map) { + pb::IguanaTypeMsg* it_msg = + &((*msg.mutable_str_iguana_type_msg_map())[pair.first]); + SetIguanaTypeMsg(pair.second, *it_msg); + } + for (const auto& pair : st.int_repeat_base_msg_map) { + pb::RepeatBaseTypeMsg* rb_msg = + &((*msg.mutable_int_repeat_base_msg_map())[pair.first]); + SetRepeatBaseTypeMsg(pair.second, *rb_msg); + } +} + +void CheckMapMsg(const stpb::MapMsg& st, const pb::MapMsg& msg) { + CHECK(msg.sfix64_str_map_size() == st.sfix64_str_map.size()); + for (const auto& pair : st.sfix64_str_map) { + auto it = msg.sfix64_str_map().find(pair.first.val); + CHECK(it != msg.sfix64_str_map().end()); + CHECK(it->second == pair.second); + } + CHECK(msg.str_iguana_type_msg_map_size() == + st.str_iguana_type_msg_map.size()); + for (const auto& pair : st.str_iguana_type_msg_map) { + auto it = msg.str_iguana_type_msg_map().find(pair.first); + CHECK(it != msg.str_iguana_type_msg_map().end()); + CheckIguanaTypeMsg(pair.second, it->second); + } + + CHECK(msg.int_repeat_base_msg_map_size() == + st.int_repeat_base_msg_map.size()); + for (const auto& pair : st.int_repeat_base_msg_map) { + auto it = msg.int_repeat_base_msg_map().find(pair.first); + CHECK(it != msg.int_repeat_base_msg_map().end()); + CheckRepeatBaseTypeMsg(pair.second, it->second); + } +} + +void SetBaseOneofMsg(const stpb::BaseOneofMsg& st, pb::BaseOneofMsg& msg) { + msg.set_optional_int32(st.optional_int32); + msg.set_optional_double(st.optional_double); + + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + msg.set_one_of_double(value); + } + else if constexpr (std::is_same_v) { + msg.set_one_of_string(value); + } + else if constexpr (std::is_same_v) { + auto* submsg = msg.mutable_one_of_base_type_msg(); + SetBaseTypeMsg(value, *submsg); + } + }, + st.one_of); +} + +void CheckBaseOneofMsg(const stpb::BaseOneofMsg& st, + const pb::BaseOneofMsg& msg) { + CHECK(st.optional_int32 == msg.optional_int32()); + CHECK(st.optional_double == msg.optional_double()); + + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + CHECK(value == msg.one_of_double()); + } + else if constexpr (std::is_same_v) { + CHECK(value == msg.one_of_string()); + } + else if constexpr (std::is_same_v) { + CheckBaseTypeMsg(value, msg.one_of_base_type_msg()); + } + }, + st.one_of); +} + +void SetNestOneofMsg(const stpb::NestOneofMsg& st, pb::NestOneofMsg& msg) { + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + msg.set_base_one_of_string(value); + } + else if constexpr (std::is_same_v) { + auto* submsg = msg.mutable_base_one_of_msg(); + SetBaseOneofMsg(value, *submsg); + } + }, + st.nest_one_of_msg); +} + +void CheckNestOneofMsg(const stpb::NestOneofMsg& st, + const pb::NestOneofMsg& msg) { + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + CHECK(value == msg.base_one_of_string()); + } + else if constexpr (std::is_same_v) { + CheckBaseOneofMsg(value, msg.base_one_of_msg()); + } + }, + st.nest_one_of_msg); +} + +inline void print_hex_str(const std::string& str) { + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + for (unsigned char c : str) { + oss << std::setw(2) << static_cast(c); + } + std::cout << oss.str() << std::endl; +} diff --git a/src/struct_pb/tests/unittest_proto3.proto b/src/struct_pb/tests/unittest_proto3.proto new file mode 100644 index 000000000..c736d6ef3 --- /dev/null +++ b/src/struct_pb/tests/unittest_proto3.proto @@ -0,0 +1,108 @@ +syntax = "proto3"; + +package pb; + +option optimize_for = SPEED; + +enum Enum { + ZERO = 0; + FOO = 1; + BAR = 2; + BAZ = 123456; + NEG = -1; // Intentionally negative. +} + +message BaseTypeMsg { + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + float optional_float = 5; + double optional_double = 6; + bool optional_bool = 7; + string optional_string = 8; + Enum optional_enum = 9; +} + +message RepeatBaseTypeMsg { + repeated uint32 repeated_uint32 = 1; + repeated uint64 repeated_uint64 = 2; + repeated int32 repeated_int32 = 3; + repeated int64 repeated_int64 = 4; + repeated float repeated_float = 5; + repeated double repeated_double = 6; + repeated string repeated_string = 7; + repeated Enum repeated_enum = 8; +} + +message IguanaTypeMsg { + sint32 optional_sint32 = 1; + sint64 optional_sint64 = 2; + fixed32 optional_fixed32 = 3; + fixed64 optional_fixed64 = 4; + sfixed32 optional_sfixed32 = 5; + sfixed64 optional_sfixed64 = 6; +} + +message RepeatIguanaTypeMsg { + repeated sfixed32 repeated_sint32 = 1; + repeated sfixed64 repeated_sint64 = 2; + repeated fixed32 repeated_fixed32 = 3; + repeated fixed64 repeated_fixed64 = 4; + repeated sfixed32 repeated_sfixed32 = 5; + repeated sfixed64 repeated_sfixed64 = 6; +} + +message NestedMsg { + BaseTypeMsg base_msg = 1; + repeated BaseTypeMsg repeat_base_msg = 2; + IguanaTypeMsg iguana_type_msg = 3; + repeated IguanaTypeMsg repeat_iguna_msg = 4; + repeated RepeatBaseTypeMsg repeat_repeat_base_msg = 5; +} + +message MapMsg { + map sfix64_str_map = 1; + map str_iguana_type_msg_map = 2; + map int_repeat_base_msg_map = 3; + // Key in map fields cannot be float/double, bytes or message types. +} + +message BaseOneofMsg { + int32 optional_int32 = 1; + oneof one_of { + double one_of_double = 2; + string one_of_string = 3; + BaseTypeMsg one_of_base_type_msg = 4; + } + double optional_double = 5; +} + +message NestOneofMsg { + oneof nest_one_of_msg { + string base_one_of_string = 1; + BaseOneofMsg base_one_of_msg = 2; + } +} + +message Simple { + int32 a = 1; + int32 b = 2; + int64 c = 3; + int64 d = 4; + string str = 5; +} + +enum Color { + Red = 0; + Green = 1; + Blue = 2; +} + +message Simple2 { + int32 a = 1; + int32 b = 2; + Color c = 3; + int64 d = 4; + string str = 5; +} \ No newline at end of file