Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
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 * Exporter testcase. 19 * 20 * @package core 21 * @copyright 2015 Damyon Wiese 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace core; 26 27 use core_external\external_format_value; 28 use core_external\external_multiple_structure; 29 use core_external\external_settings; 30 use core_external\external_single_structure; 31 use core_external\external_value; 32 33 /** 34 * Exporter testcase. 35 * 36 * @package core 37 * @copyright 2015 Damyon Wiese 38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 */ 40 class exporter_test extends \advanced_testcase { 41 42 protected $validrelated = null; 43 protected $invalidrelated = null; 44 protected $validdata = null; 45 protected $invaliddata = null; 46 47 public function setUp(): void { 48 $s = new \stdClass(); 49 $this->validrelated = array( 50 'simplestdClass' => $s, 51 'arrayofstdClass' => array($s, $s), 52 'context' => null, 53 'aint' => 5, 54 'astring' => 'valid string', 55 'abool' => false, 56 'ints' => [] 57 ); 58 $this->invalidrelated = array( 59 'simplestdClass' => 'a string', 60 'arrayofstdClass' => 5, 61 'context' => null, 62 'aint' => false, 63 'astring' => 4, 64 'abool' => 'not a boolean', 65 'ints' => null 66 ); 67 68 $this->validdata = array('stringA' => 'A string', 'stringAformat' => FORMAT_HTML, 'intB' => 4); 69 70 $this->invaliddata = array('stringA' => 'A string'); 71 } 72 73 public function test_get_read_structure() { 74 $structure = core_testable_exporter::get_read_structure(); 75 76 $this->assertInstanceOf(external_single_structure::class, $structure); 77 $this->assertInstanceOf(external_value::class, $structure->keys['stringA']); 78 $this->assertInstanceOf(external_format_value::class, $structure->keys['stringAformat']); 79 $this->assertInstanceOf(external_value::class, $structure->keys['intB']); 80 $this->assertInstanceOf(external_value::class, $structure->keys['otherstring']); 81 $this->assertInstanceOf(external_multiple_structure::class, $structure->keys['otherstrings']); 82 } 83 84 public function test_get_create_structure() { 85 $structure = core_testable_exporter::get_create_structure(); 86 87 $this->assertInstanceOf(external_single_structure::class, $structure); 88 $this->assertInstanceOf(external_value::class, $structure->keys['stringA']); 89 $this->assertInstanceOf(external_format_value::class, $structure->keys['stringAformat']); 90 $this->assertInstanceOf(external_value::class, $structure->keys['intB']); 91 $this->assertArrayNotHasKey('otherstring', $structure->keys); 92 $this->assertArrayNotHasKey('otherstrings', $structure->keys); 93 } 94 95 public function test_get_update_structure() { 96 $structure = core_testable_exporter::get_update_structure(); 97 98 $this->assertInstanceOf(external_single_structure::class, $structure); 99 $this->assertInstanceOf(external_value::class, $structure->keys['stringA']); 100 $this->assertInstanceOf(external_format_value::class, $structure->keys['stringAformat']); 101 $this->assertInstanceOf(external_value::class, $structure->keys['intB']); 102 $this->assertArrayNotHasKey('otherstring', $structure->keys); 103 $this->assertArrayNotHasKey('otherstrings', $structure->keys); 104 } 105 106 public function test_invalid_data() { 107 global $PAGE; 108 $exporter = new core_testable_exporter($this->invaliddata, $this->validrelated); 109 $output = $PAGE->get_renderer('core'); 110 111 // The exception message is a bit misleading, it actually indicates an expected property wasn't found. 112 $this->expectException(\coding_exception::class); 113 $this->expectExceptionMessage('Unexpected property stringAformat'); 114 $result = $exporter->export($output); 115 } 116 117 public function test_invalid_related() { 118 $this->expectException(\coding_exception::class); 119 $this->expectExceptionMessage('Exporter class is missing required related data: (core\core_testable_exporter) ' . 120 'simplestdClass => stdClass'); 121 $exporter = new core_testable_exporter($this->validdata, $this->invalidrelated); 122 } 123 124 public function test_invalid_related_all_cases() { 125 global $PAGE; 126 127 foreach ($this->invalidrelated as $key => $value) { 128 $data = $this->validrelated; 129 $data[$key] = $value; 130 131 try { 132 $exporter = new core_testable_exporter($this->validdata, $data); 133 $output = $PAGE->get_renderer('core'); 134 $result = $exporter->export($output); 135 } catch (\coding_exception $e) { 136 $this->assertNotFalse(strpos($e->getMessage(), $key)); 137 } 138 } 139 } 140 141 public function test_valid_data_and_related() { 142 global $PAGE; 143 $output = $PAGE->get_renderer('core'); 144 $exporter = new core_testable_exporter($this->validdata, $this->validrelated); 145 $result = $exporter->export($output); 146 $this->assertSame('>Another string', $result->otherstring); 147 $this->assertSame(array('String >a', 'String b'), $result->otherstrings); 148 } 149 150 public function test_format_text() { 151 global $PAGE; 152 153 $this->resetAfterTest(); 154 $course = $this->getDataGenerator()->create_course(); 155 $syscontext = \context_system::instance(); 156 $coursecontext = \context_course::instance($course->id); 157 158 external_settings::get_instance()->set_filter(true); 159 filter_set_global_state('urltolink', TEXTFILTER_OFF); 160 filter_set_local_state('urltolink', $coursecontext->id, TEXTFILTER_ON); 161 set_config('formats', FORMAT_MARKDOWN, 'filter_urltolink'); 162 \filter_manager::reset_caches(); 163 164 $data = [ 165 'stringA' => '__Watch out:__ https://moodle.org @@PLUGINFILE@@/test.pdf', 166 'stringAformat' => FORMAT_MARKDOWN, 167 'intB' => 1 168 ]; 169 170 // Export simulated in the system context. 171 $output = $PAGE->get_renderer('core'); 172 $exporter = new core_testable_exporter($data, ['context' => $syscontext] + $this->validrelated); 173 $result = $exporter->export($output); 174 175 $youtube = 'https://moodle.org'; 176 $fileurl = (new \moodle_url('/webservice/pluginfile.php/' . $syscontext->id . '/test/area/9/test.pdf'))->out(false); 177 $expected = "<p><strong>Watch out:</strong> $youtube $fileurl</p>\n"; 178 $this->assertEquals($expected, $result->stringA); 179 $this->assertEquals(FORMAT_HTML, $result->stringAformat); 180 181 // Export simulated in the course context where the filter is enabled. 182 $exporter = new core_testable_exporter($data, ['context' => $coursecontext] + $this->validrelated); 183 $result = $exporter->export($output); 184 $youtube = '<a href="https://moodle.org" class="_blanktarget">https://moodle.org</a>'; 185 $fileurl = (new \moodle_url('/webservice/pluginfile.php/' . $coursecontext->id . '/test/area/9/test.pdf'))->out(false); 186 $expected = "<p><strong>Watch out:</strong> $youtube <a href=\"$fileurl\" class=\"_blanktarget\">$fileurl</a></p>\n"; 187 $this->assertEquals($expected, $result->stringA); 188 $this->assertEquals(FORMAT_HTML, $result->stringAformat); 189 } 190 191 public function test_properties_description() { 192 $properties = core_testable_exporter::read_properties_definition(); 193 // Properties default description. 194 $this->assertEquals('stringA', $properties['stringA']['description']); 195 $this->assertEquals('stringAformat', $properties['stringAformat']['description']); 196 // Properties custom description. 197 $this->assertEquals('intB description', $properties['intB']['description']); 198 // Other properties custom description. 199 $this->assertEquals('otherstring description', $properties['otherstring']['description']); 200 // Other properties default description. 201 $this->assertEquals('otherstrings', $properties['otherstrings']['description']); 202 // Assert nested elements are formatted correctly. 203 $this->assertEquals('id', $properties['nestedarray']['type']['id']['description']); 204 } 205 } 206 207 /** 208 * Example persistent class. 209 * 210 * @package core 211 * @copyright 2015 Frédéric Massart - FMCorz.net 212 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 213 */ 214 class core_testable_exporter extends \core\external\exporter { 215 216 protected static function define_related() { 217 // We cache the context so it does not need to be retrieved from the course. 218 return array('simplestdClass' => 'stdClass', 'arrayofstdClass' => 'stdClass[]', 'context' => 'context?', 219 'astring' => 'string', 'abool' => 'bool', 'aint' => 'int', 'ints' => 'int[]'); 220 } 221 222 protected function get_other_values(\renderer_base $output) { 223 return array( 224 'otherstring' => '>Another <strong>string</strong>', 225 'otherstrings' => array('String >a', 'String <strong>b</strong>') 226 ); 227 } 228 229 public static function define_properties() { 230 return array( 231 'stringA' => array( 232 'type' => PARAM_RAW, 233 ), 234 'stringAformat' => array( 235 'type' => PARAM_INT, 236 ), 237 'intB' => array( 238 'type' => PARAM_INT, 239 'description' => 'intB description', 240 ) 241 ); 242 } 243 244 public static function define_other_properties() { 245 return array( 246 'otherstring' => array( 247 'type' => PARAM_TEXT, 248 'description' => 'otherstring description', 249 ), 250 'otherstrings' => array( 251 'type' => PARAM_TEXT, 252 'multiple' => true 253 ), 254 'nestedarray' => array( 255 'multiple' => true, 256 'optional' => true, 257 'type' => [ 258 'id' => ['type' => PARAM_INT] 259 ] 260 ) 261 ); 262 } 263 264 protected function get_format_parameters_for_stringA() { 265 return [ 266 // For testing use the passed context if any. 267 'context' => isset($this->related['context']) ? $this->related['context'] : \context_system::instance(), 268 'component' => 'test', 269 'filearea' => 'area', 270 'itemid' => 9, 271 ]; 272 } 273 274 protected function get_format_parameters_for_otherstring() { 275 return [ 276 'context' => \context_system::instance(), 277 'options' => ['escape' => false] 278 ]; 279 } 280 281 protected function get_format_parameters_for_otherstrings() { 282 return [ 283 'context' => \context_system::instance(), 284 ]; 285 } 286 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body