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 310 and 311] [Versions 39 and 311]

   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 the XML-RPC web service server.
  19   *
  20   * @package    webservice_xmlrpc
  21   * @category   test
  22   * @copyright  2016 Cameron Ball
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  namespace webservice_xmlrpc;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  global $CFG;
  30  require_once($CFG->dirroot . '/webservice/xmlrpc/locallib.php');
  31  
  32  /**
  33   * Unit tests for the XML-RPC web service server.
  34   *
  35   * @package    webservice_xmlrpc
  36   * @category   test
  37   * @copyright  2016 Cameron Ball
  38   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   */
  40  class locallib_test extends \advanced_testcase {
  41  
  42      /**
  43       * Setup.
  44       */
  45      public function setUp(): void {
  46          if (!function_exists('xmlrpc_decode')) {
  47              $this->markTestSkipped('XMLRPC is not installed.');
  48          }
  49      }
  50  
  51      /**
  52       * Test that the response generated is correct
  53       *
  54       * There is a bug in PHP that causes the xml_rpc library to
  55       * incorrectly escape multibyte characters. See https://bugs.php.net/bug.php?id=41650
  56       *
  57       * @dataProvider prepare_response_provider
  58       * @param string $returnsdesc  Webservice function return description
  59       * @param string $returns       Webservice function description
  60       * @param string $expected      The expected XML-RPC response
  61       */
  62      public function test_prepare_response($returnsdesc, $returns, $expected) {
  63          $server = $this->getMockBuilder('webservice_xmlrpc_server')
  64              ->disableOriginalConstructor()
  65              ->onlyMethods([])
  66              ->getMock();
  67  
  68          $rc = new \ReflectionClass('webservice_xmlrpc_server');
  69          $rcm = $rc->getMethod('prepare_response');
  70          $rcm->setAccessible(true);
  71  
  72          $func = $rc->getProperty('function');
  73          $func->setAccessible(true);
  74          $func->setValue($server, (object) ['returns_desc' => new \external_value(PARAM_RAW, $returnsdesc, VALUE_OPTIONAL)]);
  75  
  76          $ret = $rc->getProperty('returns');
  77          $ret->setAccessible(true);
  78          $ret->setValue($server, $returns);
  79  
  80          $rcm->invokeArgs($server, []);
  81          $response = $rc->getProperty('response');
  82          $response->setAccessible(true);
  83  
  84          $this->assertEquals($expected, $response->getValue($server));
  85      }
  86  
  87      /**
  88       * Test that the response generated is correct
  89       *
  90       * There is a bug in PHP that causes the xml_rpc library to
  91       * incorrectly escape multibyte characters. See https://bugs.php.net/bug.php?id=41650
  92       *
  93       * @dataProvider generate_error_provider
  94       * @param Exception $exception An exception to be provided to generate_error
  95       * @param string    $code      An error code to be provided to generate_error
  96       * @param string    $expected  The expected XML-RPC response
  97       */
  98      public function test_generate_error($exception, $code, $expected) {
  99          $server = $this->getMockBuilder('webservice_xmlrpc_server')
 100              ->disableOriginalConstructor()
 101              ->onlyMethods([])
 102              ->getMock();
 103  
 104          $rc = new \ReflectionClass('webservice_xmlrpc_server');
 105          $rcm = $rc->getMethod('generate_error');
 106          $rcm->setAccessible(true);
 107  
 108          if ($code === null) {
 109              $result = $rcm->invokeArgs($server, [$exception]);
 110          } else {
 111              $result = $rcm->invokeArgs($server, [$exception, $code]);
 112          }
 113          $this->assertEquals($expected, $result);
 114      }
 115  
 116      /**
 117       * Data provider for the prepare_response testcase
 118       *
 119       * @return array of testcases
 120       */
 121      public function prepare_response_provider() {
 122          return [
 123              'Description written with Latin script' => [
 124                  'Ennyn Durin, Aran Moria: pedo mellon a minno',
 125                  'Mellon!',
 126                  '<?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value><string>Mellon!</string></value>'
 127                  . '</param></params></methodResponse>'
 128              ],
 129              'Description with non-Latin glyphs' => [
 130                  'What biscuits do you have?',
 131                  // V         Unicode 9!         V.
 132                  '😂🤵😂 𝒪𝓃𝓁𝓎 𝓉𝒽𝑒 𝒻𝒾𝓃𝑒𝓈𝓉 𝐼𝓉𝒶𝓁𝒾𝒶𝓃 𝒷𝒾𝓈𝒸𝓊𝒾𝓉𝓈 😂🤵😂',
 133                  '<?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value><string>'
 134                  . '😂🤵😂 𝒪𝓃𝓁𝓎 𝓉𝒽𝑒 𝒻𝒾𝓃𝑒𝓈𝓉 𝐼𝓉𝒶𝓁𝒾𝒶𝓃 𝒷𝒾𝓈𝒸𝓊𝒾𝓉𝓈 😂🤵😂</string></value></param></params></methodResponse>'
 135              ]
 136          ];
 137      }
 138  
 139      /**
 140       * Data provider for the generate_error testcase
 141       *
 142       * @return array of testcases
 143       */
 144      public function generate_error_provider() {
 145          return [
 146              'Standard exception with default faultcode' => [
 147                  new \Exception(),
 148                  null,
 149                  '<?xml version="1.0" encoding="UTF-8"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>404</int></value></member><member><name>faultString</name><value><string/></value></member></struct></value></fault></methodResponse>'
 150              ],
 151              'Standard exception with default faultcode and exception content' => [
 152                  new \Exception('PC LOAD LETTER'),
 153                  null,
 154                  '<?xml version="1.0" encoding="UTF-8"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>404</int></value></member><member><name>faultString</name><value><string>PC LOAD LETTER</string></value></member></struct></value></fault></methodResponse>'
 155              ],
 156              'Standard exception with really messed up non-Latin glyphs' => [
 157                  new \Exception('P̫̬̳̫̓͊̇r̨͎̜ͧa͚̬̙̺͎̙ͬẏ͎̲̦̲e̶̞͎͙̻͐̉r͙̙ͮ̓̈ͧ̔̃ ̠ͨ́ͭ̎̎̇̿n̗̥̞͗o̼̖͛̂̒̿ͮ͘t̷̞͎̘̘̝̥̲͂̌ͭ ͕̹͚̪͖̖̊̆́̒ͫ̓̀fͤͦͭͥ͊ͩo̼̱̻̹͒̿͒u̡͕̞͕̜̠͕ͥͭ̈̄̈́͐ń̘̼̇͜d̸̰̻͎͉̱̰̥̿͒'),
 158                  null,
 159                  '<?xml version="1.0" encoding="UTF-8"?><methodResponse><fault><value><struct><member><name>faultCode</name><value><int>404</int></value></member><member><name>faultString</name><value><string>P̫̬̳̫̓͊̇r̨͎̜ͧa͚̬̙̺͎̙ͬẏ͎̲̦̲e̶̞͎͙̻͐̉r͙̙ͮ̓̈ͧ̔̃ ̠ͨ́ͭ̎̎̇̿n̗̥̞͗o̼̖͛̂̒̿ͮ͘t̷̞͎̘̘̝̥̲͂̌ͭ ͕̹͚̪͖̖̊̆́̒ͫ̓̀fͤͦͭͥ͊ͩo̼̱̻̹͒̿͒u̡͕̞͕̜̠͕ͥͭ̈̄̈́͐ń̘̼̇͜d̸̰̻͎͉̱̰̥̿͒</string></value></member></struct></value></fault></methodResponse>'
 160              ]
 161          ];
 162      }
 163  }