either_stream_test.cxx 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. //
  2. // either_stream.t.h
  3. // optional.stream
  4. //
  5. // Created by Sam Jaffe on 1/30/17.
  6. //
  7. #include <gmock/gmock.h>
  8. #include <cmath>
  9. #include "stream/either_stream.hpp"
  10. enum class MathError {
  11. OutOfBounds,
  12. DivideByZero,
  13. DomainError
  14. };
  15. using MathObject = either<double, MathError>;
  16. MathObject divide(double num, double den) {
  17. if (std::abs(den) < 0.000000001) {
  18. return MathError::DivideByZero;
  19. } else {
  20. return num / den;
  21. }
  22. }
  23. double multiply(double lhs, double rhs) { return lhs * rhs; }
  24. MathObject log(double value, double base) {
  25. if (value <= 0) {
  26. return MathError::DomainError;
  27. } else {
  28. return divide(std::log(value), std::log(base));
  29. }
  30. }
  31. using ::testing::DoubleNear;
  32. using ::testing::Eq;
  33. TEST(EitherStreamTest, ContainsErrorValue) {
  34. auto strm = stream::either::make_stream<MathObject>(1.0)
  35. .flatmap([](double d) { return divide(d, 0); });
  36. EXPECT_THAT(strm.value().index(), Eq(1));
  37. EXPECT_THAT(std::get<MathError>(strm.value()), Eq(MathError::DivideByZero));
  38. }
  39. TEST(EitherStreamTest, ErrorValueMatchesToErrorHandler) {
  40. auto bad_value = [](double) { throw std::logic_error("Expected error"); };
  41. auto strm = stream::either::make_stream<MathObject>(1.0)
  42. .flatmap([](double d) { return divide(d, 0); });
  43. EXPECT_NO_THROW(strm.match(bad_value, [](MathError e) {}));
  44. }
  45. TEST(EitherStreamTest, ConcreteValueMatchesToConreteHandler) {
  46. auto bad_error = [](MathError) { throw std::logic_error("Expected value"); };
  47. auto strm = stream::either::make_stream<MathObject>(1.0)
  48. .map([](double d) { return multiply(d, 10.0); });
  49. EXPECT_NO_THROW(strm.match([](double d) {}, bad_error));
  50. }
  51. TEST(EitherStreamTest, ErrorPropogatesBypassingMap) {
  52. auto bad_value = [](double) { throw std::logic_error("Expected error"); };
  53. auto strm = stream::either::make_stream<MathObject>(1.0)
  54. .flatmap([](double d) { return divide(d, 0); });
  55. EXPECT_NO_THROW(strm = strm.map([](double) {
  56. throw std::runtime_error("Mapping while invalid");
  57. return 0.0;
  58. }));
  59. EXPECT_NO_THROW(strm.match(bad_value, [](MathError e) {}));
  60. }
  61. TEST(EitherStreamTest, ErrorPropogatesBypassingFlatmap) {
  62. auto ex = stream::either::make_stream<MathObject>(1.0)
  63. .flatmap([](double d) { return log(0.0, d); });
  64. EXPECT_THAT(std::get<MathError>(ex.value()), Eq(MathError::DomainError));
  65. auto strm = stream::either::make_stream<MathObject>(1.0)
  66. .flatmap([](double d) { return log(1.0, d); });
  67. EXPECT_THAT(std::get<MathError>(strm.value()), Eq(MathError::DivideByZero));
  68. strm = strm.flatmap([](double d) { return log(0.0, d); });
  69. EXPECT_THAT(std::get<MathError>(strm.value()), Eq(MathError::DivideByZero));
  70. }