OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 /// Tests algorithm utilities. | |
6 | |
7 import "package:collection_helpers/all.dart"; | |
8 import "package:unittest/unittest.dart"; | |
9 import 'dart:math'; | |
10 | |
11 void main() { | |
12 void testShuffle(List list) { | |
13 List copy = list.toList(); | |
14 shuffle(list); | |
15 expect(new UnorderedIterableEquality().equals(list, copy), isTrue); | |
16 } | |
17 | |
18 test("Shuffle 0", () { | |
19 testShuffle([]); | |
20 }); | |
21 test("Shuffle 1", () { | |
22 testShuffle([1]); | |
23 }); | |
24 test("Shuffle 3", () { | |
25 testShuffle([1, 2, 3]); | |
26 }); | |
27 test("Shuffle 10", () { | |
28 testShuffle([1, 2, 3, 4, 5, 1, 3, 5, 7, 9]); | |
29 }); | |
30 test("Shuffle shuffles", () { | |
31 List l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; | |
32 List c = l.toList(); | |
33 int count = 0; | |
34 do { | |
35 shuffle(l); | |
36 if (!const ListEquality().equals(c, l)) return; | |
37 // Odds of not changing the order should be one in ~ 16! ~= 2e+13. | |
38 // Repeat this 10 times, and the odds of accidentally shuffling to the | |
39 // same result every time is disappearingly tiny. | |
40 count++; | |
41 // If this happens even once, it's ok to report it. | |
42 print("Failed shuffle $count times"); | |
43 if (count == 10) fail("Shuffle didn't change order."); | |
44 } while (true); | |
45 }); | |
46 test("Shuffle sublist", (){ | |
47 List l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; | |
48 List c = l.toList(); | |
49 shuffle(l, 4, 12); | |
50 expect(const IterableEquality().equals(l.getRange(0, 4), | |
51 c.getRange(0, 4)), isTrue); | |
52 expect(const IterableEquality().equals(l.getRange(12, 16), | |
53 c.getRange(12, 16)), isTrue); | |
54 expect(const UnorderedIterableEquality().equals(l.getRange(4, 12), | |
55 c.getRange(4, 12)), | |
56 isTrue); | |
57 | |
58 }); | |
59 | |
60 test("binsearch0", () { | |
61 expect(binarySearch([], 2), equals(-1)); | |
62 }); | |
63 | |
64 test("binsearch1", () { | |
65 expect(binarySearch([5], 2), equals(-1)); | |
66 expect(binarySearch([5], 5), equals(0)); | |
67 expect(binarySearch([5], 7), equals(-1)); | |
68 }); | |
69 | |
70 test("binsearch3", () { | |
71 expect(binarySearch([0, 5, 10], -1), equals(-1)); | |
72 expect(binarySearch([0, 5, 10], 0), equals(0)); | |
73 expect(binarySearch([0, 5, 10], 2), equals(-1)); | |
74 expect(binarySearch([0, 5, 10], 5), equals(1)); | |
75 expect(binarySearch([0, 5, 10], 7), equals(-1)); | |
76 expect(binarySearch([0, 5, 10], 10), equals(2)); | |
77 expect(binarySearch([0, 5, 10], 12), equals(-1)); | |
78 }); | |
79 | |
80 test("binsearchCompare0", () { | |
81 expect(binarySearch([], new C(2), compare: compareC), equals(-1)); | |
82 }); | |
83 | |
84 test("binsearchCompare1", () { | |
85 var l1 = [new C(5)]; | |
86 expect(binarySearch(l1, new C(2), compare: compareC), equals(-1)); | |
87 expect(binarySearch(l1, new C(5), compare: compareC), equals(0)); | |
88 expect(binarySearch(l1, new C(7), compare: compareC), equals(-1)); | |
89 }); | |
90 | |
91 test("binsearchCompare3", () { | |
92 var l3 = [new C(0), new C(5), new C(10)]; | |
93 expect(binarySearch(l3, new C(-1), compare: compareC), equals(-1)); | |
94 expect(binarySearch(l3, new C(0), compare: compareC), equals(0)); | |
95 expect(binarySearch(l3, new C(2), compare: compareC), equals(-1)); | |
96 expect(binarySearch(l3, new C(5), compare: compareC), equals(1)); | |
97 expect(binarySearch(l3, new C(7), compare: compareC), equals(-1)); | |
98 expect(binarySearch(l3, new C(10), compare: compareC), equals(2)); | |
99 expect(binarySearch(l3, new C(12), compare: compareC), equals(-1)); | |
100 }); | |
101 | |
102 test("insertionSortRandom", () { | |
103 Random random = new Random(); | |
104 for (int i = 0; i < 25; i++) { | |
105 List list = new List(i); | |
106 for (int j = 0; j < i; j++) { | |
107 list[j] = random.nextInt(25); // Expect some equal elements. | |
108 } | |
109 insertionSort(list); | |
110 for (int j = 1; j < i; j++) { | |
111 expect(list[j - 1], lessThanOrEqualTo(list[j])); | |
112 } | |
113 } | |
114 }); | |
115 | |
116 test("insertionSortSubRanges", () { | |
117 List l = [6, 5, 4, 3, 2, 1]; | |
118 insertionSort(l, start: 2, end: 4); | |
119 expect(l, equals([6, 5, 3, 4, 2, 1])); | |
120 insertionSort(l, start: 1, end: 1); | |
121 expect(l, equals([6, 5, 3, 4, 2, 1])); | |
122 insertionSort(l, start: 4, end: 6); | |
123 expect(l, equals([6, 5, 3, 4, 1, 2])); | |
124 insertionSort(l, start: 0, end: 2); | |
125 expect(l, equals([5, 6, 3, 4, 1, 2])); | |
126 insertionSort(l, start: 0, end: 6); | |
127 expect(l, equals([1, 2, 3, 4, 5, 6])); | |
128 }); | |
129 | |
130 test("insertionSortSpecialCases", () { | |
131 List l = [6, 6, 6, 6, 6, 6]; | |
132 insertionSort(l); | |
133 expect(l, equals([6, 6, 6, 6, 6, 6])); | |
134 | |
135 l = [6, 6, 3, 3, 0, 0]; | |
136 insertionSort(l); | |
137 expect(l, equals([0, 0, 3, 3, 6, 6])); | |
138 }); | |
139 | |
140 test("MergeSortRandom", () { | |
141 Random random = new Random(); | |
142 for (int i = 0; i < 250; i += 1) { | |
143 List list = new List(i); | |
144 for (int j = 0; j < i; j++) { | |
145 list[j] = random.nextInt(i); // Expect some equal elements. | |
146 } | |
147 mergeSort(list); | |
148 for (int j = 1; j < i; j++) { | |
149 expect(list[j - 1], lessThanOrEqualTo(list[j])); | |
150 } | |
151 } | |
152 }); | |
153 | |
154 test("MergeSortPreservesOrder", () { | |
155 Random random = new Random(); | |
156 // Small case where only insertion call is called, | |
157 // larger case where the internal moving insertion sort is used | |
158 // larger cases with multiple splittings, numbers just around a power of 2. | |
159 for (int size in [8, 50, 511, 512, 513]) { | |
160 List list = new List(size); | |
161 // Class OC compares using id. | |
162 // With size elements with id's in the range 0..size/4, a number of | |
163 // collisions are guaranteed. These should be sorted so that the "order" | |
164 // part of the objects are still in order. | |
165 for (int i = 0; i < size; i++) { | |
166 list[i] = new OC(random.nextInt(size >> 2), i); | |
167 } | |
168 mergeSort(list); | |
169 OC prev = list[0]; | |
170 for (int i = 1; i < size; i++) { | |
171 OC next = list[i]; | |
172 expect(prev.id, lessThanOrEqualTo(next.id)); | |
173 if (next.id == prev.id) { | |
174 expect(prev.order, lessThanOrEqualTo(next.order)); | |
175 } | |
176 prev = next; | |
177 } | |
178 // Reverse compare on part of list. | |
179 List copy = list.toList(); | |
180 int min = size >> 2; | |
181 int max = size - min; | |
182 mergeSort(list, start: min, end: max, compare: (a, b) => b.compareTo(a)); | |
183 prev = list[min]; | |
184 for (int i = min + 1; i < max; i++) { | |
185 OC next = list[i]; | |
186 expect(prev.id, greaterThanOrEqualTo(next.id)); | |
187 if (next.id == prev.id) { | |
188 expect(prev.order, lessThanOrEqualTo(next.order)); | |
189 } | |
190 prev = next; | |
191 } | |
192 // Equals on OC objects is identity, so this means the parts before min, | |
193 // and the parts after max, didn't change at all. | |
194 expect(list.sublist(0, min), equals(copy.sublist(0, min))); | |
195 expect(list.sublist(max), equals(copy.sublist(max))); | |
196 } | |
197 }); | |
198 | |
199 test("MergeSortSpecialCases", () { | |
200 for (int size in [511, 512, 513]) { | |
201 // All equal. | |
202 List list = new List(size); | |
203 for (int i = 0; i < size; i++) { | |
204 list[i] = new OC(0, i); | |
205 } | |
206 mergeSort(list); | |
207 for (int i = 0; i < size; i++) { | |
208 expect(list[i].order, equals(i)); | |
209 } | |
210 // All but one equal, first. | |
211 list[0] = new OC(1, 0); | |
212 for (int i = 1; i < size; i++) { | |
213 list[i] = new OC(0, i); | |
214 } | |
215 mergeSort(list); | |
216 for (int i = 0; i < size - 1; i++) { | |
217 expect(list[i].order, equals(i + 1)); | |
218 } | |
219 expect(list[size - 1].order, equals(0)); | |
220 | |
221 // All but one equal, last. | |
222 for (int i = 0; i < size - 1; i++) { | |
223 list[i] = new OC(0, i); | |
224 } | |
225 list[size - 1] = new OC(-1, size - 1); | |
226 mergeSort(list); | |
227 expect(list[0].order, equals(size - 1)); | |
228 for (int i = 1; i < size; i++) { | |
229 expect(list[i].order, equals(i - 1)); | |
230 } | |
231 | |
232 // Reversed. | |
233 for (int i = 0; i < size; i++) { | |
234 list[i] = new OC(size - 1 - i, i); | |
235 } | |
236 mergeSort(list); | |
237 for (int i = 0; i < size; i++) { | |
238 expect(list[i].id, equals(i)); | |
239 expect(list[i].order, equals(size - 1 - i)); | |
240 } | |
241 } | |
242 }); | |
243 | |
244 test("Reverse", () { | |
245 List l = [6, 5, 4, 3, 2, 1]; | |
246 reverse(l, 2, 4); | |
247 expect(l, equals([6, 5, 3, 4, 2, 1])); | |
248 reverse(l, 1, 1); | |
249 expect(l, equals([6, 5, 3, 4, 2, 1])); | |
250 reverse(l, 4, 6); | |
251 expect(l, equals([6, 5, 3, 4, 1, 2])); | |
252 reverse(l, 0, 2); | |
253 expect(l, equals([5, 6, 3, 4, 1, 2])); | |
254 reverse(l, 0, 6); | |
255 expect(l, equals([2, 1, 4, 3, 6, 5])); | |
256 }); | |
257 } | |
258 | |
259 class C { | |
260 final int id; | |
261 C(this.id); | |
262 } | |
263 int compareC(C one, C other) => one.id - other.id; | |
264 | |
265 class OC implements Comparable<OC> { | |
266 final int id; | |
267 final int order; | |
268 OC(this.id, this.order); | |
269 int compareTo(OC other) => id - other.id; | |
270 String toString() => "OC[$id,$order]"; | |
271 } | |
OLD | NEW |