// // stream_td.hpp // stream // // Created by Sam Jaffe on 1/28/17. // #include "xcode_gtest_helper.h" #include #include #include #include "stream/streams.hpp" using ::testing::ElementsAreArray; using ::testing::Eq; namespace views = stream::views; namespace ranges = stream::ranges; // Workaround for OSX and pointer-to-member-functions template class std::basic_string; TEST(StreamTest, IteratorPreservesElements) { std::vector input{1, 2, 3, 4, 5}; auto s = views::all(input); std::vector out{s.begin(), s.end()}; EXPECT_THAT(out, Eq(input)); } TEST(MapStreamTest, IteratorPreservesElements) { std::map input{{1, 1}, {2, 2}}; auto s = views::all(input); std::map out{s.begin(), s.end()}; EXPECT_THAT(out, Eq(input)); } TEST(StreamTest, CollectPreservesElements) { std::vector input{1, 2, 3, 4, 5}; std::vector out = views::all(input) | ranges::to_vector(); EXPECT_THAT(out, Eq(input)); } TEST(StreamTest, CollectToObjectPreservesElements) { std::vector input{1, 2, 3, 4, 5}; auto s = views::all(input); std::set out = s | ranges::to_set(); EXPECT_THAT(out, ElementsAreArray(input)); } TEST(StreamTest, MapToSelfIsSelfs) { std::vector input{1, 2, 3, 4, 5}; auto identity = [](int i) { return i; }; auto out = input | views::transform(identity) | ranges::to_vector(); EXPECT_THAT(out, Eq(input)); } TEST(StreamTest, MapCanAlterValues) { std::vector input{1, 2, 3, 4, 5}; std::vector expected{3, 5, 7, 9, 11}; auto fmap = [](int i) { return 2 * i + 1; }; auto out = input | views::transform(fmap) | ranges::to_vector(); EXPECT_THAT(out, Eq(expected)); } template struct nocopy { T value; nocopy(T const & val) : value(val) {} nocopy(nocopy const &) = delete; nocopy & operator=(nocopy const &) = delete; nocopy(nocopy &&) = default; nocopy & operator=(nocopy &&) = default; operator T() const { return value; } }; TEST(MapStreamTest, MapToValue) { auto const input = []() { std::map> tmp; tmp.emplace(0, 1); tmp.emplace(2, 2); return tmp; }(); auto fmap = [](auto & pair) -> auto & { return pair.second; }; auto s = input | views::transform(fmap); std::vector out(s.begin(), s.end()); std::vector const expected{1, 2}; EXPECT_THAT(out, Eq(expected)); } TEST(StreamTest, CanBuildFromSingleElement) { int value = 11; auto even = [](int i) { return i % 2 == 0; }; auto s = views::single(value) | views::filter(even); EXPECT_THAT(ranges::size(s), 0); } TEST(StreamTest, CanBuildFromIterators) { std::vector input{1, 2, 3, 4, 5}; std::vector expected{5, 7}; auto fmap = [](int i) { return 2 * i + 1; }; auto out = ranges::ref_view(input.begin() + 1, input.begin() + 3) | views::transform(fmap) | ranges::to_vector(); EXPECT_THAT(out, Eq(expected)); } TEST(StreamTest, NoOpFilterReturnOriginal) { std::vector input{1, 2, 3, 4, 5}; auto pass = [](int) { return true; }; auto out = input | views::filter(pass) | ranges::to_vector(); EXPECT_THAT(out, Eq(input)); } TEST(StreamTest, CanFilterOutElements) { std::vector input{1, 2, 3, 4, 5}; std::vector expected{2, 4}; auto even = [](int i) { return i % 2 == 0; }; auto out = input | views::filter(even) | ranges::to_vector(); EXPECT_THAT(out, Eq(expected)); } TEST(StreamTest, AccumulateDefaultsToAdd) { std::vector input{1, 2, 3, 4, 5}; auto even = [](int i) { return i % 2 == 0; }; auto s = input | views::filter(even) | ranges::to_vector(); EXPECT_THAT(ranges::fold_left(s, 0, std::plus<>()), Eq(6)); } TEST(StreamTest, AccumulateCanTakeCustomAccumulator) { std::vector input{1, 2, 3, 4, 5}; auto even = [](int i) { return i % 2 == 0; }; auto prod = [](int lhs, int rhs) { return lhs * rhs; }; auto s = input | views::filter(even) | ranges::to_vector(); EXPECT_THAT(ranges::fold_left(s, 0, prod), Eq(0)); EXPECT_THAT(ranges::fold_left(s, 1, prod), Eq(8)); } TEST(StreamTest, FlatmapJoinsIterableOutputs) { std::vector vv{1, 2, 3, 4, 5}; auto next3 = [](int i) { return std::vector{i, i + 1, i + 2}; }; std::vector expected{1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7}; auto out = vv | views::transform(next3) | views::join() | ranges::to_vector(); EXPECT_THAT(out, Eq(expected)); } TEST(StreamTest, CanDereferenceElements) { int val = 5; std::vector input{&val}; auto data = input | views::deref() | ranges::to_vector(); EXPECT_THAT(data.front(), Eq(val)); } TEST(StreamTest, CanForEachConsume) { int hits = 0; std::vector input{1, 2, 3, 4, 5}; ranges::for_each(views::all(input), [&hits](int) { ++hits; }); EXPECT_THAT(hits, Eq(5)); } TEST(StreamTest, CanFetchMemPtr) { struct test { int val; }; std::vector input{{1}, {3}, {2}}; std::vector expected{1, 3, 2}; auto out = input | views::transform(&test::val) | ranges::to_vector(); EXPECT_THAT(out, Eq(expected)); } TEST(StreamTest, CanMapToMemFn) { std::vector input{"hello", "goodbye"}; std::vector expected{5, 7}; auto out = input | views::transform(&std::string::size) | ranges::to_vector(); EXPECT_THAT(out, Eq(expected)); } // // TEST(StreamTest, CastStreamToParentType) { // struct base { // char cat[4] = "cat"; // }; // struct test : base { // test(int v) : val(v) {} // int val; // }; // std::vector input{{1}, {3}, {2}}; // // auto addressof_void = [](auto const & p) { return (void *)&p; }; // // auto strm = stream::of(input).cast(); // auto first = stream::of(input).map(addressof_void).collect(); // auto second = strm.map(addressof_void).collect(); // // EXPECT_THAT(first, second); //} TEST(StreamTest, Iota) { static_assert(iterator::detail::has_distance_to_v< stream::ranges::iota_iterator>, ""); auto out = views::iota(0, 4) | views::transform([](size_t i) { return std::vector(i, i); }) | views::join() | ranges::to_vector(); std::vector expected{1, 2, 2, 3, 3, 3}; EXPECT_THAT(out, expected); }