functional: Added functional lib
[nit.git] / lib / functional / test_iter_extras.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2019 Louis-Vincent Boudreault <lv.boudreault95@gmail.com>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/license/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 module test_iter_extras is test
18
19 import iter_extras
20 private import test_utils
21
22 redef class Ref[E]
23 redef fun ==(other) do
24 if other isa Ref[E] then
25 return self.item == other.item
26 end
27 return false
28 end
29 end
30
31 # test cases using `iter_extras::Iterator::map`
32 class TestMapIter
33 test
34
35 # test case for an empty `Array` of `Int`
36 fun add_one_on_empty_array is test do
37 var xs = new Array[Int]
38 var actual = xs.iterator.map(add_one).to_a
39 assert actual.is_empty
40 end
41
42 # test case for an `Array` containing one `Int`
43 fun add_one_on_singleton_array is test do
44 var xs = [1]
45 var actual = xs.iterator.map(add_one).to_a
46 assert actual[0] == 2
47 end
48
49 # test case for `Range`, adding one to each elements (1 to 10)
50 fun add_one_on_range_1_to_10 is test do
51 var xs = [1..10]
52 var actual = xs.iterator.map(add_one).to_a
53 var expected = [2,3,4,5,6,7,8,9,10,11]
54 assert actual == expected
55 end
56
57 # test multiple application of map of an `Array[String]`.
58 fun snake_and_upper_strings is test do
59 var cs = ["helloWorld", "worldHello", "testCase"]
60 var actual = cs.iterator.map(snake_case_fn).map(upper_fn).to_a
61 var expected = ["HELLO_WORLD", "WORLD_HELLO", "TEST_CASE"]
62 assert actual == expected
63 end
64 end
65
66 # test cases using `iter_extras::Iterator::for_each`
67 class TestForEach
68 test
69
70 fun add_one_to_all is test do
71 var xs = new Array[Ref[Int]]
72 var expected = new Array[Ref[Int]]
73 for i in [1..10] do
74 var r1 = new Ref[Int](i)
75 var r2 = new Ref[Int](i+1)
76 xs.push(r1)
77 expected.push(r2)
78 end
79 xs.iterator.for_each(add_one_proc)
80 assert xs == expected
81 end
82
83 fun for_each_empty_array is test do
84 var xs = new Array[Ref[Int]]
85 xs.iterator.for_each(add_one_proc)
86 assert xs.is_empty
87 end
88
89 fun for_each_on_singleton_array is test do
90 var r1 = new Ref[Int](1)
91 var r2 = new Ref[Int](2)
92 var xs = [r1]
93 xs.iterator.for_each(add_one_proc)
94 assert r1 == r2
95 assert xs == [r2]
96 end
97 end
98
99 # test cases using `iter_extras::Iterator::filter`
100 class TestFilterIter
101 test
102
103 # test case for an empty `Array`
104 fun filter_empty_array is test do
105 var xs = new Array[Int]
106 var lt10 = lower_than_fn(10)
107 var actual = xs.iterator.filter(lt10).to_a
108 assert actual.is_empty
109 end
110
111 # test case for a `Range` whose elements doesn't match the predicate
112 fun filter_nomatch is test do
113 var xs = [1..10]
114 var lt0 = lower_than_fn(0)
115 var actual = xs.iterator.filter(lt0).to_a
116 assert actual.is_empty
117 end
118
119 # test case for a `Range` whose elements match 50% of a given predicate
120 fun filter_half_match_on_range_1_to_10 is test do
121 var xs = [1..10]
122 var lt6 = lower_than_fn(6)
123 var actual = xs.iterator.filter(lt6).to_a
124 var expected = [1,2,3,4,5]
125 assert actual == expected
126 end
127
128 # test case for an `Array` whose last element is the only matching element
129 # for a given predicate
130 fun only_last_element_is_a_letter is test do
131 var xs = "123a"
132 var actual = xs.iterator.filter(is_letter_fn).to_a.join
133 assert actual == "a"
134 end
135
136 # test case for a `String` containing mixed alphanumeric characters
137 fun only_letters is test do
138 var cs = "aaa123b4bb3333c1c32c"
139 assert cs.iterator.filter(is_letter_fn).to_a.join == "aaabbbccc"
140 end
141
142 # test case for a `String` containing only one letter in the middle
143 fun has_any_letter_true is test do
144 var cs = "12345a12345"
145 assert cs.iterator.any(is_letter_fn)
146 end
147
148 # test case for an empty `String` that should not contain any letter
149 fun empty_string_has_no_letter is test do
150 var cs = ""
151 assert not cs.iterator.any(is_letter_fn)
152 end
153
154 # test case for a `String` representing a number, should not have any letter
155 fun numeric_string_has_no_letter is test do
156 var cs = "123456"
157 assert not cs.iterator.any(is_letter_fn)
158 end
159 end
160
161 # test cases using `iter_extras::Iterator::flat_map`
162 class TestFlatMapIter
163 test
164
165 # test case for combining three `String`
166 fun combine_aaa_bbb_ccc_to_aaabbbccc is test do
167 var cs = ["aaa","bbb","ccc"]
168 assert cs.iterator.flat_map(chars_fn).to_a.join == "aaabbbccc"
169 end
170
171 fun combine_empty_strings is test do
172 var cs = ["", ""]
173 assert cs.iterator.flat_map(chars_fn).to_a.join == ""
174 end
175
176 fun flat_map_over_empty_array is test do
177 var cs = new Array[String]
178 assert cs.iterator.flat_map(chars_fn).to_a.join == ""
179 end
180 end
181
182 # test cases using `iter_extras::Iterator::fold`
183 class TestFoldIter
184 test
185
186 fun sum_an_empty_array is test do
187 var xs = new Array[Int]
188 var actual = xs.iterator.fold(0, sum_fn)
189 assert actual == 0
190 end
191
192 fun sum_1_to_10 is test do
193 var xs = [1..10]
194 var actual = xs.iterator.fold(0, sum_fn)
195 assert actual == 55
196 end
197
198 fun fold_one_element is test do
199 var xs = [1]
200 var actual = xs.iterator.fold(0, sum_fn)
201 assert actual == xs[0]
202 end
203 end
204
205 # test cases using `iter_extras::Iterator::fold1`
206 class TestFold1Iter
207 test
208
209 fun find_min_in_mixed_array is test do
210 var xs = [45,424,11,43,7,5,8,9,1,-100]
211 var actual = xs.iterator.fold1(min_int_fn)
212 assert actual == -100
213 end
214
215 fun fold1_with_2_elements is test do
216 var xs = [0,-100]
217 var actual = xs.iterator.fold1(min_int_fn)
218 assert actual == -100
219 end
220 end
221
222 # test cases using `iter_extras::Iterator::order_by`
223 class TestOrderedIter
224 test
225
226 fun order_empty_list_of_numbers is test do
227 var xs = new Array[Int]
228 var actual = xs.iterator.order_by(id_int).to_a
229 assert actual == xs
230 end
231
232 fun order_list_of_ints is test do
233 var xs = [5,4,3,2,1]
234 var actual = xs.iterator.order_by(id_int).to_a
235 var expected = [1,2,3,4,5]
236 assert actual == expected
237 end
238
239 fun order_singleton_list_of_ints is test do
240 var xs = [1]
241 var actual = xs.iterator.order_by(id_int).to_a
242 assert actual == xs
243 end
244
245 fun order_list_of_strings_by_alphabetical_order is test do
246 var xs = ["louis", "florian", "alexis", "jean", "alexandre"]
247 var actual = xs.iterator.order_by(id_str).to_a
248 var expected = ["alexandre", "alexis", "florian", "jean", "louis"]
249 assert actual == expected
250 end
251
252 fun order_list_of_strings_by_length is test do
253 var xs = ["louis", "florian", "alexis", "jean", "alexandre"]
254 var actual = xs.iterator.order_by(str_len).to_a
255 var expected = ["jean", "louis", "alexis", "florian", "alexandre"]
256 assert actual == expected
257 end
258 end