C++程序  |  531行  |  15.89 KB

//===- llvm/unittest/ADT/OptionalTest.cpp - Optional unit tests -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/Optional.h"
#include "gtest/gtest.h"

using namespace llvm;

namespace {

struct NonDefaultConstructible {
  static unsigned CopyConstructions;
  static unsigned Destructions;
  static unsigned CopyAssignments;
  explicit NonDefaultConstructible(int) {
  }
  NonDefaultConstructible(const NonDefaultConstructible&) {
    ++CopyConstructions;
  }
  NonDefaultConstructible &operator=(const NonDefaultConstructible&) {
    ++CopyAssignments;
    return *this;
  }
  ~NonDefaultConstructible() {
    ++Destructions;
  }
  static void ResetCounts() {
    CopyConstructions = 0;
    Destructions = 0;
    CopyAssignments = 0;
  }
};

unsigned NonDefaultConstructible::CopyConstructions = 0;
unsigned NonDefaultConstructible::Destructions = 0;
unsigned NonDefaultConstructible::CopyAssignments = 0;

// Test fixture
class OptionalTest : public testing::Test {
};

TEST_F(OptionalTest, NonDefaultConstructibleTest) {
  Optional<NonDefaultConstructible> O;
  EXPECT_FALSE(O);
}

TEST_F(OptionalTest, ResetTest) {
  NonDefaultConstructible::ResetCounts();
  Optional<NonDefaultConstructible> O(NonDefaultConstructible(3));
  EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
  EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
  EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
  NonDefaultConstructible::ResetCounts();
  O.reset();
  EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
  EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
  EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
}

TEST_F(OptionalTest, InitializationLeakTest) {
  NonDefaultConstructible::ResetCounts();
  Optional<NonDefaultConstructible>(NonDefaultConstructible(3));
  EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
  EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
  EXPECT_EQ(2u, NonDefaultConstructible::Destructions);
}

TEST_F(OptionalTest, CopyConstructionTest) {
  NonDefaultConstructible::ResetCounts();
  {
    Optional<NonDefaultConstructible> A(NonDefaultConstructible(3));
    EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
    EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
    EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
    NonDefaultConstructible::ResetCounts();
    Optional<NonDefaultConstructible> B(A);
    EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
    EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
    EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
    NonDefaultConstructible::ResetCounts();
  }
  EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
  EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
  EXPECT_EQ(2u, NonDefaultConstructible::Destructions);
}

TEST_F(OptionalTest, ConstructingCopyAssignmentTest) {
  NonDefaultConstructible::ResetCounts();
  {
    Optional<NonDefaultConstructible> A(NonDefaultConstructible(3));
    Optional<NonDefaultConstructible> B;
    EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
    EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
    EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
    NonDefaultConstructible::ResetCounts();
    B = A;
    EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
    EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
    EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
    NonDefaultConstructible::ResetCounts();
  }
  EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
  EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
  EXPECT_EQ(2u, NonDefaultConstructible::Destructions);
}

TEST_F(OptionalTest, CopyingCopyAssignmentTest) {
  NonDefaultConstructible::ResetCounts();
  {
    Optional<NonDefaultConstructible> A(NonDefaultConstructible(3));
    Optional<NonDefaultConstructible> B(NonDefaultConstructible(4));
    EXPECT_EQ(2u, NonDefaultConstructible::CopyConstructions);
    EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
    EXPECT_EQ(2u, NonDefaultConstructible::Destructions);
    NonDefaultConstructible::ResetCounts();
    B = A;
    EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
    EXPECT_EQ(1u, NonDefaultConstructible::CopyAssignments);
    EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
    NonDefaultConstructible::ResetCounts();
  }
  EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
  EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
  EXPECT_EQ(2u, NonDefaultConstructible::Destructions);
}

TEST_F(OptionalTest, DeletingCopyAssignmentTest) {
  NonDefaultConstructible::ResetCounts();
  {
    Optional<NonDefaultConstructible> A;
    Optional<NonDefaultConstructible> B(NonDefaultConstructible(3));
    EXPECT_EQ(1u, NonDefaultConstructible::CopyConstructions);
    EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
    EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
    NonDefaultConstructible::ResetCounts();
    B = A;
    EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
    EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
    EXPECT_EQ(1u, NonDefaultConstructible::Destructions);
    NonDefaultConstructible::ResetCounts();
  }
  EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
  EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
  EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
}

TEST_F(OptionalTest, NullCopyConstructionTest) {
  NonDefaultConstructible::ResetCounts();
  {
    Optional<NonDefaultConstructible> A;
    Optional<NonDefaultConstructible> B;
    EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
    EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
    EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
    NonDefaultConstructible::ResetCounts();
    B = A;
    EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
    EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
    EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
    NonDefaultConstructible::ResetCounts();
  }
  EXPECT_EQ(0u, NonDefaultConstructible::CopyConstructions);
  EXPECT_EQ(0u, NonDefaultConstructible::CopyAssignments);
  EXPECT_EQ(0u, NonDefaultConstructible::Destructions);
}

TEST_F(OptionalTest, GetValueOr) {
  Optional<int> A;
  EXPECT_EQ(42, A.getValueOr(42));

  A = 5;
  EXPECT_EQ(5, A.getValueOr(42));
}

struct MultiArgConstructor {
  int x, y;
  MultiArgConstructor(int x, int y) : x(x), y(y) {}
  explicit MultiArgConstructor(int x, bool positive)
    : x(x), y(positive ? x : -x) {}

  MultiArgConstructor(const MultiArgConstructor &) = delete;
  MultiArgConstructor(MultiArgConstructor &&) = delete;
  MultiArgConstructor &operator=(const MultiArgConstructor &) = delete;
  MultiArgConstructor &operator=(MultiArgConstructor &&) = delete;

  static unsigned Destructions;
  ~MultiArgConstructor() {
    ++Destructions;
  }
  static void ResetCounts() {
    Destructions = 0;
  }
};
unsigned MultiArgConstructor::Destructions = 0;

TEST_F(OptionalTest, Emplace) {
  MultiArgConstructor::ResetCounts();
  Optional<MultiArgConstructor> A;
  
  A.emplace(1, 2);
  EXPECT_TRUE(A.hasValue());
  EXPECT_EQ(1, A->x);
  EXPECT_EQ(2, A->y);
  EXPECT_EQ(0u, MultiArgConstructor::Destructions);

  A.emplace(5, false);
  EXPECT_TRUE(A.hasValue());
  EXPECT_EQ(5, A->x);
  EXPECT_EQ(-5, A->y);
  EXPECT_EQ(1u, MultiArgConstructor::Destructions);
}

struct MoveOnly {
  static unsigned MoveConstructions;
  static unsigned Destructions;
  static unsigned MoveAssignments;
  int val;
  explicit MoveOnly(int val) : val(val) {
  }
  MoveOnly(MoveOnly&& other) {
    val = other.val;
    ++MoveConstructions;
  }
  MoveOnly &operator=(MoveOnly&& other) {
    val = other.val;
    ++MoveAssignments;
    return *this;
  }
  ~MoveOnly() {
    ++Destructions;
  }
  static void ResetCounts() {
    MoveConstructions = 0;
    Destructions = 0;
    MoveAssignments = 0;
  }
};

unsigned MoveOnly::MoveConstructions = 0;
unsigned MoveOnly::Destructions = 0;
unsigned MoveOnly::MoveAssignments = 0;

TEST_F(OptionalTest, MoveOnlyNull) {
  MoveOnly::ResetCounts();
  Optional<MoveOnly> O;
  EXPECT_EQ(0u, MoveOnly::MoveConstructions);
  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
  EXPECT_EQ(0u, MoveOnly::Destructions);
}

TEST_F(OptionalTest, MoveOnlyConstruction) {
  MoveOnly::ResetCounts();
  Optional<MoveOnly> O(MoveOnly(3));
  EXPECT_TRUE((bool)O);
  EXPECT_EQ(3, O->val);
  EXPECT_EQ(1u, MoveOnly::MoveConstructions);
  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
  EXPECT_EQ(1u, MoveOnly::Destructions);
}

TEST_F(OptionalTest, MoveOnlyMoveConstruction) {
  Optional<MoveOnly> A(MoveOnly(3));
  MoveOnly::ResetCounts();
  Optional<MoveOnly> B(std::move(A));
  EXPECT_TRUE((bool)A);
  EXPECT_TRUE((bool)B);
  EXPECT_EQ(3, B->val);
  EXPECT_EQ(1u, MoveOnly::MoveConstructions);
  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
  EXPECT_EQ(0u, MoveOnly::Destructions);
}

TEST_F(OptionalTest, MoveOnlyAssignment) {
  MoveOnly::ResetCounts();
  Optional<MoveOnly> O;
  O = MoveOnly(3);
  EXPECT_TRUE((bool)O);
  EXPECT_EQ(3, O->val);
  EXPECT_EQ(1u, MoveOnly::MoveConstructions);
  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
  EXPECT_EQ(1u, MoveOnly::Destructions);
}

TEST_F(OptionalTest, MoveOnlyInitializingAssignment) {
  Optional<MoveOnly> A(MoveOnly(3));
  Optional<MoveOnly> B;
  MoveOnly::ResetCounts();
  B = std::move(A);
  EXPECT_TRUE((bool)A);
  EXPECT_TRUE((bool)B);
  EXPECT_EQ(3, B->val);
  EXPECT_EQ(1u, MoveOnly::MoveConstructions);
  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
  EXPECT_EQ(0u, MoveOnly::Destructions);
}

TEST_F(OptionalTest, MoveOnlyNullingAssignment) {
  Optional<MoveOnly> A;
  Optional<MoveOnly> B(MoveOnly(3));
  MoveOnly::ResetCounts();
  B = std::move(A);
  EXPECT_FALSE((bool)A);
  EXPECT_FALSE((bool)B);
  EXPECT_EQ(0u, MoveOnly::MoveConstructions);
  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
  EXPECT_EQ(1u, MoveOnly::Destructions);
}

TEST_F(OptionalTest, MoveOnlyAssigningAssignment) {
  Optional<MoveOnly> A(MoveOnly(3));
  Optional<MoveOnly> B(MoveOnly(4));
  MoveOnly::ResetCounts();
  B = std::move(A);
  EXPECT_TRUE((bool)A);
  EXPECT_TRUE((bool)B);
  EXPECT_EQ(3, B->val);
  EXPECT_EQ(0u, MoveOnly::MoveConstructions);
  EXPECT_EQ(1u, MoveOnly::MoveAssignments);
  EXPECT_EQ(0u, MoveOnly::Destructions);
}

struct Immovable {
  static unsigned Constructions;
  static unsigned Destructions;
  int val;
  explicit Immovable(int val) : val(val) {
    ++Constructions;
  }
  ~Immovable() {
    ++Destructions;
  }
  static void ResetCounts() {
    Constructions = 0;
    Destructions = 0;
  }
private:
  // This should disable all move/copy operations.
  Immovable(Immovable&& other) = delete;
};

unsigned Immovable::Constructions = 0;
unsigned Immovable::Destructions = 0;

TEST_F(OptionalTest, ImmovableEmplace) {
  Optional<Immovable> A;
  Immovable::ResetCounts();
  A.emplace(4);
  EXPECT_TRUE((bool)A);
  EXPECT_EQ(4, A->val);
  EXPECT_EQ(1u, Immovable::Constructions);
  EXPECT_EQ(0u, Immovable::Destructions);
}

#if LLVM_HAS_RVALUE_REFERENCE_THIS

TEST_F(OptionalTest, MoveGetValueOr) {
  Optional<MoveOnly> A;

  MoveOnly::ResetCounts();
  EXPECT_EQ(42, std::move(A).getValueOr(MoveOnly(42)).val);
  EXPECT_EQ(1u, MoveOnly::MoveConstructions);
  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
  EXPECT_EQ(2u, MoveOnly::Destructions);

  A = MoveOnly(5);
  MoveOnly::ResetCounts();
  EXPECT_EQ(5, std::move(A).getValueOr(MoveOnly(42)).val);
  EXPECT_EQ(1u, MoveOnly::MoveConstructions);
  EXPECT_EQ(0u, MoveOnly::MoveAssignments);
  EXPECT_EQ(2u, MoveOnly::Destructions);
}

#endif // LLVM_HAS_RVALUE_REFERENCE_THIS

struct EqualTo {
  template <typename T, typename U> static bool apply(const T &X, const U &Y) {
    return X == Y;
  }
};

struct NotEqualTo {
  template <typename T, typename U> static bool apply(const T &X, const U &Y) {
    return X != Y;
  }
};

struct Less {
  template <typename T, typename U> static bool apply(const T &X, const U &Y) {
    return X < Y;
  }
};

struct Greater {
  template <typename T, typename U> static bool apply(const T &X, const U &Y) {
    return X > Y;
  }
};

struct LessEqual {
  template <typename T, typename U> static bool apply(const T &X, const U &Y) {
    return X <= Y;
  }
};

struct GreaterEqual {
  template <typename T, typename U> static bool apply(const T &X, const U &Y) {
    return X >= Y;
  }
};

template <typename OperatorT, typename T>
void CheckRelation(const Optional<T> &Lhs, const Optional<T> &Rhs,
                   bool Expected) {
  EXPECT_EQ(Expected, OperatorT::apply(Lhs, Rhs));

  if (Lhs)
    EXPECT_EQ(Expected, OperatorT::apply(*Lhs, Rhs));
  else
    EXPECT_EQ(Expected, OperatorT::apply(None, Rhs));

  if (Rhs)
    EXPECT_EQ(Expected, OperatorT::apply(Lhs, *Rhs));
  else
    EXPECT_EQ(Expected, OperatorT::apply(Lhs, None));
}

struct EqualityMock {};
const Optional<EqualityMock> NoneEq, EqualityLhs((EqualityMock())),
    EqualityRhs((EqualityMock()));
bool IsEqual;

bool operator==(const EqualityMock &Lhs, const EqualityMock &Rhs) {
  EXPECT_EQ(&*EqualityLhs, &Lhs);
  EXPECT_EQ(&*EqualityRhs, &Rhs);
  return IsEqual;
}

TEST_F(OptionalTest, OperatorEqual) {
  CheckRelation<EqualTo>(NoneEq, NoneEq, true);
  CheckRelation<EqualTo>(NoneEq, EqualityRhs, false);
  CheckRelation<EqualTo>(EqualityLhs, NoneEq, false);

  IsEqual = false;
  CheckRelation<EqualTo>(EqualityLhs, EqualityRhs, IsEqual);
  IsEqual = true;
  CheckRelation<EqualTo>(EqualityLhs, EqualityRhs, IsEqual);
}

TEST_F(OptionalTest, OperatorNotEqual) {
  CheckRelation<NotEqualTo>(NoneEq, NoneEq, false);
  CheckRelation<NotEqualTo>(NoneEq, EqualityRhs, true);
  CheckRelation<NotEqualTo>(EqualityLhs, NoneEq, true);

  IsEqual = false;
  CheckRelation<NotEqualTo>(EqualityLhs, EqualityRhs, !IsEqual);
  IsEqual = true;
  CheckRelation<NotEqualTo>(EqualityLhs, EqualityRhs, !IsEqual);
}

struct InequalityMock {};
const Optional<InequalityMock> NoneIneq, InequalityLhs((InequalityMock())),
    InequalityRhs((InequalityMock()));
bool IsLess;

bool operator<(const InequalityMock &Lhs, const InequalityMock &Rhs) {
  EXPECT_EQ(&*InequalityLhs, &Lhs);
  EXPECT_EQ(&*InequalityRhs, &Rhs);
  return IsLess;
}

TEST_F(OptionalTest, OperatorLess) {
  CheckRelation<Less>(NoneIneq, NoneIneq, false);
  CheckRelation<Less>(NoneIneq, InequalityRhs, true);
  CheckRelation<Less>(InequalityLhs, NoneIneq, false);

  IsLess = false;
  CheckRelation<Less>(InequalityLhs, InequalityRhs, IsLess);
  IsLess = true;
  CheckRelation<Less>(InequalityLhs, InequalityRhs, IsLess);
}

TEST_F(OptionalTest, OperatorGreater) {
  CheckRelation<Greater>(NoneIneq, NoneIneq, false);
  CheckRelation<Greater>(NoneIneq, InequalityRhs, false);
  CheckRelation<Greater>(InequalityLhs, NoneIneq, true);

  IsLess = false;
  CheckRelation<Greater>(InequalityRhs, InequalityLhs, IsLess);
  IsLess = true;
  CheckRelation<Greater>(InequalityRhs, InequalityLhs, IsLess);
}

TEST_F(OptionalTest, OperatorLessEqual) {
  CheckRelation<LessEqual>(NoneIneq, NoneIneq, true);
  CheckRelation<LessEqual>(NoneIneq, InequalityRhs, true);
  CheckRelation<LessEqual>(InequalityLhs, NoneIneq, false);

  IsLess = false;
  CheckRelation<LessEqual>(InequalityRhs, InequalityLhs, !IsLess);
  IsLess = true;
  CheckRelation<LessEqual>(InequalityRhs, InequalityLhs, !IsLess);
}

TEST_F(OptionalTest, OperatorGreaterEqual) {
  CheckRelation<GreaterEqual>(NoneIneq, NoneIneq, true);
  CheckRelation<GreaterEqual>(NoneIneq, InequalityRhs, false);
  CheckRelation<GreaterEqual>(InequalityLhs, NoneIneq, true);

  IsLess = false;
  CheckRelation<GreaterEqual>(InequalityLhs, InequalityRhs, !IsLess);
  IsLess = true;
  CheckRelation<GreaterEqual>(InequalityLhs, InequalityRhs, !IsLess);
}

#if __has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)
static_assert(std::is_trivially_copyable<Optional<int>>::value,
              "Should be trivially copyable");
static_assert(
    !std::is_trivially_copyable<Optional<NonDefaultConstructible>>::value,
    "Shouldn't be trivially copyable");
#endif

} // end anonymous namespace