Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core\output;
18
 
19
/**
20
 * Unit tests for the Mustache source loader class.
21
 *
22
 * Unit tests for lib/classes/output/mustache_template_source_loader.php
23
 *
24
 * @package   core
25
 * @copyright 2018 Ryan Wyllie <ryan@moodle.com>
26
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27
 */
28
class mustache_template_source_loader_test extends \advanced_testcase {
29
    /**
30
     * Ensure that stripping comments from templates does not mutilate the template body.
31
     */
11 efrain 32
    public function test_strip_template_comments(): void {
1 efrain 33
 
34
        $templatebody = <<<'TBD'
35
        <h1>{{# str }} pluginname, mod_lemmings {{/ str }}</h1>
36
        <div>{{test}}</div>
37
        <div>{{{unescapedtest}}}</div>
38
        {{#lemmings}}
39
            <div>
40
                <h2>{{name}}</h2>
41
                {{> mod_lemmings/lemmingprofile }}
42
                {{# pix }} t/edit, core, Edit Lemming {{/ pix }}
43
            </div>
44
        {{/lemmings}}
45
        {{^lemmings}}Sorry, no lemmings today{{/lemmings}}
46
        <div id="{{ uniqid }}-tab-container">
47
            {{# tabheader }}
48
                <ul role="tablist" class="nav nav-tabs">
49
                    {{# iconlist }}
50
                        {{# icons }}
51
                            {{> core/pix_icon }}
52
                        {{/ icons }}
53
                    {{/ iconlist }}
54
                </ul>
55
            {{/ tabheader }}
56
            {{# tabbody }}
57
                <div class="tab-content">
58
                    {{# tabcontent }}
59
                        {{# tabs }}
60
                            {{> core/notification_info}}
61
                        {{/ tabs }}
62
                    {{/ tabcontent }}
63
                </div>
64
            {{/ tabbody }}
65
        </div>
66
        {{#js}}
67
            require(['jquery','core/tabs'], function($, tabs) {
68
 
69
                var container = $("#{{ uniqid }}-tab-container");
70
                tabs.create(container);
71
            });
72
        {{/js}}
73
TBD;
74
        $templatewithcomment = <<<TBC
75
        {{!
76
            This file is part of Moodle - http://moodle.org/
77
 
78
            Moodle is free software: you can redistribute it and/or modify
79
            it under the terms of the GNU General Public License as published by
80
            the Free Software Foundation, either version 3 of the License, or
81
            (at your option) any later version.
82
 
83
            Moodle is distributed in the hope that it will be useful,
84
            but WITHOUT ANY WARRANTY; without even the implied warranty of
85
            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
86
            GNU General Public License for more details.
87
 
88
            You should have received a copy of the GNU General Public License
89
            along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
90
        }}
91
        {{!
92
            @template mod_lemmings/lemmings
93
 
94
            Lemmings template.
95
 
96
            The purpose of this template is to render a lot of lemmings.
97
 
98
            Classes required for JS:
99
            * none
100
 
101
            Data attributes required for JS:
102
            * none
103
 
104
            Context variables required for this template:
105
            * attributes Array of name / value pairs.
106
 
107
            Example context (json):
108
            {
109
                "lemmings": [
110
                    { "name": "Lemmy Winks", "age" : 1, "size" : "big" },
111
                    { "name": "Rocky", "age" : 2, "size" : "small" }
112
                ]
113
            }
114
 
115
        }}
116
        $templatebody
117
        {{!
118
            Here's some more comment text
119
            Note, there is no need to test bracketed variables inside comments as gherkin does not support that!
120
            See this issue: https://github.com/mustache/spec/issues/8
121
        }}
122
TBC;
123
 
124
        $loader = new mustache_template_source_loader();
125
        $actual = \phpunit_util::call_internal_method(
126
            $loader,
127
            'strip_template_comments',
128
            [$templatewithcomment],
129
            \core\output\mustache_template_source_loader::class
130
        );
131
        $this->assertEquals(trim($templatebody), trim($actual));
132
    }
133
 
134
    /**
135
     * Data provider for the test_load function.
136
     */
137
    public function load_test_cases() {
138
        $cache = [
139
            'core' => [
140
                'test' => '{{! a comment }}The rest of the template'
141
            ]
142
        ];
143
        $loader = $this->build_loader_from_static_cache($cache);
144
 
145
        return [
146
            'with comments' => [
147
                'loader' => $loader,
148
                'component' => 'core',
149
                'name' => 'test',
150
                'includecomments' => true,
151
                'expected' => '{{! a comment }}The rest of the template'
152
            ],
153
            'without comments' => [
154
                'loader' => $loader,
155
                'component' => 'core',
156
                'name' => 'test',
157
                'includecomments' => false,
158
                'expected' => 'The rest of the template'
159
            ],
160
        ];
161
    }
162
 
163
    /**
164
     * Test the load function.
165
     *
166
     * @dataProvider load_test_cases
167
     * @param mustache_template_source_loader $loader The loader
168
     * @param string $component The moodle component
169
     * @param string $name The template name
170
     * @param bool $includecomments Whether to strip comments
171
     * @param string $expected The expected output
172
     */
11 efrain 173
    public function test_load($loader, $component, $name, $includecomments, $expected): void {
1 efrain 174
        $this->assertEquals($expected, $loader->load($component, $name, 'boost', $includecomments));
175
    }
176
 
177
    /**
178
     * Data provider for the load_with_dependencies function.
179
     */
180
    public function load_with_dependencies_test_cases() {
181
        // Create a bunch of templates that include one another in various ways. There is
182
        // multiple instances of recursive inclusions to test that the code doensn't get
183
        // stuck in an infinite loop.
184
        $foo = '{{! a comment }}{{> core/bar }}{{< test/bop }}{{/ test/bop}}{{#str}} help, core {{/str}}';
185
        $foo2 = '{{! a comment }}hello';
186
        $bar = '{{! a comment }}{{> core/baz }}';
187
        $baz = '{{! a comment }}{{#str}} hide, core {{/str}}';
188
        $bop = '{{! a comment }}{{< test/bim }}{{/ test/bim }}{{> core/foo }}';
189
        $bim = '{{! a comment }}{{< core/foo }}{{/ core/foo}}{{> test/foo }}';
190
        $foonocomment = '{{> core/bar }}{{< test/bop }}{{/ test/bop}}{{#str}} help, core {{/str}}';
191
        $foo2nocomment = 'hello';
192
        $barnocomment = '{{> core/baz }}';
193
        $baznocomment = '{{#str}} hide, core {{/str}}';
194
        $bopnocomment = '{{< test/bim }}{{/ test/bim }}{{> core/foo }}';
195
        $bimnocomment = '{{< core/foo }}{{/ core/foo}}{{> test/foo }}';
196
        $cache = [
197
            'core' => [
198
                'foo' => $foo,
199
                'bar' => $bar,
200
                'baz' => $baz,
201
            ],
202
            'test' => [
203
                'foo' => $foo2,
204
                'bop' => $bop,
205
                'bim' => $bim
206
            ]
207
        ];
208
        $loader = $this->build_loader_from_static_cache($cache);
209
 
210
        return [
211
            'no template includes w comments' => [
212
                'loader' => $loader,
213
                'component' => 'test',
214
                'name' => 'foo',
215
                'includecomments' => true,
216
                'expected' => [
217
                    'templates' => [
218
                        'test' => [
219
                            'foo' => $foo2
220
                        ]
221
                    ],
222
                    'strings' => []
223
                ]
224
            ],
225
            'no template includes w/o comments' => [
226
                'loader' => $loader,
227
                'component' => 'test',
228
                'name' => 'foo',
229
                'includecomments' => false,
230
                'expected' => [
231
                    'templates' => [
232
                        'test' => [
233
                            'foo' => $foo2nocomment
234
                        ]
235
                    ],
236
                    'strings' => []
237
                ]
238
            ],
239
            'no template includes with string w comments' => [
240
                'loader' => $loader,
241
                'component' => 'core',
242
                'name' => 'baz',
243
                'includecomments' => true,
244
                'expected' => [
245
                    'templates' => [
246
                        'core' => [
247
                            'baz' => $baz
248
                        ]
249
                    ],
250
                    'strings' => [
251
                        'core' => [
252
                            'hide' => 'Hide'
253
                        ]
254
                    ]
255
                ]
256
            ],
257
            'no template includes with string w/o comments' => [
258
                'loader' => $loader,
259
                'component' => 'core',
260
                'name' => 'baz',
261
                'includecomments' => false,
262
                'expected' => [
263
                    'templates' => [
264
                        'core' => [
265
                            'baz' => $baznocomment
266
                        ]
267
                    ],
268
                    'strings' => [
269
                        'core' => [
270
                            'hide' => 'Hide'
271
                        ]
272
                    ]
273
                ]
274
            ],
275
            'full with comments' => [
276
                'loader' => $loader,
277
                'component' => 'core',
278
                'name' => 'foo',
279
                'includecomments' => true,
280
                'expected' => [
281
                    'templates' => [
282
                        'core' => [
283
                            'foo' => $foo,
284
                            'bar' => $bar,
285
                            'baz' => $baz
286
                        ],
287
                        'test' => [
288
                            'foo' => $foo2,
289
                            'bop' => $bop,
290
                            'bim' => $bim
291
                        ]
292
                    ],
293
                    'strings' => [
294
                        'core' => [
295
                            'help' => 'Help',
296
                            'hide' => 'Hide'
297
                        ]
298
                    ]
299
                ]
300
            ],
301
            'full without comments' => [
302
                'loader' => $loader,
303
                'component' => 'core',
304
                'name' => 'foo',
305
                'includecomments' => false,
306
                'expected' => [
307
                    'templates' => [
308
                        'core' => [
309
                            'foo' => $foonocomment,
310
                            'bar' => $barnocomment,
311
                            'baz' => $baznocomment
312
                        ],
313
                        'test' => [
314
                            'foo' => $foo2nocomment,
315
                            'bop' => $bopnocomment,
316
                            'bim' => $bimnocomment
317
                        ]
318
                    ],
319
                    'strings' => [
320
                        'core' => [
321
                            'help' => 'Help',
322
                            'hide' => 'Hide'
323
                        ]
324
                    ]
325
                ]
326
            ]
327
        ];
328
    }
329
 
330
    /**
331
     * Test the load_with_dependencies function.
332
     *
333
     * @dataProvider load_with_dependencies_test_cases
334
     * @param mustache_template_source_loader $loader The loader
335
     * @param string $component The moodle component
336
     * @param string $name The template name
337
     * @param bool $includecomments Whether to strip comments
338
     * @param string $expected The expected output
339
     */
11 efrain 340
    public function test_load_with_dependencies($loader, $component, $name, $includecomments, $expected): void {
1 efrain 341
        $actual = $loader->load_with_dependencies($component, $name, 'boost', $includecomments);
342
        $this->assertEquals($expected, $actual);
343
    }
344
    /**
345
     * Data provider for the test_load function.
346
     */
347
    public function scan_template_source_for_dependencies_test_cases() {
348
        $foo = '{{! a comment }}{{> core/bar }}{{< test/bop }}{{/ test/bop}}{{#str}} help, core {{/str}}';
349
        $bar = '{{! a comment }}{{> core/baz }}';
350
        $baz = '{{! a comment }}{{#str}} hide, core {{/str}}';
351
        $bop = '{{! a comment }}hello';
352
        $multiline1 = <<<TEMPLATE
353
{{! a comment }}{{#str}} authorreplyingprivatelytoauthor,
354
mod_forum {{/str}}
355
TEMPLATE;
356
        $multiline2 = <<<TEMPLATE
357
{{! a comment }}{{#str}}
358
authorreplyingprivatelytoauthor,
359
mod_forum {{/str}}
360
TEMPLATE;
361
        $multiline3 = <<<TEMPLATE
362
{{! a comment }}{{#str}}
363
authorreplyingprivatelytoauthor,
364
mod_forum
365
{{/str}}
366
TEMPLATE;
367
        $multiline4 = <<<TEMPLATE
368
{{! a comment }}{{#str}}
369
authorreplyingprivatelytoauthor, mod_forum
370
{{/str}}
371
TEMPLATE;
372
        $multiline5 = <<<TEMPLATE
373
{{! a comment }}{{#str}}
374
hide
375
{{/str}}
376
TEMPLATE;
377
 
378
        $cache = [
379
            'core' => [
380
                'foo' => $foo,
381
                'bar' => $bar,
382
                'baz' => $baz,
383
                'bop' => $bop,
384
                'multiline1' => $multiline1,
385
                'multiline2' => $multiline2,
386
                'multiline3' => $multiline3,
387
                'multiline4' => $multiline4,
388
                'multiline5' => $multiline5,
389
            ]
390
        ];
391
        $loader = $this->build_loader_from_static_cache($cache);
392
 
393
        return [
394
            'single template include' => [
395
                'loader' => $loader,
396
                'source' => $bar,
397
                'expected' => [
398
                    'templates' => [
399
                        'core' => ['baz']
400
                    ],
401
                    'strings' => []
402
                ]
403
            ],
404
            'single string include' => [
405
                'loader' => $loader,
406
                'source' => $baz,
407
                'expected' => [
408
                    'templates' => [],
409
                    'strings' => [
410
                        'core' => ['hide']
411
                    ]
412
                ]
413
            ],
414
            'no include' => [
415
                'loader' => $loader,
416
                'source' => $bop,
417
                'expected' => [
418
                    'templates' => [],
419
                    'strings' => []
420
                ]
421
            ],
422
            'all include' => [
423
                'loader' => $loader,
424
                'source' => $foo,
425
                'expected' => [
426
                    'templates' => [
427
                        'core' => ['bar'],
428
                        'test' => ['bop']
429
                    ],
430
                    'strings' => [
431
                        'core' => ['help']
432
                    ]
433
                ]
434
            ],
435
            'string: component on new line' => [
436
                'loader' => $loader,
437
                'source' => $multiline1,
438
                'expected' => [
439
                    'templates' => [],
440
                    'strings' => [
441
                        'mod_forum' => ['authorreplyingprivatelytoauthor']
442
                    ]
443
                ]
444
            ],
445
            'string: identifier on own line' => [
446
                'loader' => $loader,
447
                'source' => $multiline2,
448
                'expected' => [
449
                    'templates' => [],
450
                    'strings' => [
451
                        'mod_forum' => ['authorreplyingprivatelytoauthor']
452
                    ]
453
                ]
454
            ],
455
            'string: all parts on new lines' => [
456
                'loader' => $loader,
457
                'source' => $multiline3,
458
                'expected' => [
459
                    'templates' => [],
460
                    'strings' => [
461
                        'mod_forum' => ['authorreplyingprivatelytoauthor']
462
                    ]
463
                ]
464
            ],
465
            'string: id and component on own line' => [
466
                'loader' => $loader,
467
                'source' => $multiline4,
468
                'expected' => [
469
                    'templates' => [],
470
                    'strings' => [
471
                        'mod_forum' => ['authorreplyingprivatelytoauthor']
472
                    ]
473
                ]
474
            ],
475
            'string: no component' => [
476
                'loader' => $loader,
477
                'source' => $multiline5,
478
                'expected' => [
479
                    'templates' => [],
480
                    'strings' => [
481
                        'core' => ['hide']
482
                    ]
483
                ]
484
            ],
485
        ];
486
    }
487
 
488
    /**
489
     * Test the scan_template_source_for_dependencies function.
490
     *
491
     * @dataProvider scan_template_source_for_dependencies_test_cases()
492
     * @param mustache_template_source_loader $loader The loader
493
     * @param string $source The template to test
494
     * @param string $expected The expected output
495
     */
11 efrain 496
    public function test_scan_template_source_for_dependencies($loader, $source, $expected): void {
1 efrain 497
        $actual = \phpunit_util::call_internal_method(
498
            $loader,
499
            'scan_template_source_for_dependencies',
500
            [$source],
501
            \core\output\mustache_template_source_loader::class
502
        );
503
        $this->assertEquals($expected, $actual);
504
    }
505
 
506
    /**
507
     * Create an instance of mustache_template_source_loader which loads its templates
508
     * from the given cache rather than disk.
509
     *
510
     * @param array $cache A cache of templates
511
     * @return mustache_template_source_loader
512
     */
513
    private function build_loader_from_static_cache(array $cache): mustache_template_source_loader {
514
        return new mustache_template_source_loader(function($component, $name, $themename) use ($cache) {
515
            return $cache[$component][$name];
516
        });
517
    }
518
}