summaryrefslogtreecommitdiff
path: root/absl/types/internal/conformance_testing_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/types/internal/conformance_testing_test.cc')
-rw-r--r--absl/types/internal/conformance_testing_test.cc372
1 files changed, 371 insertions, 1 deletions
diff --git a/absl/types/internal/conformance_testing_test.cc b/absl/types/internal/conformance_testing_test.cc
index 3dcf5305..cf262fa6 100644
--- a/absl/types/internal/conformance_testing_test.cc
+++ b/absl/types/internal/conformance_testing_test.cc
@@ -12,6 +12,8 @@
// 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>
@@ -19,6 +21,7 @@
#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 {
@@ -1181,6 +1184,373 @@ INSTANTIATE_TYPED_TEST_SUITE_P(CommonComparable, ProfileTest,
CommonComparableProfilesToTest);
INSTANTIATE_TYPED_TEST_SUITE_P(Trivial, ProfileTest, TrivialProfilesToTest);
-// TODO(calabrese) Test runtime results
+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