1<?php
2
3namespace Drupal\Tests\Core\Asset;
4
5use Drupal\Core\Asset\LibraryDependencyResolver;
6use Drupal\Tests\UnitTestCase;
7
8/**
9 * @coversDefaultClass \Drupal\Core\Asset\LibraryDependencyResolver
10 * @group Asset
11 */
12class LibraryDependencyResolverTest extends UnitTestCase {
13
14  /**
15   * The tested library dependency resolver.
16   *
17   * @var \Drupal\Core\Asset\LibraryDependencyResolver
18   */
19  protected $libraryDependencyResolver;
20
21  /**
22   * The mocked library discovery service.
23   *
24   * @var \Drupal\Core\Asset\LibraryDiscoveryInterface|\PHPUnit\Framework\MockObject\MockObject
25   */
26  protected $libraryDiscovery;
27
28  /**
29   * The mocked module handler.
30   *
31   * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
32   */
33  protected $moduleHandler;
34
35  /**
36   * Test library data.
37   *
38   * @var array
39   */
40  protected $libraryData = [
41    'no_deps_a' => ['js' => [], 'css' => []],
42    'no_deps_b' => ['js' => [], 'css' => []],
43    'no_deps_c' => ['js' => [], 'css' => []],
44    'deps_a' => ['js' => [], 'css' => [], 'dependencies' => ['test/no_deps_a']],
45    'deps_b' => ['js' => [], 'css' => [], 'dependencies' => ['test/no_deps_a', 'test/no_deps_b']],
46    'deps_c' => ['js' => [], 'css' => [], 'dependencies' => ['test/no_deps_b', 'test/no_deps_a']],
47    'nested_deps_a' => ['js' => [], 'css' => [], 'dependencies' => ['test/deps_a']],
48    'nested_deps_b' => ['js' => [], 'css' => [], 'dependencies' => ['test/nested_deps_a']],
49    'nested_deps_c' => ['js' => [], 'css' => [], 'dependencies' => ['test/nested_deps_b']],
50  ];
51
52  /**
53   * {@inheritdoc}
54   */
55  protected function setUp() {
56    $this->libraryDiscovery = $this->getMockBuilder('Drupal\Core\Asset\LibraryDiscovery')
57      ->disableOriginalConstructor()
58      ->setMethods(['getLibrariesByExtension'])
59      ->getMock();
60    $this->libraryDiscovery->expects($this->any())
61      ->method('getLibrariesByExtension')
62      ->with('test')
63      ->will($this->returnValue($this->libraryData));
64    $this->libraryDependencyResolver = new LibraryDependencyResolver($this->libraryDiscovery);
65  }
66
67  /**
68   * Provides test data for ::testGetLibrariesWithDependencies().
69   */
70  public function providerTestGetLibrariesWithDependencies() {
71    return [
72      // Empty list of libraries.
73      [[], []],
74      // Without dependencies.
75      [['test/no_deps_a'], ['test/no_deps_a']],
76      [['test/no_deps_a', 'test/no_deps_b'], ['test/no_deps_a', 'test/no_deps_b']],
77      [['test/no_deps_b', 'test/no_deps_a'], ['test/no_deps_b', 'test/no_deps_a']],
78      // Single-level (direct) dependencies.
79      [['test/deps_a'], ['test/no_deps_a', 'test/deps_a']],
80      [['test/deps_b'], ['test/no_deps_a', 'test/no_deps_b', 'test/deps_b']],
81      [['test/deps_c'], ['test/no_deps_b', 'test/no_deps_a', 'test/deps_c']],
82      [['test/deps_a', 'test/deps_b'], ['test/no_deps_a', 'test/deps_a', 'test/no_deps_b', 'test/deps_b']],
83      [['test/deps_a', 'test/deps_c'], ['test/no_deps_a', 'test/deps_a', 'test/no_deps_b', 'test/deps_c']],
84      [['test/deps_a', 'test/deps_b', 'test/deps_c'], ['test/no_deps_a', 'test/deps_a', 'test/no_deps_b', 'test/deps_b', 'test/deps_c']],
85      [['test/deps_b', 'test/deps_a'], ['test/no_deps_a', 'test/no_deps_b', 'test/deps_b', 'test/deps_a']],
86      [['test/deps_b', 'test/deps_c'], ['test/no_deps_a', 'test/no_deps_b', 'test/deps_b', 'test/deps_c']],
87      [['test/deps_c', 'test/deps_b'], ['test/no_deps_b', 'test/no_deps_a', 'test/deps_c', 'test/deps_b']],
88      // Multi-level (indirect) dependencies.
89      [['test/nested_deps_a'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a']],
90      [['test/nested_deps_b'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b']],
91      [['test/nested_deps_c'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c']],
92      [['test/nested_deps_a', 'test/nested_deps_b'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b']],
93      [['test/nested_deps_b', 'test/nested_deps_a'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b']],
94      [['test/nested_deps_a', 'test/nested_deps_c'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c']],
95      [['test/nested_deps_b', 'test/nested_deps_c'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c']],
96      [['test/nested_deps_c', 'test/nested_deps_a'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c']],
97      [['test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c']],
98      [['test/nested_deps_a', 'test/nested_deps_c', 'test/nested_deps_b'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c']],
99      [['test/nested_deps_b', 'test/nested_deps_a', 'test/nested_deps_c'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c']],
100      [['test/nested_deps_b', 'test/nested_deps_c', 'test/nested_deps_a'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c']],
101      [['test/nested_deps_c', 'test/nested_deps_a', 'test/nested_deps_b'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c']],
102      [['test/nested_deps_c', 'test/nested_deps_b', 'test/nested_deps_a'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c']],
103      // Complex dependencies, combining the above, with many intersections.
104      [['test/deps_c', 'test/nested_deps_b'], ['test/no_deps_b', 'test/no_deps_a', 'test/deps_c', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b']],
105      [['test/no_deps_a', 'test/deps_c', 'test/nested_deps_b'], ['test/no_deps_a', 'test/no_deps_b', 'test/deps_c', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b']],
106      [['test/nested_deps_b', 'test/deps_c', 'test/no_deps_c'], ['test/no_deps_a', 'test/deps_a', 'test/nested_deps_a', 'test/nested_deps_b', 'test/no_deps_b', 'test/deps_c', 'test/no_deps_c']],
107    ];
108  }
109
110  /**
111   * @covers ::getLibrariesWithDependencies
112   *
113   * @dataProvider providerTestGetLibrariesWithDependencies
114   */
115  public function testGetLibrariesWithDependencies(array $libraries, array $expected) {
116    $this->assertEquals($expected, $this->libraryDependencyResolver->getLibrariesWithDependencies($libraries));
117  }
118
119  /**
120   * Provides test data for ::testGetMinimalRepresentativeSubset().
121   */
122  public function providerTestGetMinimalRepresentativeSubset() {
123    return [
124      // Empty list of libraries.
125      [[], []],
126      // Without dependencies.
127      [['test/no_deps_a'], ['test/no_deps_a']],
128      [['test/no_deps_a', 'test/no_deps_b'], ['test/no_deps_a', 'test/no_deps_b']],
129      [['test/no_deps_b', 'test/no_deps_a'], ['test/no_deps_b', 'test/no_deps_a']],
130      // Single-level (direct) dependencies.
131      [['test/deps_a'], ['test/deps_a']],
132      [['test/deps_b'], ['test/deps_b']],
133      [['test/deps_c'], ['test/deps_c']],
134      [['test/deps_a', 'test/deps_b'], ['test/deps_a', 'test/deps_b']],
135      [['test/deps_a', 'test/deps_c'], ['test/deps_a', 'test/deps_c']],
136      [['test/deps_a', 'test/deps_b', 'test/deps_c'], ['test/deps_a', 'test/deps_b', 'test/deps_c']],
137      [['test/deps_b', 'test/deps_a'], ['test/deps_b', 'test/deps_a']],
138      [['test/deps_b', 'test/deps_c'], ['test/deps_b', 'test/deps_c']],
139      [['test/deps_c', 'test/deps_b'], ['test/deps_c', 'test/deps_b']],
140      // Multi-level (indirect) dependencies.
141      [['test/nested_deps_a'], ['test/nested_deps_a']],
142      [['test/nested_deps_b'], ['test/nested_deps_b']],
143      [['test/nested_deps_c'], ['test/nested_deps_c']],
144      [['test/nested_deps_a', 'test/nested_deps_b'], ['test/nested_deps_b']],
145      [['test/nested_deps_b', 'test/nested_deps_a'], ['test/nested_deps_b']],
146      [['test/nested_deps_a', 'test/nested_deps_c'], ['test/nested_deps_c']],
147      [['test/nested_deps_b', 'test/nested_deps_c'], ['test/nested_deps_c']],
148      [['test/nested_deps_c', 'test/nested_deps_a'], ['test/nested_deps_c']],
149      [['test/nested_deps_a', 'test/nested_deps_b', 'test/nested_deps_c'], ['test/nested_deps_c']],
150      [['test/nested_deps_a', 'test/nested_deps_c', 'test/nested_deps_b'], ['test/nested_deps_c']],
151      [['test/nested_deps_b', 'test/nested_deps_a', 'test/nested_deps_c'], ['test/nested_deps_c']],
152      [['test/nested_deps_b', 'test/nested_deps_c', 'test/nested_deps_a'], ['test/nested_deps_c']],
153      [['test/nested_deps_c', 'test/nested_deps_a', 'test/nested_deps_b'], ['test/nested_deps_c']],
154      [['test/nested_deps_c', 'test/nested_deps_b', 'test/nested_deps_a'], ['test/nested_deps_c']],
155      // Complex dependencies, combining the above, with many intersections.
156      [['test/deps_c', 'test/nested_deps_b'], ['test/deps_c', 'test/nested_deps_b']],
157      [['test/no_deps_a', 'test/deps_c', 'test/nested_deps_b'], ['test/deps_c', 'test/nested_deps_b']],
158      [['test/nested_deps_b', 'test/deps_c', 'test/no_deps_c'], ['test/nested_deps_b', 'test/deps_c', 'test/no_deps_c']],
159    ];
160  }
161
162  /**
163   * @covers ::getMinimalRepresentativeSubset
164   *
165   * @dataProvider providerTestGetMinimalRepresentativeSubset
166   */
167  public function testGetMinimalRepresentativeSubset(array $libraries, array $expected) {
168    $this->assertEquals($expected, $this->libraryDependencyResolver->getMinimalRepresentativeSubset($libraries));
169  }
170
171  /**
172   * @covers ::getMinimalRepresentativeSubset
173   */
174  public function testGetMinimalRepresentativeSubsetInvalidInput() {
175    $this->expectException(\AssertionError::class);
176    $this->expectExceptionMessage('$libraries can\'t contain duplicate items.');
177    $this->libraryDependencyResolver->getMinimalRepresentativeSubset(['test/no_deps_a', 'test/no_deps_a']);
178  }
179
180}
181