Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 401 and 402] [Versions 401 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;
  18  
  19  use externallib_advanced_testcase;
  20  
  21  defined('MOODLE_INTERNAL') || die();
  22  
  23  global $CFG;
  24  require_once($CFG->dirroot . '/lib/external/externallib.php');
  25  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  26  
  27  /**
  28   * External library functions unit tests
  29   *
  30   * @package    core
  31   * @category   phpunit
  32   * @copyright  2012 Jerome Mouneyrac
  33   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  class external_externallib_test extends externallib_advanced_testcase {
  36  
  37      /**
  38       * Test get_string
  39       */
  40      public function test_get_string() {
  41          $this->resetAfterTest(true);
  42  
  43          $service = new \stdClass();
  44          $service->name = 'Dummy Service';
  45          $service->id = 12;
  46  
  47          // String with two parameters.
  48          $returnedstring = \core_external::get_string('addservice', 'webservice', null,
  49                  array(array('name' => 'name', 'value' => $service->name),
  50                        array('name' => 'id', 'value' => $service->id)));
  51  
  52          // We need to execute the return values cleaning process to simulate the web service server.
  53          $returnedstring = \external_api::clean_returnvalue(\core_external::get_string_returns(), $returnedstring);
  54  
  55          $corestring = get_string('addservice', 'webservice', $service);
  56          $this->assertSame($corestring, $returnedstring);
  57  
  58          // String with one parameter.
  59          $acapname = 'A capability name';
  60          $returnedstring = \core_external::get_string('missingrequiredcapability', 'webservice', null,
  61                  array(array('value' => $acapname)));
  62  
  63          // We need to execute the return values cleaning process to simulate the web service server.
  64          $returnedstring = \external_api::clean_returnvalue(\core_external::get_string_returns(), $returnedstring);
  65  
  66          $corestring = get_string('missingrequiredcapability', 'webservice', $acapname);
  67          $this->assertSame($corestring, $returnedstring);
  68  
  69          // String without parameters.
  70          $returnedstring = \core_external::get_string('missingpassword', 'webservice');
  71  
  72          // We need to execute the return values cleaning process to simulate the web service server.
  73          $returnedstring = \external_api::clean_returnvalue(\core_external::get_string_returns(), $returnedstring);
  74  
  75          $corestring = get_string('missingpassword', 'webservice');
  76          $this->assertSame($corestring, $returnedstring);
  77  
  78          // String with two parameter but one is invalid (not named).
  79          $this->expectException('moodle_exception');
  80          $returnedstring = \core_external::get_string('addservice', 'webservice', null,
  81                  array(array('value' => $service->name),
  82                        array('name' => 'id', 'value' => $service->id)));
  83      }
  84  
  85      /**
  86       * Test get_string with HTML.
  87       */
  88      public function test_get_string_containing_html() {
  89          $result = \core_external::get_string('registrationinfo');
  90          $actual = \external_api::clean_returnvalue(\core_external::get_string_returns(), $result);
  91          $expected = get_string('registrationinfo', 'moodle');
  92          $this->assertSame($expected, $actual);
  93      }
  94  
  95      /**
  96       * Test get_string with arguments containing HTML.
  97       */
  98      public function test_get_string_with_args_containing_html() {
  99          $result = \core_external::get_string('added', 'moodle', null, [['value' => '<strong>Test</strong>']]);
 100          $actual = \external_api::clean_returnvalue(\core_external::get_string_returns(), $result);
 101          $expected = get_string('added', 'moodle', '<strong>Test</strong>');
 102          $this->assertSame($expected, $actual);
 103      }
 104  
 105      /**
 106       * Test get_strings
 107       */
 108      public function test_get_strings() {
 109          $this->resetAfterTest(true);
 110  
 111          $stringmanager = get_string_manager();
 112  
 113          $service = new \stdClass();
 114          $service->name = 'Dummy Service';
 115          $service->id = 12;
 116  
 117          $returnedstrings = \core_external::get_strings(
 118                  array(
 119                      array(
 120                          'stringid' => 'addservice', 'component' => 'webservice',
 121                          'stringparams' => array(array('name' => 'name', 'value' => $service->name),
 122                                array('name' => 'id', 'value' => $service->id)
 123                          ),
 124                          'lang' => 'en'
 125                      ),
 126                      array('stringid' =>  'addaservice', 'component' => 'webservice', 'lang' => 'en')
 127                  ));
 128  
 129          // We need to execute the return values cleaning process to simulate the web service server.
 130          $returnedstrings = \external_api::clean_returnvalue(\core_external::get_strings_returns(), $returnedstrings);
 131  
 132          foreach($returnedstrings as $returnedstring) {
 133              $corestring = $stringmanager->get_string($returnedstring['stringid'],
 134                                                       $returnedstring['component'],
 135                                                       $service,
 136                                                       'en');
 137              $this->assertSame($corestring, $returnedstring['string']);
 138          }
 139      }
 140  
 141      /**
 142       * Test get_strings with HTML.
 143       */
 144      public function test_get_strings_containing_html() {
 145          $result = \core_external::get_strings([['stringid' => 'registrationinfo'], ['stringid' => 'loginaspasswordexplain']]);
 146          $actual = \external_api::clean_returnvalue(\core_external::get_strings_returns(), $result);
 147          $this->assertSame(get_string('registrationinfo', 'moodle'), $actual[0]['string']);
 148          $this->assertSame(get_string('loginaspasswordexplain', 'moodle'), $actual[1]['string']);
 149      }
 150  
 151      /**
 152       * Test get_strings with arguments containing HTML.
 153       */
 154      public function test_get_strings_with_args_containing_html() {
 155          $result = \core_external::get_strings([
 156              ['stringid' => 'added', 'stringparams' => [['value' => '<strong>Test</strong>']]],
 157              ['stringid' => 'loggedinas', 'stringparams' => [['value' => '<strong>Test</strong>']]]]
 158          );
 159          $actual = \external_api::clean_returnvalue(\core_external::get_strings_returns(), $result);
 160          $this->assertSame(get_string('added', 'moodle', '<strong>Test</strong>'), $actual[0]['string']);
 161          $this->assertSame(get_string('loggedinas', 'moodle', '<strong>Test</strong>'), $actual[1]['string']);
 162      }
 163  
 164      /**
 165       * Test get_component_strings
 166       */
 167      public function test_get_component_strings() {
 168          global $USER;
 169          $this->resetAfterTest(true);
 170  
 171          $stringmanager = get_string_manager();
 172  
 173          $wsstrings = $stringmanager->load_component_strings('webservice', current_language());
 174  
 175          $componentstrings = \core_external::get_component_strings('webservice');
 176  
 177          // We need to execute the return values cleaning process to simulate the web service server.
 178          $componentstrings = \external_api::clean_returnvalue(\core_external::get_component_strings_returns(), $componentstrings);
 179  
 180          $this->assertEquals(count($componentstrings), count($wsstrings));
 181          foreach($componentstrings as $string) {
 182              $this->assertSame($string['string'], $wsstrings[$string['stringid']]);
 183          }
 184      }
 185  
 186      /**
 187       * Test update_inplace_editable()
 188       */
 189      public function test_update_inplace_editable() {
 190          $this->resetAfterTest(true);
 191  
 192          // Call service for component that does not have inplace_editable callback.
 193          try {
 194              \core_external::update_inplace_editable('tool_log', 'itemtype', 1, 'newvalue');
 195              $this->fail('Exception expected');
 196          } catch (\moodle_exception $e) {
 197              $this->assertEquals('Error calling update processor', $e->getMessage());
 198          }
 199  
 200          // This is a very basic test for the return value of the external function.
 201          // More detailed test for tag updating can be found in core_tag component.
 202          $this->setAdminUser();
 203          $tag = $this->getDataGenerator()->create_tag();
 204          $res = \core_external::update_inplace_editable('core_tag', 'tagname', $tag->id, 'new tag name');
 205          $res = \external_api::clean_returnvalue(\core_external::update_inplace_editable_returns(), $res);
 206  
 207          $this->assertEquals('new tag name', $res['value']);
 208      }
 209  
 210      /**
 211       * Test update_inplace_editable with mathjax.
 212       */
 213      public function test_update_inplace_editable_with_mathjax() {
 214          $this->resetAfterTest(true);
 215          $this->setAdminUser();
 216  
 217          // Enable MathJax filter in content and headings.
 218          $this->configure_filters([
 219              ['name' => 'mathjaxloader', 'state' => TEXTFILTER_ON, 'move' => -1, 'applytostrings' => true],
 220          ]);
 221  
 222          // Create a forum.
 223          $course = $this->getDataGenerator()->create_course();
 224          $forum = self::getDataGenerator()->create_module('forum', array('course' => $course->id, 'name' => 'forum name'));
 225  
 226          // Change the forum name.
 227          $newname = 'New forum name $$(a+b)=2$$';
 228          $res = \core_external::update_inplace_editable('core_course', 'activityname', $forum->cmid, $newname);
 229          $res = \external_api::clean_returnvalue(\core_external::update_inplace_editable_returns(), $res);
 230  
 231          // Format original data.
 232          $context = \context_module::instance($forum->cmid);
 233          $newname = external_format_string($newname, $context->id);
 234          $editlabel = get_string('newactivityname', '', $newname);
 235  
 236          // Check editlabel is the same and has mathjax.
 237          $this->assertStringContainsString('<span class="filter_mathjaxloader_equation">', $res['editlabel']);
 238          $this->assertEquals($editlabel, $res['editlabel']);
 239      }
 240  
 241      public function test_get_user_dates() {
 242          $this->resetAfterTest();
 243  
 244          $this->setAdminUser();
 245  
 246          // Set default timezone to Australia/Perth, else time calculated
 247          // will not match expected values.
 248          $this->setTimezone(99, 'Australia/Perth');
 249  
 250          $context = \context_system::instance();
 251          $request = [
 252              [
 253                  'timestamp' => 1293876000,
 254                  'format' => '%A, %d %B %Y, %I:%M'
 255              ],
 256              [
 257                  'timestamp' => 1293876000,
 258                  'format' => '%d %m %Y'
 259              ],
 260              [
 261                  'timestamp' => 1293876000,
 262                  'format' => '%d %m %Y',
 263                  'type' => 'gregorian'
 264              ],
 265              [
 266                  'timestamp' => 1293876000,
 267                  'format' => 'some invalid format'
 268              ],
 269          ];
 270  
 271          $result = \core_external::get_user_dates($context->id, null, null, $request);
 272          $result = \external_api::clean_returnvalue(\core_external::get_user_dates_returns(), $result);
 273  
 274          $this->assertEquals('Saturday, 1 January 2011, 6:00', $result['dates'][0]);
 275          $this->assertEquals('1 01 2011', $result['dates'][1]);
 276          $this->assertEquals('1 01 2011', $result['dates'][2]);
 277          $this->assertEquals('some invalid format', $result['dates'][3]);
 278      }
 279  }