Passed
Push — 4 ( 766816...36b106 )
by Maxime
06:12
created

testFindTemplateWithCacheHit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Core\Tests\Manifest;
4
5
use Psr\SimpleCache\CacheInterface;
6
use SilverStripe\Control\Director;
7
use SilverStripe\Core\Manifest\ModuleLoader;
8
use SilverStripe\View\ThemeResourceLoader;
9
use SilverStripe\View\ThemeManifest;
10
use SilverStripe\Dev\SapphireTest;
11
use SilverStripe\Core\Manifest\ModuleManifest;
12
13
/**
14
 * Tests for the {@link TemplateLoader} class.
15
 */
16
class ThemeResourceLoaderTest extends SapphireTest
17
{
18
    /**
19
     * @var string
20
     */
21
    private $base;
22
23
    /**
24
     * @var ThemeManifest
25
     */
26
    private $manifest;
27
28
    /**
29
     * @var ThemeResourceLoader
30
     */
31
    private $loader;
32
33
    /**
34
     * Set up manifest before each test
35
     */
36
    protected function setUp()
37
    {
38
        parent::setUp();
39
40
        // Fake project root
41
        $this->base = dirname(__FILE__) . '/fixtures/templatemanifest';
42
        Director::config()->set('alternate_base_folder', $this->base);
43
        ModuleManifest::config()->set('module_priority', ['$project', '$other_modules']);
44
        ModuleManifest::config()->set('project', 'myproject');
45
46
        $moduleManifest = new ModuleManifest($this->base);
47
        $moduleManifest->init();
48
        $moduleManifest->sort();
49
        ModuleLoader::inst()->pushManifest($moduleManifest);
50
51
        // New ThemeManifest for that root
52
        $this->manifest = new ThemeManifest($this->base);
53
        $this->manifest->setProject('myproject');
54
        $this->manifest->init();
55
        // New Loader for that root
56
        $this->loader = new ThemeResourceLoader($this->base);
57
        $this->loader->addSet('$default', $this->manifest);
58
59
        // Ensure the cache is flushed between tests
60
        ThemeResourceLoader::flush();
61
    }
62
63
    protected function tearDown()
64
    {
65
        ModuleLoader::inst()->popManifest();
66
        parent::tearDown();
67
    }
68
69
    /**
70
     * Test that 'main' and 'Layout' templates are loaded from module
71
     */
72
    public function testFindTemplatesInModule()
73
    {
74
        $this->assertEquals(
75
            "$this->base/module/templates/Page.ss",
76
            $this->loader->findTemplate('Page', ['$default'])
77
        );
78
79
        $this->assertEquals(
80
            "$this->base/module/templates/Layout/Page.ss",
81
            $this->loader->findTemplate(['type' => 'Layout', 'Page'], ['$default'])
82
        );
83
    }
84
85
    public function testFindNestedThemeTemplates()
86
    {
87
        // Without including the theme this template cannot be found
88
        $this->assertEquals(null, $this->loader->findTemplate('NestedThemePage', ['$default']));
89
90
        // With a nested theme available then it is available
91
        $this->assertEquals(
92
            "{$this->base}/module/themes/subtheme/templates/NestedThemePage.ss",
93
            $this->loader->findTemplate(
94
                'NestedThemePage',
95
                [
96
                    'silverstripe/module:subtheme',
97
                    '$default'
98
                ]
99
            )
100
        );
101
102
        // Can also be found if excluding $default theme
103
        $this->assertEquals(
104
            "{$this->base}/module/themes/subtheme/templates/NestedThemePage.ss",
105
            $this->loader->findTemplate(
106
                'NestedThemePage',
107
                [
108
                    'silverstripe/module:subtheme',
109
                ]
110
            )
111
        );
112
    }
113
114
    public function testFindTemplateByType()
115
    {
116
        // Test that "type" is respected properly
117
        $this->assertEquals(
118
            "{$this->base}/module/templates/MyNamespace/Layout/MyClass.ss",
119
            $this->loader->findTemplate(
120
                [
121
                    [
122
                        'type' => 'Layout',
123
                        'MyNamespace/NonExistantTemplate'
124
                    ],
125
                    [
126
                        'type' => 'Layout',
127
                        'MyNamespace/MyClass'
128
                    ],
129
                    'MyNamespace/MyClass'
130
                ],
131
                [
132
                    'silverstripe/module:subtheme',
133
                    'theme',
134
                    '$default',
135
                ]
136
            )
137
        );
138
139
        // Non-typed template can be found even if looking for typed theme at a lower priority
140
        $this->assertEquals(
141
            "{$this->base}/module/templates/MyNamespace/MyClass.ss",
142
            $this->loader->findTemplate(
143
                [
144
                    [
145
                        'type' => 'Layout',
146
                        'MyNamespace/NonExistantTemplate'
147
                    ],
148
                    'MyNamespace/MyClass',
149
                    [
150
                        'type' => 'Layout',
151
                        'MyNamespace/MyClass'
152
                    ]
153
                ],
154
                [
155
                    'silverstripe/module',
156
                    'theme',
157
                    '$default',
158
                ]
159
            )
160
        );
161
    }
162
163
    public function testFindTemplatesByPath()
164
    {
165
        // Items given as full paths are returned directly
166
        $this->assertEquals(
167
            "$this->base/themes/theme/templates/Page.ss",
168
            $this->loader->findTemplate("$this->base/themes/theme/templates/Page.ss", ['theme'])
169
        );
170
171
        $this->assertEquals(
172
            "$this->base/themes/theme/templates/Page.ss",
173
            $this->loader->findTemplate(
174
                [
175
                    "$this->base/themes/theme/templates/Page.ss",
176
                    "Page"
177
                ],
178
                ['theme']
179
            )
180
        );
181
182
        // Ensure checks for file_exists
183
        $this->assertEquals(
184
            "$this->base/themes/theme/templates/Page.ss",
185
            $this->loader->findTemplate(
186
                [
187
                    "$this->base/themes/theme/templates/NotAPage.ss",
188
                    "$this->base/themes/theme/templates/Page.ss",
189
                ],
190
                ['theme']
191
            )
192
        );
193
    }
194
195
    /**
196
     * Test that 'main' and 'Layout' templates are loaded from set theme
197
     */
198
    public function testFindTemplatesInTheme()
199
    {
200
        $this->assertEquals(
201
            "$this->base/themes/theme/templates/Page.ss",
202
            $this->loader->findTemplate('Page', ['theme'])
203
        );
204
205
        $this->assertEquals(
206
            "$this->base/themes/theme/templates/Layout/Page.ss",
207
            $this->loader->findTemplate(['type' => 'Layout', 'Page'], ['theme'])
208
        );
209
    }
210
211
    /**
212
     * Test that 'main' and 'Layout' templates are loaded from project without a set theme
213
     */
214
    public function testFindTemplatesInApplication()
215
    {
216
        // TODO: replace with one that doesn't create temporary files (so bad)
217
        $templates = array(
218
            $this->base . '/myproject/templates/Page.ss',
219
            $this->base . '/myproject/templates/Layout/Page.ss'
220
        );
221
        $this->createTestTemplates($templates);
222
223
        $this->assertEquals(
224
            "$this->base/myproject/templates/Page.ss",
225
            $this->loader->findTemplate('Page', ['$default'])
226
        );
227
228
        $this->assertEquals(
229
            "$this->base/myproject/templates/Layout/Page.ss",
230
            $this->loader->findTemplate(['type' => 'Layout', 'Page'], ['$default'])
231
        );
232
233
        $this->removeTestTemplates($templates);
234
    }
235
236
    /**
237
     * Test that 'main' template is found in theme and 'Layout' is found in module
238
     */
239
    public function testFindTemplatesMainThemeLayoutModule()
240
    {
241
        $this->assertEquals(
242
            "$this->base/themes/theme/templates/CustomThemePage.ss",
243
            $this->loader->findTemplate('CustomThemePage', ['theme', '$default'])
244
        );
245
246
        $this->assertEquals(
247
            "$this->base/module/templates/Layout/CustomThemePage.ss",
248
            $this->loader->findTemplate(['type' => 'Layout', 'CustomThemePage'], ['theme', '$default'])
249
        );
250
    }
251
252
    public function testFindThemedCSS()
253
    {
254
        $this->assertEquals(
255
            "myproject/css/project.css",
256
            $this->loader->findThemedCSS('project', ['$default', 'theme'])
257
        );
258
        $this->assertEquals(
259
            "themes/theme/css/project.css",
260
            $this->loader->findThemedCSS('project', ['theme', '$default'])
261
        );
262
        $this->assertEmpty(
263
            $this->loader->findThemedCSS('nofile', ['theme', '$default'])
264
        );
265
        $this->assertEquals(
266
            'module/css/content.css',
267
            $this->loader->findThemedCSS('content', ['/module', 'theme'])
268
        );
269
        $this->assertEquals(
270
            'module/css/content.css',
271
            $this->loader->findThemedCSS('content', ['/module', 'theme', '$default'])
272
        );
273
        $this->assertEquals(
274
            'module/css/content.css',
275
            $this->loader->findThemedCSS('content', ['$default', '/module', 'theme'])
276
        );
277
    }
278
279
    public function testFindThemedJavascript()
280
    {
281
        $this->assertEquals(
282
            "myproject/javascript/project.js",
283
            $this->loader->findThemedJavascript('project', ['$default', 'theme'])
284
        );
285
        $this->assertEquals(
286
            "themes/theme/javascript/project.js",
287
            $this->loader->findThemedJavascript('project', ['theme', '$default'])
288
        );
289
        $this->assertEmpty(
290
            $this->loader->findThemedJavascript('nofile', ['theme', '$default'])
291
        );
292
        $this->assertEquals(
293
            'module/javascript/content.js',
294
            $this->loader->findThemedJavascript('content', ['/module', 'theme'])
295
        );
296
        $this->assertEquals(
297
            'module/javascript/content.js',
298
            $this->loader->findThemedJavascript('content', ['/module', 'theme', '$default'])
299
        );
300
        $this->assertEquals(
301
            'module/javascript/content.js',
302
            $this->loader->findThemedJavascript('content', ['$default', '/module', 'theme'])
303
        );
304
    }
305
306
    protected function createTestTemplates($templates)
307
    {
308
        foreach ($templates as $template) {
309
            file_put_contents($template, '');
310
        }
311
    }
312
313
    protected function removeTestTemplates($templates)
314
    {
315
        foreach ($templates as $template) {
316
            unlink($template);
317
        }
318
    }
319
320
    public function providerTestGetPath()
321
    {
322
        return [
323
            // Legacy theme
324
            [
325
                'theme',
326
                'themes/theme',
327
            ],
328
            // Module themes
329
            [
330
                'silverstripe/vendormodule:vendortheme',
331
                'vendor/silverstripe/vendormodule/themes/vendortheme',
332
            ],
333
            [
334
                'module:subtheme',
335
                'module/themes/subtheme',
336
            ],
337
            // Module absolute paths
338
            [
339
                'silverstripe/vendormodule:/themes/vendortheme',
340
                'vendor/silverstripe/vendormodule/themes/vendortheme',
341
            ],
342
            [
343
                'module:/themes/subtheme',
344
                'module/themes/subtheme',
345
            ],
346
            // Module root directory
347
            [
348
                'silverstripe/vendormodule:/',
349
                'vendor/silverstripe/vendormodule',
350
            ],
351
            [
352
                'silverstripe/vendormodule:',
353
                'vendor/silverstripe/vendormodule',
354
            ],
355
            [
356
                'silverstripe/vendormodule',
357
                'vendor/silverstripe/vendormodule',
358
            ],
359
            [
360
                'module:',
361
                'module',
362
            ],
363
            // Absolute paths
364
            [
365
                '/vendor/silverstripe/vendormodule/themes/vendortheme',
366
                'vendor/silverstripe/vendormodule/themes/vendortheme',
367
            ],
368
            [
369
                '/module/themes/subtheme',
370
                'module/themes/subtheme'
371
            ]
372
        ];
373
    }
374
375
    /**
376
     * @dataProvider providerTestGetPath
377
     * @param string $name Theme identifier
378
     * @param string $path Path to theme
379
     */
380
    public function testGetPath($name, $path)
381
    {
382
        $this->assertEquals($path, $this->loader->getPath($name));
383
    }
384
385
    public function testFindTemplateWithCacheMiss()
386
    {
387
        $mockCache = $this->createMock(CacheInterface::class);
388
        $mockCache->expects($this->once())->method('has')->willReturn(false);
389
        $mockCache->expects($this->never())->method('get');
390
        $mockCache->expects($this->once())->method('set');
391
392
        $loader = new ThemeResourceLoader();
393
        $loader->setCache($mockCache);
394
        $loader->findTemplate('Page', ['$default']);
395
    }
396
397
    public function testFindTemplateWithCacheHit()
398
    {
399
        $mockCache = $this->createMock(CacheInterface::class);
400
        $mockCache->expects($this->once())->method('has')->willReturn(true);
401
        $mockCache->expects($this->never())->method('set');
402
        $mockCache->expects($this->once())->method('get')->willReturn('mock_template.ss');
403
404
        $loader = new ThemeResourceLoader();
405
        $loader->setCache($mockCache);
406
        $this->assertSame('mock_template.ss', $loader->findTemplate('Page', ['$default']));
407
    }
408
}
409