Offer Either::left_opt() and Either::right_opt() and add some test cases

This commit is contained in:
Sebastian Messmer 2015-06-26 01:07:46 +02:00
parent e1c4327338
commit d5dadc74e7
2 changed files with 93 additions and 9 deletions

View File

@ -2,7 +2,7 @@
#ifndef MESSMER_CPP_UTILS_EITHER_H
#define MESSMER_CPP_UTILS_EITHER_H
#include <type_traits>
#include <boost/optional.hpp>
namespace cpputils {
@ -65,21 +65,50 @@ namespace cpputils {
return _side == Side::right;
}
//TODO Also offer a safe version of getting left/right (exceptions? nullptr?)
const Left &left() const {
return _left;
}
Left &left() {
return const_cast<Left&>(const_cast<const Either<Left, Right>*>(this)->left());
}
const Right &right() const {
return _right;
}
Left &left() {
return const_cast<Left&>(const_cast<const Either<Left, Right>*>(this)->left());
}
Right &right() {
return const_cast<Right&>(const_cast<const Either<Left, Right>*>(this)->right());
}
boost::optional<const Left&> left_opt() const {
if (_side == Side::left) {
return _left;
} else {
return boost::none;
}
}
boost::optional<Left&> left_opt() {
if (_side == Side::left) {
return _left;
} else {
return boost::none;
}
}
boost::optional<const Right&> right_opt() const {
if (_side == Side::right) {
return _right;
} else {
return boost::none;
}
}
boost::optional<Right&> right_opt() {
if (_side == Side::right) {
return _right;
} else {
return boost::none;
}
}
private:
union {
Left _left;

View File

@ -1,8 +1,16 @@
#include <google/gtest/gtest.h>
#include <google/gmock/gmock.h>
#include <boost/optional/optional_io.hpp>
#include "../either.h"
#include "../macros.h"
//TODO Go through all test cases and think about whether it makes sense to add the same test case but with primitive types.
using std::string;
using std::vector;
using namespace cpputils;
using ::testing::Test;
class OnlyMoveable {
public:
OnlyMoveable(int value_): value(value_) {}
@ -12,9 +20,11 @@ private:
DISALLOW_COPY_AND_ASSIGN(OnlyMoveable);
};
using std::string;
using namespace cpputils;
using ::testing::Test;
template<typename T>
struct StoreWith1ByteFlag {
T val;
char flag;
};
class EitherTest: public Test {
public:
@ -32,18 +42,39 @@ public:
void EXPECT_LEFT_IS(const Expected &expected, Either<Left, Right> &value) {
EXPECT_IS_LEFT(value);
EXPECT_EQ(expected, value.left());
EXPECT_EQ(expected, value.left_opt().get());
EXPECT_EQ(boost::none, value.right_opt());
const Either<Left, Right> &const_value = value;
EXPECT_EQ(expected, const_value.left());
EXPECT_EQ(expected, const_value.left_opt().get());
EXPECT_EQ(boost::none, const_value.right_opt());
}
template<class Left, class Right, class Expected>
void EXPECT_RIGHT_IS(const Expected &expected, Either<Left, Right> &value) {
EXPECT_IS_RIGHT(value);
EXPECT_EQ(expected, value.right());
EXPECT_EQ(expected, value.right_opt().get());
EXPECT_EQ(boost::none, value.left_opt());
const Either<Left, Right> &const_value = value;
EXPECT_EQ(expected, const_value.right());
EXPECT_EQ(expected, const_value.right_opt().get());
EXPECT_EQ(boost::none, const_value.left_opt());
}
};
template<typename Left, typename Right>
void TestSpaceUsage() {
EXPECT_EQ(std::max(sizeof(StoreWith1ByteFlag<Left>), sizeof(StoreWith1ByteFlag<Right>)), sizeof(Either<Left, Right>));
}
TEST_F(EitherTest, SpaceUsage) {
TestSpaceUsage<char, int>();
TestSpaceUsage<int, short>();
TestSpaceUsage<char, short>();
TestSpaceUsage<int, string>();
TestSpaceUsage<string, vector<string>>();
}
TEST_F(EitherTest, LeftCanBeConstructed) {
Either<int, string> val = 3;
UNUSED(val);
@ -142,6 +173,30 @@ TEST_F(EitherTest, RightCanBeMoved) {
EXPECT_EQ(5, val2.right().value);
}
TEST_F(EitherTest, ModifyLeft) {
Either<string, int> val = string("mystring1");
val.left() = "mystring2";
EXPECT_LEFT_IS("mystring2", val);
}
TEST_F(EitherTest, ModifyRight) {
Either<int, string> val = string("mystring1");
val.right() = "mystring2";
EXPECT_RIGHT_IS("mystring2", val);
}
TEST_F(EitherTest, ModifyLeftOpt) {
Either<string, int> val = string("mystring1");
val.left_opt().get() = "mystring2";
EXPECT_LEFT_IS("mystring2", val);
}
TEST_F(EitherTest, ModifyRightOpt) {
Either<int, string> val = string("mystring1");
val.right_opt().get() = "mystring2";
EXPECT_RIGHT_IS("mystring2", val);
}
TEST_F(EitherTest, LeftEquals) {
Either<string, int> val1 = string("mystring");
Either<string, int> val2 = string("mystring");