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

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