// Copyright 2019 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/internal/conformance_testing.h" #include <new> #include <type_traits> #include <utility> #include "gtest/gtest.h" #include "absl/meta/type_traits.h" #include "absl/types/internal/conformance_aliases.h" #include "absl/types/internal/conformance_profile.h" namespace { namespace ti = absl::types_internal; template <class T> using DefaultConstructibleWithNewImpl = decltype(::new (std::nothrow) T); template <class T> using DefaultConstructibleWithNew = absl::type_traits_internal::is_detected<DefaultConstructibleWithNewImpl, T>; template <class T> using MoveConstructibleWithNewImpl = decltype(::new (std::nothrow) T(std::declval<T>())); template <class T> using MoveConstructibleWithNew = absl::type_traits_internal::is_detected<MoveConstructibleWithNewImpl, T>; template <class T> using CopyConstructibleWithNewImpl = decltype(::new (std::nothrow) T(std::declval<const T&>())); template <class T> using CopyConstructibleWithNew = absl::type_traits_internal::is_detected<CopyConstructibleWithNewImpl, T>; template <class T, class Result = std::integral_constant<bool, noexcept(::new (std::nothrow) T)>> using NothrowDefaultConstructibleWithNewImpl = typename std::enable_if<Result::value>::type; template <class T> using NothrowDefaultConstructibleWithNew = absl::type_traits_internal::is_detected< NothrowDefaultConstructibleWithNewImpl, T>; template <class T, class Result = std::integral_constant< bool, noexcept(::new (std::nothrow) T(std::declval<T>()))>> using NothrowMoveConstructibleWithNewImpl = typename std::enable_if<Result::value>::type; template <class T> using NothrowMoveConstructibleWithNew = absl::type_traits_internal::is_detected<NothrowMoveConstructibleWithNewImpl, T>; template <class T, class Result = std::integral_constant< bool, noexcept(::new (std::nothrow) T(std::declval<const T&>()))>> using NothrowCopyConstructibleWithNewImpl = typename std::enable_if<Result::value>::type; template <class T> using NothrowCopyConstructibleWithNew = absl::type_traits_internal::is_detected<NothrowCopyConstructibleWithNewImpl, T>; // NOTE: ?: is used to verify contextually-convertible to bool and not simply // implicit or explicit convertibility. #define ABSL_INTERNAL_COMPARISON_OP_EXPR(op) \ ((std::declval<const T&>() op std::declval<const T&>()) ? true : true) #define ABSL_INTERNAL_COMPARISON_OP_TRAIT(name, op) \ template <class T> \ using name##Impl = decltype(ABSL_INTERNAL_COMPARISON_OP_EXPR(op)); \ \ template <class T> \ using name = absl::type_traits_internal::is_detected<name##Impl, T>; \ \ template <class T, \ class Result = std::integral_constant< \ bool, noexcept(ABSL_INTERNAL_COMPARISON_OP_EXPR(op))>> \ using Nothrow##name##Impl = typename std::enable_if<Result::value>::type; \ \ template <class T> \ using Nothrow##name = \ absl::type_traits_internal::is_detected<Nothrow##name##Impl, T> ABSL_INTERNAL_COMPARISON_OP_TRAIT(EqualityComparable, ==); ABSL_INTERNAL_COMPARISON_OP_TRAIT(InequalityComparable, !=); ABSL_INTERNAL_COMPARISON_OP_TRAIT(LessThanComparable, <); ABSL_INTERNAL_COMPARISON_OP_TRAIT(LessEqualComparable, <=); ABSL_INTERNAL_COMPARISON_OP_TRAIT(GreaterEqualComparable, >=); ABSL_INTERNAL_COMPARISON_OP_TRAIT(GreaterThanComparable, >); #undef ABSL_INTERNAL_COMPARISON_OP_TRAIT template <class T> class ProfileTest : public ::testing::Test {}; TYPED_TEST_SUITE_P(ProfileTest); TYPED_TEST_P(ProfileTest, HasAppropriateConstructionProperties) { using profile = typename TypeParam::profile; using arch = typename TypeParam::arch; using expected_profile = typename TypeParam::expected_profile; using props = ti::PropertiesOfT<profile>; using arch_props = ti::PropertiesOfArchetypeT<arch>; using expected_props = ti::PropertiesOfT<expected_profile>; // Make sure all of the properties are as expected. // There are seemingly redundant tests here to make it easier to diagnose // the specifics of the failure if something were to go wrong. EXPECT_TRUE((std::is_same<props, arch_props>::value)); EXPECT_TRUE((std::is_same<props, expected_props>::value)); EXPECT_TRUE((std::is_same<arch_props, expected_props>::value)); EXPECT_EQ(props::default_constructible_support, expected_props::default_constructible_support); EXPECT_EQ(props::move_constructible_support, expected_props::move_constructible_support); EXPECT_EQ(props::copy_constructible_support, expected_props::copy_constructible_support); EXPECT_EQ(props::destructible_support, expected_props::destructible_support); // Avoid additional error message noise when profile and archetype match with // each other but were not what was expected. if (!std::is_same<props, arch_props>::value) { EXPECT_EQ(arch_props::default_constructible_support, expected_props::default_constructible_support); EXPECT_EQ(arch_props::move_constructible_support, expected_props::move_constructible_support); EXPECT_EQ(arch_props::copy_constructible_support, expected_props::copy_constructible_support); EXPECT_EQ(arch_props::destructible_support, expected_props::destructible_support); } ////////////////////////////////////////////////////////////////////////////// // Default constructor checks // ////////////////////////////////////////////////////////////////////////////// EXPECT_EQ(props::default_constructible_support, expected_props::default_constructible_support); switch (expected_props::default_constructible_support) { case ti::default_constructible::maybe: EXPECT_FALSE(DefaultConstructibleWithNew<arch>::value); EXPECT_FALSE(NothrowDefaultConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_FALSE(std::is_default_constructible<arch>::value); EXPECT_FALSE(std::is_nothrow_default_constructible<arch>::value); EXPECT_FALSE(absl::is_trivially_default_constructible<arch>::value); } break; case ti::default_constructible::yes: EXPECT_TRUE(DefaultConstructibleWithNew<arch>::value); EXPECT_FALSE(NothrowDefaultConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_TRUE(std::is_default_constructible<arch>::value); EXPECT_FALSE(std::is_nothrow_default_constructible<arch>::value); EXPECT_FALSE(absl::is_trivially_default_constructible<arch>::value); } break; case ti::default_constructible::nothrow: EXPECT_TRUE(DefaultConstructibleWithNew<arch>::value); EXPECT_TRUE(NothrowDefaultConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_TRUE(std::is_default_constructible<arch>::value); EXPECT_TRUE(std::is_nothrow_default_constructible<arch>::value); EXPECT_FALSE(absl::is_trivially_default_constructible<arch>::value); // Constructor traits also check the destructor. if (std::is_nothrow_destructible<arch>::value) { EXPECT_TRUE(std::is_nothrow_default_constructible<arch>::value); } } break; case ti::default_constructible::trivial: EXPECT_TRUE(DefaultConstructibleWithNew<arch>::value); EXPECT_TRUE(NothrowDefaultConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_TRUE(std::is_default_constructible<arch>::value); EXPECT_TRUE(std::is_nothrow_default_constructible<arch>::value); // Constructor triviality traits require trivially destructible types. if (absl::is_trivially_destructible<arch>::value) { EXPECT_TRUE(absl::is_trivially_default_constructible<arch>::value); } } break; } ////////////////////////////////////////////////////////////////////////////// // Move constructor checks // ////////////////////////////////////////////////////////////////////////////// EXPECT_EQ(props::move_constructible_support, expected_props::move_constructible_support); switch (expected_props::move_constructible_support) { case ti::move_constructible::maybe: EXPECT_FALSE(MoveConstructibleWithNew<arch>::value); EXPECT_FALSE(NothrowMoveConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_FALSE(std::is_move_constructible<arch>::value); EXPECT_FALSE(std::is_nothrow_move_constructible<arch>::value); EXPECT_FALSE(absl::is_trivially_move_constructible<arch>::value); } break; case ti::move_constructible::yes: EXPECT_TRUE(MoveConstructibleWithNew<arch>::value); EXPECT_FALSE(NothrowMoveConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_TRUE(std::is_move_constructible<arch>::value); EXPECT_FALSE(std::is_nothrow_move_constructible<arch>::value); EXPECT_FALSE(absl::is_trivially_move_constructible<arch>::value); } break; case ti::move_constructible::nothrow: EXPECT_TRUE(MoveConstructibleWithNew<arch>::value); EXPECT_TRUE(NothrowMoveConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_TRUE(std::is_move_constructible<arch>::value); EXPECT_TRUE(std::is_nothrow_move_constructible<arch>::value); EXPECT_FALSE(absl::is_trivially_move_constructible<arch>::value); // Constructor traits also check the destructor. if (std::is_nothrow_destructible<arch>::value) { EXPECT_TRUE(std::is_nothrow_move_constructible<arch>::value); } } break; case ti::move_constructible::trivial: EXPECT_TRUE(MoveConstructibleWithNew<arch>::value); EXPECT_TRUE(NothrowMoveConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_TRUE(std::is_move_constructible<arch>::value); EXPECT_TRUE(std::is_nothrow_move_constructible<arch>::value); // Constructor triviality traits require trivially destructible types. if (absl::is_trivially_destructible<arch>::value) { EXPECT_TRUE(absl::is_trivially_move_constructible<arch>::value); } } break; } ////////////////////////////////////////////////////////////////////////////// // Copy constructor checks // ////////////////////////////////////////////////////////////////////////////// EXPECT_EQ(props::copy_constructible_support, expected_props::copy_constructible_support); switch (expected_props::copy_constructible_support) { case ti::copy_constructible::maybe: EXPECT_FALSE(CopyConstructibleWithNew<arch>::value); EXPECT_FALSE(NothrowCopyConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_FALSE(std::is_copy_constructible<arch>::value); EXPECT_FALSE(std::is_nothrow_copy_constructible<arch>::value); EXPECT_FALSE(absl::is_trivially_copy_constructible<arch>::value); } break; case ti::copy_constructible::yes: EXPECT_TRUE(CopyConstructibleWithNew<arch>::value); EXPECT_FALSE(NothrowCopyConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_TRUE(std::is_copy_constructible<arch>::value); EXPECT_FALSE(std::is_nothrow_copy_constructible<arch>::value); EXPECT_FALSE(absl::is_trivially_copy_constructible<arch>::value); } break; case ti::copy_constructible::nothrow: EXPECT_TRUE(CopyConstructibleWithNew<arch>::value); EXPECT_TRUE(NothrowCopyConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_TRUE(std::is_copy_constructible<arch>::value); EXPECT_TRUE(std::is_nothrow_copy_constructible<arch>::value); EXPECT_FALSE(absl::is_trivially_copy_constructible<arch>::value); // Constructor traits also check the destructor. if (std::is_nothrow_destructible<arch>::value) { EXPECT_TRUE(std::is_nothrow_copy_constructible<arch>::value); } } break; case ti::copy_constructible::trivial: EXPECT_TRUE(CopyConstructibleWithNew<arch>::value); EXPECT_TRUE(NothrowCopyConstructibleWithNew<arch>::value); // Standard constructible traits depend on the destructor. if (std::is_destructible<arch>::value) { EXPECT_TRUE(std::is_copy_constructible<arch>::value); EXPECT_TRUE(std::is_nothrow_copy_constructible<arch>::value); // Constructor triviality traits require trivially destructible types. if (absl::is_trivially_destructible<arch>::value) { EXPECT_TRUE(absl::is_trivially_copy_constructible<arch>::value); } } break; } ////////////////////////////////////////////////////////////////////////////// // Destructible checks // ////////////////////////////////////////////////////////////////////////////// EXPECT_EQ(props::destructible_support, expected_props::destructible_support); switch (expected_props::destructible_support) { case ti::destructible::maybe: EXPECT_FALSE(std::is_destructible<arch>::value); EXPECT_FALSE(std::is_nothrow_destructible<arch>::value); EXPECT_FALSE(absl::is_trivially_destructible<arch>::value); break; case ti::destructible::yes: EXPECT_TRUE(std::is_destructible<arch>::value); EXPECT_FALSE(std::is_nothrow_destructible<arch>::value); EXPECT_FALSE(absl::is_trivially_destructible<arch>::value); break; case ti::destructible::nothrow: EXPECT_TRUE(std::is_destructible<arch>::value); EXPECT_TRUE(std::is_nothrow_destructible<arch>::value); EXPECT_FALSE(absl::is_trivially_destructible<arch>::value); break; case ti::destructible::trivial: EXPECT_TRUE(std::is_destructible<arch>::value); EXPECT_TRUE(std::is_nothrow_destructible<arch>::value); EXPECT_TRUE(absl::is_trivially_destructible<arch>::value); break; } } TYPED_TEST_P(ProfileTest, HasAppropriateAssignmentProperties) { using profile = typename TypeParam::profile; using arch = typename TypeParam::arch; using expected_profile = typename TypeParam::expected_profile; using props = ti::PropertiesOfT<profile>; using arch_props = ti::PropertiesOfArchetypeT<arch>; using expected_props = ti::PropertiesOfT<expected_profile>; // Make sure all of the properties are as expected. // There are seemingly redundant tests here to make it easier to diagnose // the specifics of the failure if something were to go wrong. EXPECT_TRUE((std::is_same<props, arch_props>::value)); EXPECT_TRUE((std::is_same<props, expected_props>::value)); EXPECT_TRUE((std::is_same<arch_props, expected_props>::value)); EXPECT_EQ(props::move_assignable_support, expected_props::move_assignable_support); EXPECT_EQ(props::copy_assignable_support, expected_props::copy_assignable_support); // Avoid additional error message noise when profile and archetype match with // each other but were not what was expected. if (!std::is_same<props, arch_props>::value) { EXPECT_EQ(arch_props::move_assignable_support, expected_props::move_assignable_support); EXPECT_EQ(arch_props::copy_assignable_support, expected_props::copy_assignable_support); } ////////////////////////////////////////////////////////////////////////////// // Move assignment checks // ////////////////////////////////////////////////////////////////////////////// EXPECT_EQ(props::move_assignable_support, expected_props::move_assignable_support); switch (expected_props::move_assignable_support) { case ti::move_assignable::maybe: EXPECT_FALSE(std::is_move_assignable<arch>::value); EXPECT_FALSE(std::is_nothrow_move_assignable<arch>::value); EXPECT_FALSE(absl::is_trivially_move_assignable<arch>::value); break; case ti::move_assignable::yes: EXPECT_TRUE(std::is_move_assignable<arch>::value); EXPECT_FALSE(std::is_nothrow_move_assignable<arch>::value); EXPECT_FALSE(absl::is_trivially_move_assignable<arch>::value); break; case ti::move_assignable::nothrow: EXPECT_TRUE(std::is_move_assignable<arch>::value); EXPECT_TRUE(std::is_nothrow_move_assignable<arch>::value); EXPECT_FALSE(absl::is_trivially_move_assignable<arch>::value); break; case ti::move_assignable::trivial: EXPECT_TRUE(std::is_move_assignable<arch>::value); EXPECT_TRUE(std::is_nothrow_move_assignable<arch>::value); EXPECT_TRUE(absl::is_trivially_move_assignable<arch>::value); break; } ////////////////////////////////////////////////////////////////////////////// // Copy assignment checks // ////////////////////////////////////////////////////////////////////////////// EXPECT_EQ(props::copy_assignable_support, expected_props::copy_assignable_support); switch (expected_props::copy_assignable_support) { case ti::copy_assignable::maybe: EXPECT_FALSE(std::is_copy_assignable<arch>::value); EXPECT_FALSE(std::is_nothrow_copy_assignable<arch>::value); EXPECT_FALSE(absl::is_trivially_copy_assignable<arch>::value); break; case ti::copy_assignable::yes: EXPECT_TRUE(std::is_copy_assignable<arch>::value); EXPECT_FALSE(std::is_nothrow_copy_assignable<arch>::value); EXPECT_FALSE(absl::is_trivially_copy_assignable<arch>::value); break; case ti::copy_assignable::nothrow: EXPECT_TRUE(std::is_copy_assignable<arch>::value); EXPECT_TRUE(std::is_nothrow_copy_assignable<arch>::value); EXPECT_FALSE(absl::is_trivially_copy_assignable<arch>::value); break; case ti::copy_assignable::trivial: EXPECT_TRUE(std::is_copy_assignable<arch>::value); EXPECT_TRUE(std::is_nothrow_copy_assignable<arch>::value); EXPECT_TRUE(absl::is_trivially_copy_assignable<arch>::value); break; } } TYPED_TEST_P(ProfileTest, HasAppropriateComparisonProperties) { using profile = typename TypeParam::profile; using arch = typename TypeParam::arch; using expected_profile = typename TypeParam::expected_profile; using props = ti::PropertiesOfT<profile>; using arch_props = ti::PropertiesOfArchetypeT<arch>; using expected_props = ti::PropertiesOfT<expected_profile>; // Make sure all of the properties are as expected. // There are seemingly redundant tests here to make it easier to diagnose // the specifics of the failure if something were to go wrong. EXPECT_TRUE((std::is_same<props, arch_props>::value)); EXPECT_TRUE((std::is_same<props, expected_props>::value)); EXPECT_TRUE((std::is_same<arch_props, expected_props>::value)); EXPECT_EQ(props::equality_comparable_support, expected_props::equality_comparable_support); EXPECT_EQ(props::inequality_comparable_support, expected_props::inequality_comparable_support); EXPECT_EQ(props::less_than_comparable_support, expected_props::less_than_comparable_support); EXPECT_EQ(props::less_equal_comparable_support, expected_props::less_equal_comparable_support); EXPECT_EQ(props::greater_equal_comparable_support, expected_props::greater_equal_comparable_support); EXPECT_EQ(props::greater_than_comparable_support, expected_props::greater_than_comparable_support); // Avoid additional error message noise when profile and archetype match with // each other but were not what was expected. if (!std::is_same<props, arch_props>::value) { EXPECT_EQ(arch_props::equality_comparable_support, expected_props::equality_comparable_support); EXPECT_EQ(arch_props::inequality_comparable_support, expected_props::inequality_comparable_support); EXPECT_EQ(arch_props::less_than_comparable_support, expected_props::less_than_comparable_support); EXPECT_EQ(arch_props::less_equal_comparable_support, expected_props::less_equal_comparable_support); EXPECT_EQ(arch_props::greater_equal_comparable_support, expected_props::greater_equal_comparable_support); EXPECT_EQ(arch_props::greater_than_comparable_support, expected_props::greater_than_comparable_support); } ////////////////////////////////////////////////////////////////////////////// // Equality comparable checks // ////////////////////////////////////////////////////////////////////////////// switch (expected_props::equality_comparable_support) { case ti::equality_comparable::maybe: EXPECT_FALSE(EqualityComparable<arch>::value); EXPECT_FALSE(NothrowEqualityComparable<arch>::value); break; case ti::equality_comparable::yes: EXPECT_TRUE(EqualityComparable<arch>::value); EXPECT_FALSE(NothrowEqualityComparable<arch>::value); break; case ti::equality_comparable::nothrow: EXPECT_TRUE(EqualityComparable<arch>::value); EXPECT_TRUE(NothrowEqualityComparable<arch>::value); break; } ////////////////////////////////////////////////////////////////////////////// // Inequality comparable checks // ////////////////////////////////////////////////////////////////////////////// switch (expected_props::inequality_comparable_support) { case ti::inequality_comparable::maybe: EXPECT_FALSE(InequalityComparable<arch>::value); EXPECT_FALSE(NothrowInequalityComparable<arch>::value); break; case ti::inequality_comparable::yes: EXPECT_TRUE(InequalityComparable<arch>::value); EXPECT_FALSE(NothrowInequalityComparable<arch>::value); break; case ti::inequality_comparable::nothrow: EXPECT_TRUE(InequalityComparable<arch>::value); EXPECT_TRUE(NothrowInequalityComparable<arch>::value); break; } ////////////////////////////////////////////////////////////////////////////// // Less than comparable checks // ////////////////////////////////////////////////////////////////////////////// switch (expected_props::less_than_comparable_support) { case ti::less_than_comparable::maybe: EXPECT_FALSE(LessThanComparable<arch>::value); EXPECT_FALSE(NothrowLessThanComparable<arch>::value); break; case ti::less_than_comparable::yes: EXPECT_TRUE(LessThanComparable<arch>::value); EXPECT_FALSE(NothrowLessThanComparable<arch>::value); break; case ti::less_than_comparable::nothrow: EXPECT_TRUE(LessThanComparable<arch>::value); EXPECT_TRUE(NothrowLessThanComparable<arch>::value); break; } ////////////////////////////////////////////////////////////////////////////// // Less equal comparable checks // ////////////////////////////////////////////////////////////////////////////// switch (expected_props::less_equal_comparable_support) { case ti::less_equal_comparable::maybe: EXPECT_FALSE(LessEqualComparable<arch>::value); EXPECT_FALSE(NothrowLessEqualComparable<arch>::value); break; case ti::less_equal_comparable::yes: EXPECT_TRUE(LessEqualComparable<arch>::value); EXPECT_FALSE(NothrowLessEqualComparable<arch>::value); break; case ti::less_equal_comparable::nothrow: EXPECT_TRUE(LessEqualComparable<arch>::value); EXPECT_TRUE(NothrowLessEqualComparable<arch>::value); break; } ////////////////////////////////////////////////////////////////////////////// // Greater equal comparable checks // ////////////////////////////////////////////////////////////////////////////// switch (expected_props::greater_equal_comparable_support) { case ti::greater_equal_comparable::maybe: EXPECT_FALSE(GreaterEqualComparable<arch>::value); EXPECT_FALSE(NothrowGreaterEqualComparable<arch>::value); break; case ti::greater_equal_comparable::yes: EXPECT_TRUE(GreaterEqualComparable<arch>::value); EXPECT_FALSE(NothrowGreaterEqualComparable<arch>::value); break; case ti::greater_equal_comparable::nothrow: EXPECT_TRUE(GreaterEqualComparable<arch>::value); EXPECT_TRUE(NothrowGreaterEqualComparable<arch>::value); break; } ////////////////////////////////////////////////////////////////////////////// // Greater than comparable checks // ////////////////////////////////////////////////////////////////////////////// switch (expected_props::greater_than_comparable_support) { case ti::greater_than_comparable::maybe: EXPECT_FALSE(GreaterThanComparable<arch>::value); EXPECT_FALSE(NothrowGreaterThanComparable<arch>::value); break; case ti::greater_than_comparable::yes: EXPECT_TRUE(GreaterThanComparable<arch>::value); EXPECT_FALSE(NothrowGreaterThanComparable<arch>::value); break; case ti::greater_than_comparable::nothrow: EXPECT_TRUE(GreaterThanComparable<arch>::value); EXPECT_TRUE(NothrowGreaterThanComparable<arch>::value); break; } } TYPED_TEST_P(ProfileTest, HasAppropriateAuxilliaryProperties) { using profile = typename TypeParam::profile; using arch = typename TypeParam::arch; using expected_profile = typename TypeParam::expected_profile; using props = ti::PropertiesOfT<profile>; using arch_props = ti::PropertiesOfArchetypeT<arch>; using expected_props = ti::PropertiesOfT<expected_profile>; // Make sure all of the properties are as expected. // There are seemingly redundant tests here to make it easier to diagnose // the specifics of the failure if something were to go wrong. EXPECT_TRUE((std::is_same<props, arch_props>::value)); EXPECT_TRUE((std::is_same<props, expected_props>::value)); EXPECT_TRUE((std::is_same<arch_props, expected_props>::value)); EXPECT_EQ(props::swappable_support, expected_props::swappable_support); EXPECT_EQ(props::hashable_support, expected_props::hashable_support); // Avoid additional error message noise when profile and archetype match with // each other but were not what was expected. if (!std::is_same<props, arch_props>::value) { EXPECT_EQ(arch_props::swappable_support, expected_props::swappable_support); EXPECT_EQ(arch_props::hashable_support, expected_props::hashable_support); } ////////////////////////////////////////////////////////////////////////////// // Swappable checks // ////////////////////////////////////////////////////////////////////////////// switch (expected_props::swappable_support) { case ti::swappable::maybe: EXPECT_FALSE(absl::type_traits_internal::IsSwappable<arch>::value); EXPECT_FALSE(absl::type_traits_internal::IsNothrowSwappable<arch>::value); break; case ti::swappable::yes: EXPECT_TRUE(absl::type_traits_internal::IsSwappable<arch>::value); EXPECT_FALSE(absl::type_traits_internal::IsNothrowSwappable<arch>::value); break; case ti::swappable::nothrow: EXPECT_TRUE(absl::type_traits_internal::IsSwappable<arch>::value); EXPECT_TRUE(absl::type_traits_internal::IsNothrowSwappable<arch>::value); break; } ////////////////////////////////////////////////////////////////////////////// // Hashable checks // ////////////////////////////////////////////////////////////////////////////// switch (expected_props::hashable_support) { case ti::hashable::maybe: #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ EXPECT_FALSE(absl::type_traits_internal::IsHashable<arch>::value); #endif // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ break; case ti::hashable::yes: EXPECT_TRUE(absl::type_traits_internal::IsHashable<arch>::value); break; } } REGISTER_TYPED_TEST_SUITE_P(ProfileTest, HasAppropriateConstructionProperties, HasAppropriateAssignmentProperties, HasAppropriateComparisonProperties, HasAppropriateAuxilliaryProperties); template <class Profile, class Arch, class ExpectedProfile> struct ProfileAndExpectation { using profile = Profile; using arch = Arch; using expected_profile = ExpectedProfile; }; using CoreProfilesToTest = ::testing::Types< // The terminating case of combine (all properties are "maybe"). ProfileAndExpectation<ti::CombineProfiles<>, ti::Archetype<ti::CombineProfiles<>>, ti::ConformanceProfile<>>, // Core default constructor profiles ProfileAndExpectation< ti::HasDefaultConstructorProfile, ti::HasDefaultConstructorArchetype, ti::ConformanceProfile<ti::default_constructible::yes>>, ProfileAndExpectation< ti::HasNothrowDefaultConstructorProfile, ti::HasNothrowDefaultConstructorArchetype, ti::ConformanceProfile<ti::default_constructible::nothrow>>, ProfileAndExpectation< ti::HasTrivialDefaultConstructorProfile, ti::HasTrivialDefaultConstructorArchetype, ti::ConformanceProfile<ti::default_constructible::trivial>>, // Core move constructor profiles ProfileAndExpectation< ti::HasMoveConstructorProfile, ti::HasMoveConstructorArchetype, ti::ConformanceProfile<ti::default_constructible::maybe, ti::move_constructible::yes>>, ProfileAndExpectation< ti::HasNothrowMoveConstructorProfile, ti::HasNothrowMoveConstructorArchetype, ti::ConformanceProfile<ti::default_constructible::maybe, ti::move_constructible::nothrow>>, ProfileAndExpectation< ti::HasTrivialMoveConstructorProfile, ti::HasTrivialMoveConstructorArchetype, ti::ConformanceProfile<ti::default_constructible::maybe, ti::move_constructible::trivial>>, // Core copy constructor profiles ProfileAndExpectation< ti::HasCopyConstructorProfile, ti::HasCopyConstructorArchetype, ti::ConformanceProfile<ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::yes>>, ProfileAndExpectation< ti::HasNothrowCopyConstructorProfile, ti::HasNothrowCopyConstructorArchetype, ti::ConformanceProfile<ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::nothrow>>, ProfileAndExpectation< ti::HasTrivialCopyConstructorProfile, ti::HasTrivialCopyConstructorArchetype, ti::ConformanceProfile<ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::trivial>>, // Core move assignment profiles ProfileAndExpectation< ti::HasMoveAssignProfile, ti::HasMoveAssignArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::yes>>, ProfileAndExpectation< ti::HasNothrowMoveAssignProfile, ti::HasNothrowMoveAssignArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::nothrow>>, ProfileAndExpectation< ti::HasTrivialMoveAssignProfile, ti::HasTrivialMoveAssignArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::trivial>>, // Core copy assignment profiles ProfileAndExpectation< ti::HasCopyAssignProfile, ti::HasCopyAssignArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::yes>>, ProfileAndExpectation< ti::HasNothrowCopyAssignProfile, ti::HasNothrowCopyAssignArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::nothrow>>, ProfileAndExpectation< ti::HasTrivialCopyAssignProfile, ti::HasTrivialCopyAssignArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::trivial>>, // Core destructor profiles ProfileAndExpectation< ti::HasDestructorProfile, ti::HasDestructorArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::yes>>, ProfileAndExpectation< ti::HasNothrowDestructorProfile, ti::HasNothrowDestructorArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::nothrow>>, ProfileAndExpectation< ti::HasTrivialDestructorProfile, ti::HasTrivialDestructorArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::trivial>>, // Core equality comparable profiles ProfileAndExpectation< ti::HasEqualityProfile, ti::HasEqualityArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::yes>>, ProfileAndExpectation< ti::HasNothrowEqualityProfile, ti::HasNothrowEqualityArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::nothrow>>, // Core inequality comparable profiles ProfileAndExpectation< ti::HasInequalityProfile, ti::HasInequalityArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::yes>>, ProfileAndExpectation< ti::HasNothrowInequalityProfile, ti::HasNothrowInequalityArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::nothrow>>, // Core less than comparable profiles ProfileAndExpectation< ti::HasLessThanProfile, ti::HasLessThanArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::yes>>, ProfileAndExpectation< ti::HasNothrowLessThanProfile, ti::HasNothrowLessThanArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::nothrow>>, // Core less equal comparable profiles ProfileAndExpectation< ti::HasLessEqualProfile, ti::HasLessEqualArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::yes>>, ProfileAndExpectation< ti::HasNothrowLessEqualProfile, ti::HasNothrowLessEqualArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::nothrow>>, // Core greater equal comparable profiles ProfileAndExpectation< ti::HasGreaterEqualProfile, ti::HasGreaterEqualArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::yes>>, ProfileAndExpectation< ti::HasNothrowGreaterEqualProfile, ti::HasNothrowGreaterEqualArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::nothrow>>, // Core greater than comparable profiles ProfileAndExpectation< ti::HasGreaterThanProfile, ti::HasGreaterThanArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::maybe, ti::greater_than_comparable::yes>>, ProfileAndExpectation< ti::HasNothrowGreaterThanProfile, ti::HasNothrowGreaterThanArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::maybe, ti::greater_than_comparable::nothrow>>, // Core swappable profiles ProfileAndExpectation< ti::HasSwapProfile, ti::HasSwapArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::maybe, ti::greater_than_comparable::maybe, ti::swappable::yes>>, ProfileAndExpectation< ti::HasNothrowSwapProfile, ti::HasNothrowSwapArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::maybe, ti::greater_than_comparable::maybe, ti::swappable::nothrow>>, // Core hashable profiles ProfileAndExpectation< ti::HasStdHashSpecializationProfile, ti::HasStdHashSpecializationArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::maybe, ti::greater_than_comparable::maybe, ti::swappable::maybe, ti::hashable::yes>>>; using CommonProfilesToTest = ::testing::Types< // NothrowMoveConstructible ProfileAndExpectation< ti::NothrowMoveConstructibleProfile, ti::NothrowMoveConstructibleArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::nothrow, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::nothrow>>, // CopyConstructible ProfileAndExpectation< ti::CopyConstructibleProfile, ti::CopyConstructibleArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::nothrow, ti::copy_constructible::yes, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::nothrow>>, // NothrowMovable ProfileAndExpectation< ti::NothrowMovableProfile, ti::NothrowMovableArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::nothrow, ti::copy_constructible::maybe, ti::move_assignable::nothrow, ti::copy_assignable::maybe, ti::destructible::nothrow, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::maybe, ti::greater_than_comparable::maybe, ti::swappable::nothrow>>, // Value ProfileAndExpectation< ti::ValueProfile, ti::ValueArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::nothrow, ti::copy_constructible::yes, ti::move_assignable::nothrow, ti::copy_assignable::yes, ti::destructible::nothrow, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::maybe, ti::greater_than_comparable::maybe, ti::swappable::nothrow>>, //////////////////////////////////////////////////////////////////////////// // Common but also DefaultConstructible // //////////////////////////////////////////////////////////////////////////// // DefaultConstructibleNothrowMoveConstructible ProfileAndExpectation< ti::DefaultConstructibleNothrowMoveConstructibleProfile, ti::DefaultConstructibleNothrowMoveConstructibleArchetype, ti::ConformanceProfile< ti::default_constructible::yes, ti::move_constructible::nothrow, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::nothrow>>, // DefaultConstructibleCopyConstructible ProfileAndExpectation< ti::DefaultConstructibleCopyConstructibleProfile, ti::DefaultConstructibleCopyConstructibleArchetype, ti::ConformanceProfile< ti::default_constructible::yes, ti::move_constructible::nothrow, ti::copy_constructible::yes, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::nothrow>>, // DefaultConstructibleNothrowMovable ProfileAndExpectation< ti::DefaultConstructibleNothrowMovableProfile, ti::DefaultConstructibleNothrowMovableArchetype, ti::ConformanceProfile< ti::default_constructible::yes, ti::move_constructible::nothrow, ti::copy_constructible::maybe, ti::move_assignable::nothrow, ti::copy_assignable::maybe, ti::destructible::nothrow, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::maybe, ti::greater_than_comparable::maybe, ti::swappable::nothrow>>, // DefaultConstructibleValue ProfileAndExpectation< ti::DefaultConstructibleValueProfile, ti::DefaultConstructibleValueArchetype, ti::ConformanceProfile< ti::default_constructible::yes, ti::move_constructible::nothrow, ti::copy_constructible::yes, ti::move_assignable::nothrow, ti::copy_assignable::yes, ti::destructible::nothrow, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::maybe, ti::greater_than_comparable::maybe, ti::swappable::nothrow>>>; using ComparableHelpersProfilesToTest = ::testing::Types< // Equatable ProfileAndExpectation< ti::EquatableProfile, ti::EquatableArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::yes, ti::inequality_comparable::yes>>, // Comparable ProfileAndExpectation< ti::ComparableProfile, ti::ComparableArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::yes, ti::inequality_comparable::yes, ti::less_than_comparable::yes, ti::less_equal_comparable::yes, ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes>>, // NothrowEquatable ProfileAndExpectation< ti::NothrowEquatableProfile, ti::NothrowEquatableArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::nothrow, ti::inequality_comparable::nothrow>>, // NothrowComparable ProfileAndExpectation< ti::NothrowComparableProfile, ti::NothrowComparableArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::maybe, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::maybe, ti::equality_comparable::nothrow, ti::inequality_comparable::nothrow, ti::less_than_comparable::nothrow, ti::less_equal_comparable::nothrow, ti::greater_equal_comparable::nothrow, ti::greater_than_comparable::nothrow>>>; using CommonComparableProfilesToTest = ::testing::Types< // ComparableNothrowMoveConstructible ProfileAndExpectation< ti::ComparableNothrowMoveConstructibleProfile, ti::ComparableNothrowMoveConstructibleArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::nothrow, ti::copy_constructible::maybe, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::nothrow, ti::equality_comparable::yes, ti::inequality_comparable::yes, ti::less_than_comparable::yes, ti::less_equal_comparable::yes, ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes>>, // ComparableCopyConstructible ProfileAndExpectation< ti::ComparableCopyConstructibleProfile, ti::ComparableCopyConstructibleArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::nothrow, ti::copy_constructible::yes, ti::move_assignable::maybe, ti::copy_assignable::maybe, ti::destructible::nothrow, ti::equality_comparable::yes, ti::inequality_comparable::yes, ti::less_than_comparable::yes, ti::less_equal_comparable::yes, ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes>>, // ComparableNothrowMovable ProfileAndExpectation< ti::ComparableNothrowMovableProfile, ti::ComparableNothrowMovableArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::nothrow, ti::copy_constructible::maybe, ti::move_assignable::nothrow, ti::copy_assignable::maybe, ti::destructible::nothrow, ti::equality_comparable::yes, ti::inequality_comparable::yes, ti::less_than_comparable::yes, ti::less_equal_comparable::yes, ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes, ti::swappable::nothrow>>, // ComparableValue ProfileAndExpectation< ti::ComparableValueProfile, ti::ComparableValueArchetype, ti::ConformanceProfile< ti::default_constructible::maybe, ti::move_constructible::nothrow, ti::copy_constructible::yes, ti::move_assignable::nothrow, ti::copy_assignable::yes, ti::destructible::nothrow, ti::equality_comparable::yes, ti::inequality_comparable::yes, ti::less_than_comparable::yes, ti::less_equal_comparable::yes, ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes, ti::swappable::nothrow>>>; using TrivialProfilesToTest = ::testing::Types< ProfileAndExpectation< ti::TrivialSpecialMemberFunctionsProfile, ti::TrivialSpecialMemberFunctionsArchetype, ti::ConformanceProfile< ti::default_constructible::trivial, ti::move_constructible::trivial, ti::copy_constructible::trivial, ti::move_assignable::trivial, ti::copy_assignable::trivial, ti::destructible::trivial, ti::equality_comparable::maybe, ti::inequality_comparable::maybe, ti::less_than_comparable::maybe, ti::less_equal_comparable::maybe, ti::greater_equal_comparable::maybe, ti::greater_than_comparable::maybe, ti::swappable::nothrow>>, ProfileAndExpectation< ti::TriviallyCompleteProfile, ti::TriviallyCompleteArchetype, ti::ConformanceProfile< ti::default_constructible::trivial, ti::move_constructible::trivial, ti::copy_constructible::trivial, ti::move_assignable::trivial, ti::copy_assignable::trivial, ti::destructible::trivial, ti::equality_comparable::yes, ti::inequality_comparable::yes, ti::less_than_comparable::yes, ti::less_equal_comparable::yes, ti::greater_equal_comparable::yes, ti::greater_than_comparable::yes, ti::swappable::nothrow, ti::hashable::yes>>>; INSTANTIATE_TYPED_TEST_SUITE_P(Core, ProfileTest, CoreProfilesToTest); INSTANTIATE_TYPED_TEST_SUITE_P(Common, ProfileTest, CommonProfilesToTest); INSTANTIATE_TYPED_TEST_SUITE_P(ComparableHelpers, ProfileTest, ComparableHelpersProfilesToTest); INSTANTIATE_TYPED_TEST_SUITE_P(CommonComparable, ProfileTest, CommonComparableProfilesToTest); INSTANTIATE_TYPED_TEST_SUITE_P(Trivial, ProfileTest, TrivialProfilesToTest); TEST(ConformanceTestingTest, Basic) { using profile = ti::CombineProfiles<ti::TriviallyCompleteProfile, ti::NothrowComparableProfile>; using lim = std::numeric_limits<float>; ABSL_INTERNAL_ASSERT_CONFORMANCE_OF(float) .INITIALIZER(-lim::infinity()) .INITIALIZER(lim::lowest()) .INITIALIZER(-1.f) .INITIALIZER(-lim::min()) .EQUIVALENCE_CLASS(INITIALIZER(-0.f), INITIALIZER(0.f)) .INITIALIZER(lim::min()) .INITIALIZER(1.f) .INITIALIZER(lim::max()) .INITIALIZER(lim::infinity()) .WITH_STRICT_PROFILE(absl::types_internal::RegularityDomain, profile); } struct BadMoveConstruct { BadMoveConstruct() = default; BadMoveConstruct(BadMoveConstruct&& other) noexcept : value(other.value + 1) {} BadMoveConstruct& operator=(BadMoveConstruct&& other) noexcept = default; int value = 0; friend bool operator==(BadMoveConstruct const& lhs, BadMoveConstruct const& rhs) { return lhs.value == rhs.value; } friend bool operator!=(BadMoveConstruct const& lhs, BadMoveConstruct const& rhs) { return lhs.value != rhs.value; } }; struct BadMoveAssign { BadMoveAssign() = default; BadMoveAssign(BadMoveAssign&& other) noexcept = default; BadMoveAssign& operator=(BadMoveAssign&& other) noexcept { int new_value = other.value + 1; value = new_value; return *this; } int value = 0; friend bool operator==(BadMoveAssign const& lhs, BadMoveAssign const& rhs) { return lhs.value == rhs.value; } friend bool operator!=(BadMoveAssign const& lhs, BadMoveAssign const& rhs) { return lhs.value != rhs.value; } }; enum class WhichCompIsBad { eq, ne, lt, le, ge, gt }; template <WhichCompIsBad Which> struct BadCompare { int value; friend bool operator==(BadCompare const& lhs, BadCompare const& rhs) { return Which == WhichCompIsBad::eq ? lhs.value != rhs.value : lhs.value == rhs.value; } friend bool operator!=(BadCompare const& lhs, BadCompare const& rhs) { return Which == WhichCompIsBad::ne ? lhs.value == rhs.value : lhs.value != rhs.value; } friend bool operator<(BadCompare const& lhs, BadCompare const& rhs) { return Which == WhichCompIsBad::lt ? lhs.value >= rhs.value : lhs.value < rhs.value; } friend bool operator<=(BadCompare const& lhs, BadCompare const& rhs) { return Which == WhichCompIsBad::le ? lhs.value > rhs.value : lhs.value <= rhs.value; } friend bool operator>=(BadCompare const& lhs, BadCompare const& rhs) { return Which == WhichCompIsBad::ge ? lhs.value < rhs.value : lhs.value >= rhs.value; } friend bool operator>(BadCompare const& lhs, BadCompare const& rhs) { return Which == WhichCompIsBad::gt ? lhs.value <= rhs.value : lhs.value > rhs.value; } }; TEST(ConformanceTestingDeathTest, Failures) { { using profile = ti::CombineProfiles<ti::TriviallyCompleteProfile, ti::NothrowComparableProfile>; // Note: The initializers are intentionally in the wrong order. ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(float) .INITIALIZER(1.f) .INITIALIZER(0.f) .WITH_LOOSE_PROFILE(profile); } { using profile = ti::CombineProfiles<ti::NothrowMovableProfile, ti::EquatableProfile>; ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadMoveConstruct) .DUE_TO("Move construction") .INITIALIZER(BadMoveConstruct()) .WITH_LOOSE_PROFILE(profile); } { using profile = ti::CombineProfiles<ti::NothrowMovableProfile, ti::EquatableProfile>; ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadMoveAssign) .DUE_TO("Move assignment") .INITIALIZER(BadMoveAssign()) .WITH_LOOSE_PROFILE(profile); } } TEST(ConformanceTestingDeathTest, CompFailures) { using profile = ti::ComparableProfile; { using BadComp = BadCompare<WhichCompIsBad::eq>; ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp) .DUE_TO("Comparison") .INITIALIZER(BadComp{0}) .INITIALIZER(BadComp{1}) .WITH_LOOSE_PROFILE(profile); } { using BadComp = BadCompare<WhichCompIsBad::ne>; ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp) .DUE_TO("Comparison") .INITIALIZER(BadComp{0}) .INITIALIZER(BadComp{1}) .WITH_LOOSE_PROFILE(profile); } { using BadComp = BadCompare<WhichCompIsBad::lt>; ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp) .DUE_TO("Comparison") .INITIALIZER(BadComp{0}) .INITIALIZER(BadComp{1}) .WITH_LOOSE_PROFILE(profile); } { using BadComp = BadCompare<WhichCompIsBad::le>; ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp) .DUE_TO("Comparison") .INITIALIZER(BadComp{0}) .INITIALIZER(BadComp{1}) .WITH_LOOSE_PROFILE(profile); } { using BadComp = BadCompare<WhichCompIsBad::ge>; ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp) .DUE_TO("Comparison") .INITIALIZER(BadComp{0}) .INITIALIZER(BadComp{1}) .WITH_LOOSE_PROFILE(profile); } { using BadComp = BadCompare<WhichCompIsBad::gt>; ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadComp) .DUE_TO("Comparison") .INITIALIZER(BadComp{0}) .INITIALIZER(BadComp{1}) .WITH_LOOSE_PROFILE(profile); } } struct BadSelfMove { BadSelfMove() = default; BadSelfMove(BadSelfMove&&) = default; BadSelfMove& operator=(BadSelfMove&& other) noexcept { if (this == &other) { broken_state = true; } return *this; } friend bool operator==(const BadSelfMove& lhs, const BadSelfMove& rhs) { return !(lhs.broken_state || rhs.broken_state); } friend bool operator!=(const BadSelfMove& lhs, const BadSelfMove& rhs) { return lhs.broken_state || rhs.broken_state; } bool broken_state = false; }; TEST(ConformanceTestingDeathTest, SelfMoveFailure) { using profile = ti::EquatableNothrowMovableProfile; { ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadSelfMove) .DUE_TO("Move assignment") .INITIALIZER(BadSelfMove()) .WITH_LOOSE_PROFILE(profile); } } struct BadSelfCopy { BadSelfCopy() = default; BadSelfCopy(BadSelfCopy&&) = default; BadSelfCopy(const BadSelfCopy&) = default; BadSelfCopy& operator=(BadSelfCopy&&) = default; BadSelfCopy& operator=(BadSelfCopy const& other) { if (this == &other) { broken_state = true; } return *this; } friend bool operator==(const BadSelfCopy& lhs, const BadSelfCopy& rhs) { return !(lhs.broken_state || rhs.broken_state); } friend bool operator!=(const BadSelfCopy& lhs, const BadSelfCopy& rhs) { return lhs.broken_state || rhs.broken_state; } bool broken_state = false; }; TEST(ConformanceTestingDeathTest, SelfCopyFailure) { using profile = ti::EquatableValueProfile; { ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadSelfCopy) .DUE_TO("Copy assignment") .INITIALIZER(BadSelfCopy()) .WITH_LOOSE_PROFILE(profile); } } struct BadSelfSwap { friend void swap(BadSelfSwap& lhs, BadSelfSwap& rhs) noexcept { if (&lhs == &rhs) lhs.broken_state = true; } friend bool operator==(const BadSelfSwap& lhs, const BadSelfSwap& rhs) { return !(lhs.broken_state || rhs.broken_state); } friend bool operator!=(const BadSelfSwap& lhs, const BadSelfSwap& rhs) { return lhs.broken_state || rhs.broken_state; } bool broken_state = false; }; TEST(ConformanceTestingDeathTest, SelfSwapFailure) { using profile = ti::EquatableNothrowMovableProfile; { ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadSelfSwap) .DUE_TO("Swap") .INITIALIZER(BadSelfSwap()) .WITH_LOOSE_PROFILE(profile); } } struct BadDefaultInitializedMoveAssign { BadDefaultInitializedMoveAssign() : default_initialized(true) {} explicit BadDefaultInitializedMoveAssign(int v) : value(v) {} BadDefaultInitializedMoveAssign( BadDefaultInitializedMoveAssign&& other) noexcept : value(other.value) {} BadDefaultInitializedMoveAssign& operator=( BadDefaultInitializedMoveAssign&& other) noexcept { value = other.value; if (default_initialized) ++value; // Bad move if lhs is default initialized return *this; } friend bool operator==(const BadDefaultInitializedMoveAssign& lhs, const BadDefaultInitializedMoveAssign& rhs) { return lhs.value == rhs.value; } friend bool operator!=(const BadDefaultInitializedMoveAssign& lhs, const BadDefaultInitializedMoveAssign& rhs) { return lhs.value != rhs.value; } bool default_initialized = false; int value = 0; }; TEST(ConformanceTestingDeathTest, DefaultInitializedMoveAssignFailure) { using profile = ti::CombineProfiles<ti::DefaultConstructibleNothrowMovableProfile, ti::EquatableProfile>; { ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadDefaultInitializedMoveAssign) .DUE_TO("move assignment") .INITIALIZER(BadDefaultInitializedMoveAssign(0)) .WITH_LOOSE_PROFILE(profile); } } struct BadDefaultInitializedCopyAssign { BadDefaultInitializedCopyAssign() : default_initialized(true) {} explicit BadDefaultInitializedCopyAssign(int v) : value(v) {} BadDefaultInitializedCopyAssign( BadDefaultInitializedCopyAssign&& other) noexcept : value(other.value) {} BadDefaultInitializedCopyAssign(const BadDefaultInitializedCopyAssign& other) : value(other.value) {} BadDefaultInitializedCopyAssign& operator=( BadDefaultInitializedCopyAssign&& other) noexcept { value = other.value; return *this; } BadDefaultInitializedCopyAssign& operator=( const BadDefaultInitializedCopyAssign& other) { value = other.value; if (default_initialized) ++value; // Bad move if lhs is default initialized return *this; } friend bool operator==(const BadDefaultInitializedCopyAssign& lhs, const BadDefaultInitializedCopyAssign& rhs) { return lhs.value == rhs.value; } friend bool operator!=(const BadDefaultInitializedCopyAssign& lhs, const BadDefaultInitializedCopyAssign& rhs) { return lhs.value != rhs.value; } bool default_initialized = false; int value = 0; }; TEST(ConformanceTestingDeathTest, DefaultInitializedAssignFailure) { using profile = ti::CombineProfiles<ti::DefaultConstructibleValueProfile, ti::EquatableProfile>; { ABSL_INTERNAL_ASSERT_NONCONFORMANCE_OF(BadDefaultInitializedCopyAssign) .DUE_TO("copy assignment") .INITIALIZER(BadDefaultInitializedCopyAssign(0)) .WITH_LOOSE_PROFILE(profile); } } } // namespace