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