6b69e00d4046c7456f94beb44c7569da23eecc2c
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Tests / Unit / Package / DependencyResolverTest.php
1 <?php
2 namespace TYPO3\CMS\Core\Tests\Unit\Package;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2013 Markus Klein <klein.t3@mfc-linz.at>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 use TYPO3\CMS\Core\Package\DependencyResolver;
28
29 /**
30 * Testcase for the dependency resolver class
31 *
32 * @author Markus Klein <klein.t3@mfc-linz.at>
33 */
34 class DependencyResolverTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
35
36 /**
37 * @test
38 * @param array $unsortedPackageStatesConfiguration
39 * @param array $frameworkPackageKeys
40 * @param array $expectedGraph
41 * @dataProvider buildDependencyGraphBuildsCorrectGraphDataProvider
42 */
43 public function buildDependencyGraphBuildsCorrectGraph(array $unsortedPackageStatesConfiguration, array $frameworkPackageKeys, array $expectedGraph) {
44 $packageKeys = array_keys($unsortedPackageStatesConfiguration);
45
46 $basePathAssignment = array(
47 array($unsortedPackageStatesConfiguration, '', array(DependencyResolver::SYSEXT_FOLDER), array_diff($packageKeys, $frameworkPackageKeys)),
48 array($unsortedPackageStatesConfiguration, DependencyResolver::SYSEXT_FOLDER, array(), $frameworkPackageKeys),
49 );
50
51 $dependencyResolver = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\DependencyResolver', array('getPackageKeysInBasePath'));
52 $dependencyResolver->expects($this->any())->method('getPackageKeysInBasePath')->will($this->returnValueMap($basePathAssignment));
53 $dependencyGraph = $dependencyResolver->_call('buildDependencyGraph', $unsortedPackageStatesConfiguration);
54
55 $this->assertEquals($expectedGraph, $dependencyGraph);
56 }
57
58 /**
59 * @test
60 * @dataProvider packageSortingDataProvider
61 */
62 public function sortPackageStatesConfigurationByDependencyMakesSureThatDependantPackagesAreStandingBeforeAPackageInTheInternalPackagesAndPackagesConfigurationArrays($unsortedPackageStatesConfiguration, $frameworkPackageKeys, $expectedSortedPackageStatesConfiguration) {
63 $packageKeys = array_keys($unsortedPackageStatesConfiguration);
64
65 $basePathAssignment = array(
66 array($unsortedPackageStatesConfiguration, '', array(DependencyResolver::SYSEXT_FOLDER), array_diff($packageKeys, $frameworkPackageKeys)),
67 array($unsortedPackageStatesConfiguration, DependencyResolver::SYSEXT_FOLDER, array(), $frameworkPackageKeys),
68 );
69
70 $dependencyResolver = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\DependencyResolver', array('getPackageKeysInBasePath'));
71 $dependencyResolver->expects($this->any())->method('getPackageKeysInBasePath')->will($this->returnValueMap($basePathAssignment));
72 $sortedPackageStatesConfiguration = $dependencyResolver->_call('sortPackageStatesConfigurationByDependency', $unsortedPackageStatesConfiguration);
73
74 $this->assertEquals($expectedSortedPackageStatesConfiguration, $sortedPackageStatesConfiguration, 'The package states configurations have not been ordered according to their dependencies!');
75 }
76
77 /**
78 * @test
79 * @dataProvider buildDependencyGraphForPackagesBuildsCorrectGraphDataProvider
80 */
81 public function buildDependencyGraphForPackagesBuildsCorrectGraph($packages, $expectedGraph) {
82 $dependencyResolver = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\DependencyResolver', array('dummy'));
83 $dependencyGraph = $dependencyResolver->_call('buildDependencyGraphForPackages', $packages, array_keys($packages));
84
85 $this->assertEquals($expectedGraph, $dependencyGraph);
86 }
87
88 /**
89 * @test
90 * @expectedException \UnexpectedValueException
91 */
92 public function sortPackageStatesConfigurationByDependencyThrowsExceptionWhenCycleDetected() {
93 $unsortedPackageStatesConfiguration = array(
94 'A' => array(
95 'state' => 'active',
96 'dependencies' => array('B'),
97 ),
98 'B' => array(
99 'state' => 'active',
100 'dependencies' => array('A')
101 ),
102 );
103
104 $packageKeys = array_keys($unsortedPackageStatesConfiguration);
105
106 $basePathAssignment = array(
107 array($unsortedPackageStatesConfiguration, '', array(DependencyResolver::SYSEXT_FOLDER), $packageKeys),
108 array($unsortedPackageStatesConfiguration, DependencyResolver::SYSEXT_FOLDER, array(), array()),
109 );
110
111 $dependencyResolver = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\DependencyResolver', array('getActivePackageKeysOfType'));
112 $dependencyResolver->expects($this->any())->method('getActivePackageKeysOfType')->will($this->returnValueMap($basePathAssignment));
113 $dependencyResolver->_call('sortPackageStatesConfigurationByDependency', $unsortedPackageStatesConfiguration);
114 }
115
116 /**
117 * @test
118 * @expectedException \UnexpectedValueException
119 */
120 public function buildDependencyGraphForPackagesThrowsExceptionWhenDependencyOnUnavailablePackageDetected() {
121 $packages = array(
122 'A' => array(
123 'dependencies' => array('B'),
124 )
125 );
126 $dependencyResolver = $this->getAccessibleMock('\TYPO3\CMS\Core\Package\DependencyResolver', array('dummy'));
127 $dependencyResolver->_call('buildDependencyGraphForPackages', $packages, array_keys($packages));
128 }
129
130 /**
131 * @return array
132 */
133 public function buildDependencyGraphBuildsCorrectGraphDataProvider() {
134 return array(
135 'TYPO3 Flow Packages' => array(
136 array(
137 'TYPO3.Flow' => array(
138 'state' => 'active',
139 'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
140 ),
141 'Doctrine.ORM' => array(
142 'state' => 'active',
143 'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
144 ),
145 'Doctrine.Common' => array(
146 'state' => 'active',
147 'dependencies' => array()
148 ),
149 'Doctrine.DBAL' => array(
150 'state' => 'active',
151 'dependencies' => array('Doctrine.Common')
152 ),
153 'Symfony.Component.Yaml' => array(
154 'state' => 'active',
155 'dependencies' => array()
156 ),
157 ),
158 array(
159 'Doctrine.Common'
160 ),
161 array(
162 'TYPO3.Flow' => array(
163 'TYPO3.Flow' => FALSE,
164 'Doctrine.ORM' => TRUE,
165 'Doctrine.Common' => TRUE,
166 'Doctrine.DBAL' => TRUE,
167 'Symfony.Component.Yaml' => TRUE,
168 ),
169 'Doctrine.ORM' => array(
170 'TYPO3.Flow' => FALSE,
171 'Doctrine.ORM' => FALSE,
172 'Doctrine.Common' => TRUE,
173 'Doctrine.DBAL' => TRUE,
174 'Symfony.Component.Yaml' => FALSE,
175 ),
176 'Doctrine.Common' => array(
177 'TYPO3.Flow' => FALSE,
178 'Doctrine.ORM' => FALSE,
179 'Doctrine.Common' => FALSE,
180 'Doctrine.DBAL' => FALSE,
181 'Symfony.Component.Yaml' => FALSE,
182 ),
183 'Doctrine.DBAL' => array(
184 'TYPO3.Flow' => FALSE,
185 'Doctrine.ORM' => FALSE,
186 'Doctrine.Common' => TRUE,
187 'Doctrine.DBAL' => FALSE,
188 'Symfony.Component.Yaml' => FALSE,
189 ),
190 'Symfony.Component.Yaml' => array(
191 'TYPO3.Flow' => FALSE,
192 'Doctrine.ORM' => FALSE,
193 'Doctrine.Common' => TRUE,
194 'Doctrine.DBAL' => FALSE,
195 'Symfony.Component.Yaml' => FALSE,
196 ),
197 ),
198 ),
199 'TYPO3 CMS Extensions' => array(
200 array(
201 'core' => array(
202 'state' => 'active',
203 'dependencies' => array(),
204 ),
205 'setup' => array (
206 'state' => 'active',
207 'dependencies' => array('core'),
208 ),
209 'openid' => array(
210 'state' => 'active',
211 'dependencies' => array('core', 'setup')
212 ),
213 'news' => array (
214 'state' => 'active',
215 'dependencies' => array('extbase'),
216 ),
217 'extbase' => array (
218 'state' => 'active',
219 'dependencies' => array('core'),
220 ),
221 'pt_extbase' => array (
222 'state' => 'active',
223 'dependencies' => array('extbase'),
224 ),
225 'foo' => array (
226 'state' => 'active',
227 'dependencies' => array(),
228 ),
229 ),
230 array(
231 'core', 'setup', 'openid', 'extbase'
232 ),
233 array(
234 'core' => array(
235 'core' => FALSE,
236 'setup' => FALSE,
237 'openid' => FALSE,
238 'news' => FALSE,
239 'extbase' => FALSE,
240 'pt_extbase' => FALSE,
241 'foo' => FALSE
242 ),
243 'setup' => array(
244 'core' => TRUE,
245 'setup' => FALSE,
246 'openid' => FALSE,
247 'news' => FALSE,
248 'extbase' => FALSE,
249 'pt_extbase' => FALSE,
250 'foo' => FALSE
251 ),
252 'openid' => array (
253 'core' => TRUE,
254 'setup' => TRUE,
255 'openid' => FALSE,
256 'news' => FALSE,
257 'extbase' => FALSE,
258 'pt_extbase' => FALSE,
259 'foo' => FALSE
260 ),
261 'news' => array (
262 'core' => FALSE,
263 'setup' => FALSE,
264 'openid' => TRUE,
265 'news' => FALSE,
266 'extbase' => TRUE,
267 'pt_extbase' => FALSE,
268 'foo' => FALSE
269 ),
270 'extbase' => array (
271 'core' => TRUE,
272 'setup' => FALSE,
273 'openid' => FALSE,
274 'news' => FALSE,
275 'extbase' => FALSE,
276 'pt_extbase' => FALSE,
277 'foo' => FALSE
278 ),
279 'pt_extbase' => array(
280 'core' => FALSE,
281 'setup' => FALSE,
282 'openid' => TRUE,
283 'news' => FALSE,
284 'extbase' => TRUE,
285 'pt_extbase' => FALSE,
286 'foo' => FALSE
287 ),
288 'foo' => array(
289 'core' => FALSE,
290 'setup' => FALSE,
291 'openid' => TRUE,
292 'news' => FALSE,
293 'extbase' => TRUE,
294 'pt_extbase' => FALSE,
295 'foo' => FALSE
296 ),
297 ),
298 ),
299 'Dummy Packages' => array(
300 array(
301 'A' => array(
302 'state' => 'active',
303 'dependencies' => array('B', 'D', 'C'),
304 ),
305 'B' => array(
306 'state' => 'active',
307 'dependencies' => array()
308 ),
309 'C' => array(
310 'state' => 'active',
311 'dependencies' => array('E')
312 ),
313 'D' => array (
314 'state' => 'active',
315 'dependencies' => array('E'),
316 ),
317 'E' => array (
318 'state' => 'active',
319 'dependencies' => array(),
320 ),
321 'F' => array (
322 'state' => 'active',
323 'dependencies' => array(),
324 ),
325 ),
326 array(
327 'B', 'C', 'E'
328 ),
329 array(
330 'A' => array(
331 'A' => FALSE,
332 'B' => TRUE,
333 'C' => TRUE,
334 'D' => TRUE,
335 'E' => FALSE,
336 'F' => FALSE,
337 ),
338 'B' => array(
339 'A' => FALSE,
340 'B' => FALSE,
341 'C' => FALSE,
342 'D' => FALSE,
343 'E' => FALSE,
344 'F' => FALSE,
345 ),
346 'C' => array(
347 'A' => FALSE,
348 'B' => FALSE,
349 'C' => FALSE,
350 'D' => FALSE,
351 'E' => TRUE,
352 'F' => FALSE,
353 ),
354 'D' => array (
355 'A' => FALSE,
356 'B' => TRUE,
357 'C' => TRUE,
358 'D' => FALSE,
359 'E' => FALSE,
360 'F' => FALSE,
361 ),
362 'E' => array (
363 'A' => FALSE,
364 'B' => FALSE,
365 'C' => FALSE,
366 'D' => FALSE,
367 'E' => FALSE,
368 'F' => FALSE,
369 ),
370 'F' => array (
371 'A' => FALSE,
372 'B' => TRUE,
373 'C' => TRUE,
374 'D' => FALSE,
375 'E' => FALSE,
376 'F' => FALSE,
377 ),
378 ),
379 ),
380 );
381 }
382
383 /**
384 * @return array
385 */
386 public function packageSortingDataProvider() {
387 return array(
388 'TYPO3 Flow Packages' => array(
389 array(
390 'TYPO3.Flow' => array(
391 'state' => 'active',
392 'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
393 ),
394 'Doctrine.ORM' => array(
395 'state' => 'active',
396 'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
397 ),
398 'Doctrine.Common' => array(
399 'state' => 'active',
400 'dependencies' => array()
401 ),
402 'Doctrine.DBAL' => array(
403 'state' => 'active',
404 'dependencies' => array('Doctrine.Common')
405 ),
406 'Symfony.Component.Yaml' => array(
407 'state' => 'active',
408 'dependencies' => array()
409 ),
410 ),
411 array(
412 'Doctrine.Common'
413 ),
414 array(
415 'Doctrine.Common' => array(
416 'state' => 'active',
417 'dependencies' => array()
418 ),
419 'Doctrine.DBAL' => array(
420 'state' => 'active',
421 'dependencies' => array('Doctrine.Common')
422 ),
423 'Doctrine.ORM' => array(
424 'state' => 'active',
425 'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
426 ),
427 'Symfony.Component.Yaml' => array(
428 'state' => 'active',
429 'dependencies' => array()
430 ),
431 'TYPO3.Flow' => array(
432 'state' => 'active',
433 'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
434 ),
435 ),
436 ),
437 'TYPO3 CMS Extensions' => array(
438 array(
439 'core' => array(
440 'state' => 'active',
441 'dependencies' => array(),
442 ),
443 'setup' => array (
444 'state' => 'active',
445 'dependencies' => array('core'),
446 ),
447 'openid' => array(
448 'state' => 'active',
449 'dependencies' => array('core', 'setup')
450 ),
451 'news' => array (
452 'state' => 'active',
453 'dependencies' => array('extbase'),
454 ),
455 'extbase' => array (
456 'state' => 'active',
457 'dependencies' => array('core'),
458 ),
459 'pt_extbase' => array (
460 'state' => 'active',
461 'dependencies' => array('extbase'),
462 ),
463 'foo' => array (
464 'state' => 'active',
465 'dependencies' => array(),
466 ),
467 ),
468 array(
469 'core', 'setup', 'openid', 'extbase'
470 ),
471 array(
472 'core' => array(
473 'state' => 'active',
474 'dependencies' => array(),
475 ),
476 'setup' => array (
477 'state' => 'active',
478 'dependencies' => array('core'),
479 ),
480 'openid' => array(
481 'state' => 'active',
482 'dependencies' => array('core', 'setup')
483 ),
484 'extbase' => array (
485 'state' => 'active',
486 'dependencies' => array('core'),
487 ),
488 'foo' => array (
489 'state' => 'active',
490 'dependencies' => array(),
491 ),
492 'pt_extbase' => array (
493 'state' => 'active',
494 'dependencies' => array('extbase'),
495 ),
496 'news' => array (
497 'state' => 'active',
498 'dependencies' => array('extbase'),
499 ),
500 ),
501 ),
502 'Dummy Packages' => array(
503 array(
504 'A' => array(
505 'state' => 'active',
506 'dependencies' => array('B', 'D', 'C'),
507 ),
508 'B' => array(
509 'state' => 'active',
510 'dependencies' => array()
511 ),
512 'C' => array(
513 'state' => 'active',
514 'dependencies' => array('E')
515 ),
516 'D' => array (
517 'state' => 'active',
518 'dependencies' => array('E'),
519 ),
520 'E' => array (
521 'state' => 'active',
522 'dependencies' => array(),
523 ),
524 'F' => array (
525 'state' => 'active',
526 'dependencies' => array(),
527 ),
528 ),
529 array(
530 'B', 'C', 'E'
531 ),
532 array(
533 'B' => array(
534 'state' => 'active',
535 'dependencies' => array(),
536 ),
537 'E' => array (
538 'state' => 'active',
539 'dependencies' => array(),
540 ),
541 'C' => array (
542 'state' => 'active',
543 'dependencies' => array('E'),
544 ),
545 'F' => array (
546 'state' => 'active',
547 'dependencies' => array(),
548 ),
549 'D' => array(
550 'state' => 'active',
551 'dependencies' => array('E'),
552 ),
553 'A' => array(
554 'state' => 'active',
555 'dependencies' => array('B', 'D', 'C'),
556 ),
557 ),
558 ),
559 );
560 }
561
562 /**
563 * @return array
564 */
565 public function buildDependencyGraphForPackagesBuildsCorrectGraphDataProvider() {
566 return array(
567 'TYPO3 Flow Packages' => array(
568 array(
569 'TYPO3.Flow' => array(
570 'state' => 'active',
571 'dependencies' => array('Symfony.Component.Yaml', 'Doctrine.Common', 'Doctrine.DBAL', 'Doctrine.ORM')
572 ),
573 'Doctrine.ORM' => array(
574 'state' => 'active',
575 'dependencies' => array('Doctrine.Common', 'Doctrine.DBAL')
576 ),
577 'Doctrine.Common' => array(
578 'state' => 'active',
579 'dependencies' => array()
580 ),
581 'Doctrine.DBAL' => array(
582 'state' => 'active',
583 'dependencies' => array('Doctrine.Common')
584 ),
585 'Symfony.Component.Yaml' => array(
586 'state' => 'active',
587 'dependencies' => array()
588 ),
589 ),
590 array(
591 'TYPO3.Flow' => array(
592 'TYPO3.Flow' => FALSE,
593 'Doctrine.ORM' => TRUE,
594 'Doctrine.Common' => TRUE,
595 'Doctrine.DBAL' => TRUE,
596 'Symfony.Component.Yaml' => TRUE,
597 ),
598 'Doctrine.ORM' => array(
599 'TYPO3.Flow' => FALSE,
600 'Doctrine.ORM' => FALSE,
601 'Doctrine.Common' => TRUE,
602 'Doctrine.DBAL' => TRUE,
603 'Symfony.Component.Yaml' => FALSE,
604 ),
605 'Doctrine.Common' => array(
606 'TYPO3.Flow' => FALSE,
607 'Doctrine.ORM' => FALSE,
608 'Doctrine.Common' => FALSE,
609 'Doctrine.DBAL' => FALSE,
610 'Symfony.Component.Yaml' => FALSE,
611 ),
612 'Doctrine.DBAL' => array(
613 'TYPO3.Flow' => FALSE,
614 'Doctrine.ORM' => FALSE,
615 'Doctrine.Common' => TRUE,
616 'Doctrine.DBAL' => FALSE,
617 'Symfony.Component.Yaml' => FALSE,
618 ),
619 'Symfony.Component.Yaml' => array(
620 'TYPO3.Flow' => FALSE,
621 'Doctrine.ORM' => FALSE,
622 'Doctrine.Common' => FALSE,
623 'Doctrine.DBAL' => FALSE,
624 'Symfony.Component.Yaml' => FALSE,
625 ),
626 ),
627 ),
628 'TYPO3 CMS Extensions' => array(
629 array(
630 'core' => array(
631 'state' => 'active',
632 'dependencies' => array(),
633 ),
634 'openid' => array(
635 'state' => 'active',
636 'dependencies' => array('core', 'setup')
637 ),
638 'scheduler' => array (
639 'state' => 'active',
640 'dependencies' => array('core'),
641 ),
642 'setup' => array (
643 'state' => 'active',
644 'dependencies' => array('core'),
645 ),
646 'sv' => array (
647 'state' => 'active',
648 'dependencies' => array('core'),
649 ),
650 ),
651 array(
652 'core' => array(
653 'core' => FALSE,
654 'setup' => FALSE,
655 'sv' => FALSE,
656 'scheduler' => FALSE,
657 'openid' => FALSE,
658 ),
659 'openid' => array(
660 'core' => TRUE,
661 'setup' => TRUE,
662 'sv' => FALSE,
663 'scheduler' => FALSE,
664 'openid' => FALSE,
665 ),
666 'scheduler' => array (
667 'core' => TRUE,
668 'setup' => FALSE,
669 'sv' => FALSE,
670 'scheduler' => FALSE,
671 'openid' => FALSE,
672 ),
673 'setup' => array (
674 'core' => TRUE,
675 'setup' => FALSE,
676 'sv' => FALSE,
677 'scheduler' => FALSE,
678 'openid' => FALSE,
679 ),
680 'sv' => array (
681 'core' => TRUE,
682 'setup' => FALSE,
683 'sv' => FALSE,
684 'scheduler' => FALSE,
685 'openid' => FALSE,
686 ),
687 ),
688 ),
689 'Dummy Packages' => array(
690 array(
691 'A' => array(
692 'state' => 'active',
693 'dependencies' => array('B', 'D', 'C'),
694 ),
695 'B' => array(
696 'state' => 'active',
697 'dependencies' => array()
698 ),
699 'C' => array(
700 'state' => 'active',
701 'dependencies' => array('E')
702 ),
703 'D' => array (
704 'state' => 'active',
705 'dependencies' => array('E'),
706 ),
707 'E' => array (
708 'state' => 'active',
709 'dependencies' => array(),
710 ),
711 'F' => array (
712 'state' => 'active',
713 'dependencies' => array(),
714 ),
715 ),
716 array(
717 'A' => array(
718 'A' => FALSE,
719 'B' => TRUE,
720 'C' => TRUE,
721 'D' => TRUE,
722 'E' => FALSE,
723 'F' => FALSE,
724 ),
725 'B' => array(
726 'A' => FALSE,
727 'B' => FALSE,
728 'C' => FALSE,
729 'D' => FALSE,
730 'E' => FALSE,
731 'F' => FALSE,
732 ),
733 'C' => array(
734 'A' => FALSE,
735 'B' => FALSE,
736 'C' => FALSE,
737 'D' => FALSE,
738 'E' => TRUE,
739 'F' => FALSE,
740 ),
741 'D' => array (
742 'A' => FALSE,
743 'B' => FALSE,
744 'C' => FALSE,
745 'D' => FALSE,
746 'E' => TRUE,
747 'F' => FALSE,
748 ),
749 'E' => array (
750 'A' => FALSE,
751 'B' => FALSE,
752 'C' => FALSE,
753 'D' => FALSE,
754 'E' => FALSE,
755 'F' => FALSE,
756 ),
757 'F' => array (
758 'A' => FALSE,
759 'B' => FALSE,
760 'C' => FALSE,
761 'D' => FALSE,
762 'E' => FALSE,
763 'F' => FALSE,
764 ),
765 ),
766 ),
767 );
768 }
769
770 }