Proyectos de Subversion Moodle

Rev

Ir a la última revisión | | Ultima modificación | Ver Log |

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