/* * 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 #include #include #include #include #include namespace apache::thrift::op { namespace { using namespace apache::thrift::test; template void testClearImpl( const type::native_type& expected, type::native_type unexpected, bool emptiable) { EXPECT_EQ(isEmpty(expected), emptiable); EXPECT_THAT(getIntrinsicDefault(), IsIdenticalTo(expected)); EXPECT_FALSE(isEmpty(unexpected)); EXPECT_THAT(unexpected, ::testing::Not(IsIdenticalTo(expected))); if constexpr (IsField) { uint8_t isset = 1; TestStruct obj; clear_field( apache::thrift::detail::make_field_ref(unexpected, isset), obj); } else { clear(unexpected); } EXPECT_EQ(isEmpty(expected), emptiable); EXPECT_THAT(unexpected, IsIdenticalTo(expected)); } template void testClear( const type::native_type& expected, type::native_type unexpected, bool emptiable = true) { testClearImpl(expected, unexpected, emptiable); testClearImpl< type::field>, true>(expected, unexpected, emptiable); } TEST(ClearTest, InferTag) { bool val = true; EXPECT_FALSE(op::isEmpty<>(val)); op::clear<>(val); EXPECT_TRUE(op::isEmpty<>(val)); EXPECT_EQ(op::getIntrinsicDefault(), 0); } TEST(ClearTest, Integral) { testClear(false, true); testClear(0, 1); testClear(0, 1); testClear(0, 1); testClear(0, 1); testClear>( type::BaseTypeEnum::Void, type::BaseTypeEnum::Bool); } TEST(ClearTest, FloatingPoint) { testClear(0, -0.0); testClear(0, -0.0); } TEST(ClearTest, String) { testClear("", "hi"); testClear("", "bye"); } TEST(ClearTest, Container) { testClear>({}, {"hi"}); testClear>({}, {"hi"}); testClear>({}, {{"hi", "bye"}}); } TEST(ClearTest, Structured) { testClear>( {}, {apache::thrift::FragileConstructor(), 1}, false); testClear>( {}, {apache::thrift::FragileConstructor(), 1}); testClear>( {}, {apache::thrift::FragileConstructor(), 1}, false); testClear>( {}, {apache::thrift::FragileConstructor(), 1}); testset::union_i64 one; one.field_1_ref().ensure() = 1; testClear>({}, one); } TEST(ClearTest, IOBufPtr) { using T = std::unique_ptr; using Tag = type::cpp_type; T empty; EXPECT_TRUE(op::isEmpty(empty)); empty = folly::IOBuf::wrapBuffer("", 0); EXPECT_TRUE(op::isEmpty(empty)); T one = folly::IOBuf::wrapBuffer("one", 3); EXPECT_FALSE(op::isEmpty(one)); op::clear(one); EXPECT_TRUE(op::isEmpty(one)); EXPECT_EQ(one, nullptr); // Normalizes to nullptr. EXPECT_NE(empty, nullptr); op::clear(empty); EXPECT_EQ(empty, nullptr); } TEST(ClearTest, Adapter) { testClearImpl>({}, {1}, true); testClearImpl>>( {}, {{1}}, true); testClearImpl< type::field< type::adapted, FieldContext>, true>({}, {1}, true); testClearImpl< type::field< type::adapted>, FieldContext>, true>({}, {{1}}, true); } template void test_custom_default() { using Adapter = detail::get_adapter_t; auto defaultObj = getDefault(); const auto& intrinsicDefaultObj = getIntrinsicDefault(); EXPECT_FALSE(apache::thrift::adapt_detail::equal( defaultObj, intrinsicDefaultObj)); // The default of a field with field adapter is constructed with the default // parent struct. Meanwhile, the intrinsic default of a field with field // adapter is constructed with the intrinsic default parent struct. if constexpr (IsFieldAdapter) { EXPECT_EQ(*defaultObj.meta, "meta"); EXPECT_EQ(*intrinsicDefaultObj.meta, ""); } // TODO(dokwon): Fix op::clear for adapted types with custom default. // clear(defaultObj); // EXPECT_TRUE(apache::thrift::adapt_detail::equal( // defaultObj, intrinsicDefaultObj)); } TEST(ClearTest, CustomDefaultTypeAdapter) { using Tag = type::adapted< TestAdapter, type::struct_t>; using FieldTag = type::field>; test_custom_default(); test_custom_default(); } TEST(ClearTest, CustomDefaultFieldAdapter) { using Tag = type::field< type::adapted< FieldAdapterWithContext, type::struct_t>, FieldContext>; test_custom_default(); } TEST(ClearTest, Default) { // Default of structured with no custom default returns the reference of // intrinsic default for the terse intern box optimization. using TagWithNoCustomDefault = type::struct_t; using TagWithCustomDefault = type::struct_t; EXPECT_EQ( &getDefault(), &getIntrinsicDefault()); EXPECT_NE( &getDefault(), &getIntrinsicDefault()); } } // namespace } // namespace apache::thrift::op