‪TYPO3CMS  11.5
DependencyOrderingServiceTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
21 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
22 
26 class ‪DependencyOrderingServiceTest extends UnitTestCase
27 {
36  public function ‪orderByDependenciesBuildsCorrectOrder(array $items, string $beforeKey, string $afterKey, array $expectedOrderedItems): void
37  {
38  $orderedItems = (new ‪DependencyOrderingService())->orderByDependencies($items, $beforeKey, $afterKey);
39  self::assertSame($expectedOrderedItems, $orderedItems);
40  }
41 
46  {
47  return [
48  'unordered' => [
49  [ // $items
50  1 => [],
51  2 => [],
52  ],
53  'before',
54  'after',
55  [ // $expectedOrderedItems
56  1 => [],
57  2 => [],
58  ],
59  ],
60  'ordered' => [
61  [ // $items
62  1 => [],
63  2 => [
64  'precedes' => [ 1 ],
65  ],
66  ],
67  'precedes',
68  'after',
69  [ // $expectedOrderedItems
70  2 => [
71  'precedes' => [ 1 ],
72  ],
73  1 => [],
74  ],
75  ],
76  'mixed' => [
77  [ // $items
78  1 => [],
79  2 => [
80  'before' => [ 1 ],
81  ],
82  3 => [
83  'otherProperty' => true,
84  ],
85  ],
86  'before',
87  'after',
88  [ // $expectedOrderedItems
89  2 => [
90  'before' => [ 1 ],
91  ],
92  1 => [],
93  3 => [
94  'otherProperty' => true,
95  ],
96  ],
97  ],
98  'reference to non-existing' => [
99  [ // $items
100  2 => [
101  'before' => [ 1 ],
102  'depends' => [ 3 ],
103  ],
104  3 => [
105  'otherProperty' => true,
106  ],
107  ],
108  'before',
109  'depends',
110  [ // $expectedOrderedItems
111  3 => [
112  'otherProperty' => true,
113  ],
114  2 => [
115  'before' => [ 1 ],
116  'depends' => [ 3 ],
117  ],
118  ],
119  ],
120  'multiple dependencies' => [
121  [ // $items
122  1 => [
123  'depends' => [ 3, 2, 4 ],
124  ],
125  2 => [],
126  3 => [
127  'depends' => [ 2 ],
128  ],
129  ],
130  'before',
131  'depends',
132  [ // $expectedOrderedItems
133  2 => [],
134  3 => [
135  'depends' => [ 2 ],
136  ],
137  1 => [
138  'depends' => [ 3, 2, 4 ],
139  ],
140  ],
141  ],
142  'direct dependency is moved up' => [
143  [ // $items
144  1 => [],
145  2 => [],
146  3 => [
147  'depends' => [ 1 ],
148  ],
149  ],
150  'before',
151  'depends',
152  [ // $expectedOrderedItems
153  1 => [],
154  3 => [
155  'depends' => [ 1 ],
156  ],
157  2 => [],
158  ],
159  ],
160  ];
161  }
162 
168  public function ‪prepareDependenciesBuildsFullIdentifierList(array $dependencies, array $expectedDependencies): void
169  {
170  $dependencyOrderingService = $this->getAccessibleMock(DependencyOrderingService::class, ['dummy']);
171  $preparedDependencies = $dependencyOrderingService->_call('prepareDependencies', $dependencies);
172  self::assertEquals($expectedDependencies, $preparedDependencies);
173  }
174 
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 
225  public function ‪buildDependencyGraphBuildsValidGraph(array $dependencies, array $expectedGraph): void
226  {
227  $graph = (new ‪DependencyOrderingService())->buildDependencyGraph($dependencies);
228  self::assertEquals($expectedGraph, $graph);
229  }
230 
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' => [
336  [ // dependencies
337  'TYPO3.Flow' => [
338  'before' => [],
339  'after' => ['Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM'],
340  ],
341  'Doctrine.ORM' => [
342  'before' => [],
343  'after' => ['Doctrine.Common', 'Doctrine.DBAL'],
344  ],
345  'Doctrine.Common' => [
346  'before' => [],
347  'after' => [],
348  ],
349  'Doctrine.DBAL' => [
350  'before' => [],
351  'after' => ['Doctrine.Common'],
352  ],
353  'Symfony.Component.Yaml' => [
354  'before' => [],
355  'after' => [],
356  ],
357  ],
358  [ // graph
359  'TYPO3.Flow' => [
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' => [
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' => [
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' => [
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' => [
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' => [
397  [ // dependencies
398  'core' => [
399  'before' => [],
400  'after' => [],
401  ],
402  'openid' => [
403  'before' => [],
404  'after' => ['core', 'setup'],
405  ],
406  'scheduler' => [
407  'before' => [],
408  'after' => ['core'],
409  ],
410  'setup' => [
411  'before' => [],
412  'after' => ['core'],
413  ],
414  ],
415  [ // graph
416  'core' => [
417  'core' => false,
418  'setup' => false,
419  'scheduler' => false,
420  'openid' => false,
421  ],
422  'openid' => [
423  'core' => true,
424  'setup' => true,
425  'scheduler' => false,
426  'openid' => false,
427  ],
428  'scheduler' => [
429  'core' => true,
430  'setup' => false,
431  'scheduler' => false,
432  'openid' => false,
433  ],
434  'setup' => [
435  'core' => true,
436  'setup' => false,
437  'scheduler' => false,
438  'openid' => false,
439  ],
440  ],
441  ],
442  'Dummy Packages' => [
443  [ // dependencies
444  'A' => [
445  'before' => [],
446  'after' => ['B', 'D', 'C'],
447  ],
448  'B' => [
449  'before' => [],
450  'after' => [],
451  ],
452  'C' => [
453  'before' => [],
454  'after' => ['E'],
455  ],
456  'D' => [
457  'before' => [],
458  'after' => ['E'],
459  ],
460  'E' => [
461  'before' => [],
462  'after' => [],
463  ],
464  'F' => [
465  'before' => [],
466  'after' => [],
467  ],
468  ],
469  [ // graph
470  'A' => [
471  'A' => false,
472  'B' => true,
473  'C' => true,
474  'D' => true,
475  'E' => false,
476  'F' => false,
477  ],
478  'B' => [
479  'A' => false,
480  'B' => false,
481  'C' => false,
482  'D' => false,
483  'E' => false,
484  'F' => false,
485  ],
486  'C' => [
487  'A' => false,
488  'B' => false,
489  'C' => false,
490  'D' => false,
491  'E' => true,
492  'F' => false,
493  ],
494  'D' => [
495  'A' => false,
496  'B' => false,
497  'C' => false,
498  'D' => false,
499  'E' => true,
500  'F' => false,
501  ],
502  'E' => [
503  'A' => false,
504  'B' => false,
505  'C' => false,
506  'D' => false,
507  'E' => false,
508  'F' => false,
509  ],
510  'F' => [
511  'A' => false,
512  'B' => false,
513  'C' => false,
514  'D' => false,
515  'E' => false,
516  'F' => false,
517  ],
518  ],
519  ],
520  'Suggestions without reverse dependency' => [
521  [ // dependencies
522  'A' => [
523  'before' => [],
524  'after' => [],
525  'after-resilient' => ['B'], // package suggestion
526  ],
527  'B' => [
528  'before' => [],
529  'after' => [],
530  ],
531  'C' => [
532  'before' => [],
533  'after' => ['A'],
534  ],
535  ],
536  [ // graph
537  'A' => [
538  'A' => false,
539  'B' => true,
540  'C' => false,
541  ],
542  'B' => [
543  'A' => false,
544  'B' => false,
545  'C' => false,
546  ],
547  'C' => [
548  'A' => true,
549  'B' => false,
550  'C' => false,
551  ],
552  ],
553  ],
554  'Suggestions with reverse dependency' => [
555  [ // dependencies
556  'A' => [
557  'before' => [],
558  'after' => [],
559  'after-resilient' => ['B'], // package suggestion
560  ],
561  'B' => [
562  'before' => [],
563  'after' => ['A'],
564  ],
565  'C' => [
566  'before' => [],
567  'after' => ['A'],
568  ],
569  ],
570  [ // graph
571  'A' => [
572  'A' => false,
573  'B' => false,
574  'C' => false,
575  ],
576  'B' => [
577  'A' => true,
578  'B' => false,
579  'C' => false,
580  ],
581  'C' => [
582  'A' => true,
583  'B' => false,
584  'C' => false,
585  ],
586  ],
587  ],
588  ];
589  }
590 
597  public function ‪calculateOrderResolvesCorrectOrder(array $graph, array $expectedList): void
598  {
599  $list = (new ‪DependencyOrderingService())->calculateOrder($graph);
600  self::assertSame($expectedList, $list);
601  }
602 
607  {
608  return [
609  'list1' => [
610  [ // $graph
611  1 => [
612  1 => false,
613  2 => true,
614  ],
615  2 => [
616  1 => false,
617  2 => false,
618  ],
619  ],
620  [ // $expectedList
621  2, 1,
622  ],
623  ],
624  'list2' => [
625  [ // $graph
626  1 => [
627  1 => false,
628  2 => true,
629  3 => false,
630  ],
631  2 => [
632  1 => false,
633  2 => false,
634  3 => false,
635  ],
636  3 => [
637  1 => true,
638  2 => true,
639  3 => false,
640  ],
641  ],
642  [ // $expectedList
643  2, 1, 3,
644  ],
645  ],
646  ];
647  }
648 
652  public function ‪calculateOrderDetectsCyclicGraph(): void
653  {
654  $this->expectException(\UnexpectedValueException::class);
655  $this->expectExceptionCode(1381960494);
656 
657  (new ‪DependencyOrderingService())->calculateOrder([
658  1 => [
659  1 => false,
660  2 => true,
661  ],
662  2 => [
663  1 => true,
664  2 => false,
665  ],
666  ]);
667  }
668 
673  {
674  return [
675  'Simple path' => [
676  [
677  'A' => ['A' => false, 'B' => false, 'C' => false, 'Z' => true],
678  'B' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
679  'C' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
680  'Z' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
681  ],
682  'A', 'Z',
683  ['A', 'Z'],
684  ],
685  'No path' => [
686  [
687  'A' => ['A' => false, 'B' => true, 'C' => false, 'Z' => false],
688  'B' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
689  'C' => ['A' => false, 'B' => true, 'C' => false, 'Z' => false],
690  'Z' => ['A' => false, 'B' => true, 'C' => false, 'Z' => false],
691  ],
692  'A', 'C',
693  [],
694  ],
695  'Longer path' => [
696  [
697  'A' => ['A' => false, 'B' => true, 'C' => true, 'Z' => true],
698  'B' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
699  'C' => ['A' => false, 'B' => false, 'C' => false, 'Z' => true],
700  'Z' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
701  ],
702  'A', 'Z',
703  ['A', 'C', 'Z'],
704  ],
705  ];
706  }
707 
716  public function ‪findPathInGraphReturnsCorrectPath(array $graph, string $from, string $to, array $expected): void
717  {
718  $dependencyOrderingService = $this->getAccessibleMock(DependencyOrderingService::class, ['dummy']);
719  $path = $dependencyOrderingService->_call('findPathInGraph', $graph, $from, $to);
720 
721  self::assertSame($expected, $path);
722  }
723 }
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\prepareDependenciesBuildsFullIdentifierList
‪prepareDependenciesBuildsFullIdentifierList(array $dependencies, array $expectedDependencies)
Definition: DependencyOrderingServiceTest.php:168
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\findPathInGraphReturnsCorrectPathDataProvider
‪array findPathInGraphReturnsCorrectPathDataProvider()
Definition: DependencyOrderingServiceTest.php:672
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest
Definition: DependencyOrderingServiceTest.php:27
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\buildDependencyGraphBuildsValidGraph
‪buildDependencyGraphBuildsValidGraph(array $dependencies, array $expectedGraph)
Definition: DependencyOrderingServiceTest.php:225
‪TYPO3\CMS\Core\Service\DependencyOrderingService
Definition: DependencyOrderingService.php:32
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\orderByDependenciesBuildsCorrectOrder
‪orderByDependenciesBuildsCorrectOrder(array $items, string $beforeKey, string $afterKey, array $expectedOrderedItems)
Definition: DependencyOrderingServiceTest.php:36
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\orderByDependenciesBuildsCorrectOrderDataProvider
‪array orderByDependenciesBuildsCorrectOrderDataProvider()
Definition: DependencyOrderingServiceTest.php:45
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\buildDependencyGraphBuildsValidGraphDataProvider
‪array buildDependencyGraphBuildsValidGraphDataProvider()
Definition: DependencyOrderingServiceTest.php:234
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\findPathInGraphReturnsCorrectPath
‪findPathInGraphReturnsCorrectPath(array $graph, string $from, string $to, array $expected)
Definition: DependencyOrderingServiceTest.php:716
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\calculateOrderResolvesCorrectOrder
‪calculateOrderResolvesCorrectOrder(array $graph, array $expectedList)
Definition: DependencyOrderingServiceTest.php:597
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\calculateOrderResolvesCorrectOrderDataProvider
‪array calculateOrderResolvesCorrectOrderDataProvider()
Definition: DependencyOrderingServiceTest.php:606
‪TYPO3\CMS\Core\Tests\Unit\Service
Definition: DependencyOrderingServiceTest.php:18
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\prepareDependenciesBuildsFullIdentifierListDataProvider
‪array prepareDependenciesBuildsFullIdentifierListDataProvider()
Definition: DependencyOrderingServiceTest.php:178
‪TYPO3\CMS\Core\Tests\Unit\Service\DependencyOrderingServiceTest\calculateOrderDetectsCyclicGraph
‪calculateOrderDetectsCyclicGraph()
Definition: DependencyOrderingServiceTest.php:652