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 * Test xml_writer tests. 19 * 20 * @package core_backup 21 * @category test 22 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 namespace core_backup; 27 28 use memory_xml_output; 29 use xml_contenttransformer; 30 use xml_output; 31 use xml_writer; 32 use xml_writer_exception; 33 34 defined('MOODLE_INTERNAL') || die(); 35 36 // Include all the needed stuff 37 global $CFG; 38 require_once($CFG->dirroot . '/backup/util/xml/xml_writer.class.php'); 39 require_once($CFG->dirroot . '/backup/util/xml/output/xml_output.class.php'); 40 require_once($CFG->dirroot . '/backup/util/xml/output/memory_xml_output.class.php'); 41 require_once($CFG->dirroot . '/backup/util/xml/contenttransformer/xml_contenttransformer.class.php'); 42 43 /** 44 * Test xml_writer tests. 45 * 46 * @package core_backup 47 * @category test 48 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} 49 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 50 */ 51 class writer_test extends \basic_testcase { 52 53 /** 54 * test xml_writer public methods 55 */ 56 function test_xml_writer_public_api() { 57 global $CFG; 58 // Instantiate xml_output 59 $xo = new memory_xml_output(); 60 $this->assertTrue($xo instanceof xml_output); 61 62 // Instantiate xml_writer with null xml_output 63 try { 64 $xw = new mock_xml_writer(null); 65 $this->assertTrue(false, 'xml_writer_exception expected'); 66 } catch (\Exception $e) { 67 $this->assertTrue($e instanceof xml_writer_exception); 68 $this->assertEquals($e->errorcode, 'invalid_xml_output'); 69 } 70 71 // Instantiate xml_writer with wrong xml_output object 72 try { 73 $xw = new mock_xml_writer(new \stdClass()); 74 $this->assertTrue(false, 'xml_writer_exception expected'); 75 } catch (\Exception $e) { 76 $this->assertTrue($e instanceof xml_writer_exception); 77 $this->assertEquals($e->errorcode, 'invalid_xml_output'); 78 } 79 80 // Instantiate xml_writer with wrong xml_contenttransformer object 81 try { 82 $xw = new mock_xml_writer($xo, new \stdClass()); 83 $this->assertTrue(false, 'xml_writer_exception expected'); 84 } catch (\Exception $e) { 85 $this->assertTrue($e instanceof xml_writer_exception); 86 $this->assertEquals($e->errorcode, 'invalid_xml_contenttransformer'); 87 } 88 89 // Instantiate xml_writer and start it twice 90 $xw = new mock_xml_writer($xo); 91 $xw->start(); 92 try { 93 $xw->start(); 94 $this->assertTrue(false, 'xml_writer_exception expected'); 95 } catch (\Exception $e) { 96 $this->assertTrue($e instanceof xml_writer_exception); 97 $this->assertEquals($e->errorcode, 'xml_writer_already_started'); 98 } 99 100 // Instantiate xml_writer and stop it twice 101 $xo = new memory_xml_output(); 102 $xw = new mock_xml_writer($xo); 103 $xw->start(); 104 $xw->stop(); 105 try { 106 $xw->stop(); 107 $this->assertTrue(false, 'xml_writer_exception expected'); 108 } catch (\Exception $e) { 109 $this->assertTrue($e instanceof xml_writer_exception); 110 $this->assertEquals($e->errorcode, 'xml_writer_already_stopped'); 111 } 112 113 // Stop writer without starting it 114 $xo = new memory_xml_output(); 115 $xw = new mock_xml_writer($xo); 116 try { 117 $xw->stop(); 118 $this->assertTrue(false, 'xml_writer_exception expected'); 119 } catch (\Exception $e) { 120 $this->assertTrue($e instanceof xml_writer_exception); 121 $this->assertEquals($e->errorcode, 'xml_writer_not_started'); 122 } 123 124 // Start writer after stopping it 125 $xo = new memory_xml_output(); 126 $xw = new mock_xml_writer($xo); 127 $xw->start(); 128 $xw->stop(); 129 try { 130 $xw->start(); 131 $this->assertTrue(false, 'xml_writer_exception expected'); 132 } catch (\Exception $e) { 133 $this->assertTrue($e instanceof xml_writer_exception); 134 $this->assertEquals($e->errorcode, 'xml_writer_already_stopped'); 135 } 136 137 // Try to set prologue/schema after start 138 $xo = new memory_xml_output(); 139 $xw = new mock_xml_writer($xo); 140 $xw->start(); 141 try { 142 $xw->set_nonamespace_schema('http://moodle.org'); 143 $this->assertTrue(false, 'xml_writer_exception expected'); 144 } catch (\Exception $e) { 145 $this->assertTrue($e instanceof xml_writer_exception); 146 $this->assertEquals($e->errorcode, 'xml_writer_already_started'); 147 } 148 try { 149 $xw->set_prologue('sweet prologue'); 150 $this->assertTrue(false, 'xml_writer_exception expected'); 151 } catch (\Exception $e) { 152 $this->assertTrue($e instanceof xml_writer_exception); 153 $this->assertEquals($e->errorcode, 'xml_writer_already_started'); 154 } 155 156 // Instantiate properly with memory_xml_output, start and stop. 157 // Must get default UTF-8 prologue 158 $xo = new memory_xml_output(); 159 $xw = new mock_xml_writer($xo); 160 $xw->start(); 161 $xw->stop(); 162 $this->assertEquals($xo->get_allcontents(), $xw->get_default_prologue()); 163 164 // Instantiate, set prologue and schema, put 1 full tag and get results 165 $xo = new memory_xml_output(); 166 $xw = new mock_xml_writer($xo); 167 $xw->set_prologue('CLEARLY WRONG PROLOGUE'); 168 $xw->set_nonamespace_schema('http://moodle.org/littleschema'); 169 $xw->start(); 170 $xw->full_tag('TEST', 'Hello World!', array('id' => 1)); 171 $xw->stop(); 172 $result = $xo->get_allcontents(); 173 // Perform various checks 174 $this->assertEquals(strpos($result, 'WRONG'), 8); 175 $this->assertEquals(strpos($result, '<TEST id="1"'), 22); 176 $this->assertEquals(strpos($result, 'xmlns:xsi='), 39); 177 $this->assertEquals(strpos($result, 'http://moodle.org/littleschema'), 128); 178 $this->assertEquals(strpos($result, 'Hello World'), 160); 179 $this->assertFalse(strpos($result, $xw->get_default_prologue())); 180 181 // Try to close one tag in wrong order 182 $xo = new memory_xml_output(); 183 $xw = new mock_xml_writer($xo); 184 $xw->start(); 185 $xw->begin_tag('first'); 186 $xw->begin_tag('second'); 187 try { 188 $xw->end_tag('first'); 189 $this->assertTrue(false, 'xml_writer_exception expected'); 190 } catch (\Exception $e) { 191 $this->assertTrue($e instanceof xml_writer_exception); 192 $this->assertEquals($e->errorcode, 'xml_writer_end_tag_no_match'); 193 } 194 195 // Try to close one tag before starting any tag 196 $xo = new memory_xml_output(); 197 $xw = new mock_xml_writer($xo); 198 $xw->start(); 199 try { 200 $xw->end_tag('first'); 201 $this->assertTrue(false, 'xml_writer_exception expected'); 202 } catch (\Exception $e) { 203 $this->assertTrue($e instanceof xml_writer_exception); 204 $this->assertEquals($e->errorcode, 'xml_writer_end_tag_no_match'); 205 } 206 207 // Full tag without contents (null and empty string) 208 $xo = new memory_xml_output(); 209 $xw = new mock_xml_writer($xo); 210 $xw->set_prologue(''); // empty prologue for easier matching 211 $xw->start(); 212 $xw->full_tag('tagname', null, array('attrname' => 'attrvalue')); 213 $xw->full_tag('tagname2', '', array('attrname' => 'attrvalue')); 214 $xw->stop(); 215 $result = $xo->get_allcontents(); 216 $this->assertEquals($result, '<tagname attrname="attrvalue" /><tagname2 attrname="attrvalue"></tagname2>'); 217 218 219 // Test case-folding is working 220 $xo = new memory_xml_output(); 221 $xw = new mock_xml_writer($xo, null, true); 222 $xw->set_prologue(''); // empty prologue for easier matching 223 $xw->start(); 224 $xw->full_tag('tagname', 'textcontent', array('attrname' => 'attrvalue')); 225 $xw->stop(); 226 $result = $xo->get_allcontents(); 227 $this->assertEquals($result, '<TAGNAME ATTRNAME="attrvalue">textcontent</TAGNAME>'); 228 229 // Test UTF-8 chars in tag and attribute names, attr values and contents 230 $xo = new memory_xml_output(); 231 $xw = new mock_xml_writer($xo); 232 $xw->set_prologue(''); // empty prologue for easier matching 233 $xw->start(); 234 $xw->full_tag('áéíóú', 'ÁÉÍÓÚ', array('àèìòù' => 'ÀÈÌÒÙ')); 235 $xw->stop(); 236 $result = $xo->get_allcontents(); 237 $this->assertEquals($result, '<áéíóú àèìòù="ÀÈÌÒÙ">ÁÉÍÓÚ</áéíóú>'); 238 239 // Try non-safe content in attributes 240 $xo = new memory_xml_output(); 241 $xw = new mock_xml_writer($xo); 242 $xw->set_prologue(''); // empty prologue for easier matching 243 $xw->start(); 244 $xw->full_tag('tagname', 'textcontent', array('attrname' => 'attr' . chr(27) . '\'"value')); 245 $xw->stop(); 246 $result = $xo->get_allcontents(); 247 $this->assertEquals($result, '<tagname attrname="attr\'"value">textcontent</tagname>'); 248 249 // Try non-safe content in text 250 $xo = new memory_xml_output(); 251 $xw = new mock_xml_writer($xo); 252 $xw->set_prologue(''); // empty prologue for easier matching 253 $xw->start(); 254 $xw->full_tag('tagname', "text\r\ncontent\rwith" . chr(27), array('attrname' => 'attrvalue')); 255 $xw->stop(); 256 $result = $xo->get_allcontents(); 257 $this->assertEquals($result, '<tagname attrname="attrvalue">text' . "\ncontent\n" . 'with</tagname>'); 258 259 // Try to stop the writer without clossing all the open tags 260 $xo = new memory_xml_output(); 261 $xw = new mock_xml_writer($xo); 262 $xw->start(); 263 $xw->begin_tag('first'); 264 try { 265 $xw->stop(); 266 $this->assertTrue(false, 'xml_writer_exception expected'); 267 } catch (\Exception $e) { 268 $this->assertTrue($e instanceof xml_writer_exception); 269 $this->assertEquals($e->errorcode, 'xml_writer_open_tags_remaining'); 270 } 271 272 // Test simple transformer 273 $xo = new memory_xml_output(); 274 $xt = new mock_xml_contenttransformer(); 275 $xw = new mock_xml_writer($xo, $xt); 276 $xw->set_prologue(''); // empty prologue for easier matching 277 $xw->start(); 278 $xw->full_tag('tagname', null, array('attrname' => 'attrvalue')); 279 $xw->full_tag('tagname2', 'somecontent', array('attrname' => 'attrvalue')); 280 $xw->stop(); 281 $result = $xo->get_allcontents(); 282 $this->assertEquals($result, '<tagname attrname="attrvalue" /><tagname2 attrname="attrvalue">testsomecontent</tagname2>'); 283 284 // Build a complex XML file and test results against stored file in fixtures 285 $xo = new memory_xml_output(); 286 $xw = new mock_xml_writer($xo); 287 $xw->start(); 288 $xw->begin_tag('toptag', array('name' => 'toptag', 'level' => 1, 'path' => '/toptag')); 289 $xw->full_tag('secondtag', 'secondvalue', array('name' => 'secondtag', 'level' => 2, 'path' => '/toptag/secondtag', 'value' => 'secondvalue')); 290 $xw->begin_tag('thirdtag', array('name' => 'thirdtag', 'level' => 2, 'path' => '/toptag/thirdtag')); 291 $xw->full_tag('onevalue', 'onevalue', array('name' => 'onevalue', 'level' => 3, 'path' => '/toptag/thirdtag/onevalue')); 292 $xw->full_tag('onevalue', 'anothervalue', array('name' => 'onevalue', 'level' => 3, 'value' => 'anothervalue')); 293 $xw->full_tag('onevalue', 'yetanothervalue', array('name' => 'onevalue', 'level' => 3, 'value' => 'yetanothervalue')); 294 $xw->full_tag('twovalue', 'twovalue', array('name' => 'twovalue', 'level' => 3, 'path' => '/toptag/thirdtag/twovalue')); 295 $xw->begin_tag('forthtag', array('name' => 'forthtag', 'level' => 3, 'path' => '/toptag/thirdtag/forthtag')); 296 $xw->full_tag('innervalue', 'innervalue'); 297 $xw->begin_tag('innertag'); 298 $xw->begin_tag('superinnertag', array('name' => 'superinnertag', 'level' => 5)); 299 $xw->full_tag('superinnervalue', 'superinnervalue', array('name' => 'superinnervalue', 'level' => 6)); 300 $xw->end_tag('superinnertag'); 301 $xw->end_tag('innertag'); 302 $xw->end_tag('forthtag'); 303 $xw->begin_tag('fifthtag', array('level' => 3)); 304 $xw->begin_tag('sixthtag', array('level' => 4)); 305 $xw->full_tag('seventh', 'seventh', array('level' => 5)); 306 $xw->end_tag('sixthtag'); 307 $xw->end_tag('fifthtag'); 308 $xw->full_tag('finalvalue', 'finalvalue', array('name' => 'finalvalue', 'level' => 3, 'path' => '/toptag/thirdtag/finalvalue')); 309 $xw->full_tag('finalvalue'); 310 $xw->end_tag('thirdtag'); 311 $xw->end_tag('toptag'); 312 $xw->stop(); 313 $result = $xo->get_allcontents(); 314 $fcontents = file_get_contents($CFG->dirroot . '/backup/util/xml/tests/fixtures/test1.xml'); 315 316 // Normalise carriage return characters. 317 $fcontents = str_replace("\r\n", "\n", $fcontents); 318 $this->assertEquals(trim($result), trim($fcontents)); 319 } 320 } 321 322 /* 323 * helper extended xml_writer class that makes some methods public for testing 324 */ 325 class mock_xml_writer extends xml_writer { 326 public function get_default_prologue() { 327 return parent::get_default_prologue(); 328 } 329 } 330 331 /* 332 * helper extended xml_contenttransformer prepending "test" to all the notnull contents 333 */ 334 class mock_xml_contenttransformer extends xml_contenttransformer { 335 public function process($content) { 336 return is_null($content) ? null : 'test' . $content; 337 } 338 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body