TYPO3 CMS  TYPO3_8-7
DependencyOrderingServiceTest.php
Go to the documentation of this file.
1 <?php
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 
18 
22 class DependencyOrderingServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
23 {
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 
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 
166  public function prepareDependenciesBuildsFullIdentifierList(array $dependencies, array $expectedDependencies)
167  {
169  $dependencyOrderingService = $this->getAccessibleMock(DependencyOrderingService::class, ['dummy']);
170  $preparedDependencies = $dependencyOrderingService->_call('prepareDependencies', $dependencies);
171  $this->assertEquals($expectedDependencies, $preparedDependencies);
172  }
173 
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 
224  public function buildDependencyGraphBuildsValidGraph(array $dependencies, array $expectedGraph)
225  {
226  $graph = (new DependencyOrderingService())->buildDependencyGraph($dependencies);
227  $this->assertEquals($expectedGraph, $graph);
228  }
229 
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  'sv' => [
414  'before' => [],
415  'after' => ['core'],
416  ],
417  ],
418  [ // graph
419  'core' => [
420  'core' => false,
421  'setup' => false,
422  'sv' => false,
423  'scheduler' => false,
424  'openid' => false,
425  ],
426  'openid' => [
427  'core' => true,
428  'setup' => true,
429  'sv' => false,
430  'scheduler' => false,
431  'openid' => false,
432  ],
433  'scheduler' => [
434  'core' => true,
435  'setup' => false,
436  'sv' => false,
437  'scheduler' => false,
438  'openid' => false,
439  ],
440  'setup' => [
441  'core' => true,
442  'setup' => false,
443  'sv' => false,
444  'scheduler' => false,
445  'openid' => false,
446  ],
447  'sv' => [
448  'core' => true,
449  'setup' => false,
450  'sv' => false,
451  'scheduler' => false,
452  'openid' => false,
453  ],
454  ],
455  ],
456  'Dummy Packages' => [
457  [ // dependencies
458  'A' => [
459  'before' => [],
460  'after' => ['B', 'D', 'C'],
461  ],
462  'B' => [
463  'before' => [],
464  'after' => []
465  ],
466  'C' => [
467  'before' => [],
468  'after' => ['E']
469  ],
470  'D' => [
471  'before' => [],
472  'after' => ['E'],
473  ],
474  'E' => [
475  'before' => [],
476  'after' => [],
477  ],
478  'F' => [
479  'before' => [],
480  'after' => [],
481  ],
482  ],
483  [ // graph
484  'A' => [
485  'A' => false,
486  'B' => true,
487  'C' => true,
488  'D' => true,
489  'E' => false,
490  'F' => false,
491  ],
492  'B' => [
493  'A' => false,
494  'B' => false,
495  'C' => false,
496  'D' => false,
497  'E' => false,
498  'F' => false,
499  ],
500  'C' => [
501  'A' => false,
502  'B' => false,
503  'C' => false,
504  'D' => false,
505  'E' => true,
506  'F' => false,
507  ],
508  'D' => [
509  'A' => false,
510  'B' => false,
511  'C' => false,
512  'D' => false,
513  'E' => true,
514  'F' => false,
515  ],
516  'E' => [
517  'A' => false,
518  'B' => false,
519  'C' => false,
520  'D' => false,
521  'E' => false,
522  'F' => false,
523  ],
524  'F' => [
525  'A' => false,
526  'B' => false,
527  'C' => false,
528  'D' => false,
529  'E' => false,
530  'F' => false,
531  ],
532  ],
533  ],
534  'Suggestions without reverse dependency' => [
535  [ // dependencies
536  'A' => [
537  'before' => [],
538  'after' => [],
539  'after-resilient' => ['B'] // package suggestion
540  ],
541  'B' => [
542  'before' => [],
543  'after' => [],
544  ],
545  'C' => [
546  'before' => [],
547  'after' => ['A']
548  ],
549  ],
550  [ // graph
551  'A' => [
552  'A' => false,
553  'B' => true,
554  'C' => false,
555  ],
556  'B' => [
557  'A' => false,
558  'B' => false,
559  'C' => false,
560  ],
561  'C' => [
562  'A' => true,
563  'B' => false,
564  'C' => false,
565  ],
566  ],
567  ],
568  'Suggestions with reverse dependency' => [
569  [ // dependencies
570  'A' => [
571  'before' => [],
572  'after' => [],
573  'after-resilient' => ['B'], // package suggestion
574  ],
575  'B' => [
576  'before' => [],
577  'after' => ['A']
578  ],
579  'C' => [
580  'before' => [],
581  'after' => ['A']
582  ],
583  ],
584  [ // graph
585  'A' => [
586  'A' => false,
587  'B' => false,
588  'C' => false,
589  ],
590  'B' => [
591  'A' => true,
592  'B' => false,
593  'C' => false,
594  ],
595  'C' => [
596  'A' => true,
597  'B' => false,
598  'C' => false,
599  ],
600  ],
601  ],
602  ];
603  }
604 
611  public function calculateOrderResolvesCorrectOrder(array $graph, array $expectedList)
612  {
613  $list = (new DependencyOrderingService())->calculateOrder($graph);
614  $this->assertSame($expectedList, $list);
615  }
616 
621  {
622  return [
623  'list1' => [
624  [ // $graph
625  1 => [
626  1 => false,
627  2 => true
628  ],
629  2 => [
630  1 => false,
631  2 => false
632  ],
633  ],
634  [ // $expectedList
635  2, 1
636  ]
637  ],
638  'list2' => [
639  [ // $graph
640  1 => [
641  1 => false,
642  2 => true,
643  3 => false,
644  ],
645  2 => [
646  1 => false,
647  2 => false,
648  3 => false,
649  ],
650  3 => [
651  1 => true,
652  2 => true,
653  3 => false,
654  ],
655  ],
656  [ // $expectedList
657  2, 1, 3
658  ]
659  ],
660  ];
661  }
662 
667  {
668  $this->expectException(\UnexpectedValueException::class);
669  $this->expectExceptionCode(1381960494);
670 
671  (new DependencyOrderingService())->calculateOrder([
672  1 => [
673  1 => false,
674  2 => true,
675  ],
676  2 => [
677  1 => true,
678  2 => false,
679  ],
680  ]);
681  }
682 
687  {
688  return [
689  'Simple path' => [
690  [
691  'A' => ['A' => false, 'B' => false, 'C' => false, 'Z' => true],
692  'B' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
693  'C' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
694  'Z' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false]
695  ],
696  'A', 'Z',
697  ['A', 'Z']
698  ],
699  'No path' => [
700  [
701  'A' => ['A' => false, 'B' => true, 'C' => false, 'Z' => false],
702  'B' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
703  'C' => ['A' => false, 'B' => true, 'C' => false, 'Z' => false],
704  'Z' => ['A' => false, 'B' => true, 'C' => false, 'Z' => false]
705  ],
706  'A', 'C',
707  []
708  ],
709  'Longer path' => [
710  [
711  'A' => ['A' => false, 'B' => true, 'C' => true, 'Z' => true],
712  'B' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false],
713  'C' => ['A' => false, 'B' => false, 'C' => false, 'Z' => true],
714  'Z' => ['A' => false, 'B' => false, 'C' => false, 'Z' => false]
715  ],
716  'A', 'Z',
717  ['A', 'C', 'Z']
718  ],
719  ];
720  }
721 
730  public function findPathInGraphReturnsCorrectPath(array $graph, $from, $to, array $expected)
731  {
733  $dependencyOrderingService = $this->getAccessibleMock(DependencyOrderingService::class, ['dummy']);
734  $path = $dependencyOrderingService->_call('findPathInGraph', $graph, $from, $to);
735 
736  $this->assertSame($expected, $path);
737  }
738 }
orderByDependenciesBuildsCorrectOrder(array $items, $beforeKey, $afterKey, array $expectedOrderedItems)