/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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 * * http://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 #include #include #include #include FATAL_S(struct1s, "struct1"); FATAL_S(field0s, "field0"); FATAL_S(field1s, "field1"); FATAL_S(field2s, "field2"); FATAL_S(field3s, "field3"); FATAL_S(field4s, "field4"); FATAL_S(field5s, "field5"); FATAL_S(fieldAs, "fieldA"); FATAL_S(fieldBs, "fieldB"); FATAL_S(fieldCs, "fieldC"); FATAL_S(fieldDs, "fieldD"); FATAL_S(fieldEs, "fieldE"); FATAL_S(fieldFs, "fieldF"); FATAL_S(fieldGs, "fieldG"); template using field_id = std::integral_constant; template using required = std::integral_constant; namespace test_cpp2 { namespace cpp_reflection { using apache::thrift::detail::st::IsThriftClass; using apache::thrift::detail::st::IsThriftUnion; static_assert(IsThriftClass::value); static_assert(IsThriftClass::value); static_assert(IsThriftClass::value); static_assert(IsThriftClass::value); static_assert(IsThriftClass::value); static_assert(IsThriftClass::value); static_assert(!IsThriftClass::value); static_assert(!IsThriftClass::value); static_assert(!IsThriftClass::value); static_assert(IsThriftUnion::value); static_assert(IsThriftUnion::value); static_assert(IsThriftUnion::value); static_assert(!IsThriftUnion::value); static_assert(!IsThriftUnion::value); static_assert(!IsThriftUnion::value); static_assert(!IsThriftUnion::value); static_assert(!IsThriftUnion::value); static_assert(!IsThriftUnion::value); TEST(fatal_struct, struct1_sanity_check) { using traits = apache::thrift::reflect_struct; EXPECT_SAME(); EXPECT_SAME(); EXPECT_SAME(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME(); EXPECT_SAME(); EXPECT_SAME(); EXPECT_SAME(); EXPECT_SAME(); EXPECT_SAME(); struct1 pod; *pod.field0() = 19; pod.field1() = "hello"; *pod.field2() = enum1::field2; *pod.field3() = enum2::field1_2; pod.field4() = {}; pod.field4()->set_ud(5.6); pod.field5()->set_us_2("world"); EXPECT_EQ(*pod.field0(), traits::member::field0::getter{}(pod)); EXPECT_EQ(*pod.field1(), traits::member::field1::getter{}(pod)); EXPECT_EQ(*pod.field2(), traits::member::field2::getter{}(pod)); EXPECT_EQ(*pod.field3(), traits::member::field3::getter{}(pod)); EXPECT_EQ(*pod.field4(), traits::member::field4::getter{}(pod)); EXPECT_EQ(*pod.field5(), traits::member::field5::getter{}(pod)); traits::member::field0::getter{}(pod) = 98; EXPECT_EQ(98, *pod.field0()); traits::member::field1::getter{}(pod) = "test"; EXPECT_EQ("test", *pod.field1()); traits::member::field2::getter{}(pod) = enum1::field0; EXPECT_EQ(enum1::field0, *pod.field2()); traits::member::field3::getter{}(pod) = enum2::field2_2; EXPECT_EQ(enum2::field2_2, *pod.field3()); traits::member::field4::getter{}(pod).set_ui(56); EXPECT_EQ(union1::Type::ui, pod.field4()->getType()); EXPECT_EQ(56, pod.field4()->get_ui()); traits::member::field5::getter{}(pod).set_ue_2(enum1::field1); EXPECT_EQ(union2::Type::ue_2, pod.field5()->getType()); EXPECT_EQ(enum1::field1, pod.field5()->get_ue_2()); EXPECT_SAME< field0s, fatal::get::name>(); EXPECT_SAME< field1s, fatal::get::name>(); EXPECT_SAME< field2s, fatal::get::name>(); EXPECT_SAME< field3s, fatal::get::name>(); EXPECT_SAME< field4s, fatal::get::name>(); EXPECT_SAME< field5s, fatal::get::name>(); EXPECT_SAME< std::int32_t, fatal::get::type>(); EXPECT_SAME< std::string, fatal::get::type>(); EXPECT_SAME< enum1, fatal::get::type>(); EXPECT_SAME< enum2, fatal::get::type>(); EXPECT_SAME< union1, fatal::get::type>(); EXPECT_SAME< union2, fatal::get::type>(); EXPECT_SAME< field_id<1>, fatal::get::id>(); EXPECT_SAME< field_id<2>, fatal::get::id>(); EXPECT_SAME< field_id<4>, fatal::get::id>(); EXPECT_SAME< field_id<8>, fatal::get::id>(); EXPECT_SAME< field_id<16>, fatal::get::id>(); EXPECT_SAME< field_id<32>, fatal::get::id>(); EXPECT_SAME< required, fatal::get::optional>(); EXPECT_SAME< required, fatal::get::optional>(); EXPECT_SAME< required, fatal::get::optional>(); EXPECT_SAME< required, fatal::get::optional>(); EXPECT_SAME< required, fatal::get::optional>(); EXPECT_SAME< required, fatal::get::optional>(); EXPECT_EQ( 98, (fatal::get< traits::members, traits::member::field0::name, fatal::get_type::name>::getter{}(pod))); EXPECT_EQ( "test", (fatal::get< traits::members, traits::member::field1::name, fatal::get_type::name>::getter{}(pod))); EXPECT_EQ( enum1::field0, (fatal::get< traits::members, traits::member::field2::name, fatal::get_type::name>::getter{}(pod))); EXPECT_EQ( enum2::field2_2, (fatal::get< traits::members, traits::member::field3::name, fatal::get_type::name>::getter{}(pod))); EXPECT_EQ( union1::Type::ui, (fatal::get< traits::members, traits::member::field4::name, fatal::get_type::name>::getter{}(pod) .getType())); EXPECT_EQ( 56, (fatal::get< traits::members, traits::member::field4::name, fatal::get_type::name>::getter{}(pod) .get_ui())); EXPECT_EQ( union2::Type::ue_2, (fatal::get< traits::members, traits::member::field5::name, fatal::get_type::name>::getter{}(pod) .getType())); EXPECT_EQ( enum1::field1, (fatal::get< traits::members, traits::member::field5::name, fatal::get_type::name>::getter{}(pod) .get_ue_2())); EXPECT_SAME< apache::thrift::type_class::integral, fatal::get:: type_class>(); EXPECT_SAME< apache::thrift::type_class::string, fatal::get:: type_class>(); EXPECT_SAME< apache::thrift::type_class::enumeration, fatal::get:: type_class>(); EXPECT_SAME< apache::thrift::type_class::enumeration, fatal::get:: type_class>(); EXPECT_SAME< apache::thrift::type_class::variant, fatal::get:: type_class>(); EXPECT_SAME< apache::thrift::type_class::variant, fatal::get:: type_class>(); EXPECT_SAME< traits::member::field0, fatal::get< traits::members, traits::member::field0::name, fatal::get_type::name>>(); EXPECT_SAME< traits::member::field1, fatal::get< traits::members, traits::member::field1::name, fatal::get_type::name>>(); EXPECT_SAME< traits::member::field2, fatal::get< traits::members, traits::member::field2::name, fatal::get_type::name>>(); EXPECT_SAME< traits::member::field3, fatal::get< traits::members, traits::member::field3::name, fatal::get_type::name>>(); EXPECT_SAME< traits::member::field4, fatal::get< traits::members, traits::member::field4::name, fatal::get_type::name>>(); EXPECT_SAME< traits::member::field5, fatal::get< traits::members, traits::member::field5::name, fatal::get_type::name>>(); } FATAL_S(structB_annotation1k, "multi_line_annotation"); FATAL_S(structB_annotation1v, "line one\nline two"); FATAL_S(structB_annotation2k, "some.annotation"); FATAL_S(structB_annotation2v, "this is its value"); FATAL_S(structB_annotation3k, "some.other.annotation"); FATAL_S(structB_annotation3v, "this is its other value"); FATAL_S(struct3_annotation1k, "thrift.uri"); FATAL_S( struct3_annotation1v, "facebook.com/thrift/test/reflection/reflection/struct3"); TEST(fatal_struct, annotations) { EXPECT_SAME< fatal::list<>, apache::thrift::reflect_struct::annotations::map>(); EXPECT_SAME< fatal::list<>, apache::thrift::reflect_struct::annotations::map>(); EXPECT_SAME< fatal::list>, apache::thrift::reflect_struct::annotations::map>(); EXPECT_SAME< fatal::list<>, apache::thrift::reflect_struct::annotations::map>(); using structB_annotations = apache::thrift::reflect_struct::annotations; EXPECT_SAME< structB_annotation1k, structB_annotations::keys::multi_line_annotation>(); EXPECT_SAME< structB_annotation1v, structB_annotations::values::multi_line_annotation>(); EXPECT_SAME< structB_annotation2k, structB_annotations::keys::some_annotation>(); EXPECT_SAME< structB_annotation2v, structB_annotations::values::some_annotation>(); EXPECT_SAME< structB_annotation3k, structB_annotations::keys::some_other_annotation>(); EXPECT_SAME< structB_annotation3v, structB_annotations::values::some_other_annotation>(); EXPECT_SAME< fatal::list< apache::thrift:: annotation, apache::thrift:: annotation, apache::thrift:: annotation>, structB_annotations::map>(); EXPECT_SAME< fatal::list<>, apache::thrift::reflect_struct::annotations::map>(); } FATAL_S(structBd_annotation1k, "another.annotation"); FATAL_S(structBd_annotation1v, "another value"); FATAL_S(structBd_annotation2k, "some.annotation"); FATAL_S(structBd_annotation2v, "some value"); TEST(fatal_struct, member_annotations) { using info = apache::thrift::reflect_struct; EXPECT_SAME, info::members_annotations::c::map>(); EXPECT_SAME< fatal::list<>, fatal::get:: annotations::map>(); using annotations_d = fatal::get:: annotations; using expected_d_map = fatal::list< apache::thrift::annotation, apache::thrift::annotation>; EXPECT_SAME(); EXPECT_SAME(); EXPECT_SAME< structBd_annotation1k, info::members_annotations::d::keys::another_annotation>(); EXPECT_SAME< structBd_annotation1v, info::members_annotations::d::values::another_annotation>(); EXPECT_SAME< structBd_annotation2k, info::members_annotations::d::keys::some_annotation>(); EXPECT_SAME< structBd_annotation2v, info::members_annotations::d::values::some_annotation>(); EXPECT_SAME(); EXPECT_SAME< structBd_annotation1v, annotations_d::values::another_annotation>(); EXPECT_SAME(); EXPECT_SAME(); } FATAL_S(annotated_s_b_false, "s_b_false"); FATAL_S(annotated_s_b_true, "s_b_true"); FATAL_S(annotated_s_int, "s_int"); FATAL_S(annotated_s_string, "s_string"); FATAL_S(annotated_s_int_list, "s_int_list"); FATAL_S(annotated_s_str_list, "s_str_list"); FATAL_S(annotated_s_mixed_list, "s_mixed_list"); FATAL_S(annotated_s_int_map, "s_int_map"); FATAL_S(annotated_s_str_map, "s_str_map"); FATAL_S(annotated_s_mixed_map, "s_mixed_map"); FATAL_S(annotated_v_s_b_false, "false"); FATAL_S(annotated_v_s_b_true, "true"); FATAL_S(annotated_v_s_int, "10"); FATAL_S(annotated_v_s_string, "\"hello\""); FATAL_S(annotated_v_s_int_list, "[-1, 2, 3]"); FATAL_S(annotated_v_s_str_list, "[\"a\", \"b\", \"c\"]"); FATAL_S(annotated_v_s_mixed_list, "[\"a\", 1, \"b\", 2]"); FATAL_S(annotated_v_s_int_map, "{\"a\": 1, \"b\": -2, \"c\": -3}"); FATAL_S(annotated_v_s_str_map, "{\"a\": \"A\", \"b\": \"B\", \"c\": \"C\"}"); FATAL_S(annotated_v_s_mixed_map, "{\"a\": -2, \"b\": \"B\", \"c\": 3}"); TEST(fatal_struct, structured_annotations) { using info = apache::thrift::reflect_struct::annotations; using bf = apache::thrift::annotation; using bt = apache::thrift::annotation; using i = apache::thrift::annotation; using s = apache::thrift::annotation; using il = apache::thrift::annotation; using sl = apache::thrift::annotation; using ml = apache::thrift:: annotation; using im = apache::thrift::annotation; using sm = apache::thrift::annotation; using mm = apache::thrift:: annotation; EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME, info::map>(); } FATAL_S(annotated_m_b_false, "m_b_false"); FATAL_S(annotated_m_b_true, "m_b_true"); FATAL_S(annotated_m_int, "m_int"); FATAL_S(annotated_m_string, "m_string"); FATAL_S(annotated_m_int_list, "m_int_list"); FATAL_S(annotated_m_str_list, "m_str_list"); FATAL_S(annotated_m_mixed_list, "m_mixed_list"); FATAL_S(annotated_m_int_map, "m_int_map"); FATAL_S(annotated_m_str_map, "m_str_map"); FATAL_S(annotated_m_mixed_map, "m_mixed_map"); FATAL_S(annotated_v_m_b_false, "false"); FATAL_S(annotated_v_m_b_true, "true"); FATAL_S(annotated_v_m_int, "10"); FATAL_S(annotated_v_m_string, "\"hello\""); FATAL_S(annotated_v_m_int_list, "[-1, 2, 3]"); FATAL_S(annotated_v_m_str_list, "[\"a\", \"b\", \"c\"]"); FATAL_S(annotated_v_m_mixed_list, "[\"a\", 1, \"b\", 2]"); FATAL_S(annotated_v_m_int_map, "{\"a\": 1, \"b\": -2, \"c\": -3}"); FATAL_S(annotated_v_m_str_map, "{\"a\": \"A\", \"b\": \"B\", \"c\": \"C\"}"); FATAL_S(annotated_v_m_mixed_map, "{\"a\": -2, \"b\": \"B\", \"c\": 3}"); TEST(fatal_struct, structured_member_annotations) { using info = apache::thrift::reflect_struct::members_annotations::a; using bf = apache::thrift::annotation; using bt = apache::thrift::annotation; using i = apache::thrift::annotation; using s = apache::thrift::annotation; using il = apache::thrift::annotation; using sl = apache::thrift::annotation; using ml = apache::thrift:: annotation; using im = apache::thrift::annotation; using sm = apache::thrift::annotation; using mm = apache::thrift:: annotation; EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME>(); EXPECT_SAME, info::map>(); } TEST(fatal_struct, set_methods) { using info = apache::thrift::reflect_struct; using req_field = fatal:: get; using opt_field = fatal:: get; using def_field = fatal:: get; using ref_field = fatal:: get; struct4 a; EXPECT_TRUE(req_field::is_set(a)); EXPECT_TRUE(req_field::mark_set(a, true)); EXPECT_TRUE(req_field::is_set(a)); EXPECT_FALSE(req_field::mark_set(a, false)); EXPECT_TRUE(req_field::is_set(a)); EXPECT_FALSE(opt_field::is_set(a)); EXPECT_TRUE(opt_field::mark_set(a, true)); EXPECT_TRUE(opt_field::is_set(a)); EXPECT_FALSE(opt_field::mark_set(a, false)); EXPECT_FALSE(opt_field::is_set(a)); EXPECT_FALSE(def_field::is_set(a)); EXPECT_TRUE(def_field::mark_set(a, true)); EXPECT_TRUE(def_field::is_set(a)); EXPECT_FALSE(def_field::mark_set(a, false)); EXPECT_FALSE(def_field::is_set(a)); EXPECT_TRUE(ref_field::is_set(a)); EXPECT_TRUE(ref_field::mark_set(a, true)); } TEST(fatal_struct, field_ref_getter) { using info = apache::thrift::reflect_struct; using req_field = fatal:: get; using opt_field = fatal:: get; using def_field = fatal:: get; using ref_field = fatal:: get; struct4 a; req_field::field_ref_getter req; EXPECT_TRUE(req(a).has_value()); req(a) = 1; EXPECT_EQ(a.field0(), 1); a.field0() = 2; EXPECT_EQ(req(a), 2); static_assert( std::is_same< apache::thrift::required_field_ref, decltype(req(a))>::value, ""); opt_field::field_ref_getter opt; EXPECT_FALSE(opt(a)); opt(a) = "1"; EXPECT_EQ(a.field1(), "1"); a.field1() = "2"; EXPECT_EQ(opt(a), "2"); static_assert( std::is_same< apache::thrift::optional_field_ref, decltype(opt(a))>::value, ""); def_field::field_ref_getter def; EXPECT_FALSE(def(a).is_set()); def(a) = enum1::field1; EXPECT_EQ(a.field2(), enum1::field1); a.field2() = enum1::field2; EXPECT_EQ(def(a), enum1::field2); static_assert( std::is_same, decltype(def(a))>::value, ""); ref_field::field_ref_getter ref; EXPECT_TRUE(ref(a)); ref(a)->a() = 1; EXPECT_EQ(a.field3_ref()->a(), 1); a.field3_ref()->a() = 2; EXPECT_EQ(ref(a)->a(), 2); static_assert( std::is_same&, decltype(ref(a))>::value, ""); } TEST(fatal_struct, renamed_field) { using meta = apache::thrift::reflect_struct; using fmeta = meta::member::boring_cxx_name; auto fname = fatal::to_instance(); EXPECT_EQ("fancy.idl.name", fname); } TEST(fatal_struct, StructWithAdaptedField) { using info = apache::thrift::reflect_struct; using type_adapted_field = fatal::get< info::members, info::member::typeAdapted::name, fatal::get_type::name>; using field_adapted_field = fatal::get< info::members, info::member::fieldAdapted::name, fatal::get_type::name>; StructWithAdaptedField a; using type_adapted_type = apache::thrift::test::Wrapper; using field_adapted_type = apache::thrift::test:: AdaptedWithContext; static_assert( // std::is_same_v< info::member::typeAdapted::type_class, apache::thrift::type_class::structure>); static_assert( // std::is_same_v< info::member::typeAdapted::type_class, apache::thrift::type_class::structure>); static_assert( // std::is_same_v< // info::member::fieldAdapted::type, field_adapted_type>); static_assert( // std::is_same_v< info::member::fieldAdapted::type_class, apache::thrift::type_class::structure>); type_adapted_field::field_ref_getter get_type_adapted; static_assert( // std::is_same_v< apache::thrift::field_ref, decltype(get_type_adapted(a))>); field_adapted_field::field_ref_getter get_field_adapted; static_assert( // std::is_same_v< apache::thrift::field_ref, decltype(get_field_adapted(a))>); } TEST(fatal_struct, Terse) { using traits = apache::thrift::reflect_struct; EXPECT_SAME< required, fatal::get::optional>(); } } // namespace cpp_reflection } // namespace test_cpp2