312 lines · cpp
1//===- SequenceTest.cpp - Unit tests for a sequence abstraciton -----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/ADT/Sequence.h"10#include "llvm/ADT/STLExtras.h"11#include "gmock/gmock.h"12#include "gtest/gtest.h"13 14#include <iterator>15#include <limits>16#include <vector>17 18using namespace llvm;19 20using testing::ElementsAre;21using testing::IsEmpty;22 23namespace {24 25using detail::canTypeFitValue;26using detail::CheckedInt;27 28using IntegralTypes = testing::Types<uint8_t, // 029 uint16_t, // 130 uint32_t, // 231 uint64_t, // 332 uintmax_t, // 433 int8_t, // 534 int16_t, // 635 int32_t, // 736 int64_t, // 837 intmax_t // 938 >;39 40template <class T> class StrongIntTest : public testing::Test {};41TYPED_TEST_SUITE(StrongIntTest, IntegralTypes, );42TYPED_TEST(StrongIntTest, Operations) {43 using T = TypeParam;44 auto Max = std::numeric_limits<T>::max();45 auto Min = std::numeric_limits<T>::min();46 47 // We bail out for types that are not entirely representable within intmax_t.48 if (!canTypeFitValue<intmax_t>(Max) || !canTypeFitValue<intmax_t>(Min))49 return;50 51 // All representable values convert back and forth.52 EXPECT_EQ(CheckedInt::from(Min).template to<T>(), Min);53 EXPECT_EQ(CheckedInt::from(Max).template to<T>(), Max);54 55 // Addition -2, -1, 0, 1, 2.56 const T Expected = Max / 2;57 const CheckedInt Actual = CheckedInt::from(Expected);58 EXPECT_EQ((Actual + -2).template to<T>(), Expected - 2);59 EXPECT_EQ((Actual + -1).template to<T>(), Expected - 1);60 EXPECT_EQ((Actual + 0).template to<T>(), Expected);61 EXPECT_EQ((Actual + 1).template to<T>(), Expected + 1);62 EXPECT_EQ((Actual + 2).template to<T>(), Expected + 2);63 64 // EQ/NEQ65 EXPECT_EQ(Actual, Actual);66 EXPECT_NE(Actual, Actual + 1);67 68 // Difference69 EXPECT_EQ(Actual - Actual, 0);70 EXPECT_EQ((Actual + 1) - Actual, 1);71 EXPECT_EQ(Actual - (Actual + 2), -2);72}73 74#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)75TEST(StrongIntDeathTest, OutOfBounds) {76 // Values above 'INTMAX_MAX' are not representable.77 EXPECT_DEATH(CheckedInt::from<uintmax_t>(INTMAX_MAX + 1ULL), "Out of bounds");78 EXPECT_DEATH(CheckedInt::from<uintmax_t>(UINTMAX_MAX), "Out of bounds");79 // Casting to narrower type asserts when out of bounds.80 EXPECT_DEATH(CheckedInt::from(-1).to<uint8_t>(), "Out of bounds");81 EXPECT_DEATH(CheckedInt::from(256).to<uint8_t>(), "Out of bounds");82 // Operations leading to intmax_t overflow assert.83 EXPECT_DEATH(CheckedInt::from(INTMAX_MAX) + 1, "Out of bounds");84 EXPECT_DEATH(CheckedInt::from(INTMAX_MIN) + -1, "Out of bounds");85 EXPECT_DEATH(CheckedInt::from(INTMAX_MIN) - CheckedInt::from(INTMAX_MAX),86 "Out of bounds");87}88#endif89 90TEST(SafeIntIteratorTest, Operations) {91 detail::SafeIntIterator<int, false> Forward(0);92 detail::SafeIntIterator<int, true> Reverse(0);93 94 const auto SetToZero = [&]() {95 Forward = detail::SafeIntIterator<int, false>(0);96 Reverse = detail::SafeIntIterator<int, true>(0);97 };98 99 // Equality / Comparisons100 SetToZero();101 EXPECT_EQ(Forward, Forward);102 EXPECT_LT(Forward - 1, Forward);103 EXPECT_LE(Forward, Forward);104 EXPECT_LE(Forward - 1, Forward);105 EXPECT_GT(Forward + 1, Forward);106 EXPECT_GE(Forward, Forward);107 EXPECT_GE(Forward + 1, Forward);108 109 EXPECT_EQ(Reverse, Reverse);110 EXPECT_LT(Reverse - 1, Reverse);111 EXPECT_LE(Reverse, Reverse);112 EXPECT_LE(Reverse - 1, Reverse);113 EXPECT_GT(Reverse + 1, Reverse);114 EXPECT_GE(Reverse, Reverse);115 EXPECT_GE(Reverse + 1, Reverse);116 117 // Dereference118 SetToZero();119 EXPECT_EQ(*Forward, 0);120 EXPECT_EQ(*Reverse, 0);121 122 // Indexing123 SetToZero();124 EXPECT_EQ(Forward[2], 2);125 EXPECT_EQ(Reverse[2], -2);126 127 // Pre-increment128 SetToZero();129 ++Forward;130 EXPECT_EQ(*Forward, 1);131 ++Reverse;132 EXPECT_EQ(*Reverse, -1);133 134 // Pre-decrement135 SetToZero();136 --Forward;137 EXPECT_EQ(*Forward, -1);138 --Reverse;139 EXPECT_EQ(*Reverse, 1);140 141 // Post-increment142 SetToZero();143 EXPECT_EQ(*(Forward++), 0);144 EXPECT_EQ(*Forward, 1);145 EXPECT_EQ(*(Reverse++), 0);146 EXPECT_EQ(*Reverse, -1);147 148 // Post-decrement149 SetToZero();150 EXPECT_EQ(*(Forward--), 0);151 EXPECT_EQ(*Forward, -1);152 EXPECT_EQ(*(Reverse--), 0);153 EXPECT_EQ(*Reverse, 1);154 155 // Compound assignment operators156 SetToZero();157 Forward += 1;158 EXPECT_EQ(*Forward, 1);159 Reverse += 1;160 EXPECT_EQ(*Reverse, -1);161 SetToZero();162 Forward -= 2;163 EXPECT_EQ(*Forward, -2);164 Reverse -= 2;165 EXPECT_EQ(*Reverse, 2);166 167 // Arithmetic168 SetToZero();169 EXPECT_EQ(*(Forward + 3), 3);170 EXPECT_EQ(*(Reverse + 3), -3);171 SetToZero();172 EXPECT_EQ(*(Forward - 4), -4);173 EXPECT_EQ(*(Reverse - 4), 4);174 175 // Difference176 SetToZero();177 EXPECT_EQ(Forward - Forward, 0);178 EXPECT_EQ(Reverse - Reverse, 0);179 EXPECT_EQ((Forward + 1) - Forward, 1);180 EXPECT_EQ(Forward - (Forward + 1), -1);181 EXPECT_EQ((Reverse + 1) - Reverse, 1);182 EXPECT_EQ(Reverse - (Reverse + 1), -1);183}184 185TEST(SequenceTest, Iteration) {186 EXPECT_THAT(seq(5), ElementsAre(0, 1, 2, 3, 4));187 188 EXPECT_THAT(seq(-4, 5), ElementsAre(-4, -3, -2, -1, 0, 1, 2, 3, 4));189 EXPECT_THAT(reverse(seq(-4, 5)), ElementsAre(4, 3, 2, 1, 0, -1, -2, -3, -4));190 191 EXPECT_THAT(seq_inclusive(-4, 5),192 ElementsAre(-4, -3, -2, -1, 0, 1, 2, 3, 4, 5));193 EXPECT_THAT(reverse(seq_inclusive(-4, 5)),194 ElementsAre(5, 4, 3, 2, 1, 0, -1, -2, -3, -4));195}196 197TEST(SequenceTest, Distance) {198 const auto Forward = seq(0, 10);199 EXPECT_EQ(std::distance(Forward.begin(), Forward.end()), 10);200 EXPECT_EQ(std::distance(Forward.rbegin(), Forward.rend()), 10);201}202 203TEST(SequenceTest, Dereference) {204 const auto Forward = seq(0, 10).begin();205 EXPECT_EQ(Forward[0], 0);206 EXPECT_EQ(Forward[2], 2);207 const auto Backward = seq(0, 10).rbegin();208 EXPECT_EQ(Backward[0], 9);209 EXPECT_EQ(Backward[2], 7);210}211 212enum UntypedEnum { A = 3 };213enum TypedEnum : uint32_t { B = 3 };214 215namespace X {216enum class ScopedEnum : uint16_t { C = 3 };217} // namespace X218 219struct S {220 enum NestedEnum { D = 4 };221 enum NestedEnum2 { E = 5 };222 223private:224 enum NestedEnum3 { F = 6 };225 friend struct llvm::enum_iteration_traits<NestedEnum3>;226 227public:228 static auto getNestedEnum3() { return NestedEnum3::F; }229};230 231} // namespace232 233namespace llvm {234 235template <> struct enum_iteration_traits<UntypedEnum> {236 static constexpr bool is_iterable = true;237};238 239template <> struct enum_iteration_traits<TypedEnum> {240 static constexpr bool is_iterable = true;241};242 243template <> struct enum_iteration_traits<X::ScopedEnum> {244 static constexpr bool is_iterable = true;245};246 247template <> struct enum_iteration_traits<S::NestedEnum> {248 static constexpr bool is_iterable = true;249};250 251template <> struct enum_iteration_traits<S::NestedEnum3> {252 static constexpr bool is_iterable = true;253};254 255} // namespace llvm256 257namespace {258 259TEST(StrongIntTest, Enums) {260 EXPECT_EQ(CheckedInt::from(A).to<UntypedEnum>(), A);261 EXPECT_EQ(CheckedInt::from(B).to<TypedEnum>(), B);262 EXPECT_EQ(CheckedInt::from(X::ScopedEnum::C).to<X::ScopedEnum>(),263 X::ScopedEnum::C);264}265 266TEST(SequenceTest, IterableEnums) {267 EXPECT_THAT(enum_seq(UntypedEnum::A, UntypedEnum::A), IsEmpty());268 EXPECT_THAT(enum_seq_inclusive(UntypedEnum::A, UntypedEnum::A),269 ElementsAre(UntypedEnum::A));270 271 EXPECT_THAT(enum_seq(TypedEnum::B, TypedEnum::B), IsEmpty());272 EXPECT_THAT(enum_seq_inclusive(TypedEnum::B, TypedEnum::B),273 ElementsAre(TypedEnum::B));274 275 EXPECT_THAT(enum_seq(X::ScopedEnum::C, X::ScopedEnum::C), IsEmpty());276 EXPECT_THAT(enum_seq_inclusive(X::ScopedEnum::C, X::ScopedEnum::C),277 ElementsAre(X::ScopedEnum::C));278 279 EXPECT_THAT(enum_seq_inclusive(S::NestedEnum::D, S::NestedEnum::D),280 ElementsAre(S::NestedEnum::D));281 EXPECT_THAT(enum_seq_inclusive(S::getNestedEnum3(), S::getNestedEnum3()),282 ElementsAre(S::getNestedEnum3()));283}284 285TEST(SequenceTest, NonIterableEnums) {286 EXPECT_THAT(enum_seq(S::NestedEnum2::E, S::NestedEnum2::E,287 force_iteration_on_noniterable_enum),288 IsEmpty());289 EXPECT_THAT(enum_seq_inclusive(S::NestedEnum2::E, S::NestedEnum2::E,290 force_iteration_on_noniterable_enum),291 ElementsAre(S::NestedEnum2::E));292 293 // Check that this also works with enums marked as iterable.294 EXPECT_THAT(enum_seq(UntypedEnum::A, UntypedEnum::A,295 force_iteration_on_noniterable_enum),296 IsEmpty());297 EXPECT_THAT(enum_seq_inclusive(UntypedEnum::A, UntypedEnum::A,298 force_iteration_on_noniterable_enum),299 ElementsAre(UntypedEnum::A));300}301 302// Reproducer for https://github.com/llvm/llvm-project/issues/61122303TEST(SequenceTest, CorrectReferenceType) {304 std::vector<int> vals = {1, 2, 3};305 detail::SafeIntIterator<int, false> begin(4);306 detail::SafeIntIterator<int, false> end(6);307 vals.insert(vals.end(), begin, end);308 EXPECT_THAT(vals, ElementsAre(1, 2, 3, 4, 5));309}310 311} // namespace312