Search moodle.org's
Developer Documentation

See Release Notes

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