either_stream_test.cxx 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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, becomes_error) {
  34. auto strm = stream::either::make_stream<MathObject>(1.0);
  35. strm.flatmap([](double d) { return divide(d, 0); })
  36. .match([](double) { throw std::runtime_error("Expected error"); },
  37. [](MathError e) { EXPECT_THAT(e, Eq(MathError::DivideByZero)); });
  38. }
  39. TEST(EitherStreamTest, computes_result) {
  40. auto strm = stream::either::make_stream<MathObject>(1.0);
  41. strm.map([](double d) { return multiply(d, 10.0); })
  42. .match([](double d) { EXPECT_THAT(10.0, DoubleNear(d, 0.00001)); },
  43. [](MathError) { throw std::runtime_error("Expected concrete"); });
  44. }
  45. TEST(EitherStreamTest, computes_result2) {
  46. auto strm = stream::either::make_stream<MathObject>(1.0);
  47. bool is_error = strm.map([](double d) { return multiply(d, 10.0); })
  48. .match([](double) { return false; },
  49. [](MathError) { return true; });
  50. EXPECT_FALSE(is_error);
  51. }
  52. TEST(EitherStreamTest, propogates_error) {
  53. auto strm = stream::either::make_stream<MathObject>(1.0);
  54. strm.flatmap([](double d) { return divide(d, 0); })
  55. .map([](double) { throw std::runtime_error("Mapping while invalid"); return 0; })
  56. .match([](double) { throw std::runtime_error("Expected error"); },
  57. [](MathError e) { EXPECT_THAT(e, Eq(MathError::DivideByZero)); });
  58. }
  59. TEST(EitherStreamTest, propogates_same_error) {
  60. auto strm = stream::either::make_stream<MathObject>(1.0);
  61. strm.flatmap([](double d) { return log(1.0, d); })
  62. .flatmap([](double d) { return log(d, 1.0); })
  63. .match([](double) { throw std::runtime_error("Expected error"); },
  64. [](MathError e) { EXPECT_THAT(e, Eq(MathError::DivideByZero)); });
  65. }
  66. TEST(EitherStreamTest, propogates_same_error2) {
  67. auto strm = stream::either::make_stream<MathObject>(1.0);
  68. strm.flatmap([](double d) { return log(0.0, d); })
  69. .flatmap([](double d) { return log(d, 1.0); })
  70. .match([](double) { throw std::runtime_error("Expected error"); },
  71. [](MathError e) { EXPECT_THAT(e, Eq(MathError::DomainError)); });
  72. }
  73. TEST(EitherStreamTest, propogates_same_error3) {
  74. auto strm = stream::either::make_stream<MathObject>(1.0);
  75. bool is_error = strm.flatmap([](double d) { return log(0.0, d); })
  76. .flatmap([](double d) { return log(d, 1.0); })
  77. .match([](double) { return false; },
  78. [](MathError) { return true; });
  79. EXPECT_TRUE(is_error);
  80. }