Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 and 402] [Versions 311 and 403]

   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_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 mustache_helper_collection_test extends \advanced_testcase {
  28  
  29      /**
  30       * Test cases to confirm that disallowed helpers are stripped from the source
  31       * text by the helper before being passed to other another helper. This prevents
  32       * nested calls to helpers.
  33       */
  34      public function get_strip_disallowed_helpers_testcases() {
  35          return [
  36              'no disallowed' => [
  37                  'disallowed' => [],
  38                  'input' => 'core, move, {{#js}} some nasty JS {{/js}}',
  39                  'expected' => 'core, move, {{#js}} some nasty JS {{/js}}'
  40              ],
  41              'disallowed no match' => [
  42                  'disallowed' => ['foo'],
  43                  'input' => 'core, move, {{#js}} some nasty JS {{/js}}',
  44                  'expected' => 'core, move, {{#js}} some nasty JS {{/js}}'
  45              ],
  46              'disallowed partial match 1' => [
  47                  'disallowed' => ['js'],
  48                  'input' => 'core, move, {{#json}} some nasty JS {{/json}}',
  49                  'expected' => 'core, move, {{#json}} some nasty JS {{/json}}'
  50              ],
  51              'disallowed partial match 2' => [
  52                  'disallowed' => ['js'],
  53                  'input' => 'core, move, {{#onjs}} some nasty JS {{/onjs}}',
  54                  'expected' => 'core, move, {{#onjs}} some nasty JS {{/onjs}}'
  55              ],
  56              'single disallowed 1' => [
  57                  'disallowed' => ['js'],
  58                  'input' => 'core, move, {{#js}} some nasty JS {{/js}}',
  59                  'expected' => 'core, move, {{}}'
  60              ],
  61              'single disallowed 2' => [
  62                  'disallowed' => ['js'],
  63                  'input' => 'core, move, {{ # js }} some nasty JS {{ /  js }}',
  64                  'expected' => 'core, move, {{}}'
  65              ],
  66              'single disallowed 3' => [
  67                  'disallowed' => ['js'],
  68                  'input' => 'core, {{#js}} some nasty JS {{/js}}, test',
  69                  'expected' => 'core, {{}}, test'
  70              ],
  71              'single disallowed 4' => [
  72                  'disallowed' => ['js'],
  73                  'input' => 'core, {{#ok}} this is ok {{/ok}}, {{#js}} some nasty JS {{/js}}',
  74                  'expected' => 'core, {{#ok}} this is ok {{/ok}}, {{}}'
  75              ],
  76              'single disallowed multiple matches 1' => [
  77                  'disallowed' => ['js'],
  78                  'input' => 'core, {{#js}} some nasty JS {{/js}}, {{#js}} some nasty JS {{/js}}',
  79                  'expected' => 'core, {{}}'
  80              ],
  81              'single disallowed multiple matches 2' => [
  82                  'disallowed' => ['js'],
  83                  'input' => 'core, {{ # js }} some nasty JS {{ /  js }}, {{ # js }} some nasty JS {{ /  js }}',
  84                  'expected' => 'core, {{}}'
  85              ],
  86              'single disallowed multiple matches nested 1' => [
  87                  'disallowed' => ['js'],
  88                  'input' => 'core, move, {{#js}} some nasty JS {{#js}} some nasty JS {{/js}} {{/js}}',
  89                  'expected' => 'core, move, {{}}'
  90              ],
  91              'single disallowed multiple matches nested 2' => [
  92                  'disallowed' => ['js'],
  93                  'input' => 'core, move, {{ # js }} some nasty JS {{ # js }} some nasty JS {{ /  js }}{{ /  js }}',
  94                  'expected' => 'core, move, {{}}'
  95              ],
  96              'multiple disallowed 1' => [
  97                  'disallowed' => ['js', 'foo'],
  98                  'input' => 'core, move, {{#js}} some nasty JS {{/js}}',
  99                  'expected' => 'core, move, {{}}'
 100              ],
 101              'multiple disallowed 2' => [
 102                  'disallowed' => ['js', 'foo'],
 103                  'input' => 'core, {{#foo}} blah {{/foo}}, {{#js}} js {{/js}}',
 104                  'expected' => 'core, {{}}, {{}}'
 105              ],
 106              'multiple disallowed 3' => [
 107                  'disallowed' => ['js', 'foo'],
 108                  'input' => '{{#foo}} blah {{/foo}}, {{#foo}} blah {{/foo}}, {{#js}} js {{/js}}',
 109                  'expected' => '{{}}, {{}}'
 110              ],
 111              'multiple disallowed 4' => [
 112                  'disallowed' => ['js', 'foo'],
 113                  'input' => '{{#foo}} blah {{/foo}}, {{#js}} js {{/js}}, {{#foo}} blah {{/foo}}',
 114                  'expected' => '{{}}'
 115              ],
 116              'multiple disallowed 5' => [
 117                  'disallowed' => ['js', 'foo'],
 118                  'input' => 'core, move, {{#js}} JS {{#foo}} blah {{/foo}} {{/js}}',
 119                  'expected' => 'core, move, {{}}'
 120              ],
 121          ];
 122      }
 123  
 124      /**
 125       * Test that the mustache_helper_collection class correctly strips
 126       * @dataProvider get_strip_disallowed_helpers_testcases()
 127       * @param string[] $disallowed The list of helpers to strip
 128       * @param string $input The input string for the helper
 129       * @param string $expected The expected output of the string after disallowed strip
 130       */
 131      public function test_strip_disallowed_helpers($disallowed, $input, $expected) {
 132          $collection = new mustache_helper_collection(null, $disallowed);
 133          $this->assertEquals($expected, $collection->strip_disallowed_helpers($disallowed, $input));
 134      }
 135  
 136      /**
 137       * Test that the disallowed helpers are disabled during the execution of other
 138       * helpers.
 139       *
 140       * Any allowed helper should still be available to call during the
 141       * execution of a helper.
 142       */
 143      public function test_disallowed_helpers_disabled_during_execution() {
 144          $engine = new \Mustache_Engine();
 145          $context = new \Mustache_Context();
 146          $lambdahelper = new \Mustache_LambdaHelper($engine, $context);
 147          $disallowed = ['bad'];
 148          $collection = new mustache_helper_collection(null, $disallowed);
 149          $badcalled = false;
 150          $goodcalled = false;
 151  
 152          $badhelper = function() use (&$badcalled) {
 153              $badcalled = true;
 154              return '';
 155          };
 156          $goodhelper = function() use (&$goodcalled) {
 157              $goodcalled = true;
 158              return '';
 159          };
 160          // A test helper that just returns the text without modifying it.
 161          $testhelper = function($text, $lambda) use ($collection) {
 162              $collection->get('good')($text, $lambda);
 163              $collection->get('bad')($text, $lambda);
 164              return $text;
 165          };
 166          $collection->add('bad', $badhelper);
 167          $collection->add('good', $goodhelper);
 168          $collection->add('test', $testhelper);
 169  
 170          $this->assertEquals('success output', $collection->get('test')('success output', $lambdahelper));
 171          $this->assertTrue($goodcalled);
 172          $this->assertFalse($badcalled);
 173      }
 174  
 175      /**
 176       * Test that calling deprecated method strip_blacklisted_helpers() still works and shows developer debugging.
 177       */
 178      public function test_deprecated_strip_blacklisted_helpers() {
 179  
 180          $collection = new mustache_helper_collection(null, ['js']);
 181          $stripped = $collection->strip_blacklisted_helpers(['js'], '{{#js}} JS {{/js}}');
 182          $this->assertEquals('{{}}', $stripped);
 183          $this->assertDebuggingCalled('mustache_helper_collection::strip_blacklisted_helpers() is deprecated. ' .
 184              'Please use mustache_helper_collection::strip_disallowed_helpers() instead.', DEBUG_DEVELOPER);
 185      }
 186  }