about summary refs log tree commit diff
path: root/absl/types/internal/conformance_testing_test.cc
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2020-04-17T15·13-0700
committerMark Barolak <mbar@google.com>2020-04-17T15·58-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 3dcf53056703..cf262fa6c222 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