brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.3 KiB · ab50ad0 Raw
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