1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00
llvm-mirror/unittests/ADT/OptionalTest.cpp
Benjamin Kramer 2bb5afc3db [ADT] Make moving Optional not reset the Optional it moves from.
This brings it in line with std::optional. My recent changes to
make Optional of trivial types trivially copyable introduced
diverging behavior depending on the type, which is bad. Now all
types have the same moving behavior.

llvm-svn: 323445
2018-01-25 17:24:22 +00:00

531 lines
16 KiB
C++

//===- 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