1 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
2 // https://github.com/Dobiasd/FunctionalPlus
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 //  http://www.boost.org/LICENSE_1_0.txt)
6 
7 #include <doctest/doctest.h>
8 #include <fplus/fplus.hpp>
9 #include <vector>
10 
11 namespace {
12     auto is_even = [](auto value)
__anon356105bb0202(auto value) 13     {
14         return (value % 2 == 0);
15     };
16 
17     auto is_even_size_t = [](auto value)
__anon356105bb0302(auto value) 18     {
19         return ( value % 2 == 0 );
20     };
21 
22     auto accept_with_index = [](std::size_t index, auto value)
__anon356105bb0402(std::size_t index, auto value) 23     {
24         return ( index % 2 == 0 ) && ( value >= 10 );
25     };
26 
27     typedef std::vector<int> IntVector;
28     typedef std::vector<IntVector> IntVectors;
29 }
30 
31 TEST_CASE("filter_test - keep_if")
32 {
33     const std::vector<int> v = { 1, 2, 3, 2, 4, 5 };
34     auto result = fplus::keep_if(is_even, v);
35     REQUIRE_EQ(result, std::vector<int>({2, 2, 4}));
36 
37     const auto keep_evens = fplus::bind_1st_of_2(
38         fplus::keep_if<decltype(is_even), const IntVector&>, is_even);
39 
40     REQUIRE_EQ(
41         fplus::transform(keep_evens, IntVectors({{1,3,4},{1,2}})),
42         IntVectors({{4},{2}}));
43 }
44 
45 TEST_CASE("filter_test - keep_if_r_value")
46 {
47     auto result = fplus::keep_if(is_even, std::vector<int>({1,2,3,2,4,5}));
48     REQUIRE_EQ(result, std::vector<int>({2, 2, 4}));
49 }
50 
51 TEST_CASE("filter_test - drop_if")
52 {
53     const std::vector<int> v = { 1, 2, 3, 2, 4, 5 };
54     auto result = fplus::drop_if(is_even, v);
55     REQUIRE_EQ(result, std::vector<int>({1, 3, 5}));
56 }
57 
58 TEST_CASE("filter_test - without")
59 {
60     using namespace fplus;
61     typedef std::vector<int> Ints;
62     REQUIRE_EQ(without(1, Ints({1,2,3})), Ints({2,3}));
63     REQUIRE_EQ(without(5, Ints({1,2,3})), Ints({1,2,3}));
64     REQUIRE_EQ(without(5, Ints({})), Ints({}));
65 }
66 
67 TEST_CASE("filter_test - keep_if_with_idx")
68 {
69     const std::vector<int> v = { 1, 20, 30, 4, 50, 60, 7 };
70     auto result = fplus::keep_if_with_idx(accept_with_index, v);
71     REQUIRE_EQ(result, std::vector<int>({30, 50}));
72 }
73 
74 TEST_CASE("filter_test - drop_if_with_idx")
75 {
76     const std::vector<int> v = { 1, 20, 30, 4, 50, 60, 7 };
77     auto result = fplus::drop_if_with_idx(accept_with_index, v);
78     REQUIRE_EQ(result, std::vector<int>({1, 20, 4, 60, 7}));
79 }
80 
81 TEST_CASE("filter_test - keep_by_idx")
82 {
83     const std::vector<int> v = { 11, 17, 3, 8, 49, 6 };
84     auto result = fplus::keep_by_idx(is_even_size_t, v);
85     REQUIRE_EQ(result, std::vector<int>({11, 3, 49}));
86     auto result_rvalue = fplus::keep_by_idx(is_even_size_t, std::vector<int>({ 11, 17, 3, 8, 49, 6 }));
87     REQUIRE_EQ(result_rvalue, std::vector<int>({11, 3, 49}));
88 
89     const std::vector<std::string> v_strs = { "foo", "bar" };
90     const auto result_kept_all_strs = fplus::keep_by_idx(fplus::always<std::size_t>(true), v_strs);
91     REQUIRE_EQ(result_kept_all_strs, v_strs);
92     const auto result_kept_all_strs_r_value =
93         fplus::keep_by_idx(fplus::always<std::size_t>(true), std::vector<std::string>({ "foo", "bar" }));
94     REQUIRE_EQ(result_kept_all_strs_r_value, std::vector<std::string>({ "foo", "bar" }));
95 }
96 
97 TEST_CASE("filter_test - drop_by_idx")
98 {
99     const std::vector<int> v = { 11, 17, 3, 8, 49, 6 };
100     auto result = fplus::drop_by_idx(is_even_size_t, v);
101     REQUIRE_EQ(result, std::vector<int>({17, 8, 6}));
102 }
103 
104 TEST_CASE("filter_test - keep_idxs")
105 {
106     const std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7 };
107     const std::vector<std::size_t> indices = { 2, 5 };
108     auto result = fplus::keep_idxs(indices, v);
109     REQUIRE_EQ(result, std::vector<int>({3, 6}));
110 }
111 
112 TEST_CASE("filter_test - drop_idx")
113 {
114     const std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7 };
115     auto result = fplus::drop_idx(2, v);
116     REQUIRE_EQ(result, std::vector<int>({1, 2, 4, 5, 6, 7}));
117 }
118 
119 TEST_CASE("filter_test - drop_idxs")
120 {
121     const std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7 };
122     const std::vector<std::size_t> indices = { 2, 5 };
123     auto result = fplus::drop_idxs(indices, v);
124     REQUIRE_EQ(result, std::vector<int>({1, 2, 4, 5, 7}));
125 }
126 
127 TEST_CASE("filter_test - justs")
128 {
129     using fplus::maybe;
130     using fplus::just;
131     using fplus::nothing;
132 
133     const std::vector<maybe<int>> v = { just(1), nothing<int>(), just(2) };
134     auto result = fplus::justs(v);
135     REQUIRE_EQ(result, std::vector<int>({1, 2}));
136 }
137 
138 TEST_CASE("filter_test - oks")
139 {
140     using fplus::ok;
141     using fplus::error;
142     const std::vector<fplus::result<int, std::string>> v = { ok<int, std::string>(1),
143                                                             error<int>(std::string("abc")),
144                                                             ok<int, std::string>(2) };
145     auto result = fplus::oks(v);
146     REQUIRE_EQ(result, std::vector<int>({1, 2}));
147 }
148 
149 TEST_CASE("filter_test - errors")
150 {
151     using fplus::ok;
152     using fplus::error;
153     const std::vector<fplus::result<int, std::string>> v = { ok<int, std::string>(1),
154                                                             error<int>(std::string("abc")),
155                                                             ok<int, std::string>(2) };
156     auto result = fplus::errors(v);
157     REQUIRE_EQ(result, std::vector<std::string>({"abc"}));
158 }
159 
160 TEST_CASE("filter_test - trim_left")
161 {
162     const std::vector<int> v = { 0, 0, 0, 5, 6, 7, 8, 6, 4 };
163     auto result = fplus::trim_left(0, v);
164     REQUIRE_EQ(result, std::vector<int>({5, 6, 7, 8, 6, 4}));
165 }
166 
167 TEST_CASE("filter_test - trim_token_left")
168 {
169     const std::vector<int> v = { 0, 1, 2, 0, 1, 2, 7, 5, 9 };
170     const std::vector<int> token = { 0, 1, 2 };
171     auto result = fplus::trim_token_left(token, v);
172     REQUIRE_EQ(result, std::vector<int>({7, 5, 9}));
173 }
174 
175 TEST_CASE("filter_test - trim_right_by")
176 {
177     const std::vector<int> v = { 0, 2, 4, 5, 6, 7, 8, 6, 4 };
178     auto result = fplus::trim_right_by(is_even, v);
179     REQUIRE_EQ(result, std::vector<int>({0, 2, 4, 5, 6, 7}));
180 }
181 
182 TEST_CASE("filter_test - trim_right_by_trims_all")
183 {
184     const std::vector<int> v = { 4, 8 };
185     auto result = fplus::trim_right_by(is_even, v);
186     REQUIRE(result.empty());
187 }
188 
189 TEST_CASE("filter_test - trim_right")
190 {
191     const std::vector<int> v = { 0, 2, 4, 5, 6, 7, 8, 4, 4 };
192     auto result = fplus::trim_right(4, v);
193     REQUIRE_EQ(result, std::vector<int>({0, 2, 4, 5, 6, 7, 8}));
194 }
195 
196 TEST_CASE("filter_test - trim_token_right")
197 {
198     const std::vector<int> v = { 7, 5, 9, 0, 1, 2, 0, 1, 2 };
199     const std::vector<int> token = { 0, 1, 2 };
200     auto result = fplus::trim_token_right(token, v);
201     REQUIRE_EQ(result, std::vector<int>({7, 5, 9}));
202 }
203 
204 TEST_CASE("filter_test - trim_by")
205 {
206     const std::vector<int> v = { 0, 2, 4, 5, 6, 7, 8, 6, 4 };
207     auto result = fplus::trim_by(is_even, v);
208     REQUIRE_EQ(result, std::vector<int>({5, 6, 7}));
209 }
210 
211 TEST_CASE("filter_test - trim")
212 {
213     const std::vector<int> v = { 0, 2, 4, 5, 6, 7, 8, 0, 0 };
214     auto result = fplus::trim(0, v);
215     REQUIRE_EQ(result, std::vector<int>({2, 4, 5, 6, 7, 8}));
216 }
217 
218 TEST_CASE("filter_test - trim_token")
219 {
220     const std::vector<int> v = { 0, 1, 7, 8, 9, 0, 1 };
221     const std::vector<int> token = { 0, 1 };
222     auto result = fplus::trim_token(token, v);
223     REQUIRE_EQ(result, std::vector<int>({7, 8, 9}));
224 }
225 
226 TEST_CASE("filter_test - adjacent_keep_snd_if")
227 {
228     const std::vector<int> v = { 0, 1, 7, 8, 9, 0, 1 };
229     REQUIRE_EQ(fplus::adjacent_keep_snd_if(std::greater<>(), v), std::vector<int>({0,0}));
230     REQUIRE_EQ(fplus::adjacent_keep_snd_if(std::less<int>(), v), std::vector<int>({0,1,7,8,9,1}));
231 }
232 
233 TEST_CASE("filter_test - adjacent_drop_snd_if")
234 {
235     const std::vector<int> v = { 0, 1, 7, 8, 9, 0, 1 };
236     REQUIRE_EQ(fplus::adjacent_drop_snd_if(std::less<>(), v), std::vector<int>({0,0}));
237     REQUIRE_EQ(fplus::adjacent_drop_snd_if(std::greater<int>(), v), std::vector<int>({0,1,7,8,9,1}));
238 }
239 
240 TEST_CASE("filter_test - adjacent_drop_fst_if")
241 {
242     const std::vector<int> v = { 0, 1, 7, 8, 9, 0, 1 };
243     REQUIRE_EQ(fplus::adjacent_drop_fst_if(std::less<>(), v), std::vector<int>({9,1}));
244     REQUIRE_EQ(fplus::adjacent_drop_fst_if(std::greater<int>(), v), std::vector<int>({0,1,7,8,0,1}));
245 }
246 
247 TEST_CASE("filter_test - adjacent_keep_fst_if")
248 {
249     const std::vector<int> v = { 0, 1, 7, 8, 9, 0, 1 };
250     REQUIRE_EQ(fplus::adjacent_keep_fst_if(std::greater<>(), v), std::vector<int>({9,1}));
251     REQUIRE_EQ(fplus::adjacent_keep_fst_if(std::less<int>(), v), std::vector<int>({0,1,7,8,0,1}));
252 }
253