// Copyright 2017 The Abseil Authors. // // 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 // // https://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 "absl/types/any.h" // This test is a no-op when absl::any is an alias for std::any. #if !defined(ABSL_USES_STD_ANY) #include #include #include #include #include "gtest/gtest.h" #include "absl/base/config.h" #include "absl/base/internal/exception_testing.h" #include "absl/base/internal/raw_logging.h" #include "absl/container/internal/test_instance_tracker.h" namespace { using absl::test_internal::CopyableOnlyInstance; using absl::test_internal::InstanceTracker; template const T& AsConst(const T& t) { return t; } struct MoveOnly { MoveOnly() = default; explicit MoveOnly(int value) : value(value) {} MoveOnly(MoveOnly&&) = default; MoveOnly& operator=(MoveOnly&&) = default; int value = 0; }; struct CopyOnly { CopyOnly() = default; explicit CopyOnly(int value) : value(value) {} CopyOnly(CopyOnly&&) = delete; CopyOnly& operator=(CopyOnly&&) = delete; CopyOnly(const CopyOnly&) = default; CopyOnly& operator=(const CopyOnly&) = default; int value = 0; }; struct MoveOnlyWithListConstructor { MoveOnlyWithListConstructor() = default; explicit MoveOnlyWithListConstructor(std::initializer_list /*ilist*/, int value) : value(value) {} MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default; MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) = default; int value = 0; }; struct IntMoveOnlyCopyOnly { IntMoveOnlyCopyOnly(int value, MoveOnly /*move_only*/, CopyOnly /*copy_only*/) : value(value) {} int value; }; struct ListMoveOnlyCopyOnly { ListMoveOnlyCopyOnly(std::initializer_list ilist, MoveOnly /*move_only*/, CopyOnly /*copy_only*/) : values(ilist) {} std::vector values; }; using FunctionType = void(); void FunctionToEmplace() {} using ArrayType = int[2]; using DecayedArray = absl::decay_t; TEST(AnyTest, Noexcept) { static_assert(std::is_nothrow_default_constructible(), ""); static_assert(std::is_nothrow_move_constructible(), ""); static_assert(std::is_nothrow_move_assignable(), ""); static_assert(noexcept(std::declval().has_value()), ""); static_assert(noexcept(std::declval().type()), ""); static_assert(noexcept(absl::any_cast(std::declval())), ""); static_assert( noexcept(std::declval().swap(std::declval())), ""); using std::swap; static_assert( noexcept(swap(std::declval(), std::declval())), ""); } TEST(AnyTest, HasValue) { absl::any o; EXPECT_FALSE(o.has_value()); o.emplace(); EXPECT_TRUE(o.has_value()); o.reset(); EXPECT_FALSE(o.has_value()); } TEST(AnyTest, Type) { absl::any o; EXPECT_EQ(typeid(void), o.type()); o.emplace(5); EXPECT_EQ(typeid(int), o.type()); o.emplace(5.f); EXPECT_EQ(typeid(float), o.type()); o.reset(); EXPECT_EQ(typeid(void), o.type()); } TEST(AnyTest, EmptyPointerCast) { // pointer-to-unqualified overload { absl::any o; EXPECT_EQ(nullptr, absl::any_cast(&o)); o.emplace(); EXPECT_NE(nullptr, absl::any_cast(&o)); o.reset(); EXPECT_EQ(nullptr, absl::any_cast(&o)); } // pointer-to-const overload { absl::any o; EXPECT_EQ(nullptr, absl::any_cast(&AsConst(o))); o.emplace(); EXPECT_NE(nullptr, absl::any_cast(&AsConst(o))); o.reset(); EXPECT_EQ(nullptr, absl::any_cast(&AsConst(o))); } } TEST(AnyTest, InPlaceConstruction) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type_t(), 5, MoveOnly(), copy_only); IntMoveOnlyCopyOnly& v = absl::any_cast(o); EXPECT_EQ(5, v.value); } TEST(AnyTest, InPlaceConstructionVariableTemplate) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type, 5, MoveOnly(), copy_only); auto& v = absl::any_cast(o); EXPECT_EQ(5, v.value); } TEST(AnyTest, InPlaceConstructionWithCV) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type_t(), 5, MoveOnly(), copy_only); IntMoveOnlyCopyOnly& v = absl::any_cast(o); EXPECT_EQ(5, v.value); } TEST(AnyTest, InPlaceConstructionWithCVVariableTemplate) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type, 5, MoveOnly(), copy_only); auto& v = absl::any_cast(o); EXPECT_EQ(5, v.value); } TEST(AnyTest, InPlaceConstructionWithFunction) { absl::any o(absl::in_place_type_t(), FunctionToEmplace); FunctionType*& construction_result = absl::any_cast(o); EXPECT_EQ(&FunctionToEmplace, construction_result); } TEST(AnyTest, InPlaceConstructionWithFunctionVariableTemplate) { absl::any o(absl::in_place_type, FunctionToEmplace); auto& construction_result = absl::any_cast(o); EXPECT_EQ(&FunctionToEmplace, construction_result); } TEST(AnyTest, InPlaceConstructionWithArray) { ArrayType ar = {5, 42}; absl::any o(absl::in_place_type_t(), ar); DecayedArray& construction_result = absl::any_cast(o); EXPECT_EQ(&ar[0], construction_result); } TEST(AnyTest, InPlaceConstructionWithArrayVariableTemplate) { ArrayType ar = {5, 42}; absl::any o(absl::in_place_type, ar); auto& construction_result = absl::any_cast(o); EXPECT_EQ(&ar[0], construction_result); } TEST(AnyTest, InPlaceConstructionIlist) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type_t(), {1, 2, 3, 4}, MoveOnly(), copy_only); ListMoveOnlyCopyOnly& v = absl::any_cast(o); std::vector expected_values = {1, 2, 3, 4}; EXPECT_EQ(expected_values, v.values); } TEST(AnyTest, InPlaceConstructionIlistVariableTemplate) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type, {1, 2, 3, 4}, MoveOnly(), copy_only); auto& v = absl::any_cast(o); std::vector expected_values = {1, 2, 3, 4}; EXPECT_EQ(expected_values, v.values); } TEST(AnyTest, InPlaceConstructionIlistWithCV) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type_t(), {1, 2, 3, 4}, MoveOnly(), copy_only); ListMoveOnlyCopyOnly& v = absl::any_cast(o); std::vector expected_values = {1, 2, 3, 4}; EXPECT_EQ(expected_values, v.values); } TEST(AnyTest, InPlaceConstructionIlistWithCVVariableTemplate) { const CopyOnly copy_only{}; absl::any o(absl::in_place_type, {1, 2, 3, 4}, MoveOnly(), copy_only); auto& v = absl::any_cast(o); std::vector expected_values = {1, 2, 3, 4}; EXPECT_EQ(expected_values, v.values); } TEST(AnyTest, InPlaceNoArgs) { absl::any o(absl::in_place_type_t{}); EXPECT_EQ(0, absl::any_cast(o)); } TEST(AnyTest, InPlaceNoArgsVariableTemplate) { absl::any o(absl::in_place_type); EXPECT_EQ(0, absl::any_cast(o)); } template struct CanEmplaceAnyImpl : std::false_type {}; template struct CanEmplaceAnyImpl< absl::void_t().emplace(std::declval()...))>, T, Args...> : std::true_type {}; template using CanEmplaceAny = CanEmplaceAnyImpl; TEST(AnyTest, Emplace) { const CopyOnly copy_only{}; absl::any o; EXPECT_TRUE((std::is_same( 5, MoveOnly(), copy_only)), IntMoveOnlyCopyOnly&>::value)); IntMoveOnlyCopyOnly& emplace_result = o.emplace(5, MoveOnly(), copy_only); EXPECT_EQ(5, emplace_result.value); IntMoveOnlyCopyOnly& v = absl::any_cast(o); EXPECT_EQ(5, v.value); EXPECT_EQ(&emplace_result, &v); static_assert(!CanEmplaceAny::value, ""); static_assert(!CanEmplaceAny::value, ""); } TEST(AnyTest, EmplaceWithCV) { const CopyOnly copy_only{}; absl::any o; EXPECT_TRUE( (std::is_same( 5, MoveOnly(), copy_only)), IntMoveOnlyCopyOnly&>::value)); IntMoveOnlyCopyOnly& emplace_result = o.emplace(5, MoveOnly(), copy_only); EXPECT_EQ(5, emplace_result.value); IntMoveOnlyCopyOnly& v = absl::any_cast(o); EXPECT_EQ(5, v.value); EXPECT_EQ(&emplace_result, &v); } TEST(AnyTest, EmplaceWithFunction) { absl::any o; EXPECT_TRUE( (std::is_same(FunctionToEmplace)), FunctionType*&>::value)); FunctionType*& emplace_result = o.emplace(FunctionToEmplace); EXPECT_EQ(&FunctionToEmplace, emplace_result); } TEST(AnyTest, EmplaceWithArray) { absl::any o; ArrayType ar = {5, 42}; EXPECT_TRUE( (std::is_same(ar)), DecayedArray&>::value)); DecayedArray& emplace_result = o.emplace(ar); EXPECT_EQ(&ar[0], emplace_result); } TEST(AnyTest, EmplaceIlist) { const CopyOnly copy_only{}; absl::any o; EXPECT_TRUE((std::is_same( {1, 2, 3, 4}, MoveOnly(), copy_only)), ListMoveOnlyCopyOnly&>::value)); ListMoveOnlyCopyOnly& emplace_result = o.emplace({1, 2, 3, 4}, MoveOnly(), copy_only); ListMoveOnlyCopyOnly& v = absl::any_cast(o); EXPECT_EQ(&v, &emplace_result); std::vector expected_values = {1, 2, 3, 4}; EXPECT_EQ(expected_values, v.values); static_assert(!CanEmplaceAny>::value, ""); static_assert(!CanEmplaceAny, int>::value, ""); } TEST(AnyTest, EmplaceIlistWithCV) { const CopyOnly copy_only{}; absl::any o; EXPECT_TRUE( (std::is_same( {1, 2, 3, 4}, MoveOnly(), copy_only)), ListMoveOnlyCopyOnly&>::value)); ListMoveOnlyCopyOnly& emplace_result = o.emplace({1, 2, 3, 4}, MoveOnly(), copy_only); ListMoveOnlyCopyOnly& v = absl::any_cast(o); EXPECT_EQ(&v, &emplace_result); std::vector expected_values = {1, 2, 3, 4}; EXPECT_EQ(expected_values, v.values); } TEST(AnyTest, EmplaceNoArgs) { absl::any o; o.emplace(); EXPECT_EQ(0, absl::any_cast(o)); } TEST(AnyTest, ConversionConstruction) { { absl::any o = 5; EXPECT_EQ(5, absl::any_cast(o)); } { const CopyOnly copy_only(5); absl::any o = copy_only; EXPECT_EQ(5, absl::any_cast(o).value); } static_assert(!std::is_convertible::value, ""); } TEST(AnyTest, ConversionAssignment) { { absl::any o; o = 5; EXPECT_EQ(5, absl::any_cast(o)); } { const CopyOnly copy_only(5); absl::any o; o = copy_only; EXPECT_EQ(5, absl::any_cast(o).value); } static_assert(!std::is_assignable::value, ""); } // Suppress MSVC warnings. // 4521: multiple copy constructors specified // We wrote multiple of them to test that the correct overloads are selected. #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4521) #endif // Weird type for testing, only used to make sure we "properly" perfect-forward // when being placed into an absl::any (use the l-value constructor if given an // l-value rather than use the copy constructor). struct WeirdConstructor42 { explicit WeirdConstructor42(int value) : value(value) {} // Copy-constructor WeirdConstructor42(const WeirdConstructor42& other) : value(other.value) {} // L-value "weird" constructor (used when given an l-value) WeirdConstructor42( WeirdConstructor42& /*other*/) // NOLINT(runtime/references) : value(42) {} int value; }; #ifdef _MSC_VER #pragma warning( pop ) #endif TEST(AnyTest, WeirdConversionConstruction) { { const WeirdConstructor42 source(5); absl::any o = source; // Actual copy EXPECT_EQ(5, absl::any_cast(o).value); } { WeirdConstructor42 source(5); absl::any o = source; // Weird "conversion" EXPECT_EQ(42, absl::any_cast(o).value); } } TEST(AnyTest, WeirdConversionAssignment) { { const WeirdConstructor42 source(5); absl::any o; o = source; // Actual copy EXPECT_EQ(5, absl::any_cast(o).value); } { WeirdConstructor42 source(5); absl::any o; o = source; // Weird "conversion" EXPECT_EQ(42, absl::any_cast(o).value); } } struct Value {}; TEST(AnyTest, AnyCastValue) { { absl::any o; o.emplace(5); EXPECT_EQ(5, absl::any_cast(o)); EXPECT_EQ(5, absl::any_cast(AsConst(o))); static_assert( std::is_same(o)), Value>::value, ""); } { absl::any o; o.emplace(5); EXPECT_EQ(5, absl::any_cast(o)); EXPECT_EQ(5, absl::any_cast(AsConst(o))); static_assert(std::is_same(o)), const Value>::value, ""); } } TEST(AnyTest, AnyCastReference) { { absl::any o; o.emplace(5); EXPECT_EQ(5, absl::any_cast(o)); EXPECT_EQ(5, absl::any_cast(AsConst(o))); static_assert( std::is_same(o)), Value&>::value, ""); } { absl::any o; o.emplace(5); EXPECT_EQ(5, absl::any_cast(o)); EXPECT_EQ(5, absl::any_cast(AsConst(o))); static_assert(std::is_same(o)), const Value&>::value, ""); } { absl::any o; o.emplace(5); EXPECT_EQ(5, absl::any_cast(std::move(o))); static_assert(std::is_same(std::move(o))), Value&&>::value, ""); } { absl::any o; o.emplace(5); EXPECT_EQ(5, absl::any_cast(std::move(o))); static_assert( std::is_same(std::move(o))), const Value&&>::value, ""); } } TEST(AnyTest, AnyCastPointer) { { absl::any o; EXPECT_EQ(nullptr, absl::any_cast(&o)); o.emplace(5); EXPECT_EQ(nullptr, absl::any_cast(&o)); o.emplace('a'); EXPECT_EQ('a', *absl::any_cast(&o)); static_assert( std::is_same(&o)), Value*>::value, ""); } { absl::any o; EXPECT_EQ(nullptr, absl::any_cast(&o)); o.emplace(5); EXPECT_EQ(nullptr, absl::any_cast(&o)); o.emplace('a'); EXPECT_EQ('a', *absl::any_cast(&o)); static_assert(std::is_same(&o)), const Value*>::value, ""); } } TEST(AnyTest, MakeAny) { const CopyOnly copy_only{}; auto o = absl::make_any(5, MoveOnly(), copy_only); static_assert(std::is_same::value, ""); EXPECT_EQ(5, absl::any_cast(o).value); } TEST(AnyTest, MakeAnyIList) { const CopyOnly copy_only{}; auto o = absl::make_any({1, 2, 3}, MoveOnly(), copy_only); static_assert(std::is_same::value, ""); ListMoveOnlyCopyOnly& v = absl::any_cast(o); std::vector expected_values = {1, 2, 3}; EXPECT_EQ(expected_values, v.values); } // Test the use of copy constructor and operator= TEST(AnyTest, Copy) { InstanceTracker tracker_raii; { absl::any o(absl::in_place_type, 123); CopyableOnlyInstance* f1 = absl::any_cast(&o); absl::any o2(o); const CopyableOnlyInstance* f2 = absl::any_cast(&o2); EXPECT_EQ(123, f2->value()); EXPECT_NE(f1, f2); absl::any o3; o3 = o2; const CopyableOnlyInstance* f3 = absl::any_cast(&o3); EXPECT_EQ(123, f3->value()); EXPECT_NE(f2, f3); const absl::any o4(4); // copy construct from const lvalue ref. absl::any o5 = o4; EXPECT_EQ(4, absl::any_cast(o4)); EXPECT_EQ(4, absl::any_cast(o5)); // Copy construct from const rvalue ref. absl::any o6 = std::move(o4); // NOLINT EXPECT_EQ(4, absl::any_cast(o4)); EXPECT_EQ(4, absl::any_cast(o6)); } } TEST(AnyTest, Move) { InstanceTracker tracker_raii; absl::any any1; any1.emplace(5); // This is a copy, so copy count increases to 1. absl::any any2 = any1; EXPECT_EQ(5, absl::any_cast(any1).value()); EXPECT_EQ(5, absl::any_cast(any2).value()); EXPECT_EQ(1, tracker_raii.copies()); // This isn't a copy, so copy count doesn't increase. absl::any any3 = std::move(any2); EXPECT_EQ(5, absl::any_cast(any3).value()); EXPECT_EQ(1, tracker_raii.copies()); absl::any any4; any4 = std::move(any3); EXPECT_EQ(5, absl::any_cast(any4).value()); EXPECT_EQ(1, tracker_raii.copies()); absl::any tmp4(4); absl::any o4(std::move(tmp4)); // move construct EXPECT_EQ(4, absl::any_cast(o4)); o4 = *&o4; // self assign EXPECT_EQ(4, absl::any_cast(o4)); EXPECT_TRUE(o4.has_value()); absl::any o5; absl::any tmp5(5); o5 = std::move(tmp5); // move assign EXPECT_EQ(5, absl::any_cast(o5)); } // Reset the ObjectOwner with an object of a different type TEST(AnyTest, Reset) { absl::any o; o.emplace(); o.reset(); EXPECT_FALSE(o.has_value()); o.emplace(); EXPECT_TRUE(o.has_value()); } TEST(AnyTest, ConversionConstructionCausesOneCopy) { InstanceTracker tracker_raii; CopyableOnlyInstance counter(5); absl::any o(counter); EXPECT_EQ(5, absl::any_cast(o).value()); EXPECT_EQ(1, tracker_raii.copies()); } ////////////////////////////////// // Tests for Exception Behavior // ////////////////////////////////// #if defined(ABSL_USES_STD_ANY) // If using a std `any` implementation, we can't check for a specific message. #define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \ ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \ "") #else // If using the absl `any` implementation, we can rely on a specific message. #define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \ ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \ "Bad any cast") #endif // defined(ABSL_USES_STD_ANY) TEST(AnyTest, ThrowBadAlloc) { { absl::any a; ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(a)); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(a)); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(absl::any{})); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(absl::any{})); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(a)); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(a)); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(absl::any{})); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(absl::any{})); // const absl::any operand ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(AsConst(a))); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(AsConst(a))); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(AsConst(a))); } { absl::any a(absl::in_place_type); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(a)); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(a)); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(absl::any{})); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST( absl::any_cast(absl::any{})); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(a)); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(a)); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(absl::any{})); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(absl::any{})); // const absl::any operand ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(AsConst(a))); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(AsConst(a))); ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast(AsConst(a))); } } class BadCopy {}; struct BadCopyable { BadCopyable() = default; BadCopyable(BadCopyable&&) = default; BadCopyable(const BadCopyable&) { #ifdef ABSL_HAVE_EXCEPTIONS throw BadCopy(); #else ABSL_RAW_LOG(FATAL, "Bad copy"); #endif } }; #define ABSL_ANY_TEST_EXPECT_BAD_COPY(...) \ ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), BadCopy, "Bad copy") // Test the guarantees regarding exceptions in copy/assign. TEST(AnyTest, FailedCopy) { { const BadCopyable bad{}; ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{bad}); } { absl::any src(absl::in_place_type); ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{src}); } { BadCopyable bad; absl::any target; ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad); } { BadCopyable bad; absl::any target(absl::in_place_type); ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad); EXPECT_TRUE(target.has_value()); } { absl::any src(absl::in_place_type); absl::any target; ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src); EXPECT_FALSE(target.has_value()); } { absl::any src(absl::in_place_type); absl::any target(absl::in_place_type); ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src); EXPECT_TRUE(target.has_value()); } } // Test the guarantees regarding exceptions in emplace. TEST(AnyTest, FailedEmplace) { { BadCopyable bad; absl::any target; ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace(bad)); } { BadCopyable bad; absl::any target(absl::in_place_type); ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace(bad)); #if defined(ABSL_USES_STD_ANY) && defined(__GLIBCXX__) // libstdc++ std::any::emplace() implementation (as of 7.2) has a bug: if an // exception is thrown, *this contains a value. #define ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG 1 #endif #if defined(ABSL_HAVE_EXCEPTIONS) && \ !defined(ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG) EXPECT_FALSE(target.has_value()); #endif } } } // namespace #endif // #if !defined(ABSL_USES_STD_ANY)