Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like CollectionSpec often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use CollectionSpec, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
21 | class CollectionSpec extends ObjectBehavior |
||
22 | { |
||
23 | function it_is_initializable() |
||
24 | { |
||
25 | $this->beConstructedWith([1, 2, 3]); |
||
26 | $this->shouldHaveType(Collection::class); |
||
27 | $this->shouldHaveType(Traversable::class); |
||
28 | $this->shouldHaveType(Serializable::class); |
||
29 | } |
||
30 | |||
31 | function it_can_be_instantiated_from_iterator() |
||
32 | { |
||
33 | $iterator = new ArrayIterator([1, 2]); |
||
34 | $this->beConstructedWith($iterator); |
||
35 | $this->toArray()->shouldReturn([1, 2]); |
||
36 | } |
||
37 | |||
38 | function it_can_be_instantiated_from_iterator_aggregate(IteratorAggregate $iteratorAggregate) |
||
39 | { |
||
40 | $iterator = new ArrayIterator([1, 2]); |
||
41 | $iteratorAggregate->getIterator()->willReturn($iterator); |
||
42 | $this->beConstructedWith($iteratorAggregate); |
||
43 | $this->toArray()->shouldReturn([1, 2]); |
||
44 | } |
||
45 | |||
46 | function it_can_be_instantiated_from_array() |
||
47 | { |
||
48 | $this->beConstructedWith([1, 2, 3]); |
||
49 | $this->toArray()->shouldReturn([1, 2, 3]); |
||
50 | } |
||
51 | |||
52 | function it_will_throw_when_passed_something_other_than_array_or_traversable() |
||
53 | { |
||
54 | $this->beConstructedWith(1); |
||
55 | $this->shouldThrow(InvalidArgument::class)->duringInstantiation(); |
||
56 | } |
||
57 | |||
58 | function it_can_be_instantiated_from_callable_returning_an_array() |
||
59 | { |
||
60 | $this->beConstructedWith(function () { return [1, 2, 3]; }); |
||
61 | $this->toArray()->shouldReturn([1, 2, 3]); |
||
62 | } |
||
63 | |||
64 | function it_can_be_instantiated_from_callable_returning_an_iterator() |
||
65 | { |
||
66 | $this->beConstructedWith(function () { return new ArrayIterator([1, 2, 3]); }); |
||
67 | $this->toArray()->shouldReturn([1, 2, 3]); |
||
68 | } |
||
69 | |||
70 | function it_can_be_instantiated_from_callable_returning_a_generator() |
||
71 | { |
||
72 | $this->beConstructedWith(function () { |
||
73 | foreach ([1, 2, 3] as $value) { |
||
74 | yield $value; |
||
75 | } |
||
76 | }); |
||
77 | $this->toArray()->shouldReturn([1, 2, 3]); |
||
78 | } |
||
79 | |||
80 | function it_will_throw_when_passed_callable_will_return_something_other_than_array_or_traversable() |
||
81 | { |
||
82 | $this->beConstructedWith(function () { return 1; }); |
||
83 | $this->shouldThrow(InvalidReturnValue::class)->duringInstantiation(); |
||
84 | } |
||
85 | |||
86 | function it_can_be_created_statically() |
||
87 | { |
||
88 | $this->beConstructedThrough('from', [[1, 2]]); |
||
89 | $this->toArray()->shouldReturn([1, 2]); |
||
90 | } |
||
91 | |||
92 | function it_can_be_created_to_iterate_over_function_infinitely() |
||
93 | { |
||
94 | $this->beConstructedThrough('iterate', [1, function ($i) {return $i + 1;}]); |
||
95 | $this->take(2)->toArray()->shouldReturn([1, 2]); |
||
96 | } |
||
97 | |||
98 | function it_can_be_created_to_iterate_over_function_non_infinitely() |
||
99 | { |
||
100 | $this->beConstructedThrough( |
||
101 | 'iterate', |
||
102 | [ |
||
103 | 1, |
||
104 | function ($i) { |
||
105 | if ($i > 3) { |
||
106 | throw new NoMoreItems; |
||
107 | } |
||
108 | |||
109 | return $i + 1; |
||
110 | }, |
||
111 | ] |
||
112 | ); |
||
113 | $this->toArray()->shouldReturn([1, 2, 3, 4]); |
||
114 | } |
||
115 | |||
116 | function it_can_be_created_to_repeat_a_value_infinite_times() |
||
117 | { |
||
118 | $this->beConstructedThrough('repeat', [1]); |
||
119 | $this->take(2)->toArray()->shouldReturn([1, 1]); |
||
120 | } |
||
121 | |||
122 | function it_can_convert_to_array() |
||
123 | { |
||
124 | $iterator = new \ArrayIterator([ |
||
125 | 'foo', |
||
126 | ]); |
||
127 | |||
128 | $this->beConstructedWith(function () use ($iterator) { |
||
129 | yield 'no key'; |
||
130 | yield 'with key' => 'this value is overwritten by the same key'; |
||
131 | yield 'nested' => [ |
||
132 | 'y' => 'z', |
||
133 | ]; |
||
134 | yield 'iterator is not converted' => $iterator; |
||
135 | yield 'with key' => 'x'; |
||
136 | }); |
||
137 | |||
138 | $this |
||
139 | ->toArray() |
||
140 | ->shouldReturn([ |
||
141 | 'no key', |
||
142 | 'with key' => 'x', |
||
143 | 'nested' => [ |
||
144 | 'y' => 'z', |
||
145 | ], |
||
146 | 'iterator is not converted' => $iterator, |
||
147 | ]); |
||
148 | } |
||
149 | |||
150 | function it_can_filter() |
||
151 | { |
||
152 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
153 | |||
154 | $this |
||
155 | ->filter(function ($item) { |
||
156 | return $item > 2; |
||
157 | }) |
||
158 | ->toArray() |
||
159 | ->shouldReturn([1 => 3, 2 => 3]); |
||
160 | |||
161 | $this |
||
162 | ->filter(function ($item, $key) { |
||
163 | return $key > 2 && $item < 3; |
||
164 | }) |
||
165 | ->toArray() |
||
166 | ->shouldReturn([3 => 2]); |
||
167 | } |
||
168 | |||
169 | function it_can_filter_falsy_values() |
||
170 | { |
||
171 | $this->beConstructedWith([false, null, '', 0, 0.0, []]); |
||
172 | |||
173 | $this->filter()->isEmpty()->shouldReturn(true); |
||
174 | } |
||
175 | |||
176 | function it_can_distinct() |
||
177 | { |
||
178 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
179 | |||
180 | $this |
||
181 | ->distinct() |
||
182 | ->toArray() |
||
183 | ->shouldReturn([1, 3, 3 => 2]); |
||
184 | } |
||
185 | |||
186 | function it_can_concat() |
||
187 | { |
||
188 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
189 | |||
190 | $collection = $this->concat([4, 5]); |
||
191 | $collection->toArray()->shouldReturn([4, 5, 3, 2]); |
||
192 | $collection->size()->shouldReturn(6); |
||
193 | } |
||
194 | |||
195 | function it_can_map() |
||
196 | { |
||
197 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
198 | |||
199 | $this |
||
200 | ->map(function ($item) { |
||
201 | return $item + 1; |
||
202 | }) |
||
203 | ->toArray() |
||
204 | ->shouldReturn([2, 4, 4, 3]); |
||
205 | } |
||
206 | |||
207 | function it_can_reduce() |
||
208 | { |
||
209 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
210 | |||
211 | $this |
||
212 | ->reduce( |
||
213 | function ($temp, $item) { |
||
214 | $temp[] = $item; |
||
215 | |||
216 | return $temp; |
||
217 | }, |
||
218 | ['a' => [1]], |
||
219 | true |
||
220 | ) |
||
221 | ->values() |
||
222 | ->toArray() |
||
223 | ->shouldReturn([[1], 1, 3, 3, 2]); |
||
224 | |||
225 | $this |
||
226 | ->reduce( |
||
227 | function ($temp, $item) { |
||
228 | return $temp + $item; |
||
229 | }, |
||
230 | 0 |
||
231 | ) |
||
232 | ->shouldReturn(9); |
||
233 | |||
234 | $this |
||
235 | ->reduce( |
||
236 | function ($temp, $item, $key) { |
||
237 | return $temp + $key + $item; |
||
238 | }, |
||
239 | 0 |
||
240 | ) |
||
241 | ->shouldReturn(15); |
||
242 | |||
243 | $this |
||
244 | ->reduce( |
||
245 | function (Collection $temp, $item) { |
||
246 | return $temp->append($item); |
||
247 | }, |
||
248 | new Collection([]) |
||
249 | ) |
||
250 | ->toArray() |
||
251 | ->shouldReturn([1, 3, 3, 2]); |
||
252 | } |
||
253 | |||
254 | function it_can_flatten() |
||
255 | { |
||
256 | $this->beConstructedWith([1, [2, [3]]]); |
||
257 | $this->flatten()->values()->toArray()->shouldReturn([1, 2, 3]); |
||
258 | $this->flatten(1)->values()->toArray()->shouldReturn([1, 2, [3]]); |
||
259 | } |
||
260 | |||
261 | function it_can_sort() |
||
262 | { |
||
263 | $this->beConstructedWith([3, 1, 2]); |
||
264 | |||
265 | $this |
||
266 | ->sort(function ($a, $b) { |
||
267 | return $a > $b; |
||
268 | }) |
||
269 | ->toArray() |
||
270 | ->shouldReturn([1 => 1, 2 => 2, 0 => 3]); |
||
271 | |||
272 | $this |
||
273 | ->sort(function ($v1, $v2, $k1, $k2) { |
||
274 | return $k1 < $k2 || $v1 == $v2; |
||
275 | }) |
||
276 | ->toArray() |
||
277 | ->shouldReturn([2 => 2, 1 => 1, 0 => 3]); |
||
278 | } |
||
279 | |||
280 | function it_can_slice() |
||
281 | { |
||
282 | $this->beConstructedWith([1, 2, 3, 4, 5]); |
||
283 | |||
284 | $this |
||
285 | ->slice(2, 4) |
||
286 | ->toArray() |
||
287 | ->shouldReturn([2 => 3, 3 => 4]); |
||
288 | |||
289 | $this |
||
290 | ->slice(4) |
||
291 | ->toArray() |
||
292 | ->shouldReturn([4 => 5]); |
||
293 | } |
||
294 | |||
295 | function it_can_group_by() |
||
296 | { |
||
297 | $this->beConstructedWith([1, 2, 3, 4, 5]); |
||
298 | |||
299 | $collection = $this->groupBy(function ($i) { |
||
300 | return $i % 2; |
||
301 | }); |
||
302 | |||
303 | $collection->get(0)->toArray()->shouldReturn([2, 4]); |
||
304 | $collection->get(1)->toArray()->shouldReturn([1, 3, 5]); |
||
305 | |||
306 | $collection = $this->groupBy(function ($k, $i) { |
||
307 | return ($k + $i) % 3; |
||
308 | }); |
||
309 | $collection->get(0)->toArray()->shouldReturn([2, 5]); |
||
310 | $collection->get(1)->toArray()->shouldReturn([1, 4]); |
||
311 | $collection->get(2)->toArray()->shouldReturn([3]); |
||
312 | } |
||
313 | |||
314 | function it_can_group_by_key() |
||
315 | { |
||
316 | $this->beConstructedWith([ |
||
317 | 'some' => 'thing', |
||
318 | ['letter' => 'A', 'type' => 'caps'], |
||
319 | ['letter' => 'a', 'type' => 'small'], |
||
320 | ['letter' => 'B', 'type' => 'caps'], |
||
321 | ['letter' => 'Z'], |
||
322 | ]); |
||
323 | |||
324 | $collection = $this->groupByKey('type'); |
||
325 | $collection->get('small')->toArray()->shouldReturn([ |
||
326 | ['letter' => 'a', 'type' => 'small'], |
||
327 | ]); |
||
328 | $collection->get('caps')->toArray()->shouldReturn([ |
||
329 | ['letter' => 'A', 'type' => 'caps'], |
||
330 | ['letter' => 'B', 'type' => 'caps'], |
||
331 | ]); |
||
332 | |||
333 | $collection = $this->groupByKey('types'); |
||
334 | $collection->shouldThrow(new ItemNotFound)->during('get', ['caps']); |
||
335 | } |
||
336 | |||
337 | function it_can_execute_callback_for_each_item(DOMXPath $a) |
||
338 | { |
||
339 | $a->query('asd')->shouldBeCalled(); |
||
340 | $this->beConstructedWith([$a]); |
||
341 | |||
342 | $this |
||
343 | ->each(function (DOMXPath $i) { |
||
344 | $i->query('asd'); |
||
345 | }) |
||
346 | ->toArray() |
||
347 | ->shouldReturn([$a]); |
||
348 | } |
||
349 | |||
350 | function it_can_get_size() |
||
351 | { |
||
352 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
353 | $this->size()->shouldReturn(4); |
||
354 | } |
||
355 | |||
356 | function it_can_get_item_by_key() |
||
357 | { |
||
358 | $this->beConstructedWith([1, [2], 3]); |
||
359 | $this->get(0)->shouldReturn(1); |
||
360 | $this->get(1, true)->first()->shouldReturn(2); |
||
361 | $this->get(1)->shouldReturn([2]); |
||
362 | $this->shouldThrow(new ItemNotFound)->during('get', [5]); |
||
363 | } |
||
364 | |||
365 | function it_can_get_item_by_key_or_return_default() |
||
366 | { |
||
367 | $this->beConstructedWith([1, [2], 3]); |
||
368 | $this->getOrDefault(0)->shouldReturn(1); |
||
369 | $this->getOrDefault(1, null, true)->first()->shouldReturn(2); |
||
370 | $this->getOrDefault(1, null)->shouldReturn([2]); |
||
371 | $this->getOrDefault(5)->shouldReturn(null); |
||
372 | $this->getOrDefault(5, 'not found')->shouldReturn('not found'); |
||
373 | } |
||
374 | |||
375 | function it_can_find() |
||
376 | { |
||
377 | $this->beConstructedWith([1, 3, 3, 2, [5]]); |
||
378 | |||
379 | $this |
||
380 | ->find(function ($v) { |
||
381 | return $v < 3; |
||
382 | }) |
||
383 | ->shouldReturn(1); |
||
384 | |||
385 | $this |
||
386 | ->find(function ($v, $k) { |
||
387 | return $v < 3 && $k > 1; |
||
388 | }) |
||
389 | ->shouldReturn(2); |
||
390 | |||
391 | $this |
||
392 | ->find(function ($v) { |
||
393 | return $v < 0; |
||
394 | }) |
||
395 | ->shouldReturn(null); |
||
396 | |||
397 | $this |
||
398 | ->find( |
||
399 | function ($v) { |
||
400 | return $v < 0; |
||
401 | }, |
||
402 | 'not found' |
||
403 | ) |
||
404 | ->shouldReturn('not found'); |
||
405 | |||
406 | $this->find('\DusanKasan\Knapsack\isCollection', null, true)->first()->shouldReturn(5); |
||
407 | $this->find('\DusanKasan\Knapsack\isCollection')->shouldReturn([5]); |
||
408 | } |
||
409 | |||
410 | function it_can_count_by() |
||
411 | { |
||
412 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
413 | |||
414 | $this |
||
415 | ->countBy(function ($v) { |
||
416 | return $v % 2 == 0 ? 'even' : 'odd'; |
||
417 | }) |
||
418 | ->toArray() |
||
419 | ->shouldReturn(['odd' => 3, 'even' => 1]); |
||
420 | |||
421 | $this |
||
422 | ->countBy(function ($k, $v) { |
||
423 | return ($k + $v) % 2 == 0 ? 'even' : 'odd'; |
||
424 | }) |
||
425 | ->toArray() |
||
426 | ->shouldReturn(['odd' => 3, 'even' => 1]); |
||
427 | } |
||
428 | |||
429 | function it_can_index_by() |
||
430 | { |
||
431 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
432 | |||
433 | $this |
||
434 | ->indexBy(function ($v) { |
||
435 | return $v; |
||
436 | }) |
||
437 | ->toArray() |
||
438 | ->shouldReturn([1 => 1, 3 => 3, 2 => 2]); |
||
439 | |||
440 | $this |
||
441 | ->indexBy(function ($v, $k) { |
||
442 | return $k . $v; |
||
443 | }) |
||
444 | ->toArray() |
||
445 | ->shouldReturn(['01' => 1, '13' => 3, '23' => 3, '32' => 2]); |
||
446 | } |
||
447 | |||
448 | function it_can_check_if_every_item_passes_predicament_test() |
||
449 | { |
||
450 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
451 | |||
452 | $this |
||
453 | ->every(function ($v) { |
||
454 | return $v > 0; |
||
455 | }) |
||
456 | ->shouldReturn(true); |
||
457 | |||
458 | $this |
||
459 | ->every(function ($v) { |
||
460 | return $v > 1; |
||
461 | }) |
||
462 | ->shouldReturn(false); |
||
463 | |||
464 | $this |
||
465 | ->every(function ($v, $k) { |
||
466 | return $v > 0 && $k >= 0; |
||
467 | }) |
||
468 | ->shouldReturn(true); |
||
469 | |||
470 | $this |
||
471 | ->every(function ($v, $k) { |
||
472 | return $v > 0 && $k > 0; |
||
473 | }) |
||
474 | ->shouldReturn(false); |
||
475 | } |
||
476 | |||
477 | function it_can_check_if_some_items_pass_predicament_test() |
||
478 | { |
||
479 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
480 | |||
481 | $this |
||
482 | ->some(function ($v) { |
||
483 | return $v < -1; |
||
484 | }) |
||
485 | ->shouldReturn(false); |
||
486 | |||
487 | $this |
||
488 | ->some(function ($v, $k) { |
||
489 | return $v > 0 && $k < -1; |
||
490 | }) |
||
491 | ->shouldReturn(false); |
||
492 | |||
493 | $this |
||
494 | ->some(function ($v) { |
||
495 | return $v < 2; |
||
496 | }) |
||
497 | ->shouldReturn(true); |
||
498 | |||
499 | $this |
||
500 | ->some(function ($v, $k) { |
||
501 | return $v > 0 && $k > 0; |
||
502 | }) |
||
503 | ->shouldReturn(true); |
||
504 | } |
||
505 | |||
506 | function it_can_check_if_it_contains_a_value() |
||
507 | { |
||
508 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
509 | |||
510 | $this |
||
511 | ->contains(3) |
||
512 | ->shouldReturn(true); |
||
513 | |||
514 | $this |
||
515 | ->contains(true) |
||
516 | ->shouldReturn(false); |
||
517 | } |
||
518 | |||
519 | function it_can_reverse() |
||
520 | { |
||
521 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
522 | |||
523 | $this |
||
524 | ->reverse() |
||
525 | ->toArray() |
||
526 | ->shouldReturn([ |
||
527 | 3 => 2, |
||
528 | 2 => 3, |
||
529 | 1 => 3, |
||
530 | 0 => 1, |
||
531 | ]) |
||
532 | ; |
||
533 | } |
||
534 | |||
535 | function it_can_reduce_from_right() |
||
536 | { |
||
537 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
538 | |||
539 | $this |
||
540 | ->reduceRight( |
||
541 | function ($temp, $e) { |
||
542 | return $temp . $e; |
||
543 | }, |
||
544 | 0 |
||
545 | ) |
||
546 | ->shouldReturn('02331'); |
||
547 | |||
548 | $this |
||
549 | ->reduceRight( |
||
550 | function ($temp, $key, $item) { |
||
551 | return $temp + $key + $item; |
||
552 | }, |
||
553 | 0 |
||
554 | ) |
||
555 | ->shouldReturn(15); |
||
556 | |||
557 | $this |
||
558 | ->reduceRight( |
||
559 | function (Collection $temp, $item) { |
||
560 | return $temp->append($item); |
||
561 | }, |
||
562 | new Collection([]) |
||
563 | ) |
||
564 | ->toArray() |
||
565 | ->shouldReturn([2, 3, 3, 1]); |
||
566 | } |
||
567 | |||
568 | function it_can_return_only_first_x_elements() |
||
569 | { |
||
570 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
571 | |||
572 | $this->take(2) |
||
573 | ->toArray() |
||
574 | ->shouldReturn([1, 3]); |
||
575 | } |
||
576 | |||
577 | function it_can_skip_first_x_elements() |
||
578 | { |
||
579 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
580 | |||
581 | $this->drop(2) |
||
582 | ->toArray() |
||
583 | ->shouldReturn([2 => 3, 3 => 2]); |
||
584 | } |
||
585 | |||
586 | function it_can_return_values() |
||
587 | { |
||
588 | $this->beConstructedWith(['a' => 1, 'b' => 2]); |
||
589 | $this->values()->toArray()->shouldReturn([1, 2]); |
||
590 | } |
||
591 | |||
592 | function it_can_reject_elements_from_collection() |
||
593 | { |
||
594 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
595 | |||
596 | $this |
||
597 | ->reject(function ($v) { |
||
598 | return $v == 3; |
||
599 | }) |
||
600 | ->toArray() |
||
601 | ->shouldReturn([1, 3 => 2]); |
||
602 | |||
603 | $this |
||
604 | ->reject(function ($v, $k) { |
||
605 | return $k == 2 && $v == 3; |
||
606 | }) |
||
607 | ->toArray() |
||
608 | ->shouldReturn([1, 3, 3 => 2]); |
||
609 | } |
||
610 | |||
611 | function it_can_get_keys() |
||
612 | { |
||
613 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
614 | |||
615 | $this |
||
616 | ->keys() |
||
617 | ->toArray() |
||
618 | ->shouldReturn([0, 1, 2, 3]); |
||
619 | } |
||
620 | |||
621 | function it_can_interpose() |
||
622 | { |
||
623 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
624 | |||
625 | $this |
||
626 | ->interpose('a') |
||
627 | ->values() |
||
628 | ->toArray() |
||
629 | ->shouldReturn([1, 'a', 3, 'a', 3, 'a', 2]); |
||
630 | } |
||
631 | |||
632 | function it_can_drop_elements_from_end_of_the_collection() |
||
633 | { |
||
634 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
635 | |||
636 | $this |
||
637 | ->dropLast() |
||
638 | ->toArray() |
||
639 | ->shouldReturn([1, 3, 3]); |
||
640 | |||
641 | $this |
||
642 | ->dropLast(2) |
||
643 | ->toArray() |
||
644 | ->shouldReturn([1, 3]); |
||
645 | } |
||
646 | |||
647 | function it_can_interleave_elements() |
||
648 | { |
||
649 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
650 | |||
651 | $this |
||
652 | ->interleave(['a', 'b', 'c', 'd', 'e']) |
||
653 | ->values() |
||
654 | ->toArray() |
||
655 | ->shouldReturn([1, 'a', 3, 'b', 3, 'c', 2, 'd', 'e']); |
||
656 | } |
||
657 | |||
658 | function it_can_repeat_items_of_collection_infinitely() |
||
659 | { |
||
660 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
661 | |||
662 | $this |
||
663 | ->cycle() |
||
664 | ->take(8) |
||
665 | ->values() |
||
666 | ->toArray() |
||
667 | ->shouldReturn([1, 3, 3, 2, 1, 3, 3, 2]); |
||
668 | } |
||
669 | |||
670 | function it_can_prepend_item() |
||
671 | { |
||
672 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
673 | |||
674 | $this |
||
675 | ->prepend(1) |
||
676 | ->values() |
||
677 | ->toArray() |
||
678 | ->shouldReturn([1, 1, 3, 3, 2]); |
||
679 | } |
||
680 | |||
681 | function it_can_prepend_item_with_key() |
||
682 | { |
||
683 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
684 | |||
685 | $this |
||
686 | ->prepend(1, 'a') |
||
687 | ->toArray() |
||
688 | ->shouldReturn(['a' => 1, 0 => 1, 1 => 3, 2 => 3, 3 => 2]); |
||
689 | } |
||
690 | |||
691 | function it_can_append_item() |
||
692 | { |
||
693 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
694 | |||
695 | $this |
||
696 | ->append(1) |
||
697 | ->values() |
||
698 | ->toArray() |
||
699 | ->shouldReturn([1, 3, 3, 2, 1]); |
||
700 | } |
||
701 | |||
702 | function it_can_append_item_with_key() |
||
703 | { |
||
704 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
705 | |||
706 | $this |
||
707 | ->append(1, 'a') |
||
708 | ->toArray() |
||
709 | ->shouldReturn([1, 3, 3, 2, 'a' => 1]); |
||
710 | } |
||
711 | |||
712 | function it_can_drop_items_while_predicament_is_true() |
||
713 | { |
||
714 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
715 | |||
716 | $this |
||
717 | ->dropWhile(function ($v) { |
||
718 | return $v < 3; |
||
719 | }) |
||
720 | ->toArray() |
||
721 | ->shouldReturn([1 => 3, 2 => 3, 3 => 2]); |
||
722 | |||
723 | $this |
||
724 | ->dropWhile(function ($v, $k) { |
||
725 | return $k < 2 && $v < 3; |
||
726 | }) |
||
727 | ->toArray() |
||
728 | ->shouldReturn([1 => 3, 2 => 3, 3 => 2]); |
||
729 | } |
||
730 | |||
731 | function it_can_map_and_then_concatenate_a_collection() |
||
732 | { |
||
733 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
734 | |||
735 | $this |
||
736 | ->mapcat(function ($v) { |
||
737 | return [[$v]]; |
||
738 | }) |
||
739 | ->values() |
||
740 | ->toArray() |
||
741 | ->shouldReturn([[1], [3], [3], [2]]); |
||
742 | |||
743 | $this |
||
744 | ->mapcat(function ($v, $k) { |
||
745 | return [[$k + $v]]; |
||
746 | }) |
||
747 | ->values() |
||
748 | ->toArray() |
||
749 | ->shouldReturn([[1], [4], [5], [5]]); |
||
750 | } |
||
751 | |||
752 | function it_can_take_items_while_predicament_is_true() |
||
753 | { |
||
754 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
755 | |||
756 | $this |
||
757 | ->takeWhile(function ($v) { |
||
758 | return $v < 3; |
||
759 | }) |
||
760 | ->toArray() |
||
761 | ->shouldReturn([1]); |
||
762 | |||
763 | $this |
||
764 | ->takeWhile(function ($v, $k) { |
||
765 | return $k < 2 && $v < 3; |
||
766 | }) |
||
767 | ->toArray() |
||
768 | ->shouldReturn([1]); |
||
769 | } |
||
770 | |||
771 | function it_can_split_the_collection_at_nth_item() |
||
772 | { |
||
773 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
774 | |||
775 | $this->splitAt(2)->size()->shouldBe(2); |
||
776 | $this->splitAt(2)->first()->toArray()->shouldBeLike([1, 3]); |
||
777 | $this->splitAt(2)->second()->toArray()->shouldBeLike([2 => 3, 3 => 2]); |
||
778 | } |
||
779 | |||
780 | function it_can_split_the_collection_with_predicament() |
||
781 | { |
||
782 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
783 | |||
784 | $s1 = $this->splitWith(function ($v) { |
||
785 | return $v < 3; |
||
786 | }); |
||
787 | |||
788 | $s1->size()->shouldBe(2); |
||
789 | $s1->first()->toArray()->shouldBe([1]); |
||
790 | $s1->second()->toArray()->shouldBe([1 => 3, 2 => 3, 3 => 2]); |
||
791 | |||
792 | $s2 = $this->splitWith(function ($v, $k) { |
||
793 | return $v < 2 && $k < 3; |
||
794 | }); |
||
795 | |||
796 | $s2->size()->shouldBe(2); |
||
797 | $s2->first()->toArray()->shouldBe([1]); |
||
798 | $s2->second()->toArray()->shouldBe([1 => 3, 2 => 3, 3 => 2]); |
||
799 | } |
||
800 | |||
801 | function it_can_replace_items_by_items_from_another_collection() |
||
802 | { |
||
803 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
804 | |||
805 | $this |
||
806 | ->replace([3 => 'a']) |
||
807 | ->toArray() |
||
808 | ->shouldReturn([1, 'a', 'a', 2]); |
||
809 | } |
||
810 | |||
811 | function it_can_get_reduction_steps() |
||
812 | { |
||
813 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
814 | |||
815 | $this |
||
816 | ->reductions( |
||
817 | function ($tmp, $i) { |
||
818 | return $tmp + $i; |
||
819 | }, |
||
820 | 0 |
||
821 | ) |
||
822 | ->toArray() |
||
823 | ->shouldReturn([0, 1, 4, 7, 9]); |
||
824 | } |
||
825 | |||
826 | function it_can_return_every_nth_item() |
||
827 | { |
||
828 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
829 | |||
830 | $this->takeNth(2) |
||
831 | ->toArray() |
||
832 | ->shouldReturn([1, 2 => 3]); |
||
833 | } |
||
834 | |||
835 | function it_can_shuffle_itself() |
||
836 | { |
||
837 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
838 | |||
839 | $this |
||
840 | ->shuffle() |
||
841 | ->reduce( |
||
842 | function ($tmp, $i) { |
||
843 | return $tmp + $i; |
||
844 | }, |
||
845 | 0 |
||
846 | ) |
||
847 | ->shouldReturn(9); |
||
848 | } |
||
849 | |||
850 | function it_can_partition() |
||
851 | { |
||
852 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
853 | |||
854 | $s1 = $this->partition(3, 2, [0, 1]); |
||
855 | $s1->size()->shouldBe(2); |
||
856 | $s1->first()->toArray()->shouldBe([1, 3, 3]); |
||
857 | $s1->second()->toArray()->shouldBe([2 => 3, 3 => 2, 0 => 0]); |
||
858 | |||
859 | $s2 = $this->partition(3, 2); |
||
860 | $s2->size()->shouldBe(2); |
||
861 | $s2->first()->toArray()->shouldBe([1, 3, 3]); |
||
862 | $s2->second()->toArray()->shouldBe([2 => 3, 3 => 2]); |
||
863 | |||
864 | $s3 = $this->partition(3); |
||
865 | $s3->size()->shouldBe(2); |
||
866 | $s3->first()->toArray()->shouldBe([1, 3, 3]); |
||
867 | $s3->second()->toArray()->shouldBe([3 => 2]); |
||
868 | |||
869 | $s4 = $this->partition(1, 3); |
||
870 | $s4->size()->shouldBe(2); |
||
871 | $s4->first()->toArray()->shouldBe([1,]); |
||
872 | $s4->second()->toArray()->shouldBe([3 => 2]); |
||
873 | } |
||
874 | |||
875 | function it_can_partition_by() |
||
876 | { |
||
877 | $this->beConstructedWith([1, 3, 3, 2]); |
||
878 | |||
879 | $s1 = $this->partitionBy(function ($v) { |
||
880 | return $v % 3 == 0; |
||
881 | }); |
||
882 | $s1->size()->shouldBe(3); |
||
883 | $s1->first()->toArray()->shouldBe([1]); |
||
884 | $s1->second()->toArray()->shouldBe([1 => 3, 2 => 3]); |
||
885 | $s1->values()->get(2)->toArray()->shouldBe([3 => 2]); |
||
886 | |||
887 | $s2 = $this->partitionBy(function ($v, $k) { |
||
888 | return $k - $v; |
||
889 | }); |
||
890 | $s2->size()->shouldBe(4); |
||
891 | $s2->first()->toArray()->shouldBe([1]); |
||
892 | $s2->values()->get(1)->toArray()->shouldBe([1 => 3]); |
||
893 | $s2->values()->get(2)->toArray()->shouldBe([2 => 3]); |
||
894 | $s2->values()->get(3)->toArray()->shouldBe([3 => 2]); |
||
895 | } |
||
896 | |||
897 | function it_can_get_nth_value() |
||
898 | { |
||
899 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
900 | |||
901 | $this->first(0)->shouldReturn(1); |
||
902 | $this->values()->get(3)->shouldReturn(2); |
||
903 | } |
||
904 | |||
905 | function it_can_create_infinite_collection_of_repeated_values() |
||
906 | { |
||
907 | $this->beConstructedThrough('repeat', [1]); |
||
908 | $this->take(3)->toArray()->shouldReturn([1, 1, 1]); |
||
909 | } |
||
910 | |||
911 | function it_can_create_finite_collection_of_repeated_values() |
||
912 | { |
||
913 | $this->beConstructedThrough('repeat', [1, 1]); |
||
914 | $this->toArray()->shouldReturn([1]); |
||
915 | } |
||
916 | |||
917 | function it_can_create_range_from_value_to_infinity() |
||
918 | { |
||
919 | $this->beConstructedThrough('range', [5]); |
||
920 | $this->take(2)->toArray()->shouldReturn([5, 6]); |
||
921 | } |
||
922 | |||
923 | function it_can_create_range_from_value_to_another_value() |
||
924 | { |
||
925 | $this->beConstructedThrough('range', [5, 6]); |
||
926 | $this->take(4)->toArray()->shouldReturn([5, 6]); |
||
927 | } |
||
928 | |||
929 | function it_can_check_if_it_is_not_empty() |
||
930 | { |
||
931 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
932 | |||
933 | $this->isEmpty()->shouldReturn(false); |
||
934 | $this->isNotEmpty()->shouldReturn(true); |
||
935 | } |
||
936 | |||
937 | function it_can_check_if_it_is_empty() |
||
938 | { |
||
939 | $this->beConstructedWith([]); |
||
940 | |||
941 | $this->isEmpty()->shouldReturn(true); |
||
942 | $this->isNotEmpty()->shouldReturn(false); |
||
943 | } |
||
944 | |||
945 | function it_can_check_frequency_of_distinct_items() |
||
946 | { |
||
947 | $this->beConstructedWith([1, 3, 3, 2,]); |
||
948 | |||
949 | $this |
||
950 | ->frequencies() |
||
951 | ->toArray() |
||
952 | ->shouldReturn([1 => 1, 3 => 2, 2 => 1]); |
||
953 | } |
||
954 | |||
955 | function it_can_get_first_item() |
||
956 | { |
||
957 | $this->beConstructedWith([1, [2], 3]); |
||
958 | $this->first()->shouldReturn(1); |
||
959 | $this->drop(1)->first()->shouldReturn([2]); |
||
960 | $this->drop(1)->first(true)->toArray()->shouldReturn([2]); |
||
961 | } |
||
962 | |||
963 | function it_will_throw_when_trying_to_get_first_item_of_empty_collection() |
||
964 | { |
||
965 | $this->beConstructedWith([]); |
||
966 | $this->shouldThrow(ItemNotFound::class)->during('first'); |
||
967 | } |
||
968 | |||
969 | function it_can_get_last_item() |
||
970 | { |
||
971 | $this->beConstructedWith([1, [2], 3]); |
||
972 | $this->last()->shouldReturn(3); |
||
973 | $this->take(2)->last()->shouldReturn([2]); |
||
974 | $this->take(2)->last(true)->toArray()->shouldReturn([2]); |
||
975 | } |
||
976 | |||
977 | function it_will_throw_when_trying_to_get_last_item_of_empty_collection() |
||
978 | { |
||
979 | $this->beConstructedWith([]); |
||
980 | $this->shouldThrow(ItemNotFound::class)->during('last'); |
||
981 | } |
||
982 | |||
983 | function it_can_realize_the_collection(PlusOneAdder $adder) |
||
984 | { |
||
985 | $adder->dynamicMethod(1)->willReturn(2); |
||
986 | $adder->dynamicMethod(2)->willReturn(3); |
||
987 | |||
988 | $this->beConstructedWith(function () use ($adder) { |
||
989 | yield $adder->dynamicMethod(1); |
||
990 | yield $adder->dynamicMethod(2); |
||
991 | }); |
||
992 | |||
993 | $this->realize(); |
||
994 | } |
||
995 | |||
996 | function it_can_combine_the_collection() |
||
997 | { |
||
998 | $this->beConstructedWith(['a', 'b']); |
||
999 | $this->combine([1, 2])->toArray()->shouldReturn(['a' => 1, 'b' => 2]); |
||
1000 | $this->combine([1])->toArray()->shouldReturn(['a' => 1]); |
||
1001 | $this->combine([1, 2, 3])->toArray()->shouldReturn(['a' => 1, 'b' => 2]); |
||
1002 | } |
||
1003 | |||
1004 | function it_can_get_second_item() |
||
1005 | { |
||
1006 | $this->beConstructedWith([1, 2]); |
||
1007 | $this->second()->shouldReturn(2); |
||
1008 | } |
||
1009 | |||
1010 | function it_throws_when_trying_to_get_non_existent_second_item() |
||
1011 | { |
||
1012 | $this->beConstructedWith([1]); |
||
1013 | $this->shouldThrow(ItemNotFound::class)->during('second'); |
||
1014 | } |
||
1015 | |||
1016 | function it_can_drop_item_by_key() |
||
1017 | { |
||
1018 | $this->beConstructedWith(['a' => 1, 'b' => 2]); |
||
1019 | $this->except(['a', 'b'])->toArray()->shouldReturn([]); |
||
1020 | } |
||
1021 | |||
1022 | function it_can_get_the_difference_between_collections() |
||
1023 | { |
||
1024 | $this->beConstructedWith([1, 2, 3, 4]); |
||
1025 | $this->diff([1, 2])->toArray()->shouldReturn([2 => 3, 3 => 4]); |
||
1026 | $this->diff([1, 2], [3])->toArray()->shouldReturn([3 => 4]); |
||
1027 | } |
||
1028 | |||
1029 | function it_can_flip_the_collection() |
||
1030 | { |
||
1031 | $this->beConstructedWith(['a' => 1, 'b' => 2]); |
||
1032 | $this->flip()->toArray()->shouldReturn([1 => 'a', 2 => 'b']); |
||
1033 | } |
||
1034 | |||
1035 | function it_can_check_if_key_exits() |
||
1036 | { |
||
1037 | $this->beConstructedWith(['a' => 1, 'b' => 2]); |
||
1038 | $this->has('a')->shouldReturn(true); |
||
1039 | $this->has('x')->shouldReturn(false); |
||
1040 | } |
||
1041 | |||
1042 | function it_filters_by_keys() |
||
1043 | { |
||
1044 | $this->beConstructedWith(['a' => 1, 'b' => 2, 'c' => 3]); |
||
1045 | $this->only(['a', 'b'])->toArray()->shouldReturn(['a' => 1, 'b' => 2]); |
||
1046 | $this->only(['a', 'b', 'x'])->toArray()->shouldReturn(['a' => 1, 'b' => 2]); |
||
1047 | } |
||
1048 | |||
1049 | function it_can_serialize_and_unserialize() |
||
1050 | { |
||
1051 | $original = Collection::from([1, 2, 3])->take(2); |
||
1052 | $this->beConstructedWith([1, 2, 3, 4]); |
||
1053 | $this->shouldHaveType(Serializable::class); |
||
1054 | $this->unserialize($original->serialize()); |
||
1055 | $this->toArray()->shouldReturn([1, 2]); |
||
1056 | } |
||
1057 | |||
1058 | function it_can_zip() |
||
1059 | { |
||
1060 | $this->beConstructedWith([1, 2, 3]); |
||
1061 | $this->zip(['a' => 1, 'b' => 2, 'c' => 4]) |
||
1062 | ->map('\DusanKasan\Knapsack\toArray') |
||
1063 | ->toArray() |
||
1064 | ->shouldReturn([[1, 'a' => 1], [1 => 2, 'b' => 2], [2 => 3, 'c' => 4]]); |
||
1065 | |||
1066 | $this->zip([4, 5, 6], [7, 8, 9]) |
||
1067 | ->map('\DusanKasan\Knapsack\values') |
||
1068 | ->map('\DusanKasan\Knapsack\toArray') |
||
1069 | ->toArray() |
||
1070 | ->shouldReturn([[1, 4, 7], [2, 5, 8], [3, 6, 9]]); |
||
1071 | |||
1072 | $this->zip([4, 5]) |
||
1073 | ->map('\DusanKasan\Knapsack\values') |
||
1074 | ->map('\DusanKasan\Knapsack\toArray') |
||
1075 | ->toArray() |
||
1076 | ->shouldReturn([[1, 4], [2, 5]]); |
||
1077 | } |
||
1078 | |||
1079 | function it_can_use_callable_as_transformer() |
||
1080 | { |
||
1081 | $this->beConstructedWith([1, 2, 3]); |
||
1082 | $this |
||
1083 | ->transform(function (Collection $collection) { |
||
1084 | return $collection->map('\DusanKasan\Knapsack\increment'); |
||
1085 | }) |
||
1086 | ->toArray() |
||
1087 | ->shouldReturn([2, 3, 4]); |
||
1088 | |||
1089 | $this |
||
1090 | ->shouldThrow(InvalidReturnValue::class) |
||
1091 | ->during( |
||
1092 | 'transform', |
||
1093 | [ |
||
1094 | function (Collection $collection) { |
||
1095 | return $collection->first(); |
||
1096 | }, |
||
1097 | ] |
||
1098 | ); |
||
1099 | } |
||
1100 | |||
1101 | function it_can_extract_data_from_nested_collections() |
||
1102 | { |
||
1103 | $input = [ |
||
1104 | [ |
||
1105 | 'a' => [ |
||
1106 | 'b' => 1 |
||
1107 | ] |
||
1108 | ], |
||
1109 | [ |
||
1110 | 'a' => [ |
||
1111 | 'b' => 2 |
||
1112 | ] |
||
1113 | ], |
||
1114 | [ |
||
1115 | '*' => [ |
||
1116 | 'b' => 3 |
||
1117 | ] |
||
1118 | ], |
||
1119 | [ |
||
1120 | '.' => [ |
||
1121 | 'b' => 4 |
||
1122 | ], |
||
1123 | 'c' => [ |
||
1124 | 'b' => 5 |
||
1125 | ], |
||
1126 | [ |
||
1127 | 'a' |
||
1128 | ] |
||
1129 | ] |
||
1130 | ]; |
||
1131 | $this->beConstructedWith($input); |
||
1132 | |||
1133 | $this->extract('')->toArray()->shouldReturn($input); |
||
1134 | $this->extract('a.b')->toArray()->shouldReturn([1, 2]); |
||
1135 | $this->extract('*.b')->toArray()->shouldReturn([1, 2, 3, 4, 5]); |
||
1136 | $this->extract('\*.b')->toArray()->shouldReturn([3]); |
||
1137 | $this->extract('\..b')->toArray()->shouldReturn([4]); |
||
1138 | } |
||
1139 | |||
1140 | function it_can_get_the_intersect_of_collections() |
||
1141 | { |
||
1142 | $this->beConstructedWith([1, 2, 3]); |
||
1143 | $this->intersect([1, 2])->values()->toArray()->shouldReturn([1, 2]); |
||
1144 | $this->intersect([1], [3])->values()->toArray()->shouldReturn([1, 3]); |
||
1145 | } |
||
1146 | |||
1147 | function it_can_check_if_size_is_exactly_n() |
||
1148 | { |
||
1149 | $this->beConstructedWith([1, 2]); |
||
1150 | $this->sizeIs(2)->shouldReturn(true); |
||
1151 | $this->sizeIs(3)->shouldReturn(false); |
||
1152 | $this->sizeIs(0)->shouldReturn(false); |
||
1153 | } |
||
1154 | |||
1155 | function it_can_check_if_size_is_less_than_n() |
||
1156 | { |
||
1157 | $this->beConstructedWith([1, 2]); |
||
1158 | $this->sizeIsLessThan(0)->shouldReturn(false); |
||
1159 | $this->sizeIsLessThan(2)->shouldReturn(false); |
||
1160 | $this->sizeIsLessThan(3)->shouldReturn(true); |
||
1161 | } |
||
1162 | |||
1163 | function it_can_check_if_size_is_greater_than_n() |
||
1164 | { |
||
1165 | $this->beConstructedWith([1, 2]); |
||
1166 | $this->sizeIsGreaterThan(2)->shouldReturn(false); |
||
1167 | $this->sizeIsGreaterThan(1)->shouldReturn(true); |
||
1168 | $this->sizeIsGreaterThan(0)->shouldReturn(true); |
||
1169 | } |
||
1170 | |||
1171 | function it_can_check_if_size_is_between_n_and_m() |
||
1172 | { |
||
1173 | $this->beConstructedWith([1, 2]); |
||
1174 | $this->sizeIsBetween(1, 3)->shouldReturn(true); |
||
1175 | $this->sizeIsBetween(3, 4)->shouldReturn(false); |
||
1176 | $this->sizeIsBetween(0, 0)->shouldReturn(false); |
||
1177 | $this->sizeIsBetween(3, 1)->shouldReturn(true); |
||
1178 | } |
||
1179 | |||
1180 | function it_can_sum_the_collection() |
||
1181 | { |
||
1182 | $this->beConstructedWith([1, 2, 3, 4]); |
||
1183 | $this->sum()->shouldReturn(10); |
||
1184 | $this->append(1.5)->sum()->shouldReturn(11.5); |
||
1185 | } |
||
1186 | |||
1187 | function it_can_get_average_of_the_collection() |
||
1188 | { |
||
1189 | $this->beConstructedWith([1, 2, 2, 3]); |
||
1190 | $this->average()->shouldReturn(2); |
||
1191 | $this->append(3)->average()->shouldReturn(2.2); |
||
1192 | } |
||
1193 | |||
1194 | function it_will_return_zero_when_average_is_called_on_empty_collection() |
||
1195 | { |
||
1196 | $this->beConstructedWith([]); |
||
1197 | $this->average()->shouldReturn(0); |
||
1198 | } |
||
1199 | |||
1200 | function it_can_get_maximal_value_in_the_colleciton() |
||
1201 | { |
||
1202 | $this->beConstructedWith([1, 2, 3, 2]); |
||
1203 | $this->max()->shouldReturn(3); |
||
1204 | } |
||
1205 | |||
1206 | function it_will_return_null_when_max_is_called_on_empty_collection() |
||
1207 | { |
||
1208 | $this->beConstructedWith([]); |
||
1209 | $this->max()->shouldReturn(null); |
||
1210 | } |
||
1211 | |||
1212 | function it_can_get_min_value_in_the_colleciton() |
||
1213 | { |
||
1214 | $this->beConstructedWith([2, 1, 3, 2]); |
||
1215 | $this->min()->shouldReturn(1); |
||
1216 | } |
||
1217 | |||
1218 | function it_will_return_null_when_min_is_called_on_empty_collection() |
||
1219 | { |
||
1220 | $this->beConstructedWith([]); |
||
1221 | $this->min()->shouldReturn(null); |
||
1222 | } |
||
1223 | |||
1224 | function it_can_convert_the_collection_to_string() |
||
1225 | { |
||
1226 | $this->beConstructedWith([2, 'a', 3, null]); |
||
1227 | $this->toString()->shouldReturn('2a3'); |
||
1228 | } |
||
1229 | |||
1230 | function it_can_replace_by_key() |
||
1231 | { |
||
1232 | $this->beConstructedWith(['a' => 1, 'b' => 2, 'c' => 3]); |
||
1233 | $this->replaceByKeys(['b' => 3])->toArray()->shouldReturn(['a' => 1, 'b' => 3, 'c' => 3]); |
||
1234 | } |
||
1235 | |||
1236 | function it_can_transpose_collections_of_collections() |
||
1237 | { |
||
1238 | $this->beConstructedWith([ |
||
1239 | new Collection([1, 2, 3]), |
||
1240 | new Collection([4, 5, new Collection(['foo', 'bar'])]), |
||
1241 | new Collection([7, 8, 9]), |
||
1242 | ]); |
||
1243 | |||
1244 | $this->transpose()->toArray()->shouldBeLike([ |
||
1245 | new Collection([1, 4, 7]), |
||
1246 | new Collection([2, 5, 8]), |
||
1247 | new Collection([3, new Collection(['foo', 'bar']), 9]), |
||
1248 | ]); |
||
1249 | } |
||
1250 | |||
1251 | function it_can_transpose_arrays_of_different_lengths() |
||
1252 | { |
||
1253 | $this->beConstructedWith([ |
||
1254 | new Collection(['a', 'b', 'c', 'd']), |
||
1255 | new Collection(['apple', 'box', 'car']), |
||
1256 | ]); |
||
1257 | |||
1258 | $this->transpose()->toArray()->shouldBeLike([ |
||
1259 | new Collection(['a', 'apple']), |
||
1260 | new Collection(['b', 'box']), |
||
1261 | new Collection(['c', 'car']), |
||
1262 | new Collection(['d', null]), |
||
1263 | ]); |
||
1264 | } |
||
1265 | |||
1266 | function it_should_throw_an_invalid_argument_if_collection_items_are_not_collection() |
||
1267 | { |
||
1268 | $this->beConstructedWith([ |
||
1269 | [1, 2, 3], |
||
1270 | [4, 5, 6], |
||
1271 | [7, 8, 9], |
||
1272 | ]); |
||
1273 | |||
1274 | $this->shouldThrow(InvalidArgument::class)->during('transpose'); |
||
1275 | } |
||
1276 | |||
1277 | function it_can_use_the_utility_methods() |
||
1278 | { |
||
1279 | $this->beConstructedWith([1, 3, 2]); |
||
1280 | |||
1281 | $this |
||
1282 | ->sort('\DusanKasan\Knapsack\compare') |
||
1283 | ->values() |
||
1284 | ->toArray() |
||
1285 | ->shouldReturn([1, 2, 3]); |
||
1286 | |||
1287 | $this |
||
1288 | ->map('\DusanKasan\Knapsack\compare') |
||
1289 | ->toArray() |
||
1290 | ->shouldReturn([1, 1, 0]); |
||
1291 | |||
1292 | $this |
||
1293 | ->map('\DusanKasan\Knapsack\decrement') |
||
1294 | ->toArray() |
||
1295 | ->shouldReturn([0, 2, 1]); |
||
1296 | } |
||
1297 | |||
1298 | function it_can_dump_the_collection() |
||
1299 | { |
||
1300 | $this->beConstructedWith( |
||
1301 | [ |
||
1302 | [ |
||
1303 | [1, [2], 3], |
||
1304 | ['a' => 'b'], |
||
1305 | new ArrayIterator([1, 2, 3]) |
||
1306 | ], |
||
1307 | [1, 2, 3], |
||
1308 | new ArrayIterator(['a', 'b', 'c']), |
||
1309 | true, |
||
1310 | new \DusanKasan\Knapsack\Tests\Helpers\Car('sedan', 5), |
||
1311 | \DusanKasan\Knapsack\concat([1], [1]), |
||
1312 | ] |
||
1313 | ); |
||
1314 | |||
1315 | $this->dump()->shouldReturn( |
||
1316 | [ |
||
1317 | [ |
||
1318 | [1, [2], 3], |
||
1319 | ['a' => 'b'], |
||
1320 | [1, 2, 3] |
||
1321 | ], |
||
1322 | [1, 2, 3], |
||
1323 | ['a', 'b', 'c'], |
||
1324 | true, |
||
1325 | [ |
||
1326 | 'DusanKasan\Knapsack\Tests\Helpers\Car' => [ |
||
1327 | 'numberOfSeats' => 5, |
||
1328 | ], |
||
1329 | |||
1330 | ], |
||
1331 | [1, '0//1' => 1] |
||
1332 | ] |
||
1333 | ); |
||
1334 | |||
1335 | $this->dump(2)->shouldReturn( |
||
1336 | [ |
||
1337 | [ |
||
1338 | [1, [2], '>>>'], |
||
1339 | ['a' => 'b'], |
||
1340 | '>>>' |
||
1341 | ], |
||
1342 | [1, 2, '>>>'], |
||
1343 | '>>>' |
||
1344 | ] |
||
1345 | ); |
||
1346 | |||
1347 | $this->dump(null, 3)->shouldReturn( |
||
1348 | [ |
||
1349 | [ |
||
1350 | [1, '^^^', 3], |
||
1351 | ['a' => 'b'], |
||
1352 | [1, 2, 3] |
||
1353 | ], |
||
1354 | [1, 2, 3], |
||
1355 | ['a', 'b', 'c'], |
||
1356 | true, |
||
1357 | [ |
||
1358 | 'DusanKasan\Knapsack\Tests\Helpers\Car' => [ |
||
1359 | 'numberOfSeats' => 5, |
||
1360 | ], |
||
1361 | ], |
||
1362 | [1, '0//1' => 1] |
||
1363 | ] |
||
1364 | ); |
||
1365 | |||
1366 | $this->dump(2, 3)->shouldReturn( |
||
1367 | [ |
||
1368 | [ |
||
1369 | [1, '^^^', '>>>'], |
||
1370 | ['a' => 'b'], |
||
1371 | '>>>' |
||
1372 | ], |
||
1373 | [1, 2, '>>>'], |
||
1374 | '>>>' |
||
1375 | ] |
||
1376 | ); |
||
1377 | } |
||
1378 | |||
1379 | function it_can_print_dump() |
||
1380 | { |
||
1381 | $this->beConstructedWith([1, [2], 3]); |
||
1382 | |||
1383 | ob_start(); |
||
1384 | $this->printDump()->shouldReturn($this); |
||
1385 | $this->printDump(2)->shouldReturn($this); |
||
1386 | $this->printDump(2, 2)->shouldReturn($this); |
||
1387 | ob_clean(); |
||
1388 | } |
||
1389 | } |
||
1390 |