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