// // 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, becomes_error) { auto strm = stream::either::make_stream(1.0); strm.flatmap([](double d) { return divide(d, 0); }) .match([](double) { throw std::runtime_error("Expected error"); }, [](MathError e) { EXPECT_THAT(e, Eq(MathError::DivideByZero)); }); } TEST(EitherStreamTest, computes_result) { auto strm = stream::either::make_stream(1.0); strm.map([](double d) { return multiply(d, 10.0); }) .match([](double d) { EXPECT_THAT(10.0, DoubleNear(d, 0.00001)); }, [](MathError) { throw std::runtime_error("Expected concrete"); }); } TEST(EitherStreamTest, computes_result2) { auto strm = stream::either::make_stream(1.0); bool is_error = strm.map([](double d) { return multiply(d, 10.0); }) .match([](double) { return false; }, [](MathError) { return true; }); EXPECT_FALSE(is_error); } TEST(EitherStreamTest, propogates_error) { auto strm = stream::either::make_stream(1.0); strm.flatmap([](double d) { return divide(d, 0); }) .map([](double) { throw std::runtime_error("Mapping while invalid"); return 0; }) .match([](double) { throw std::runtime_error("Expected error"); }, [](MathError e) { EXPECT_THAT(e, Eq(MathError::DivideByZero)); }); } TEST(EitherStreamTest, propogates_same_error) { auto strm = stream::either::make_stream(1.0); strm.flatmap([](double d) { return log(1.0, d); }) .flatmap([](double d) { return log(d, 1.0); }) .match([](double) { throw std::runtime_error("Expected error"); }, [](MathError e) { EXPECT_THAT(e, Eq(MathError::DivideByZero)); }); } TEST(EitherStreamTest, propogates_same_error2) { auto strm = stream::either::make_stream(1.0); strm.flatmap([](double d) { return log(0.0, d); }) .flatmap([](double d) { return log(d, 1.0); }) .match([](double) { throw std::runtime_error("Expected error"); }, [](MathError e) { EXPECT_THAT(e, Eq(MathError::DomainError)); }); } TEST(EitherStreamTest, propogates_same_error3) { auto strm = stream::either::make_stream(1.0); bool is_error = strm.flatmap([](double d) { return log(0.0, d); }) .flatmap([](double d) { return log(d, 1.0); }) .match([](double) { return false; }, [](MathError) { return true; }); EXPECT_TRUE(is_error); }