either_stream_test.cxx 2.7 KB

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