// // either_stream.t.h // optional.stream // // Created by Sam Jaffe on 1/30/17. // #include #include #include "stream/either_stream.hpp" enum class MathError { OutOfBounds, DivideByZero, DomainError }; using MathObject = either; MathObject divide(double num, double den) { if (std::abs(den) < 0.000000001) { return MathError::DivideByZero; } else { return num / den; } } double multiply(double lhs, double rhs) { return lhs * rhs; } MathObject log(double value, double base) { if (value <= 0) { return MathError::DomainError; } else { return divide(std::log(value), std::log(base)); } } using ::testing::DoubleNear; using ::testing::Eq; TEST(EitherStreamTest, ContainsErrorValue) { auto strm = stream::either::make_stream(1.0).flatmap( [](double d) { return divide(d, 0); }); strm.match([](double) { GTEST_FAIL(); }, [](MathError me) { EXPECT_THAT(me, MathError::DivideByZero); }); } TEST(EitherStreamTest, ErrorValueMatchesToErrorHandler) { auto bad_value = [](double) { throw std::logic_error("Expected error"); }; auto strm = stream::either::make_stream(1.0).flatmap( [](double d) { return divide(d, 0); }); EXPECT_NO_THROW(strm.match(bad_value, [](MathError e) {})); } TEST(EitherStreamTest, ConcreteValueMatchesToConreteHandler) { auto bad_error = [](MathError) { throw std::logic_error("Expected value"); }; auto strm = stream::either::make_stream(1.0).map( [](double d) { return multiply(d, 10.0); }); EXPECT_NO_THROW(strm.match([](double d) {}, bad_error)); } TEST(EitherStreamTest, ErrorPropogatesBypassingMap) { auto bad_value = [](double) { throw std::logic_error("Expected error"); }; auto strm = stream::either::make_stream(1.0).flatmap( [](double d) { return divide(d, 0); }); EXPECT_NO_THROW(strm = strm.map([](double) { throw std::runtime_error("Mapping while invalid"); return 0.0; })); EXPECT_NO_THROW(strm.match(bad_value, [](MathError e) {})); } TEST(EitherStreamTest, ErrorPropogatesBypassingFlatmap) { auto ex = stream::either::make_stream(1.0).flatmap( [](double d) { return log(0.0, d); }); ex.match([](double) { GTEST_FAIL(); }, [](MathError me) { EXPECT_THAT(me, MathError::DomainError); }); auto strm = stream::either::make_stream(1.0).flatmap( [](double d) { return log(1.0, d); }); strm.match([](double) { GTEST_FAIL(); }, [](MathError me) { EXPECT_THAT(me, MathError::DivideByZero); }); strm = strm.flatmap([](double d) { return log(0.0, d); }); strm.match([](double) { GTEST_FAIL(); }, [](MathError me) { EXPECT_THAT(me, MathError::DivideByZero); }); }