#include #include #include "../either.h" #include "../macros.h" class OnlyMoveable { public: OnlyMoveable(int value_): value(value_) {} OnlyMoveable(OnlyMoveable &&source): value(source.value) {source.value = -1;} int value; private: DISALLOW_COPY_AND_ASSIGN(OnlyMoveable); }; using std::string; using namespace cpputils; using ::testing::Test; class EitherTest: public Test { public: template void EXPECT_IS_LEFT(const Either &val) { EXPECT_TRUE(val.is_left()); EXPECT_FALSE(val.is_right()); } template void EXPECT_IS_RIGHT(const Either &val) { EXPECT_FALSE(val.is_left()); EXPECT_TRUE(val.is_right()); } template void EXPECT_LEFT_IS(const Expected &expected, Either &value) { EXPECT_IS_LEFT(value); EXPECT_EQ(expected, value.left()); const Either &const_value = value; EXPECT_EQ(expected, const_value.left()); } template void EXPECT_RIGHT_IS(const Expected &expected, Either &value) { EXPECT_IS_RIGHT(value); EXPECT_EQ(expected, value.right()); const Either &const_value = value; EXPECT_EQ(expected, const_value.right()); } }; TEST_F(EitherTest, LeftCanBeConstructed) { Either val = 3; UNUSED(val); } TEST_F(EitherTest, RightCanBeConstructed) { Either val = string("string"); UNUSED(val); } TEST_F(EitherTest, IsLeft) { Either val = 3; EXPECT_IS_LEFT(val); } TEST_F(EitherTest, IsRight) { Either val = string("string"); EXPECT_IS_RIGHT(val); } TEST_F(EitherTest, LeftIsStored) { Either val = 3; EXPECT_LEFT_IS(3, val); } TEST_F(EitherTest, RightIsStored) { Either val = string("string"); EXPECT_RIGHT_IS("string", val); } TEST_F(EitherTest, LeftCanBeMoveContructed) { Either val = OnlyMoveable(1); UNUSED(val); } TEST_F(EitherTest, RightCanBeMoveContructed) { Either val = OnlyMoveable(1); UNUSED(val); } TEST_F(EitherTest, IsLeftWhenMoveContructed) { Either val = OnlyMoveable(1); EXPECT_IS_LEFT(val); } TEST_F(EitherTest, IsRightWhenMoveContructed) { Either val = OnlyMoveable(1); EXPECT_IS_RIGHT(val); } TEST_F(EitherTest, LeftIsStoredWhenMoveContructed) { Either val = OnlyMoveable(2); EXPECT_EQ(2, val.left().value); } TEST_F(EitherTest, RightIsStoredWhenMoveContructed) { Either val = OnlyMoveable(3); EXPECT_EQ(3, val.right().value); } TEST_F(EitherTest, LeftCanBeCopied) { Either val = string("string"); Either val2 = val; EXPECT_LEFT_IS("string", val2); } TEST_F(EitherTest, CopyingLeftDoesntChangeSource) { Either val = string("string"); Either val2 = val; EXPECT_LEFT_IS("string", val); } TEST_F(EitherTest, RightCanBeCopied) { Either val = string("string"); Either val2 = val; EXPECT_RIGHT_IS("string", val2); } TEST_F(EitherTest, CopyingRightDoesntChangeSource) { Either val = string("string"); Either val2 = val; EXPECT_RIGHT_IS("string", val); } TEST_F(EitherTest, LeftCanBeMoved) { Either val = OnlyMoveable(5); Either val2 = std::move(val); EXPECT_IS_LEFT(val2); EXPECT_EQ(5, val2.left().value); } TEST_F(EitherTest, RightCanBeMoved) { Either val = OnlyMoveable(5); Either val2 = std::move(val); EXPECT_IS_RIGHT(val2); EXPECT_EQ(5, val2.right().value); } TEST_F(EitherTest, LeftEquals) { Either val1 = string("mystring"); Either val2 = string("mystring"); EXPECT_TRUE(val1 == val2); EXPECT_TRUE(val2 == val1); EXPECT_FALSE(val1 != val2); EXPECT_FALSE(val2 != val1); } TEST_F(EitherTest, LeftNotEquals) { Either val1 = string("mystring"); Either val2 = string("mystring2"); EXPECT_TRUE(val1 != val2); EXPECT_TRUE(val2 != val1); EXPECT_FALSE(val1 == val2); EXPECT_FALSE(val2 == val1); } TEST_F(EitherTest, RightEquals) { Either val1 = string("mystring"); Either val2 = string("mystring"); EXPECT_TRUE(val1 == val2); EXPECT_TRUE(val2 == val1); EXPECT_FALSE(val1 != val2); EXPECT_FALSE(val2 != val1); } TEST_F(EitherTest, RightNotEquals) { Either val1 = string("mystring"); Either val2 = string("mystring2"); EXPECT_TRUE(val1 != val2); EXPECT_TRUE(val2 != val1); EXPECT_FALSE(val1 == val2); EXPECT_FALSE(val2 == val1); } TEST_F(EitherTest, LeftNotEqualsRight) { Either val1 = string("mystring"); Either val2 = 3; EXPECT_TRUE(val1 != val2); EXPECT_TRUE(val2 != val1); EXPECT_FALSE(val1 == val2); EXPECT_FALSE(val2 == val1); } class DestructorCallback { public: MOCK_CONST_METHOD0(call, void()); }; class ClassWithDestructorCallback { public: ClassWithDestructorCallback(const DestructorCallback *destructorCallback) : _destructorCallback(destructorCallback) { } ~ClassWithDestructorCallback() { _destructorCallback->call(); } private: const DestructorCallback *_destructorCallback; }; class OnlyMoveableClassWithDestructorCallback { public: OnlyMoveableClassWithDestructorCallback(const DestructorCallback *destructorCallback) : _destructorCallback(destructorCallback) { } OnlyMoveableClassWithDestructorCallback(OnlyMoveableClassWithDestructorCallback &&source): _destructorCallback(source._destructorCallback) {} ~OnlyMoveableClassWithDestructorCallback() { _destructorCallback->call(); } private: DISALLOW_COPY_AND_ASSIGN(OnlyMoveableClassWithDestructorCallback); const DestructorCallback *_destructorCallback; }; class EitherTest_Destructor: public EitherTest { public: DestructorCallback destructorCallback; void EXPECT_DESTRUCTOR_CALLED(int times = 1) { EXPECT_CALL(destructorCallback, call()).Times(times); } }; TEST_F(EitherTest_Destructor, LeftDestructorIsCalled) { ClassWithDestructorCallback temp(&destructorCallback); Either var = temp; EXPECT_DESTRUCTOR_CALLED(2); //Once for the temp object, once when the either class destructs } TEST_F(EitherTest_Destructor, RightDestructorIsCalled) { ClassWithDestructorCallback temp(&destructorCallback); Either var = temp; EXPECT_DESTRUCTOR_CALLED(2); //Once for the temp object, once when the either class destructs } TEST_F(EitherTest_Destructor, LeftDestructorIsCalledAfterCopying) { ClassWithDestructorCallback temp(&destructorCallback); Either var1 = temp; Either var2 = var1; EXPECT_DESTRUCTOR_CALLED(3); //Once for the temp object, once for var1 and once for var2 } TEST_F(EitherTest_Destructor, RightDestructorIsCalledAfterCopying) { ClassWithDestructorCallback temp(&destructorCallback); Either var1 = temp; Either var2 = var1; EXPECT_DESTRUCTOR_CALLED(3); //Once for the temp object, once for var1 and once for var2 } TEST_F(EitherTest_Destructor, LeftDestructorIsCalledAfterMoving) { OnlyMoveableClassWithDestructorCallback temp(&destructorCallback); Either var1 = std::move(temp); Either var2 = std::move(var1); EXPECT_DESTRUCTOR_CALLED(3); //Once for the temp object, once for var1 and once for var2 } TEST_F(EitherTest_Destructor, RightDestructorIsCalledAfterMoving) { OnlyMoveableClassWithDestructorCallback temp(&destructorCallback); Either var1 = std::move(temp); Either var2 = std::move(var1); EXPECT_DESTRUCTOR_CALLED(3); //Once for the temp object, once for var1 and once for var2 }