f22419f985c046df770f794f1d4a4f683743ae36
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Extension / ThemeHandlerTest.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\Tests\Core\Extension\ThemeHandlerTest.
6  */
7
8 namespace Drupal\Tests\Core\Extension;
9
10 use Drupal\Core\Extension\Extension;
11 use Drupal\Core\Extension\InfoParser;
12 use Drupal\Core\Extension\ThemeHandler;
13 use Drupal\Core\KeyValueStore\KeyValueMemoryFactory;
14 use Drupal\Core\State\State;
15 use Drupal\Tests\UnitTestCase;
16
17 /**
18  * @coversDefaultClass \Drupal\Core\Extension\ThemeHandler
19  * @group Extension
20  */
21 class ThemeHandlerTest extends UnitTestCase {
22
23   /**
24    * The mocked info parser.
25    *
26    * @var \Drupal\Core\Extension\InfoParserInterface|\PHPUnit_Framework_MockObject_MockObject
27    */
28   protected $infoParser;
29
30   /**
31    * The mocked state backend.
32    *
33    * @var \Drupal\Core\State\StateInterface|\PHPUnit_Framework_MockObject_MockObject
34    */
35   protected $state;
36
37   /**
38    * The mocked config factory.
39    *
40    * @var \Drupal\Core\Config\ConfigFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
41    */
42   protected $configFactory;
43
44   /**
45    * The mocked module handler.
46    *
47    * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
48    */
49   protected $moduleHandler;
50
51   /**
52    * The extension discovery.
53    *
54    * @var \Drupal\Core\Extension\ExtensionDiscovery|\PHPUnit_Framework_MockObject_MockObject
55    */
56   protected $extensionDiscovery;
57
58   /**
59    * The tested theme handler.
60    *
61    * @var \Drupal\Core\Extension\ThemeHandler|\Drupal\Tests\Core\Extension\StubThemeHandler
62    */
63   protected $themeHandler;
64
65   /**
66    * {@inheritdoc}
67    */
68   protected function setUp() {
69     parent::setUp();
70
71     $this->configFactory = $this->getConfigFactoryStub([
72       'core.extension' => [
73         'module' => [],
74         'theme' => [],
75         'disabled' => [
76           'theme' => [],
77         ],
78       ],
79     ]);
80     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
81     $this->state = new State(new KeyValueMemoryFactory());
82     $this->infoParser = $this->getMock('Drupal\Core\Extension\InfoParserInterface');
83     $this->extensionDiscovery = $this->getMockBuilder('Drupal\Core\Extension\ExtensionDiscovery')
84       ->disableOriginalConstructor()
85       ->getMock();
86     $this->themeHandler = new StubThemeHandler($this->root, $this->configFactory, $this->moduleHandler, $this->state, $this->infoParser, $this->extensionDiscovery);
87
88     $cache_tags_invalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface');
89     $this->getContainerWithCacheTagsInvalidator($cache_tags_invalidator);
90   }
91
92   /**
93    * Tests rebuilding the theme data.
94    *
95    * @see \Drupal\Core\Extension\ThemeHandler::rebuildThemeData()
96    */
97   public function testRebuildThemeData() {
98     $this->extensionDiscovery->expects($this->at(0))
99       ->method('scan')
100       ->with('theme')
101       ->will($this->returnValue([
102         'seven' => new Extension($this->root, 'theme', $this->root . '/core/themes/seven/seven.info.yml', 'seven.theme'),
103       ]));
104     $this->extensionDiscovery->expects($this->at(1))
105       ->method('scan')
106       ->with('theme_engine')
107       ->will($this->returnValue([
108         'twig' => new Extension($this->root, 'theme_engine', $this->root . '/core/themes/engines/twig/twig.info.yml', 'twig.engine'),
109       ]));
110     $this->infoParser->expects($this->once())
111       ->method('parse')
112       ->with($this->root . '/core/themes/seven/seven.info.yml')
113       ->will($this->returnCallback(function ($file) {
114         $info_parser = new InfoParser();
115         return $info_parser->parse($file);
116       }));
117     $this->moduleHandler->expects($this->once())
118       ->method('buildModuleDependencies')
119       ->will($this->returnArgument(0));
120
121     $this->moduleHandler->expects($this->once())
122       ->method('alter');
123
124     $theme_data = $this->themeHandler->rebuildThemeData();
125     $this->assertCount(1, $theme_data);
126     $info = $theme_data['seven'];
127
128     // Ensure some basic properties.
129     $this->assertInstanceOf('Drupal\Core\Extension\Extension', $info);
130     $this->assertEquals('seven', $info->getName());
131     $this->assertEquals($this->root . '/core/themes/seven/seven.info.yml', $info->getPathname());
132     $this->assertEquals($this->root . '/core/themes/seven/seven.theme', $info->getExtensionPathname());
133     $this->assertEquals($this->root . '/core/themes/engines/twig/twig.engine', $info->owner);
134     $this->assertEquals('twig', $info->prefix);
135
136     $this->assertEquals('twig', $info->info['engine']);
137     $this->assertEquals(['seven/global-styling'], $info->info['libraries']);
138   }
139
140   /**
141    * Tests empty libraries in theme.info.yml file.
142    */
143   public function testThemeLibrariesEmpty() {
144     $theme = new Extension($this->root, 'theme', '/core/modules/system/tests/themes/test_theme_libraries_empty', 'test_theme_libraries_empty.info.yml');
145     try {
146       $this->themeHandler->addTheme($theme);
147       $this->assertTrue(TRUE, 'Empty libraries key in theme.info.yml does not cause PHP warning');
148     }
149     catch (\Exception $e) {
150       $this->fail('Empty libraries key in theme.info.yml causes PHP warning.');
151     }
152   }
153
154   /**
155    * Tests rebuild the theme data with theme parents.
156    */
157   public function testRebuildThemeDataWithThemeParents() {
158     $this->extensionDiscovery->expects($this->at(0))
159       ->method('scan')
160       ->with('theme')
161       ->will($this->returnValue([
162         'test_subtheme' => new Extension($this->root, 'theme', $this->root . '/core/modules/system/tests/themes/test_subtheme/test_subtheme.info.yml', 'test_subtheme.info.yml'),
163         'test_basetheme' => new Extension($this->root, 'theme', $this->root . '/core/modules/system/tests/themes/test_basetheme/test_basetheme.info.yml', 'test_basetheme.info.yml'),
164       ]));
165     $this->extensionDiscovery->expects($this->at(1))
166       ->method('scan')
167       ->with('theme_engine')
168       ->will($this->returnValue([
169         'twig' => new Extension($this->root, 'theme_engine', $this->root . '/core/themes/engines/twig/twig.info.yml', 'twig.engine'),
170       ]));
171     $this->infoParser->expects($this->at(0))
172       ->method('parse')
173       ->with($this->root . '/core/modules/system/tests/themes/test_subtheme/test_subtheme.info.yml')
174       ->will($this->returnCallback(function ($file) {
175         $info_parser = new InfoParser();
176         return $info_parser->parse($file);
177       }));
178     $this->infoParser->expects($this->at(1))
179       ->method('parse')
180       ->with($this->root . '/core/modules/system/tests/themes/test_basetheme/test_basetheme.info.yml')
181       ->will($this->returnCallback(function ($file) {
182         $info_parser = new InfoParser();
183         return $info_parser->parse($file);
184       }));
185     $this->moduleHandler->expects($this->once())
186       ->method('buildModuleDependencies')
187       ->will($this->returnArgument(0));
188
189     $theme_data = $this->themeHandler->rebuildThemeData();
190     $this->assertCount(2, $theme_data);
191
192     $info_basetheme = $theme_data['test_basetheme'];
193     $info_subtheme = $theme_data['test_subtheme'];
194
195     // Ensure some basic properties.
196     $this->assertInstanceOf('Drupal\Core\Extension\Extension', $info_basetheme);
197     $this->assertEquals('test_basetheme', $info_basetheme->getName());
198     $this->assertInstanceOf('Drupal\Core\Extension\Extension', $info_subtheme);
199     $this->assertEquals('test_subtheme', $info_subtheme->getName());
200
201     // Test the parent/child-theme properties.
202     $info_subtheme->info['base theme'] = 'test_basetheme';
203     $info_basetheme->sub_themes = ['test_subtheme'];
204
205     $this->assertEquals($this->root . '/core/themes/engines/twig/twig.engine', $info_basetheme->owner);
206     $this->assertEquals('twig', $info_basetheme->prefix);
207     $this->assertEquals($this->root . '/core/themes/engines/twig/twig.engine', $info_subtheme->owner);
208     $this->assertEquals('twig', $info_subtheme->prefix);
209   }
210
211   /**
212    * Tests getting the base themes for a set a defines themes.
213    *
214    * @param array $themes
215    *   An array of available themes, keyed by the theme name.
216    * @param string $theme
217    *   The theme name to find all its base themes.
218    * @param array $expected
219    *   The expected base themes.
220    *
221    * @dataProvider providerTestGetBaseThemes
222    */
223   public function testGetBaseThemes(array $themes, $theme, array $expected) {
224     $base_themes = $this->themeHandler->getBaseThemes($themes, $theme);
225     $this->assertEquals($expected, $base_themes);
226   }
227
228   /**
229    * Provides test data for testGetBaseThemes.
230    *
231    * @return array
232    *   An array of theme test data.
233    */
234   public function providerTestGetBaseThemes() {
235     $data = [];
236
237     // Tests a theme without any base theme.
238     $themes = [];
239     $themes['test_1'] = (object) [
240       'name' => 'test_1',
241       'info' => [
242         'name' => 'test_1',
243       ],
244     ];
245     $data[] = [$themes, 'test_1', []];
246
247     // Tests a theme with a non existing base theme.
248     $themes = [];
249     $themes['test_1'] = (object) [
250       'name' => 'test_1',
251       'info' => [
252         'name' => 'test_1',
253         'base theme' => 'test_2',
254       ],
255     ];
256     $data[] = [$themes, 'test_1', ['test_2' => NULL]];
257
258     // Tests a theme with a single existing base theme.
259     $themes = [];
260     $themes['test_1'] = (object) [
261       'name' => 'test_1',
262       'info' => [
263         'name' => 'test_1',
264         'base theme' => 'test_2',
265       ],
266     ];
267     $themes['test_2'] = (object) [
268       'name' => 'test_2',
269       'info' => [
270         'name' => 'test_2',
271       ],
272     ];
273     $data[] = [$themes, 'test_1', ['test_2' => 'test_2']];
274
275     // Tests a theme with multiple base themes.
276     $themes = [];
277     $themes['test_1'] = (object) [
278       'name' => 'test_1',
279       'info' => [
280         'name' => 'test_1',
281         'base theme' => 'test_2',
282       ],
283     ];
284     $themes['test_2'] = (object) [
285       'name' => 'test_2',
286       'info' => [
287         'name' => 'test_2',
288         'base theme' => 'test_3',
289       ],
290     ];
291     $themes['test_3'] = (object) [
292       'name' => 'test_3',
293       'info' => [
294         'name' => 'test_3',
295       ],
296     ];
297     $data[] = [
298       $themes,
299       'test_1',
300       ['test_2' => 'test_2', 'test_3' => 'test_3'],
301     ];
302
303     return $data;
304   }
305
306 }
307
308 /**
309  * Extends the default theme handler to mock some drupal_ methods.
310  */
311 class StubThemeHandler extends ThemeHandler {
312
313   /**
314    * Whether the CSS cache was cleared.
315    *
316    * @var bool
317    */
318   protected $clearedCssCache;
319
320   /**
321    * Whether the registry should be rebuilt.
322    *
323    * @var bool
324    */
325   protected $registryRebuild;
326
327   /**
328    * A list of themes keyed by name.
329    *
330    * @var array
331    */
332   protected $systemList;
333
334   /**
335    * {@inheritdoc}
336    */
337   protected function clearCssCache() {
338     $this->clearedCssCache = TRUE;
339   }
340
341   /**
342    * {@inheritdoc}
343    */
344   protected function themeRegistryRebuild() {
345     $this->registryRebuild = TRUE;
346   }
347
348   /**
349    * {@inheritdoc}
350    */
351   protected function systemThemeList() {
352     return $this->systemList;
353   }
354
355   /**
356    * {@inheritdoc}
357    */
358   protected function systemListReset() {
359   }
360
361 }
362
363 if (!defined('DRUPAL_EXTENSION_NAME_MAX_LENGTH')) {
364   define('DRUPAL_EXTENSION_NAME_MAX_LENGTH', 50);
365 }
366 if (!defined('DRUPAL_PHP_FUNCTION_PATTERN')) {
367   define('DRUPAL_PHP_FUNCTION_PATTERN', '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*');
368 }
369 if (!defined('DRUPAL_MINIMUM_PHP')) {
370   define('DRUPAL_MINIMUM_PHP', '5.3.10');
371 }