//===- SequenceTest.cpp - Unit tests for a sequence abstraciton -----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/ADT/Sequence.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include #include using namespace llvm; using testing::ElementsAre; namespace { using detail::canTypeFitValue; using detail::CheckedInt; using IntegralTypes = testing::Types; template class StrongIntTest : public testing::Test {}; TYPED_TEST_SUITE(StrongIntTest, IntegralTypes); TYPED_TEST(StrongIntTest, Operations) { using T = TypeParam; auto Max = std::numeric_limits::max(); auto Min = std::numeric_limits::min(); // We bail out for types that are not entirely representable within intmax_t. if (!canTypeFitValue(Max) || !canTypeFitValue(Min)) return; // All representable values convert back and forth. EXPECT_EQ(CheckedInt::from(Min).template to(), Min); EXPECT_EQ(CheckedInt::from(Max).template to(), Max); // Addition -2, -1, 0, 1, 2. const T Expected = Max / 2; const CheckedInt Actual = CheckedInt::from(Expected); EXPECT_EQ((Actual + -2).template to(), Expected - 2); EXPECT_EQ((Actual + -1).template to(), Expected - 1); EXPECT_EQ((Actual + 0).template to(), Expected); EXPECT_EQ((Actual + 1).template to(), Expected + 1); EXPECT_EQ((Actual + 2).template to(), Expected + 2); // EQ/NEQ EXPECT_EQ(Actual, Actual); EXPECT_NE(Actual, Actual + 1); // Difference EXPECT_EQ(Actual - Actual, 0); EXPECT_EQ((Actual + 1) - Actual, 1); EXPECT_EQ(Actual - (Actual + 2), -2); } TEST(StrongIntTest, Enums) { enum UntypedEnum { A = 3 }; EXPECT_EQ(CheckedInt::from(A).to(), A); enum TypedEnum : uint32_t { B = 3 }; EXPECT_EQ(CheckedInt::from(B).to(), B); enum class ScopedEnum : uint16_t { C = 3 }; EXPECT_EQ(CheckedInt::from(ScopedEnum::C).to(), ScopedEnum::C); } #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) TEST(StrongIntDeathTest, OutOfBounds) { // Values above 'INTMAX_MAX' are not representable. EXPECT_DEATH(CheckedInt::from(INTMAX_MAX + 1ULL), "Out of bounds"); EXPECT_DEATH(CheckedInt::from(UINTMAX_MAX), "Out of bounds"); // Casting to narrower type asserts when out of bounds. EXPECT_DEATH(CheckedInt::from(-1).to(), "Out of bounds"); EXPECT_DEATH(CheckedInt::from(256).to(), "Out of bounds"); // Operations leading to intmax_t overflow assert. EXPECT_DEATH(CheckedInt::from(INTMAX_MAX) + 1, "Out of bounds"); EXPECT_DEATH(CheckedInt::from(INTMAX_MIN) + -1, "Out of bounds"); EXPECT_DEATH(CheckedInt::from(INTMAX_MIN) - CheckedInt::from(INTMAX_MAX), "Out of bounds"); } #endif TEST(SafeIntIteratorTest, Operations) { detail::SafeIntIterator Forward(0); detail::SafeIntIterator Reverse(0); const auto SetToZero = [&]() { Forward = detail::SafeIntIterator(0); Reverse = detail::SafeIntIterator(0); }; // Equality / Comparisons SetToZero(); EXPECT_EQ(Forward, Forward); EXPECT_LT(Forward - 1, Forward); EXPECT_LE(Forward, Forward); EXPECT_LE(Forward - 1, Forward); EXPECT_GT(Forward + 1, Forward); EXPECT_GE(Forward, Forward); EXPECT_GE(Forward + 1, Forward); EXPECT_EQ(Reverse, Reverse); EXPECT_LT(Reverse - 1, Reverse); EXPECT_LE(Reverse, Reverse); EXPECT_LE(Reverse - 1, Reverse); EXPECT_GT(Reverse + 1, Reverse); EXPECT_GE(Reverse, Reverse); EXPECT_GE(Reverse + 1, Reverse); // Dereference SetToZero(); EXPECT_EQ(*Forward, 0); EXPECT_EQ(*Reverse, 0); // Indexing SetToZero(); EXPECT_EQ(Forward[2], 2); EXPECT_EQ(Reverse[2], -2); // Pre-increment SetToZero(); ++Forward; EXPECT_EQ(*Forward, 1); ++Reverse; EXPECT_EQ(*Reverse, -1); // Pre-decrement SetToZero(); --Forward; EXPECT_EQ(*Forward, -1); --Reverse; EXPECT_EQ(*Reverse, 1); // Post-increment SetToZero(); EXPECT_EQ(*(Forward++), 0); EXPECT_EQ(*Forward, 1); EXPECT_EQ(*(Reverse++), 0); EXPECT_EQ(*Reverse, -1); // Post-decrement SetToZero(); EXPECT_EQ(*(Forward--), 0); EXPECT_EQ(*Forward, -1); EXPECT_EQ(*(Reverse--), 0); EXPECT_EQ(*Reverse, 1); // Compound assignment operators SetToZero(); Forward += 1; EXPECT_EQ(*Forward, 1); Reverse += 1; EXPECT_EQ(*Reverse, -1); SetToZero(); Forward -= 2; EXPECT_EQ(*Forward, -2); Reverse -= 2; EXPECT_EQ(*Reverse, 2); // Arithmetic SetToZero(); EXPECT_EQ(*(Forward + 3), 3); EXPECT_EQ(*(Reverse + 3), -3); SetToZero(); EXPECT_EQ(*(Forward - 4), -4); EXPECT_EQ(*(Reverse - 4), 4); // Difference SetToZero(); EXPECT_EQ(Forward - Forward, 0); EXPECT_EQ(Reverse - Reverse, 0); EXPECT_EQ((Forward + 1) - Forward, 1); EXPECT_EQ(Forward - (Forward + 1), -1); EXPECT_EQ((Reverse + 1) - Reverse, 1); EXPECT_EQ(Reverse - (Reverse + 1), -1); } TEST(SequenceTest, Iteration) { EXPECT_THAT(seq(-4, 5), ElementsAre(-4, -3, -2, -1, 0, 1, 2, 3, 4)); EXPECT_THAT(reverse(seq(-4, 5)), ElementsAre(4, 3, 2, 1, 0, -1, -2, -3, -4)); EXPECT_THAT(seq_inclusive(-4, 5), ElementsAre(-4, -3, -2, -1, 0, 1, 2, 3, 4, 5)); EXPECT_THAT(reverse(seq_inclusive(-4, 5)), ElementsAre(5, 4, 3, 2, 1, 0, -1, -2, -3, -4)); } TEST(SequenceTest, Distance) { const auto Forward = seq(0, 10); EXPECT_EQ(std::distance(Forward.begin(), Forward.end()), 10); EXPECT_EQ(std::distance(Forward.rbegin(), Forward.rend()), 10); } TEST(SequenceTest, Dereference) { const auto Forward = seq(0, 10).begin(); EXPECT_EQ(Forward[0], 0); EXPECT_EQ(Forward[2], 2); const auto Backward = seq(0, 10).rbegin(); EXPECT_EQ(Backward[0], 9); EXPECT_EQ(Backward[2], 7); } } // anonymous namespace