From d5dadc74e76e5cce0e53c6a9017c01cdc89f9570 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Fri, 26 Jun 2015 01:07:46 +0200 Subject: [PATCH] Offer Either::left_opt() and Either::right_opt() and add some test cases --- either.h | 41 +++++++++++++++++++++++++----- test/EitherTest.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 93 insertions(+), 9 deletions(-) diff --git a/either.h b/either.h index 84f82977..a3520c94 100644 --- a/either.h +++ b/either.h @@ -2,7 +2,7 @@ #ifndef MESSMER_CPP_UTILS_EITHER_H #define MESSMER_CPP_UTILS_EITHER_H -#include +#include 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(const_cast*>(this)->left()); + } const Right &right() const { return _right; } - - Left &left() { - return const_cast(const_cast*>(this)->left()); - } Right &right() { return const_cast(const_cast*>(this)->right()); } + + boost::optional left_opt() const { + if (_side == Side::left) { + return _left; + } else { + return boost::none; + } + } + boost::optional left_opt() { + if (_side == Side::left) { + return _left; + } else { + return boost::none; + } + } + + boost::optional right_opt() const { + if (_side == Side::right) { + return _right; + } else { + return boost::none; + } + } + boost::optional right_opt() { + if (_side == Side::right) { + return _right; + } else { + return boost::none; + } + } + private: union { Left _left; diff --git a/test/EitherTest.cpp b/test/EitherTest.cpp index f14ed66d..b12abc85 100644 --- a/test/EitherTest.cpp +++ b/test/EitherTest.cpp @@ -1,8 +1,16 @@ #include #include +#include #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 +struct StoreWith1ByteFlag { + T val; + char flag; +}; class EitherTest: public Test { public: @@ -32,18 +42,39 @@ public: void EXPECT_LEFT_IS(const Expected &expected, Either &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 &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 void EXPECT_RIGHT_IS(const Expected &expected, Either &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 &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 +void TestSpaceUsage() { + EXPECT_EQ(std::max(sizeof(StoreWith1ByteFlag), sizeof(StoreWith1ByteFlag)), sizeof(Either)); +} + +TEST_F(EitherTest, SpaceUsage) { + TestSpaceUsage(); + TestSpaceUsage(); + TestSpaceUsage(); + TestSpaceUsage(); + TestSpaceUsage>(); +} + TEST_F(EitherTest, LeftCanBeConstructed) { Either val = 3; UNUSED(val); @@ -142,6 +173,30 @@ TEST_F(EitherTest, RightCanBeMoved) { EXPECT_EQ(5, val2.right().value); } +TEST_F(EitherTest, ModifyLeft) { + Either val = string("mystring1"); + val.left() = "mystring2"; + EXPECT_LEFT_IS("mystring2", val); +} + +TEST_F(EitherTest, ModifyRight) { + Either val = string("mystring1"); + val.right() = "mystring2"; + EXPECT_RIGHT_IS("mystring2", val); +} + +TEST_F(EitherTest, ModifyLeftOpt) { + Either val = string("mystring1"); + val.left_opt().get() = "mystring2"; + EXPECT_LEFT_IS("mystring2", val); +} + +TEST_F(EitherTest, ModifyRightOpt) { + Either val = string("mystring1"); + val.right_opt().get() = "mystring2"; + EXPECT_RIGHT_IS("mystring2", val); +} + TEST_F(EitherTest, LeftEquals) { Either val1 = string("mystring"); Either val2 = string("mystring");