summaryrefslogtreecommitdiff
path: root/absl/types/internal/conformance_testing_test.cc
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2020-04-17 08:13:06 -0700
committerGravatar Mark Barolak <mbar@google.com>2020-04-17 11:58:29 -0400
commitb35973e3e35cb1eccb086d6a549c253c49579474 (patch)
tree2acab21a7c8039c1b4e7b7e5b580ac64aa743291 /absl/types/internal/conformance_testing_test.cc
parentdb5773a721a50d1fc8c9b51efea0e70be4003d36 (diff)
Export of internal Abseil changes
-- d857e6e1f9b09a3eb5abd890677a98b23346f07a by Abseil Team <absl-team@google.com>: Simplify internal TryAcquireWithSpinning. No point declaring the `result` variable: we can just return the results directly. PiperOrigin-RevId: 307045800 -- 421952252bc23be51f47f7d23f3422bad1ed382c by Derek Mauro <dmauro@google.com>: Add custom sink support for `absl::Format()` through an ADL extension mechanism. Users can now define `void AbslFormatFlush(MySink* dest, absl::string_view part)` to allow `absl::Format()` to append to a custom sink. PiperOrigin-RevId: 306929052 -- c73d5cdb62cd58ea421ed1aeeab78a0ffcfeeefb by Matt Calabrese <calabrese@google.com>: Internal-only conformance-testing macro ABSL_INTERNAL_ASSERT_CONFORMANCE_OF for compile-time and runtime checks of a specified type, expected properties of that type, and a logically-ordered series of equivalence classes of that type. PiperOrigin-RevId: 306885512 -- a8c2495a07f37d68907855e3f0535bd5c27a3b52 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 306766753 GitOrigin-RevId: d857e6e1f9b09a3eb5abd890677a98b23346f07a Change-Id: Ic23c92ac74f9ffcbb2471ff8c6691f4b7b20354b
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