blob: 4402d0187ea4517a15cdada9660d2438ee39c9bc [file] [log] [blame]
// Originally taken from
// https://raw.githubusercontent.com/cryfs/cryfs/14ad22570ddacef22d5ff139cdff68a54fc8234d/test/cpp-utils/either_test.cpp
#include <c10/macros/Macros.h>
#include <c10/util/either.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <sstream>
#include <vector>
using c10::either;
using c10::make_left;
using c10::make_right;
using std::ostringstream;
using std::pair;
using std::string;
using std::tuple;
using std::vector;
namespace {
class MovableOnly final {
public:
explicit MovableOnly(int value) : _value(value) {}
MovableOnly(const MovableOnly&) = delete;
MovableOnly& operator=(const MovableOnly&) = delete;
MovableOnly(MovableOnly&& rhs) : _value(rhs._value) {
rhs._value = 0;
}
MovableOnly& operator=(MovableOnly&& rhs) {
_value = rhs._value;
rhs._value = 0;
return *this;
}
int value() const {
return _value;
}
private:
int _value;
};
bool operator==(const MovableOnly& lhs, const MovableOnly& rhs) {
return lhs.value() == rhs.value();
}
template <class T>
void test_with_matrix(
std::vector<std::function<void(std::function<void(T&)>)>> setups,
std::vector<std::function<void(T&)>> expectations) {
for (const auto& setup : setups) {
for (const auto& expectation : expectations) {
setup(expectation);
}
}
}
template <class Left, class Right>
std::vector<std::function<void(either<Left, Right>&)>> EXPECT_IS_LEFT(
const Left& expected) {
return {
[&](either<Left, Right>& obj) { EXPECT_TRUE(obj.is_left()); },
[&](either<Left, Right>& obj) { EXPECT_FALSE(obj.is_right()); },
[&](either<Left, Right>& obj) { EXPECT_EQ(expected, obj.left()); },
[&](either<Left, Right>& obj) {
EXPECT_EQ(expected, std::move(obj).left());
},
[&](either<Left, Right>& obj) {
// NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
EXPECT_ANY_THROW(obj.right());
},
[&](either<Left, Right>& obj) {
// NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
EXPECT_ANY_THROW(std::move(obj).right());
}};
}
template <class Left, class Right>
std::vector<std::function<void(either<Left, Right>&)>> EXPECT_IS_RIGHT(
const Right& expected) {
return {
[&](either<Left, Right>& obj) { EXPECT_FALSE(obj.is_left()); },
[&](either<Left, Right>& obj) { EXPECT_TRUE(obj.is_right()); },
[&](either<Left, Right>& obj) { EXPECT_EQ(expected, obj.right()); },
[&](either<Left, Right>& obj) {
EXPECT_EQ(expected, std::move(obj).right());
},
[&](either<Left, Right>& obj) {
// NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
EXPECT_ANY_THROW(obj.left());
},
[&](either<Left, Right>& obj) {
// NOLINTNEXTLINE(hicpp-avoid-goto,cppcoreguidelines-avoid-goto)
EXPECT_ANY_THROW(std::move(obj).left());
}};
}
template <class Value>
std::vector<std::function<void(Value&)>> EXPECT_IS(const Value& v) {
return {[&](Value& obj) { return obj == v; }};
}
template <typename T>
struct StoreWith1ByteFlag {
T val;
char flag;
};
template <typename Left, typename Right>
void TestSpaceUsage() {
EXPECT_EQ(
std::max(
sizeof(StoreWith1ByteFlag<Left>), sizeof(StoreWith1ByteFlag<Right>)),
sizeof(either<Left, Right>));
}
} // namespace
TEST(EitherTest, SpaceUsage) {
TestSpaceUsage<char, int>();
TestSpaceUsage<int, short>();
TestSpaceUsage<char, short>();
TestSpaceUsage<int, string>();
TestSpaceUsage<string, vector<string>>();
}
TEST(EitherTest, givenLeft) {
test_with_matrix(
{
[](std::function<void(either<int, string>&)> test) {
either<int, string> a(4);
test(a);
},
[](std::function<void(either<int, string>&)> test) {
either<int, string> a = 4;
test(a);
},
},
EXPECT_IS_LEFT<int, string>(4));
}
TEST(EitherTest, givenRight) {
test_with_matrix(
{[](std::function<void(either<int, string>&)> test) {
either<int, string> a("4");
test(a);
},
[](std::function<void(either<int, string>&)> test) {
either<int, string> a = string("4");
test(a);
}},
EXPECT_IS_RIGHT<int, string>("4"));
}
TEST(EitherTest, givenMakeLeft) {
test_with_matrix(
{
[](std::function<void(either<int, string>&)> test) {
either<int, string> a = make_left<int, string>(4);
test(a);
},
[](std::function<void(either<int, string>&)> test) {
auto a = make_left<int, string>(4);
test(a);
},
},
EXPECT_IS_LEFT<int, string>(4));
}
TEST(EitherTest, givenMakeLeftWithSameType) {
test_with_matrix(
{
[](std::function<void(either<int, int>&)> test) {
either<int, int> a = make_left<int, int>(4);
test(a);
},
[](std::function<void(either<int, int>&)> test) {
auto a = make_left<int, int>(4);
test(a);
},
},
EXPECT_IS_LEFT<int, int>(4));
}
TEST(EitherTest, givenMakeRight) {
test_with_matrix(
{[](std::function<void(either<int, string>&)> test) {
either<int, string> a = make_right<int, string>("4");
test(a);
},
[](std::function<void(either<int, string>&)> test) {
auto a = make_right<int, string>("4");
test(a);
}},
EXPECT_IS_RIGHT<int, string>("4"));
}
TEST(EitherTest, givenMakeRightWithSameType) {
test_with_matrix(
{[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_right<string, string>("4");
test(a);
},
[](std::function<void(either<string, string>&)> test) {
auto a = make_right<string, string>("4");
test(a);
}},
EXPECT_IS_RIGHT<string, string>("4"));
}
TEST(EitherTest, givenMovableOnlyMakeLeft) {
test_with_matrix(
{
[](std::function<void(either<MovableOnly, string>&)> test) {
either<MovableOnly, string> a = make_left<MovableOnly, string>(3);
test(a);
},
[](std::function<void(either<MovableOnly, string>&)> test) {
auto a = make_left<MovableOnly, string>(3);
test(a);
},
},
EXPECT_IS_LEFT<MovableOnly, string>(MovableOnly(3)));
}
TEST(EitherTest, givenMovableOnlyMakeRight) {
test_with_matrix(
{[](std::function<void(either<int, MovableOnly>&)> test) {
either<int, MovableOnly> a = make_right<int, MovableOnly>(3);
test(a);
},
[](std::function<void(either<int, MovableOnly>&)> test) {
auto a = make_right<int, MovableOnly>(3);
test(a);
}},
EXPECT_IS_RIGHT<int, MovableOnly>(MovableOnly(3)));
}
TEST(EitherTest, givenMultiParamMakeLeft) {
test_with_matrix(
{
[](std::function<void(either<pair<int, int>, string>&)> test) {
either<pair<int, int>, string> a =
make_left<pair<int, int>, string>(5, 6);
test(a);
},
[](std::function<void(either<pair<int, int>, string>&)> test) {
auto a = make_left<pair<int, int>, string>(5, 6);
test(a);
},
},
EXPECT_IS_LEFT<pair<int, int>, string>(pair<int, int>(5, 6)));
}
TEST(EitherTest, givenMultiParamMakeRight) {
test_with_matrix(
{[](std::function<void(either<int, pair<int, int>>&)> test) {
either<int, pair<int, int>> a = make_right<int, pair<int, int>>(5, 6);
test(a);
},
[](std::function<void(either<int, pair<int, int>>&)> test) {
auto a = make_right<int, pair<int, int>>(5, 6);
test(a);
}},
EXPECT_IS_RIGHT<int, pair<int, int>>(pair<int, int>(5, 6)));
}
TEST(EitherTest, givenLeftCopyConstructedFromValue_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, int>&)> test) {
string a = "4";
either<string, int> b(a);
test(b);
}},
EXPECT_IS_LEFT<string, int>("4"));
}
TEST(EitherTest, givenLeftCopyConstructedFromValue_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(string&)> test) {
string a = "4";
either<string, int> b(a);
test(a);
}},
EXPECT_IS<string>("4"));
}
TEST(EitherTest, givenRightCopyConstructedFromValue_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<int, string>&)> test) {
string a = "4";
either<int, string> b(a);
test(b);
}},
EXPECT_IS_RIGHT<int, string>("4"));
}
TEST(EitherTest, givenRightCopyConstructedFromValue_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(string&)> test) {
string a = "4";
either<int, string> b(a);
test(a);
}},
EXPECT_IS<string>("4"));
}
TEST(EitherTest, givenLeftMoveConstructedFromValue_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, int>&)> test) {
MovableOnly a(3);
either<MovableOnly, int> b(std::move(a));
test(b);
}},
EXPECT_IS_LEFT<MovableOnly, int>(MovableOnly(3)));
}
TEST(EitherTest, givenLeftMoveConstructedFromValue_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(MovableOnly&)> test) {
MovableOnly a(3);
either<MovableOnly, int> b(std::move(a));
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS<MovableOnly>(MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenRightMoveConstructedFromValue_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<int, MovableOnly>&)> test) {
MovableOnly a(3);
either<int, MovableOnly> b(std::move(a));
test(b);
}},
EXPECT_IS_RIGHT<int, MovableOnly>(MovableOnly(3)));
}
TEST(EitherTest, givenRightMoveConstructedFromValue_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(MovableOnly&)> test) {
MovableOnly a(3);
either<int, MovableOnly> b(std::move(a));
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS<MovableOnly>(MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenLeftCopyAssignedFromValue_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, int>&)> test) {
string a = "4";
either<string, int> b(2);
b = a;
test(b);
},
[](std::function<void(either<string, int>&)> test) {
string a = "4";
either<string, int> b("2");
b = a;
test(b);
}},
EXPECT_IS_LEFT<string, int>("4"));
}
TEST(EitherTest, givenLeftCopyAssignedFromValue_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(string&)> test) {
string a = "4";
either<string, int> b(2);
b = a;
test(a);
},
[](std::function<void(string&)> test) {
string a = "4";
either<string, int> b("2");
b = a;
test(a);
}},
EXPECT_IS<string>("4"));
}
TEST(EitherTest, givenRightCopyAssignedFromValue_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<int, string>&)> test) {
string a = "4";
either<int, string> b(2);
b = a;
test(b);
},
[](std::function<void(either<int, string>&)> test) {
string a = "4";
either<int, string> b("2");
b = a;
test(b);
}},
EXPECT_IS_RIGHT<int, string>("4"));
}
TEST(EitherTest, givenRightCopyAssignedFromValue_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(string&)> test) {
string a = "4";
either<int, string> b(2);
b = a;
test(a);
},
[](std::function<void(string&)> test) {
string a = "4";
either<int, string> b("2");
b = a;
test(a);
}},
EXPECT_IS<string>("4"));
}
TEST(EitherTest, givenLeftMoveAssignedFromValue_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, string>&)> test) {
MovableOnly a(3);
either<MovableOnly, string> b(2);
b = std::move(a);
test(b);
},
[](std::function<void(either<MovableOnly, string>&)> test) {
MovableOnly a(3);
either<MovableOnly, string> b(MovableOnly(2));
b = std::move(a);
test(b);
}},
EXPECT_IS_LEFT<MovableOnly, string>(MovableOnly(3)));
}
TEST(EitherTest, givenLeftMoveAssignedFromValue_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(MovableOnly&)> test) {
MovableOnly a(3);
either<MovableOnly, string> b("2");
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
},
[](std::function<void(MovableOnly&)> test) {
MovableOnly a(3);
either<MovableOnly, string> b(MovableOnly(0));
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS<MovableOnly>(MovableOnly(0)));
}
TEST(EitherTest, givenRightMoveAssignedFromValue_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, MovableOnly>&)> test) {
MovableOnly a(3);
either<string, MovableOnly> b("2");
b = std::move(a);
test(b);
},
[](std::function<void(either<string, MovableOnly>&)> test) {
MovableOnly a(3);
either<string, MovableOnly> b(MovableOnly(2));
b = std::move(a);
test(b);
}},
EXPECT_IS_RIGHT<string, MovableOnly>(MovableOnly(3)));
}
TEST(EitherTest, givenRightMoveAssignedFromValue_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(MovableOnly&)> test) {
MovableOnly a(3);
either<string, MovableOnly> b("2");
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
},
[](std::function<void(MovableOnly&)> test) {
MovableOnly a(3);
either<string, MovableOnly> b(MovableOnly(2));
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS<MovableOnly>(MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenLeftCopyConstructed_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, int>&)> test) {
either<string, int> a("4");
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
either<string, int> b(a);
test(b);
}},
EXPECT_IS_LEFT<string, int>("4"));
}
TEST(EitherTest, givenLeftCopyConstructed_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, int>&)> test) {
either<string, int> a("4");
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
either<string, int> b(a);
test(a);
}},
EXPECT_IS_LEFT<string, int>("4"));
}
TEST(EitherTest, givenLeftCopyConstructed_withSameType_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_left<string, string>("4");
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
either<string, string> b(a);
test(b);
}},
EXPECT_IS_LEFT<string, string>("4"));
}
TEST(EitherTest, givenLeftCopyConstructed_withSameType_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_left<string, string>("4");
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
either<string, string> b(a);
test(a);
}},
EXPECT_IS_LEFT<string, string>("4"));
}
TEST(EitherTest, givenRightCopyConstructed_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<int, string>&)> test) {
either<int, string> a("4");
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
either<int, string> b(a);
test(b);
}},
EXPECT_IS_RIGHT<int, string>("4"));
}
TEST(EitherTest, givenRightCopyConstructed_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<int, string>&)> test) {
either<int, string> a("4");
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
either<int, string> b(a);
test(a);
}},
EXPECT_IS_RIGHT<int, string>("4"));
}
TEST(EitherTest, givenRightCopyConstructed_withSameType_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_right<string, string>("4");
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
either<string, string> b(a);
test(b);
}},
EXPECT_IS_RIGHT<string, string>("4"));
}
TEST(EitherTest, givenRightCopyConstructed_withSameType_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_right<string, string>("4");
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
either<string, string> b(a);
test(a);
}},
EXPECT_IS_RIGHT<string, string>("4"));
}
TEST(EitherTest, givenLeftMoveConstructed_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, int>&)> test) {
either<MovableOnly, int> a(MovableOnly(3));
either<MovableOnly, int> b(std::move(a));
test(b);
}},
EXPECT_IS_LEFT<MovableOnly, int>(MovableOnly(3)));
}
TEST(EitherTest, givenLeftMoveConstructed_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, int>&)> test) {
either<MovableOnly, int> a(MovableOnly(3));
either<MovableOnly, int> b(std::move(a));
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS_LEFT<MovableOnly, int>(MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenLeftMoveConstructed_withSameType_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_left<MovableOnly, MovableOnly>(MovableOnly(3));
either<MovableOnly, MovableOnly> b(std::move(a));
test(b);
}},
EXPECT_IS_LEFT<MovableOnly, MovableOnly>(MovableOnly(3)));
}
TEST(EitherTest, givenLeftMoveConstructed_withSameType_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_left<MovableOnly, MovableOnly>(MovableOnly(3));
either<MovableOnly, MovableOnly> b(std::move(a));
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS_LEFT<MovableOnly, MovableOnly>(
MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenRightMoveConstructed_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<int, MovableOnly>&)> test) {
either<int, MovableOnly> a(MovableOnly(3));
either<int, MovableOnly> b(std::move(a));
test(b);
}},
EXPECT_IS_RIGHT<int, MovableOnly>(MovableOnly(3)));
}
TEST(EitherTest, givenRightMoveConstructed_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<int, MovableOnly>&)> test) {
either<int, MovableOnly> a(MovableOnly(3));
either<int, MovableOnly> b(std::move(a));
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS_RIGHT<int, MovableOnly>(MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenRightMoveConstructed_withSameType_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_right<MovableOnly, MovableOnly>(MovableOnly(3));
either<MovableOnly, MovableOnly> b(std::move(a));
test(b);
}},
EXPECT_IS_RIGHT<MovableOnly, MovableOnly>(MovableOnly(3)));
}
TEST(EitherTest, givenRightMoveConstructed_withSameType_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_right<MovableOnly, MovableOnly>(MovableOnly(3));
either<MovableOnly, MovableOnly> b(std::move(a));
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS_RIGHT<MovableOnly, MovableOnly>(
MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenLeftCopyAssigned_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, int>&)> test) {
either<string, int> a("4");
either<string, int> b(2);
b = a;
test(b);
},
[](std::function<void(either<string, int>&)> test) {
either<string, int> a("4");
either<string, int> b("2");
b = a;
test(b);
}},
EXPECT_IS_LEFT<string, int>("4"));
}
TEST(EitherTest, givenLeftCopyAssigned_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, int>&)> test) {
either<string, int> a("4");
either<string, int> b(2);
b = a;
test(a);
},
[](std::function<void(either<string, int>&)> test) {
either<string, int> a("4");
either<string, int> b("2");
b = a;
test(a);
}},
EXPECT_IS_LEFT<string, int>("4"));
}
TEST(EitherTest, givenLeftCopyAssigned_withSameType_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_left<string, string>("4");
either<string, string> b = make_right<string, string>("2");
b = a;
test(b);
},
[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_left<string, string>("4");
either<string, string> b = make_left<string, string>("2");
b = a;
test(b);
}},
EXPECT_IS_LEFT<string, string>("4"));
}
TEST(EitherTest, givenLeftCopyAssigned_withSameType_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_left<string, string>("4");
either<string, string> b = make_right<string, string>("2");
b = a;
test(a);
},
[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_left<string, string>("4");
either<string, string> b = make_left<string, string>("2");
b = a;
test(a);
}},
EXPECT_IS_LEFT<string, string>("4"));
}
TEST(EitherTest, givenRightCopyAssigned_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<int, string>&)> test) {
either<int, string> a("4");
either<int, string> b(2);
b = a;
test(b);
},
[](std::function<void(either<int, string>&)> test) {
either<int, string> a("4");
either<int, string> b("2");
b = a;
test(b);
}},
EXPECT_IS_RIGHT<int, string>("4"));
}
TEST(EitherTest, givenRightCopyAssigned_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<int, string>&)> test) {
either<int, string> a("4");
either<int, string> b(2);
b = a;
test(a);
},
[](std::function<void(either<int, string>&)> test) {
either<int, string> a("4");
either<int, string> b("2");
b = a;
test(a);
}},
EXPECT_IS_RIGHT<int, string>("4"));
}
TEST(EitherTest, givenRightCopyAssigned_withSameType_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_right<string, string>("4");
either<string, string> b = make_left<string, string>("2");
b = a;
test(b);
},
[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_right<string, string>("4");
either<string, string> b = make_right<string, string>("2");
b = a;
test(b);
}},
EXPECT_IS_RIGHT<string, string>("4"));
}
TEST(EitherTest, givenRightCopyAssigned_withSameType_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_right<string, string>("4");
either<string, string> b = make_left<string, string>("2");
b = a;
test(a);
},
[](std::function<void(either<string, string>&)> test) {
either<string, string> a = make_right<string, string>("4");
either<string, string> b = make_right<string, string>("2");
b = a;
test(a);
}},
EXPECT_IS_RIGHT<string, string>("4"));
}
TEST(EitherTest, givenLeftMoveAssigned_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, string>&)> test) {
either<MovableOnly, string> a(MovableOnly(3));
either<MovableOnly, string> b(2);
b = std::move(a);
test(b);
},
[](std::function<void(either<MovableOnly, string>&)> test) {
either<MovableOnly, string> a(MovableOnly(3));
either<MovableOnly, string> b(MovableOnly(2));
b = std::move(a);
test(b);
}},
EXPECT_IS_LEFT<MovableOnly, string>(MovableOnly(3)));
}
TEST(EitherTest, givenLeftMoveAssigned_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, string>&)> test) {
either<MovableOnly, string> a(MovableOnly(3));
either<MovableOnly, string> b(2);
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
},
[](std::function<void(either<MovableOnly, string>&)> test) {
either<MovableOnly, string> a(MovableOnly(3));
either<MovableOnly, string> b(MovableOnly(2));
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS_LEFT<MovableOnly, string>(
MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenLeftMoveAssigned_withSameType_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_left<MovableOnly, MovableOnly>(3);
either<MovableOnly, MovableOnly> b =
make_right<MovableOnly, MovableOnly>(2);
b = std::move(a);
test(b);
},
[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_left<MovableOnly, MovableOnly>(3);
either<MovableOnly, MovableOnly> b =
make_left<MovableOnly, MovableOnly>(2);
b = std::move(a);
test(b);
}},
EXPECT_IS_LEFT<MovableOnly, MovableOnly>(MovableOnly(3)));
}
TEST(EitherTest, givenLeftMoveAssigned_withSameType_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_left<MovableOnly, MovableOnly>(3);
either<MovableOnly, MovableOnly> b =
make_right<MovableOnly, MovableOnly>(2);
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
},
[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_left<MovableOnly, MovableOnly>(3);
either<MovableOnly, MovableOnly> b =
make_left<MovableOnly, MovableOnly>(2);
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS_LEFT<MovableOnly, MovableOnly>(
MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenRightMoveAssigned_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, MovableOnly>&)> test) {
either<string, MovableOnly> a(MovableOnly(3));
either<string, MovableOnly> b("2");
b = std::move(a);
test(b);
},
[](std::function<void(either<string, MovableOnly>&)> test) {
either<string, MovableOnly> a(MovableOnly(3));
either<string, MovableOnly> b(MovableOnly(2));
b = std::move(a);
test(b);
}},
EXPECT_IS_RIGHT<string, MovableOnly>(MovableOnly(3)));
}
TEST(EitherTest, givenRightMoveAssigned_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<string, MovableOnly>&)> test) {
either<string, MovableOnly> a(MovableOnly(3));
either<string, MovableOnly> b("2");
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
},
[](std::function<void(either<string, MovableOnly>&)> test) {
either<string, MovableOnly> a(MovableOnly(3));
either<string, MovableOnly> b(MovableOnly(2));
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS_RIGHT<string, MovableOnly>(
MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenRightMoveAssigned_withSameType_thenNewIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_right<MovableOnly, MovableOnly>(3);
either<MovableOnly, MovableOnly> b =
make_left<MovableOnly, MovableOnly>(2);
b = std::move(a);
test(b);
},
[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_right<MovableOnly, MovableOnly>(3);
either<MovableOnly, MovableOnly> b =
make_right<MovableOnly, MovableOnly>(2);
b = std::move(a);
test(b);
}},
EXPECT_IS_RIGHT<MovableOnly, MovableOnly>(MovableOnly(3)));
}
TEST(EitherTest, givenRightMoveAssigned_withSameType_thenOldIsCorrect) {
test_with_matrix(
{[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_right<MovableOnly, MovableOnly>(3);
either<MovableOnly, MovableOnly> b =
make_left<MovableOnly, MovableOnly>(2);
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
},
[](std::function<void(either<MovableOnly, MovableOnly>&)> test) {
either<MovableOnly, MovableOnly> a =
make_right<MovableOnly, MovableOnly>(3);
either<MovableOnly, MovableOnly> b =
make_right<MovableOnly, MovableOnly>(2);
b = std::move(a);
test(a); // NOLINT(bugprone-use-after-move)
}},
EXPECT_IS_RIGHT<MovableOnly, MovableOnly>(
MovableOnly(0)) // 0 is moved-from value
);
}
TEST(EitherTest, givenLeft_whenModified_thenValueIsChanged) {
test_with_matrix(
{[](std::function<void(either<int, string>&)> test) {
either<int, string> a(4);
a.left() = 5;
test(a);
},
[](std::function<void(either<int, string>&)> test) {
either<int, string> a(4);
a.left() = 5;
test(a);
}},
EXPECT_IS_LEFT<int, string>(5));
}
TEST(EitherTest, givenRight_whenModified_thenValueIsChanged) {
test_with_matrix(
{[](std::function<void(either<int, string>&)> test) {
either<int, string> a("4");
a.right() = "5";
test(a);
},
[](std::function<void(either<int, string>&)> test) {
either<int, string> a("4");
a.right() = "5";
test(a);
}},
EXPECT_IS_RIGHT<int, string>("5"));
}
TEST(EitherTest, canEmplaceConstructLeft) {
test_with_matrix(
{[](std::function<void(either<tuple<int, int>, tuple<int, string, int>>&)>
test) {
either<tuple<int, int>, tuple<int, string, int>> a(2, 3);
test(a);
}},
EXPECT_IS_LEFT<tuple<int, int>, tuple<int, string, int>>(
tuple<int, int>(2, 3)));
}
TEST(EitherTest, canEmplaceConstructRight) {
test_with_matrix(
{[](std::function<void(either<tuple<int, int>, tuple<int, string, int>>&)>
test) {
either<tuple<int, int>, tuple<int, string, int>> a(2, "3", 4);
test(a);
}},
EXPECT_IS_RIGHT<tuple<int, int>, tuple<int, string, int>>(
tuple<int, string, int>(2, "3", 4)));
}
TEST(EitherTest, givenEqualLefts_thenAreEqual) {
either<string, int> a("3");
either<string, int> b("3");
EXPECT_TRUE(a == b);
}
TEST(EitherTest, givenEqualLefts_thenAreNotUnequal) {
either<string, int> a("3");
either<string, int> b("3");
EXPECT_FALSE(a != b);
}
TEST(EitherTest, givenEqualRights_thenAreEqual) {
either<string, int> a(3);
either<string, int> b(3);
EXPECT_TRUE(a == b);
}
TEST(EitherTest, givenEqualRights_thenAreNotUnequal) {
either<string, int> a(3);
either<string, int> b(3);
EXPECT_FALSE(a != b);
}
TEST(EitherTest, givenLeftAndRight_thenAreNotEqual) {
either<string, int> a("3");
either<string, int> b(3);
EXPECT_FALSE(a == b);
EXPECT_FALSE(b == a);
}
TEST(EitherTest, givenLeftAndRight_thenAreUnequal) {
either<string, int> a("3");
either<string, int> b(3);
EXPECT_TRUE(a != b);
EXPECT_TRUE(b != a);
}
TEST(EitherTest, OutputLeft) {
ostringstream str;
str << either<string, int>("mystring");
EXPECT_EQ("Left(mystring)", str.str());
}
TEST(EitherTest, OutputRight) {
ostringstream str;
str << either<int, string>("mystring");
EXPECT_EQ("Right(mystring)", str.str());
}
TEST(EitherTest, givenLeftAndRightWithSameType_thenAreNotEqual) {
either<string, string> a = make_left<string, string>("3");
either<string, string> b = make_right<string, string>("3");
EXPECT_FALSE(a == b);
EXPECT_FALSE(b == a);
}
TEST(EitherTest, givenLeftAndRightWithSameType_thenAreUnequal) {
either<string, string> a = make_left<string, string>("3");
either<string, string> b = make_right<string, string>("3");
EXPECT_TRUE(a != b);
EXPECT_TRUE(b != a);
}
namespace {
class DestructorCallback {
public:
MOCK_CONST_METHOD0(call, void());
void EXPECT_CALLED(int times = 1) {
EXPECT_CALL(*this, call()).Times(times);
}
};
class ClassWithDestructorCallback {
public:
ClassWithDestructorCallback(const DestructorCallback* destructorCallback)
: _destructorCallback(destructorCallback) {}
~ClassWithDestructorCallback() {
_destructorCallback->call();
}
ClassWithDestructorCallback& operator=(
const ClassWithDestructorCallback& rhs) = delete;
private:
const DestructorCallback* _destructorCallback;
};
class OnlyMoveableClassWithDestructorCallback {
public:
OnlyMoveableClassWithDestructorCallback(
const DestructorCallback* destructorCallback)
: _destructorCallback(destructorCallback) {}
OnlyMoveableClassWithDestructorCallback(
OnlyMoveableClassWithDestructorCallback&& source)
: _destructorCallback(source._destructorCallback) {}
~OnlyMoveableClassWithDestructorCallback() {
_destructorCallback->call();
}
private:
C10_DISABLE_COPY_AND_ASSIGN(OnlyMoveableClassWithDestructorCallback);
const DestructorCallback* _destructorCallback;
};
} // namespace
TEST(EitherTest_Destructor, LeftDestructorIsCalled) {
DestructorCallback destructorCallback;
destructorCallback.EXPECT_CALLED(
2); // Once for the temp object, once when the either class destructs
ClassWithDestructorCallback temp(&destructorCallback);
either<ClassWithDestructorCallback, string> var = temp;
}
TEST(EitherTest_Destructor, RightDestructorIsCalled) {
DestructorCallback destructorCallback;
destructorCallback.EXPECT_CALLED(
2); // Once for the temp object, once when the either class destructs
ClassWithDestructorCallback temp(&destructorCallback);
either<string, ClassWithDestructorCallback> var = temp;
}
TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterCopying) {
DestructorCallback destructorCallback;
destructorCallback.EXPECT_CALLED(
3); // Once for the temp object, once for var1 and once for var2
ClassWithDestructorCallback temp(&destructorCallback);
either<ClassWithDestructorCallback, string> var1 = temp;
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
either<ClassWithDestructorCallback, string> var2 = var1;
}
TEST(EitherTest_Destructor, RightDestructorIsCalledAfterCopying) {
DestructorCallback destructorCallback;
destructorCallback.EXPECT_CALLED(
3); // Once for the temp object, once for var1 and once for var2
ClassWithDestructorCallback temp(&destructorCallback);
either<string, ClassWithDestructorCallback> var1 = temp;
// NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
either<string, ClassWithDestructorCallback> var2 = var1;
}
TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterMoving) {
DestructorCallback destructorCallback;
destructorCallback.EXPECT_CALLED(
3); // Once for the temp object, once for var1 and once for var2
OnlyMoveableClassWithDestructorCallback temp(&destructorCallback);
either<OnlyMoveableClassWithDestructorCallback, string> var1 =
std::move(temp);
either<OnlyMoveableClassWithDestructorCallback, string> var2 =
std::move(var1);
}
TEST(EitherTest_Destructor, RightDestructorIsCalledAfterMoving) {
DestructorCallback destructorCallback;
destructorCallback.EXPECT_CALLED(
3); // Once for the temp object, once for var1 and once for var2
OnlyMoveableClassWithDestructorCallback temp(&destructorCallback);
either<string, OnlyMoveableClassWithDestructorCallback> var1 =
std::move(temp);
either<string, OnlyMoveableClassWithDestructorCallback> var2 =
std::move(var1);
}
TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterAssignment) {
DestructorCallback destructorCallback1;
DestructorCallback destructorCallback2;
destructorCallback1.EXPECT_CALLED(
2); // Once for the temp1 object, once at the assignment
destructorCallback2.EXPECT_CALLED(
3); // Once for the temp2 object, once in destructor of var2, once in
// destructor of var1
ClassWithDestructorCallback temp1(&destructorCallback1);
either<ClassWithDestructorCallback, string> var1 = temp1;
ClassWithDestructorCallback temp2(&destructorCallback2);
either<ClassWithDestructorCallback, string> var2 = temp2;
var1 = var2;
}
TEST(EitherTest_Destructor, RightDestructorIsCalledAfterAssignment) {
DestructorCallback destructorCallback1;
DestructorCallback destructorCallback2;
destructorCallback1.EXPECT_CALLED(
2); // Once for the temp1 object, once at the assignment
destructorCallback2.EXPECT_CALLED(
3); // Once for the temp2 object, once in destructor of var2, once in
// destructor of var1
ClassWithDestructorCallback temp1(&destructorCallback1);
either<string, ClassWithDestructorCallback> var1 = temp1;
ClassWithDestructorCallback temp2(&destructorCallback2);
either<string, ClassWithDestructorCallback> var2 = temp2;
var1 = var2;
}
TEST(EitherTest_Destructor, LeftDestructorIsCalledAfterMoveAssignment) {
DestructorCallback destructorCallback1;
DestructorCallback destructorCallback2;
destructorCallback1.EXPECT_CALLED(
2); // Once for the temp1 object, once at the assignment
destructorCallback2.EXPECT_CALLED(
3); // Once for the temp2 object, once in destructor of var2, once in
// destructor of var1
OnlyMoveableClassWithDestructorCallback temp1(&destructorCallback1);
either<OnlyMoveableClassWithDestructorCallback, string> var1 =
std::move(temp1);
OnlyMoveableClassWithDestructorCallback temp2(&destructorCallback2);
either<OnlyMoveableClassWithDestructorCallback, string> var2 =
std::move(temp2);
var1 = std::move(var2);
}
TEST(EitherTest_Destructor, RightDestructorIsCalledAfterMoveAssignment) {
DestructorCallback destructorCallback1;
DestructorCallback destructorCallback2;
destructorCallback1.EXPECT_CALLED(
2); // Once for the temp1 object, once at the assignment
destructorCallback2.EXPECT_CALLED(
3); // Once for the temp2 object, once in destructor of var2, once in
// destructor of var1
OnlyMoveableClassWithDestructorCallback temp1(&destructorCallback1);
either<string, OnlyMoveableClassWithDestructorCallback> var1 =
std::move(temp1);
OnlyMoveableClassWithDestructorCallback temp2(&destructorCallback2);
either<string, OnlyMoveableClassWithDestructorCallback> var2 =
std::move(temp2);
var1 = std::move(var2);
}