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