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