[!!!][TASK] Remove sysext:sv, move files to sysext:core
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Service / DependencyOrderingServiceTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Service;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Service\DependencyOrderingService;
18
19 /**
20 * Test case
21 */
22 class DependencyOrderingServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
23 {
24 /**
25 * @test
26 * @dataProvider orderByDependenciesBuildsCorrectOrderDataProvider
27 * @param array $items
28 * @param string $beforeKey
29 * @param string $afterKey
30 * @param array $expectedOrderedItems
31 */
32 public function orderByDependenciesBuildsCorrectOrder(array $items, $beforeKey, $afterKey, array $expectedOrderedItems)
33 {
34 $orderedItems = (new DependencyOrderingService())->orderByDependencies($items, $beforeKey, $afterKey);
35 $this->assertSame($expectedOrderedItems, $orderedItems);
36 }
37
38 /**
39 * @return array
40 */
41 public function orderByDependenciesBuildsCorrectOrderDataProvider()
42 {
43 return [
44 'unordered' => [
45 [ // $items
46 1 => [],
47 2 => [],
48 ],
49 'before',
50 'after',
51 [ // $expectedOrderedItems
52 1 => [],
53 2 => [],
54 ]
55 ],
56 'ordered' => [
57 [ // $items
58 1 => [],
59 2 => [
60 'precedes' => [ 1 ]
61 ],
62 ],
63 'precedes',
64 'after',
65 [ // $expectedOrderedItems
66 2 => [
67 'precedes' => [ 1 ]
68 ],
69 1 => [],
70 ]
71 ],
72 'mixed' => [
73 [ // $items
74 1 => [],
75 2 => [
76 'before' => [ 1 ]
77 ],
78 3 => [
79 'otherProperty' => true
80 ]
81 ],
82 'before',
83 'after',
84 [ // $expectedOrderedItems
85 2 => [
86 'before' => [ 1 ]
87 ],
88 1 => [],
89 3 => [
90 'otherProperty' => true
91 ],
92 ]
93 ],
94 'reference to non-existing' => [
95 [ // $items
96 2 => [
97 'before' => [ 1 ],
98 'depends' => [ 3 ]
99 ],
100 3 => [
101 'otherProperty' => true
102 ]
103 ],
104 'before',
105 'depends',
106 [ // $expectedOrderedItems
107 3 => [
108 'otherProperty' => true
109 ],
110 2 => [
111 'before' => [ 1 ],
112 'depends' => [ 3 ]
113 ],
114 ]
115 ],
116 'multiple dependencies' => [
117 [ // $items
118 1 => [
119 'depends' => [ 3, 2, 4 ],
120 ],
121 2 => [],
122 3 => [
123 'depends' => [ 2 ],
124 ],
125 ],
126 'before',
127 'depends',
128 [ // $expectedOrderedItems
129 2 => [],
130 3 => [
131 'depends' => [ 2 ],
132 ],
133 1 => [
134 'depends' => [ 3, 2, 4 ],
135 ],
136 ],
137 ],
138 'direct dependency is moved up' => [
139 [ // $items
140 1 => [],
141 2 => [],
142 3 => [
143 'depends' => [ 1 ],
144 ],
145 ],
146 'before',
147 'depends',
148 [ // $expectedOrderedItems
149 1 => [],
150 3 => [
151 'depends' => [ 1 ],
152 ],
153 2 => [],
154 ],
155 ],
156 ];
157 }
158
159 /**
160 * @test
161 * @dataProvider prepareDependenciesBuildsFullIdentifierListDataProvider
162 * @param array $dependencies
163 * @param $expectedDependencies
164 * @throws \InvalidArgumentException
165 */
166 public function prepareDependenciesBuildsFullIdentifierList(array $dependencies, array $expectedDependencies)
167 {
168 /** @var DependencyOrderingService|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface $dependencyOrderingService */
169 $dependencyOrderingService = $this->getAccessibleMock(DependencyOrderingService::class, ['dummy']);
170 $preparedDependencies = $dependencyOrderingService->_call('prepareDependencies', $dependencies);
171 $this->assertEquals($expectedDependencies, $preparedDependencies);
172 }
173
174 /**
175 * @return array
176 */
177 public function prepareDependenciesBuildsFullIdentifierListDataProvider()
178 {
179 return [
180 'simple' => [
181 [ // $dependencies
182 1 => [
183 'before' => [],
184 'after' => [ 2 ]
185 ],
186 ],
187 [ // $expectedDependencies
188 1 => [
189 'before' => [],
190 'after' => [ 2 ]
191 ],
192 2 => [
193 'before' => [],
194 'after' => [],
195 ]
196 ]
197 ],
198 'missing before' => [
199 [ // $dependencies
200 1 => [
201 'after' => [ 2 ]
202 ],
203 ],
204 [ // $expectedDependencies
205 1 => [
206 'before' => [],
207 'after' => [ 2 ]
208 ],
209 2 => [
210 'before' => [],
211 'after' => [],
212 ]
213 ]
214 ],
215 ];
216 }
217
218 /**
219 * @test
220 * @dataProvider buildDependencyGraphBuildsValidGraphDataProvider
221 * @param array $dependencies
222 * @param array $expectedGraph
223 */
224 public function buildDependencyGraphBuildsValidGraph(array $dependencies, array $expectedGraph)
225 {
226 $graph = (new DependencyOrderingService())->buildDependencyGraph($dependencies);
227 $this->assertEquals($expectedGraph, $graph);
228 }
229
230 /**
231 * @return array
232 */
233 public function buildDependencyGraphBuildsValidGraphDataProvider()
234 {
235 return [
236 'graph1' => [
237 [ // dependencies
238 1 => [
239 'before' => [],
240 'after' => [ 2 ]
241 ],
242 ],
243 [ // graph
244 1 => [
245 1 => false,
246 2 => true
247 ],
248 2 => [
249 1 => false,
250 2 => false
251 ],
252 ]
253 ],
254 'graph2' => [
255 [ // dependencies
256 1 => [
257 'before' => [ 3 ],
258 'after' => [ 2 ]
259 ],
260 ],
261 [ // graph
262 1 => [
263 1 => false,
264 2 => true,
265 3 => false,
266 ],
267 2 => [
268 1 => false,
269 2 => false,
270 3 => false,
271 ],
272 3 => [
273 1 => true,
274 2 => false,
275 3 => false,
276 ],
277 ]
278 ],
279 'graph3' => [
280 [ // dependencies
281 3 => [
282 'before' => [],
283 'after' => []
284 ],
285 1 => [
286 'before' => [ 3 ],
287 'after' => [ 2 ]
288 ],
289 2 => [
290 'before' => [ 3 ],
291 'after' => []
292 ]
293 ],
294 [ // graph
295 1 => [
296 1 => false,
297 2 => true,
298 3 => false,
299 ],
300 2 => [
301 1 => false,
302 2 => false,
303 3 => false,
304 ],
305 3 => [
306 1 => true,
307 2 => true,
308 3 => false,
309 ],
310 ]
311 ],
312 'cyclic graph' => [
313 [ // dependencies
314 1 => [
315 'before' => [ 2 ],
316 'after' => []
317 ],
318 2 => [
319 'before' => [ 1 ],
320 'after' => []
321 ]
322 ],
323 [ // graph
324 1 => [
325 1 => false,
326 2 => true,
327 ],
328 2 => [
329 1 => true,
330 2 => false,
331 ],
332 ]
333 ],
334 'TYPO3 Flow Packages' => [
335 [ // dependencies
336 'TYPO3.Flow' => [
337 'before' => [],
338 'after' => ['Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM']
339 ],
340 'Doctrine.ORM' => [
341 'before' => [],
342 'after' => ['Doctrine.Common', 'Doctrine.DBAL']
343 ],
344 'Doctrine.Common' => [
345 'before' => [],
346 'after' => []
347 ],
348 'Doctrine.DBAL' => [
349 'before' => [],
350 'after' => ['Doctrine.Common']
351 ],
352 'Symfony.Component.Yaml' => [
353 'before' => [],
354 'after' => []
355 ],
356 ],
357 [ // graph
358 'TYPO3.Flow' => [
359 'TYPO3.Flow' => false,
360 'Doctrine.ORM' => true,
361 'Doctrine.Common' => true,
362 'Doctrine.DBAL' => true,
363 'Symfony.Component.Yaml' => true,
364 ],
365 'Doctrine.ORM' => [
366 'TYPO3.Flow' => false,
367 'Doctrine.ORM' => false,
368 'Doctrine.Common' => true,
369 'Doctrine.DBAL' => true,
370 'Symfony.Component.Yaml' => false,
371 ],
372 'Doctrine.Common' => [
373 'TYPO3.Flow' => false,
374 'Doctrine.ORM' => false,
375 'Doctrine.Common' => false,
376 'Doctrine.DBAL' => false,
377 'Symfony.Component.Yaml' => false,
378 ],
379 'Doctrine.DBAL' => [
380 'TYPO3.Flow' => false,
381 'Doctrine.ORM' => false,
382 'Doctrine.Common' => true,
383 'Doctrine.DBAL' => false,
384 'Symfony.Component.Yaml' => false,
385 ],
386 'Symfony.Component.Yaml' => [
387 'TYPO3.Flow' => false,
388 'Doctrine.ORM' => false,
389 'Doctrine.Common' => false,
390 'Doctrine.DBAL' => false,
391 'Symfony.Component.Yaml' => false,
392 ],
393 ],
394 ],
395 'TYPO3 CMS Extensions' => [
396 [ // dependencies
397 'core' => [
398 'before' => [],
399 'after' => [],
400 ],
401 'openid' => [
402 'before' => [],
403 'after' => ['core', 'setup']
404 ],
405 'scheduler' => [
406 'before' => [],
407 'after' => ['core'],
408 ],
409 'setup' => [
410 'before' => [],
411 'after' => ['core'],
412 ],
413 ],
414 [ // graph
415 'core' => [
416 'core' => false,
417 'setup' => false,
418 'scheduler' => false,
419 'openid' => false,
420 ],
421 'openid' => [
422 'core' => true,
423 'setup' => true,
424 'scheduler' => false,
425 'openid' => false,
426 ],
427 'scheduler' => [
428 'core' => true,
429 'setup' => false,
430 'scheduler' => false,
431 'openid' => false,
432 ],
433 'setup' => [
434 'core' => true,
435 'setup' => false,
436 'scheduler' => false,
437 'openid' => false,
438 ],
439 ],
440 ],
441 'Dummy Packages' => [
442 [ // dependencies
443 'A' => [
444 'before' => [],
445 'after' => ['B', 'D', 'C'],
446 ],
447 'B' => [
448 'before' => [],
449 'after' => []
450 ],
451 'C' => [
452 'before' => [],
453 'after' => ['E']
454 ],
455 'D' => [
456 'before' => [],
457 'after' => ['E'],
458 ],
459 'E' => [
460 'before' => [],
461 'after' => [],
462 ],
463 'F' => [
464 'before' => [],
465 'after' => [],
466 ],
467 ],
468 [ // graph
469 'A' => [
470 'A' => false,
471 'B' => true,
472 'C' => true,
473 'D' => true,
474 'E' => false,
475 'F' => false,
476 ],
477 'B' => [
478 'A' => false,
479 'B' => false,
480 'C' => false,
481 'D' => false,
482 'E' => false,
483 'F' => false,
484 ],
485 'C' => [
486 'A' => false,
487 'B' => false,
488 'C' => false,
489 'D' => false,
490 'E' => true,
491 'F' => false,
492 ],
493 'D' => [
494 'A' => false,
495 'B' => false,
496 'C' => false,
497 'D' => false,
498 'E' => true,
499 'F' => false,
500 ],
501 'E' => [
502 'A' => false,
503 'B' => false,
504 'C' => false,
505 'D' => false,
506 'E' => false,
507 'F' => false,
508 ],
509 'F' => [
510 'A' => false,
511 'B' => false,
512 'C' => false,
513 'D' => false,
514 'E' => false,
515 'F' => false,
516 ],
517 ],
518 ],
519 'Suggestions without reverse dependency' => [
520 [ // dependencies
521 'A' => [
522 'before' => [],
523 'after' => [],
524 'after-resilient' => ['B'] // package suggestion
525 ],
526 'B' => [
527 'before' => [],
528 'after' => [],
529 ],
530 'C' => [
531 'before' => [],
532 'after' => ['A']
533 ],
534 ],
535 [ // graph
536 'A' => [
537 'A' => false,
538 'B' => true,
539 'C' => false,
540 ],
541 'B' => [
542 'A' => false,
543 'B' => false,
544 'C' => false,
545 ],
546 'C' => [
547 'A' => true,
548 'B' => false,
549 'C' => false,
550 ],
551 ],
552 ],
553 'Suggestions with reverse dependency' => [
554 [ // dependencies
555 'A' => [
556 'before' => [],
557 'after' => [],
558 'after-resilient' => ['B'], // package suggestion
559 ],
560 'B' => [
561 'before' => [],
562 'after' => ['A']
563 ],
564 'C' => [
565 'before' => [],
566 'after' => ['A']
567 ],
568 ],
569 [ // graph
570 'A' => [
571 'A' => false,
572 'B' => false,
573 'C' => false,
574 ],
575 'B' => [
576 'A' => true,
577 'B' => false,
578 'C' => false,
579 ],
580 'C' => [
581 'A' => true,
582 'B' => false,
583 'C' => false,
584 ],
585 ],
586 ],
587 ];
588 }
589
590 /**
591 * @test
592 * @dataProvider calculateOrderResolvesCorrectOrderDataProvider
593 * @param array $graph
594 * @param array $expectedList
595 */
596 public function calculateOrderResolvesCorrectOrder(array $graph, array $expectedList)
597 {
598 $list = (new DependencyOrderingService())->calculateOrder($graph);
599 $this->assertSame($expectedList, $list);
600 }
601
602 /**
603 * @return array
604 */
605 public function calculateOrderResolvesCorrectOrderDataProvider()
606 {
607 return [
608 'list1' => [
609 [ // $graph
610 1 => [
611 1 => false,
612 2 => true
613 ],
614 2 => [
615 1 => false,
616 2 => false
617 ],
618 ],
619 [ // $expectedList
620 2, 1
621 ]
622 ],
623 'list2' => [
624 [ // $graph
625 1 => [
626 1 => false,
627 2 => true,
628 3 => false,
629 ],
630 2 => [
631 1 => false,
632 2 => false,
633 3 => false,
634 ],
635 3 => [
636 1 => true,
637 2 => true,
638 3 => false,
639 ],
640 ],
641 [ // $expectedList
642 2, 1, 3
643 ]
644 ],
645 ];
646 }
647
648 /**
649 * @test
650 */
651 public function calculateOrderDetectsCyclicGraph()
652 {
653 $this->expectException(\UnexpectedValueException::class);
654 $this->expectExceptionCode(1381960494);
655
656 (new DependencyOrderingService())->calculateOrder([
657 1 => [
658 1 => false,
659 2 => true,
660 ],
661 2 => [
662 1 => true,
663 2 => false,
664 ],
665 ]);
666 }
667
668 /**
669 * @return array
670 */
671 public function findPathInGraphReturnsCorrectPathDataProvider()
672 {
673 return [
674 'Simple path' => [
675 [
676 'A' => ['A' => false, 'B' => false, 'C' => false, 'Z' => true],
677 'B' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
678 'C' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
679 'Z' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false]
680 ],
681 'A', 'Z',
682 ['A', 'Z']
683 ],
684 'No path' => [
685 [
686 'A' => ['A' => false, 'B' => true, 'C' => false, 'Z' => false],
687 'B' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
688 'C' => ['A' => false, 'B' => true, 'C' => false, 'Z' => false],
689 'Z' => ['A' => false, 'B' => true, 'C' => false, 'Z' => false]
690 ],
691 'A', 'C',
692 []
693 ],
694 'Longer path' => [
695 [
696 'A' => ['A' => false, 'B' => true, 'C' => true, 'Z' => true],
697 'B' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
698 'C' => ['A' => false, 'B' => false, 'C' => false, 'Z' => true],
699 'Z' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false]
700 ],
701 'A', 'Z',
702 ['A', 'C', 'Z']
703 ],
704 ];
705 }
706
707 /**
708 * @param array $graph
709 * @param string $from
710 * @param string $to
711 * @param array $expected
712 * @test
713 * @dataProvider findPathInGraphReturnsCorrectPathDataProvider
714 */
715 public function findPathInGraphReturnsCorrectPath(array $graph, $from, $to, array $expected)
716 {
717 /** @var DependencyOrderingService|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface $dependencyOrderingService */
718 $dependencyOrderingService = $this->getAccessibleMock(DependencyOrderingService::class, ['dummy']);
719 $path = $dependencyOrderingService->_call('findPathInGraph', $graph, $from, $to);
720
721 $this->assertSame($expected, $path);
722 }
723 }