98585bbf246578d690536c1677c0bb0cf20e164c
[Packages/TYPO3.CMS.git] / tests / Unit / t3lib / utility / class.t3lib_utility_arrayTest.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2011 Susanne Moog <typo3@susanne-moog.de>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25 /**
26 * Testcase for class t3lib_utility_array
27 *
28 * @author Susanne Moog <typo3@susanne-moog.de>
29 * @author Christian Kuhn <lolli@schwarzbu.ch>
30 *
31 * @package TYPO3
32 * @subpackage t3lib
33 */
34 class t3lib_utility_ArrayTest extends tx_phpunit_testcase {
35
36 ///////////////////////
37 // Tests concerning filterByValueRecursive
38 ///////////////////////
39
40 /**
41 * Data provider for filterByValueRecursiveCorrectlyFiltersArray
42 *
43 * Every array splits into:
44 * - String value to search for
45 * - Input array
46 * - Expected result array
47 */
48 public function filterByValueRecursive() {
49 return array(
50 'empty search array' => array(
51 'banana',
52 array(),
53 array(),
54 ),
55 'empty string as needle' => array(
56 '',
57 array(
58 '',
59 'apple',
60 ),
61 array(
62 '',
63 ),
64 ),
65 'flat array searching for string' => array(
66 'banana',
67 array(
68 'apple',
69 'banana',
70 ),
71 array(
72 1 => 'banana',
73 ),
74 ),
75 'flat array searching for string with two matches' => array(
76 'banana',
77 array(
78 'foo' => 'apple',
79 'firstbanana' => 'banana',
80 'secondbanana' => 'banana',
81 ),
82 array(
83 'firstbanana' => 'banana',
84 'secondbanana' => 'banana',
85 ),
86 ),
87 'multi dimensional array searching for string with multiple matches' => array(
88 'banana',
89 array(
90 'foo' => 'apple',
91 'firstbanana' => 'banana',
92 'grape' => array(
93 'foo2' => 'apple2',
94 'secondbanana' => 'banana',
95 'foo3' => array(),
96 ),
97 'bar' => 'orange',
98 ),
99 array(
100 'firstbanana' => 'banana',
101 'grape' => array(
102 'secondbanana' => 'banana',
103 ),
104 ),
105 ),
106 'multi dimensional array searching for integer with multiple matches' => array(
107 42,
108 array(
109 'foo' => 23,
110 'bar' => 42,
111 array(
112 'foo' => 23,
113 'bar' => 42,
114 ),
115 ),
116 array(
117 'bar' => 42,
118 array(
119 'bar' => 42,
120 ),
121 ),
122 ),
123 'flat array searching for boolean TRUE' => array(
124 TRUE,
125 array(
126 23 => FALSE,
127 42 => TRUE,
128 ),
129 array(
130 42 => TRUE,
131 ),
132 ),
133 'multi dimensional array searching for boolean FALSE' => array(
134 FALSE,
135 array(
136 23 => FALSE,
137 42 => TRUE,
138 'foo' => array(
139 23 => FALSE,
140 42 => TRUE,
141 ),
142 ),
143 array(
144 23 => FALSE,
145 'foo' => array(
146 23 => FALSE,
147 ),
148 ),
149 ),
150 'flat array searching for array' => array(
151 array(
152 'foo' => 'bar',
153 ),
154 array(
155 'foo' => 'bar',
156 'foobar' => array(
157 'foo' => 'bar',
158 ),
159 ),
160 array(
161 'foobar' => array(
162 'foo' => 'bar',
163 ),
164 ),
165 ),
166 );
167 }
168
169 /**
170 * @test
171 * @dataProvider filterByValueRecursive
172 */
173 public function filterByValueRecursiveCorrectlyFiltersArray($needle, $haystack, $expectedResult) {
174 $this->assertEquals($expectedResult, t3lib_utility_Array::filterByValueRecursive($needle, $haystack));
175 }
176
177 /**
178 * @test
179 */
180 public function filterByValueRecursiveMatchesReferencesToSameObject() {
181 $instance = new stdClass();
182 $this->assertEquals(array($instance), t3lib_utility_Array::filterByValueRecursive($instance, array($instance)));
183 }
184
185 /**
186 * @test
187 */
188 public function filterByValueRecursiveDoesNotMatchDifferentInstancesOfSameClass() {
189 $this->assertEquals(array(), t3lib_utility_Array::filterByValueRecursive(new stdClass(), array(new stdClass())));
190 }
191
192 ///////////////////////
193 // Tests concerning isValidPath
194 ///////////////////////
195
196 /**
197 * Mock the class under test, isValidPath() (method under test), calls
198 * static getValuePath() internally, which is mocked here to return a specific
199 * result. This works because of 'static' keyword' instead of 'self'
200 * for getValueByPath() call, using late static binding in PHP 5.3
201 *
202 * @test
203 */
204 public function isValidPathReturnsTrueIfPathExists() {
205 $className = uniqid('t3lib_utility_Array');
206 eval(
207 'class ' . $className . ' extends t3lib_utility_Array {' .
208 ' public static function getValueByPath() {' .
209 ' return 42;' .
210 ' }' .
211 '}'
212 );
213 $this->assertTrue($className::isValidPath(array('foo'), 'foo'));
214 }
215
216 /**
217 * @test
218 */
219 public function isValidPathReturnsFalseIfPathDoesNotExist() {
220 $className = uniqid('t3lib_utility_Array');
221 eval(
222 'class ' . $className . ' extends t3lib_utility_Array {' .
223 ' public static function getValueByPath() {' .
224 ' throw new RuntimeException(\'foo\', 123);' .
225 ' }' .
226 '}'
227 );
228 $this->assertFalse($className::isValidPath(array('foo'), 'foo'));
229 }
230
231 ///////////////////////
232 // Tests concerning getValueByPath
233 ///////////////////////
234
235 /**
236 * @test
237 * @expectedException RuntimeException
238 */
239 public function getValueByPathThrowsExceptionIfPathIsEmpty() {
240 t3lib_utility_Array::getValueByPath(array(), '');
241 }
242
243 /**
244 * Data provider for getValueByPathThrowsExceptionIfPathNotExists
245 * Every array splits into:
246 * - Array to get value from
247 * - String path
248 * - Expected result
249 */
250 public function getValueByPathInvalidPathDataProvider() {
251 return array(
252 'not existing path 1' => array(
253 array(
254 'foo' => array()
255 ),
256 'foo/bar/baz',
257 FALSE
258 ),
259 'not existing path 2' => array(
260 array(
261 'foo' => array(
262 'baz' => 42
263 ),
264 'bar' => array(),
265 ),
266 'foo/bar/baz',
267 FALSE
268 ),
269 // Negative test: This could be improved and the test moved to
270 // the valid data provider if the method supports this
271 'doubletick encapsulated quoted doubletick does not work' => array(
272 array(
273 '"foo"bar"' => array(
274 'baz' => 42
275 ),
276 'bar' => array(),
277 ),
278 '"foo\"bar"/baz',
279 42
280 ),
281 // Negative test: Method could be improved here
282 'path with doubletick does not work' => array(
283 array(
284 'fo"o' => array(
285 'bar' => 42,
286 ),
287 ),
288 'fo"o/foobar',
289 42,
290 ),
291 );
292 }
293
294 /**
295 * @test
296 * @dataProvider getValueByPathInvalidPathDataProvider
297 * @expectedException RuntimeException
298 */
299 public function getValueByPathThrowsExceptionIfPathNotExists(array $array, $path) {
300 t3lib_utility_Array::getValueByPath($array, $path);
301 }
302
303 /**
304 * Data provider for getValueByPathReturnsCorrectValue
305 * Every array splits into:
306 * - Array to get value from
307 * - String path
308 * - Expected result
309 */
310 public function getValueByPathValidDataProvider() {
311 $testObject = new StdClass();
312 $testObject->foo = 'foo';
313 $testObject->bar = 'bar';
314
315 return array(
316 'integer in multi level array' => array(
317 array(
318 'foo' => array(
319 'bar' => array(
320 'baz' => 42,
321 ),
322 'bar2' => array(),
323 ),
324 ),
325 'foo/bar/baz',
326 42,
327 ),
328 'zero integer in multi level array' => array(
329 array(
330 'foo' => array(
331 'bar' => array(
332 'baz' => 0,
333 ),
334 ),
335 ),
336 'foo/bar/baz',
337 0,
338 ),
339 'NULL value in multi level array' => array(
340 array(
341 'foo' => array(
342 'baz' => NULL,
343 ),
344 ),
345 'foo/baz',
346 NULL,
347 ),
348 'get string value' => array(
349 array(
350 'foo' => array(
351 'baz' => 'this is a test string',
352 ),
353 ),
354 'foo/baz',
355 'this is a test string',
356 ),
357 'get boolean value: FALSE' => array(
358 array(
359 'foo' => array(
360 'baz' => FALSE,
361 ),
362 ),
363 'foo/baz',
364 FALSE,
365 ),
366 'get boolean value: TRUE' => array(
367 array(
368 'foo' => array(
369 'baz' => TRUE,
370 ),
371 ),
372 'foo/baz',
373 TRUE,
374 ),
375 'get object value' => array(
376 array(
377 'foo' => array(
378 'baz' => $testObject,
379 ),
380 ),
381 'foo/baz',
382 $testObject,
383 ),
384 'enclosed path' => array(
385 array(
386 'foo/bar' => array(
387 'foobar' => 42,
388 ),
389 ),
390 '"foo/bar"/foobar',
391 42,
392 ),
393 );
394 }
395
396 /**
397 * @test
398 * @dataProvider getValueByPathValidDataProvider
399 */
400 public function getValueByPathGetsCorrectValue(array $array, $path, $expectedResult) {
401 $this->assertEquals(
402 $expectedResult,
403 t3lib_utility_Array::getValueByPath($array, $path)
404 );
405 }
406
407 /**
408 * @test
409 */
410 public function getValueByPathAccpetsDifferentDelimeter() {
411 $input = array(
412 'foo' => array(
413 'bar' => array(
414 'baz' => 42,
415 ),
416 'bar2' => array(),
417 ),
418 );
419 $searchPath = 'foo%bar%baz';
420 $expected = 42;
421 $delimeter = '%';
422 $this->assertEquals($expected, t3lib_utility_Array::getValueByPath($input, $searchPath, $delimeter));
423 }
424
425 ///////////////////////
426 // Tests concerning setValueByPath
427 ///////////////////////
428
429 /**
430 * @test
431 * @expectedException RuntimeException
432 */
433 public function setValueByPathThrowsExceptionIfPathIsEmpty() {
434 t3lib_utility_Array::setValueByPath(array(), '', NULL);
435 }
436
437 /**
438 * @test
439 * @expectedException RuntimeException
440 */
441 public function setValueByPathThrowsExceptionIfPathIsNotAString() {
442 t3lib_utility_Array::setValueByPath(array(), array('foo'), NULL);
443 }
444
445 /**
446 * Data provider for setValueByPathSetsCorrectValueDataProvider
447 *
448 * Every array splits into:
449 * - Array to set value in
450 * - String path
451 * - Value to set
452 * - Expected result
453 */
454 public function setValueByPathSetsCorrectValueDataProvider() {
455 $testObject = new StdClass();
456 $testObject->foo = 'foo';
457 $testObject->bar = 'bar';
458
459 return array(
460 'set integer value: 42' => array(
461 array(
462 'foo' => array(
463 'bar' => array(
464 'baz' => 0,
465 ),
466 ),
467 ),
468 'foo/bar/baz',
469 42,
470 array(
471 'foo' => array(
472 'bar' => array(
473 'baz' => 42,
474 ),
475 ),
476 ),
477 ),
478 'set integer value: 0' => array(
479 array(
480 'foo' => array(
481 'bar' => array(
482 'baz' => 42,
483 ),
484 ),
485 ),
486 'foo/bar/baz',
487 0,
488 array(
489 'foo' => array(
490 'bar' => array(
491 'baz' => 0,
492 ),
493 ),
494 ),
495 ),
496 'set null value' => array(
497 array(
498 'foo' => array(
499 'bar' => array(
500 'baz' => 42,
501 ),
502 ),
503 ),
504 'foo/bar/baz',
505 NULL,
506 array(
507 'foo' => array(
508 'bar' => array(
509 'baz' => NULL,
510 ),
511 ),
512 ),
513 ),
514 'set array value' => array(
515 array(
516 'foo' => array(
517 'bar' => array(
518 'baz' => 42,
519 ),
520 ),
521 ),
522 'foo/bar/baz',
523 array(
524 'foo' => 123,
525 ),
526 array(
527 'foo' => array(
528 'bar' => array(
529 'baz' => array(
530 'foo' => 123,
531 ),
532 ),
533 ),
534 ),
535 ),
536 'set boolean value: FALSE' => array(
537 array(
538 'foo' => array(
539 'bar' => array(
540 'baz' => TRUE,
541 ),
542 ),
543 ),
544 'foo/bar/baz',
545 FALSE,
546 array(
547 'foo' => array(
548 'bar' => array(
549 'baz' => FALSE,
550 ),
551 ),
552 ),
553 ),
554 'set boolean value: TRUE' => array(
555 array(
556 'foo' => array(
557 'bar' => array(
558 'baz' => NULL,
559 ),
560 ),
561 ),
562 'foo/bar/baz',
563 TRUE,
564 array(
565 'foo' => array(
566 'bar' => array(
567 'baz' => TRUE,
568 ),
569 ),
570 ),
571 ),
572 'set object value' => array(
573 array(
574 'foo' => array(
575 'bar' => array(
576 'baz' => NULL,
577 ),
578 ),
579 ),
580 'foo/bar/baz',
581 $testObject,
582 array(
583 'foo' => array(
584 'bar' => array(
585 'baz' => $testObject,
586 ),
587 ),
588 ),
589 ),
590 'multi keys in array' => array(
591 array(
592 'foo' => array(
593 'bar' => array(
594 'baz' => 'value',
595 ),
596 'bar2' => array(
597 'baz' => 'value',
598 ),
599 ),
600 ),
601 'foo/bar2/baz',
602 'newValue',
603 array(
604 'foo' => array(
605 'bar' => array(
606 'baz' => 'value',
607 ),
608 'bar2' => array(
609 'baz' => 'newValue',
610 ),
611 ),
612 ),
613 ),
614 );
615 }
616
617 /**
618 * @test
619 * @dataProvider setValueByPathSetsCorrectValueDataProvider
620 */
621 public function setValueByPathSetsCorrectValue(array $array, $path, $value, $expectedResult) {
622 $this->assertEquals(
623 $expectedResult,
624 t3lib_utility_Array::setValueByPath($array, $path, $value)
625 );
626 }
627
628 ///////////////////////
629 // Tests concerning sortByKeyRecursive
630 ///////////////////////
631
632 /**
633 * @test
634 */
635 public function sortByKeyRecursiveCheckIfSortingIsCorrect() {
636 $unsortedArray = array(
637 'z' => NULL,
638 'a' => NULL,
639 'd' => array(
640 'c' => NULL,
641 'b' => NULL,
642 'd' => NULL,
643 'a' => NULL,
644 ),
645 );
646 $expectedResult = array(
647 'a' => NULL,
648 'd' => array(
649 'a' => NULL,
650 'b' => NULL,
651 'c' => NULL,
652 'd' => NULL,
653 ),
654 'z' => NULL,
655 );
656 $this->assertSame($expectedResult, t3lib_utility_Array::sortByKeyRecursive($unsortedArray));
657 }
658
659 ///////////////////////
660 // Tests concerning arrayExport
661 ///////////////////////
662
663 /**
664 * @test
665 */
666 public function arrayExportReturnsFormattedMultidimensionalArray() {
667 $array = array(
668 'foo' => array(
669 'bar' => 42,
670 'bar2' => array(
671 'baz' => 'val\'ue',
672 'baz2' => TRUE,
673 'baz3' => FALSE,
674 'baz4' => array(),
675 ),
676 ),
677 'baz' => 23,
678 'foobar' => NULL,
679 );
680 $expected = 'array(' . LF .
681 TAB . '\'foo\' => array(' . LF .
682 TAB . TAB . '\'bar\' => 42,' . LF .
683 TAB . TAB . '\'bar2\' => array(' . LF .
684 TAB . TAB . TAB . '\'baz\' => \'val\\\'ue\',' . LF .
685 TAB . TAB . TAB . '\'baz2\' => TRUE,' . LF .
686 TAB . TAB . TAB . '\'baz3\' => FALSE,' . LF .
687 TAB . TAB . TAB . '\'baz4\' => array(),' . LF .
688 TAB . TAB . '),' . LF .
689 TAB . '),' . LF .
690 TAB . '\'baz\' => 23,' . LF .
691 TAB . '\'foobar\' => NULL,' . LF .
692 ')';
693
694 $this->assertSame($expected, t3lib_utility_Array::arrayExport($array));
695 }
696
697 /**
698 * @test
699 * @expectedException RuntimeException
700 */
701 public function arrayExportThrowsExceptionIfObjectShouldBeExported() {
702 $array = array(
703 'foo' => array(
704 'bar' => new stdClass(),
705 ),
706 );
707 t3lib_utility_Array::arrayExport($array);
708 }
709 }
710
711 ?>