Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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  use core\output\mustache_helper_collection;
  18  
  19  /**
  20   * Unit tests for the mustache_helper_collection class.
  21   *
  22   * @package   core
  23   * @copyright 2019 Ryan Wyllie <ryan@moodle.com>
  24   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   * @covers    \core\output\mustache_helper_collection
  26   */
  27  class core_output_mustache_helper_collection_testcase extends advanced_testcase {
  28      /**
  29       * Test cases to confirm that blacklisted helpers are stripped from the source
  30       * text by the helper before being passed to other another helper. This prevents
  31       * nested calls to helpers.
  32       */
  33      public function get_strip_blacklisted_helpers_testcases() {
  34          return [
  35              'no blacklist' => [
  36                  'blacklist' => [],
  37                  'input' => 'core, move, {{#js}} some nasty JS {{/js}}',
  38                  'expected' => 'core, move, {{#js}} some nasty JS {{/js}}'
  39              ],
  40              'blacklist no match' => [
  41                  'blacklist' => ['foo'],
  42                  'input' => 'core, move, {{#js}} some nasty JS {{/js}}',
  43                  'expected' => 'core, move, {{#js}} some nasty JS {{/js}}'
  44              ],
  45              'blacklist partial match 1' => [
  46                  'blacklist' => ['js'],
  47                  'input' => 'core, move, {{#json}} some nasty JS {{/json}}',
  48                  'expected' => 'core, move, {{#json}} some nasty JS {{/json}}'
  49              ],
  50              'blacklist partial match 2' => [
  51                  'blacklist' => ['js'],
  52                  'input' => 'core, move, {{#onjs}} some nasty JS {{/onjs}}',
  53                  'expected' => 'core, move, {{#onjs}} some nasty JS {{/onjs}}'
  54              ],
  55              'single blacklist 1' => [
  56                  'blacklist' => ['js'],
  57                  'input' => 'core, move, {{#js}} some nasty JS {{/js}}',
  58                  'expected' => 'core, move, {{}}'
  59              ],
  60              'single blacklist 2' => [
  61                  'blacklist' => ['js'],
  62                  'input' => 'core, move, {{ # js }} some nasty JS {{ /  js }}',
  63                  'expected' => 'core, move, {{}}'
  64              ],
  65              'single blacklist 3' => [
  66                  'blacklist' => ['js'],
  67                  'input' => 'core, {{#js}} some nasty JS {{/js}}, test',
  68                  'expected' => 'core, {{}}, test'
  69              ],
  70              'single blacklist 4' => [
  71                  'blacklist' => ['js'],
  72                  'input' => 'core, {{#ok}} this is ok {{/ok}}, {{#js}} some nasty JS {{/js}}',
  73                  'expected' => 'core, {{#ok}} this is ok {{/ok}}, {{}}'
  74              ],
  75              'single blacklist multiple matches 1' => [
  76                  'blacklist' => ['js'],
  77                  'input' => 'core, {{#js}} some nasty JS {{/js}}, {{#js}} some nasty JS {{/js}}',
  78                  'expected' => 'core, {{}}'
  79              ],
  80              'single blacklist multiple matches 2' => [
  81                  'blacklist' => ['js'],
  82                  'input' => 'core, {{ # js }} some nasty JS {{ /  js }}, {{ # js }} some nasty JS {{ /  js }}',
  83                  'expected' => 'core, {{}}'
  84              ],
  85              'single blacklist multiple matches nested 1' => [
  86                  'blacklist' => ['js'],
  87                  'input' => 'core, move, {{#js}} some nasty JS {{#js}} some nasty JS {{/js}} {{/js}}',
  88                  'expected' => 'core, move, {{}}'
  89              ],
  90              'single blacklist multiple matches nested 2' => [
  91                  'blacklist' => ['js'],
  92                  'input' => 'core, move, {{ # js }} some nasty JS {{ # js }} some nasty JS {{ /  js }}{{ /  js }}',
  93                  'expected' => 'core, move, {{}}'
  94              ],
  95              'multiple blacklist 1' => [
  96                  'blacklist' => ['js', 'foo'],
  97                  'input' => 'core, move, {{#js}} some nasty JS {{/js}}',
  98                  'expected' => 'core, move, {{}}'
  99              ],
 100              'multiple blacklist 2' => [
 101                  'blacklist' => ['js', 'foo'],
 102                  'input' => 'core, {{#foo}} blah {{/foo}}, {{#js}} js {{/js}}',
 103                  'expected' => 'core, {{}}, {{}}'
 104              ],
 105              'multiple blacklist 3' => [
 106                  'blacklist' => ['js', 'foo'],
 107                  'input' => '{{#foo}} blah {{/foo}}, {{#foo}} blah {{/foo}}, {{#js}} js {{/js}}',
 108                  'expected' => '{{}}, {{}}'
 109              ],
 110              'multiple blacklist 4' => [
 111                  'blacklist' => ['js', 'foo'],
 112                  'input' => '{{#foo}} blah {{/foo}}, {{#js}} js {{/js}}, {{#foo}} blah {{/foo}}',
 113                  'expected' => '{{}}'
 114              ],
 115              'multiple blacklist 5' => [
 116                  'blacklist' => ['js', 'foo'],
 117                  'input' => 'core, move, {{#js}} JS {{#foo}} blah {{/foo}} {{/js}}',
 118                  'expected' => 'core, move, {{}}'
 119              ],
 120          ];
 121      }
 122  
 123      /**
 124       * Test that the mustache_helper_collection class correctly strips
 125       * @dataProvider get_strip_blacklisted_helpers_testcases()
 126       * @param string[] $blacklist The list of helpers to strip
 127       * @param string $input The input string for the helper
 128       * @param string $expected The expected output of the string after blacklist strip
 129       */
 130      public function test_strip_blacklisted_helpers($blacklist, $input, $expected) {
 131          $collection = new mustache_helper_collection(null, $blacklist);
 132          $this->assertEquals($expected, $collection->strip_blacklisted_helpers($blacklist, $input));
 133      }
 134  
 135      /**
 136       * Test that the blacklisted helpers are disabled during the execution of other
 137       * helpers.
 138       *
 139       * Any non-blacklisted helper should still be available to call during the
 140       * execution of a helper.
 141       */
 142      public function test_blacklisted_helpers_disabled_during_execution() {
 143          $engine = new \Mustache_Engine();
 144          $context = new \Mustache_Context();
 145          $lambdahelper = new \Mustache_LambdaHelper($engine, $context);
 146          $blacklist = ['bad'];
 147          $collection = new mustache_helper_collection(null, $blacklist);
 148          $badcalled = false;
 149          $goodcalled = false;
 150  
 151          $badhelper = function() use (&$badcalled) {
 152              $badcalled = true;
 153              return '';
 154          };
 155          $goodhelper = function() use (&$goodcalled) {
 156              $goodcalled = true;
 157              return '';
 158          };
 159          // A test helper that just returns the text without modifying it.
 160          $testhelper = function($text, $lambda) use ($collection) {
 161              $collection->get('good')($text, $lambda);
 162              $collection->get('bad')($text, $lambda);
 163              return $text;
 164          };
 165          $collection->add('bad', $badhelper);
 166          $collection->add('good', $goodhelper);
 167          $collection->add('test', $testhelper);
 168  
 169          $this->assertEquals('success output', $collection->get('test')('success output', $lambdahelper));
 170          $this->assertTrue($goodcalled);
 171          $this->assertFalse($badcalled);
 172      }
 173  }