brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.4 KiB · c17aa03 Raw
292 lines · cpp
1//===- unittests/ADT/FallibleIteratorTest.cpp - fallible_iterator.h tests -===//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/fallible_iterator.h"10#include "llvm/Testing/Support/Error.h"11 12#include "gtest/gtest-spi.h"13#include "gtest/gtest.h"14 15#include <utility>16#include <vector>17 18using namespace llvm;19 20namespace {21 22enum ItemValid { ValidItem, InvalidItem };23enum LinkValid { ValidLink, InvalidLink };24 25class Item {26public:27  Item(ItemValid V) : V(V) {}28  bool isValid() const { return V == ValidItem; }29 30private:31  ItemValid V;32};33 34// A utility to mock "bad collections". It supports both invalid items,35// where the dereference operator may return an Error, and bad links36// where the inc/dec operations may return an Error.37// Each element of the mock collection contains a pair of a (possibly broken)38// item and link.39using FallibleCollection = std::vector<std::pair<Item, LinkValid>>;40 41class FallibleCollectionWalker {42public:43  FallibleCollectionWalker(FallibleCollection &C, unsigned Idx)44      : C(C), Idx(Idx) {}45 46  Item &operator*() { return C[Idx].first; }47 48  const Item &operator*() const { return C[Idx].first; }49 50  Error inc() {51    assert(Idx != C.size() && "Walking off end of (mock) collection");52    if (C[Idx].second == ValidLink) {53      ++Idx;54      return Error::success();55    }56    return make_error<StringError>("cant get next object in (mock) collection",57                                   inconvertibleErrorCode());58  }59 60  Error dec() {61    assert(Idx != 0 && "Walking off start of (mock) collection");62    --Idx;63    if (C[Idx].second == ValidLink)64      return Error::success();65    return make_error<StringError>("cant get prev object in (mock) collection",66                                   inconvertibleErrorCode());67  }68 69  friend bool operator==(const FallibleCollectionWalker &LHS,70                         const FallibleCollectionWalker &RHS) {71    assert(&LHS.C == &RHS.C && "Comparing iterators across collectionss.");72    return LHS.Idx == RHS.Idx;73  }74 75private:76  FallibleCollection &C;77  unsigned Idx;78};79 80class FallibleCollectionWalkerWithStructDeref81    : public FallibleCollectionWalker {82public:83  using FallibleCollectionWalker::FallibleCollectionWalker;84 85  Item *operator->() { return &this->operator*(); }86 87  const Item *operator->() const { return &this->operator*(); }88};89 90class FallibleCollectionWalkerWithFallibleDeref91    : public FallibleCollectionWalker {92public:93  using FallibleCollectionWalker::FallibleCollectionWalker;94 95  Expected<Item &> operator*() {96    auto &I = FallibleCollectionWalker::operator*();97    if (!I.isValid())98      return make_error<StringError>("bad item", inconvertibleErrorCode());99    return I;100  }101 102  Expected<const Item &> operator*() const {103    const auto &I = FallibleCollectionWalker::operator*();104    if (!I.isValid())105      return make_error<StringError>("bad item", inconvertibleErrorCode());106    return I;107  }108};109 110TEST(FallibleIteratorTest, BasicSuccess) {111 112  // Check that a basic use-case involing successful iteration over a113  // "FallibleCollection" works.114 115  FallibleCollection C({{ValidItem, ValidLink}, {ValidItem, ValidLink}});116 117  FallibleCollectionWalker begin(C, 0);118  FallibleCollectionWalker end(C, 2);119 120  Error Err = Error::success();121  for (auto &Elem :122       make_fallible_range<FallibleCollectionWalker>(begin, end, Err))123    EXPECT_TRUE(Elem.isValid());124  cantFail(std::move(Err));125}126 127TEST(FallibleIteratorTest, BasicFailure) {128 129  // Check that a iteration failure (due to the InvalidLink state on element one130  // of the fallible collection) breaks out of the loop and raises an Error.131 132  FallibleCollection C({{ValidItem, ValidLink}, {ValidItem, InvalidLink}});133 134  FallibleCollectionWalker begin(C, 0);135  FallibleCollectionWalker end(C, 2);136 137  Error Err = Error::success();138  for (auto &Elem :139       make_fallible_range<FallibleCollectionWalker>(begin, end, Err))140    EXPECT_TRUE(Elem.isValid());141 142  EXPECT_THAT_ERROR(std::move(Err), Failed()) << "Expected failure value";143}144 145TEST(FallibleIteratorTest, NoRedundantErrorCheckOnEarlyExit) {146 147  // Check that an early return from the loop body does not require a redundant148  // check of Err.149 150  FallibleCollection C({{ValidItem, ValidLink}, {ValidItem, ValidLink}});151 152  FallibleCollectionWalker begin(C, 0);153  FallibleCollectionWalker end(C, 2);154 155  Error Err = Error::success();156  for (auto &Elem :157       make_fallible_range<FallibleCollectionWalker>(begin, end, Err)) {158    (void)Elem;159    return;160  }161  // Err not checked, but should be ok because we exit from the loop162  // body.163}164 165#if LLVM_ENABLE_ABI_BREAKING_CHECKS166TEST(FallibleIteratorTest, RegularLoopExitRequiresErrorCheck) {167 168  // Check that Err must be checked after a normal (i.e. not early) loop exit169  // by failing to check and expecting program death (due to the unchecked170  // error).171 172  EXPECT_DEATH(173      {174        FallibleCollection C({{ValidItem, ValidLink}, {ValidItem, ValidLink}});175 176        FallibleCollectionWalker begin(C, 0);177        FallibleCollectionWalker end(C, 2);178 179        Error Err = Error::success();180        for (auto &Elem :181             make_fallible_range<FallibleCollectionWalker>(begin, end, Err))182          (void)Elem;183      },184      "Program aborted due to an unhandled Error:")185      << "Normal (i.e. not early) loop exit should require an error check";186}187#endif188 189TEST(FallibleIteratorTest, RawIncrementAndDecrementBehavior) {190 191  // Check the exact behavior of increment / decrement.192 193  FallibleCollection C({{ValidItem, ValidLink},194                        {ValidItem, InvalidLink},195                        {ValidItem, ValidLink},196                        {ValidItem, InvalidLink}});197 198  {199    // One increment from begin succeeds.200    Error Err = Error::success();201    auto I = make_fallible_itr(FallibleCollectionWalker(C, 0), Err);202    ++I;203    EXPECT_THAT_ERROR(std::move(Err), Succeeded());204  }205 206  {207    // Two increments from begin fail.208    Error Err = Error::success();209    auto I = make_fallible_itr(FallibleCollectionWalker(C, 0), Err);210    ++I;211    EXPECT_THAT_ERROR(std::move(Err), Succeeded());212    ++I;213    EXPECT_THAT_ERROR(std::move(Err), Failed()) << "Expected failure value";214  }215 216  {217    // One decement from element three succeeds.218    Error Err = Error::success();219    auto I = make_fallible_itr(FallibleCollectionWalker(C, 3), Err);220    --I;221    EXPECT_THAT_ERROR(std::move(Err), Succeeded());222  }223 224  {225    // One decement from element three succeeds.226    Error Err = Error::success();227    auto I = make_fallible_itr(FallibleCollectionWalker(C, 3), Err);228    --I;229    EXPECT_THAT_ERROR(std::move(Err), Succeeded());230    --I;231    EXPECT_THAT_ERROR(std::move(Err), Failed());232  }233}234 235TEST(FallibleIteratorTest, CheckStructDerefOperatorSupport) {236  // Check that the fallible_iterator wrapper forwards through to the237  // underlying iterator's structure dereference operator if present.238 239  FallibleCollection C({{ValidItem, ValidLink},240                        {ValidItem, ValidLink},241                        {InvalidItem, InvalidLink}});242 243  FallibleCollectionWalkerWithStructDeref begin(C, 0);244 245  {246    Error Err = Error::success();247    auto I = make_fallible_itr(begin, Err);248    EXPECT_TRUE(I->isValid());249    cantFail(std::move(Err));250  }251 252  {253    Error Err = Error::success();254    const auto I = make_fallible_itr(begin, Err);255    EXPECT_TRUE(I->isValid());256    cantFail(std::move(Err));257  }258}259 260TEST(FallibleIteratorTest, CheckDerefToExpectedSupport) {261 262  // Check that the fallible_iterator wrapper forwards value types, in263  // particular llvm::Expected, correctly.264 265  FallibleCollection C({{ValidItem, ValidLink},266                        {InvalidItem, ValidLink},267                        {ValidItem, ValidLink}});268 269  FallibleCollectionWalkerWithFallibleDeref begin(C, 0);270  FallibleCollectionWalkerWithFallibleDeref end(C, 3);271 272  Error Err = Error::success();273  auto I = make_fallible_itr(begin, Err);274  auto E = make_fallible_end(end);275 276  Expected<Item> V1 = *I;277  EXPECT_THAT_ERROR(V1.takeError(), Succeeded());278  ++I;279  EXPECT_NE(I, E); // Implicitly check error.280  Expected<Item> V2 = *I;281  EXPECT_THAT_ERROR(V2.takeError(), Failed());282  ++I;283  EXPECT_NE(I, E); // Implicitly check error.284  Expected<Item> V3 = *I;285  EXPECT_THAT_ERROR(V3.takeError(), Succeeded());286  ++I;287  EXPECT_EQ(I, E);288  cantFail(std::move(Err));289}290 291} // namespace292