MDL-32569 hide old SimpleTest UI
[moodle.git] / backup / util / xml / parser / simpletest / testparser.php
CommitLineData
be866f9d
EL
1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * @package moodlecore
20 * @subpackage backup-tests
21 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25// Prevent direct access to this file
26if (!defined('MOODLE_INTERNAL')) {
27 die('Direct access to this script is forbidden.');
28}
29
30// Include all the needed stuff
31require_once($CFG->dirroot . '/backup/util/xml/parser/progressive_parser.class.php');
32require_once($CFG->dirroot . '/backup/util/xml/parser/processors/progressive_parser_processor.class.php');
33require_once($CFG->dirroot . '/backup/util/xml/parser/processors/simplified_parser_processor.class.php');
4c7f6ac6 34require_once($CFG->dirroot . '/backup/util/xml/parser/processors/grouped_parser_processor.class.php');
be866f9d
EL
35
36/*
37 * progressive_parser and progressive_parser_processor tests
38 */
39class progressive_parser_test extends UnitTestCase {
40
41 public static $includecoverage = array('backup/util/xml/parser');
42 public static $excludecoverage = array('backup/util/xml/parser/simpletest');
43
44 /*
45 * test progressive_parser public methods
46 */
47 function test_parser_public_api() {
48 global $CFG;
49 // Instantiate progressive_parser
50 $pp = new progressive_parser();
51 $this->assertTrue($pp instanceof progressive_parser);
52 $pr = new mock_parser_processor();
53 $this->assertTrue($pr instanceof progressive_parser_processor);
54
55 // Try to process without processor
56 try {
57 $pp->process();
58 $this->assertTrue(false);
59 } catch (exception $e) {
60 $this->assertTrue($e instanceof progressive_parser_exception);
61 $this->assertEqual($e->errorcode, 'undefined_parser_processor');
62 }
63
64 // Assign processor to parser
65 $pp->set_processor($pr);
66
67 // Try to process without file and contents
68 try {
69 $pp->process();
70 $this->assertTrue(false);
71 } catch (exception $e) {
72 $this->assertTrue($e instanceof progressive_parser_exception);
73 $this->assertEqual($e->errorcode, 'undefined_xml_to_parse');
74 }
75
76 // Assign *invalid* processor to parser
77 try {
78 $pp->set_processor(new stdClass());
79 $this->assertTrue(false);
80 } catch (exception $e) {
81 $this->assertTrue($e instanceof progressive_parser_exception);
82 $this->assertEqual($e->errorcode, 'invalid_parser_processor');
83 }
84
85 // Set file from fixtures (test1.xml) and process it
86 $pp = new progressive_parser();
87 $pr = new mock_parser_processor();
88 $pp->set_processor($pr);
89 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test1.xml');
90 $pp->process();
91 $serfromfile = serialize($pr->get_chunks()); // Get serialized results (to compare later)
92 // Set *unexisting* file from fixtures
93 try {
94 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test0.xml');
95 $this->assertTrue(false);
96 } catch (exception $e) {
97 $this->assertTrue($e instanceof progressive_parser_exception);
98 $this->assertEqual($e->errorcode, 'invalid_file_to_parse');
99 }
100
101 // Set contents from fixtures (test1.xml) and process it
102 $pp = new progressive_parser();
103 $pr = new mock_parser_processor();
104 $pp->set_processor($pr);
105 $pp->set_contents(file_get_contents($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test1.xml'));
106 $pp->process();
107 $serfrommemory = serialize($pr->get_chunks()); // Get serialized results (to compare later)
108 // Set *empty* contents
109 try {
110 $pp->set_contents('');
111 $this->assertTrue(false);
112 } catch (exception $e) {
113 $this->assertTrue($e instanceof progressive_parser_exception);
114 $this->assertEqual($e->errorcode, 'invalid_contents_to_parse');
115 }
116
117 // Check that both results from file processing and content processing are equal
118 $this->assertEqual($serfromfile, $serfrommemory);
119
120 // Check case_folding is working ok
121 $pp = new progressive_parser(true);
122 $pr = new mock_parser_processor();
123 $pp->set_processor($pr);
124 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test1.xml');
125 $pp->process();
126 $chunks = $pr->get_chunks();
127 $this->assertTrue($chunks[0]['path'] === '/FIRSTTAG');
128 $this->assertTrue($chunks[0]['tags']['SECONDTAG']['name'] === 'SECONDTAG');
129 $this->assertTrue($chunks[0]['tags']['SECONDTAG']['attrs']['NAME'] === 'secondtag');
130
131 // Check invalid XML exception is working ok
132 $pp = new progressive_parser(true);
133 $pr = new mock_parser_processor();
134 $pp->set_processor($pr);
135 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test2.xml');
136 try {
137 $pp->process();
138 } catch (exception $e) {
139 $this->assertTrue($e instanceof progressive_parser_exception);
140 $this->assertEqual($e->errorcode, 'xml_parsing_error');
141 }
142
143 // Check double process throws exception
144 $pp = new progressive_parser(true);
145 $pr = new mock_parser_processor();
146 $pp->set_processor($pr);
147 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test1.xml');
148 $pp->process();
149 try { // Second process, will throw exception
150 $pp->process();
151 $this->assertTrue(false);
152 } catch (exception $e) {
153 $this->assertTrue($e instanceof progressive_parser_exception);
154 $this->assertEqual($e->errorcode, 'progressive_parser_already_used');
155 }
156 }
157
158 /*
159 * test progressive_parser parsing results using testing_parser_processor and test1.xml
160 * auto-described file from fixtures
161 */
162 function test_parser_results() {
163 global $CFG;
164 // Instantiate progressive_parser
165 $pp = new progressive_parser();
166 // Instantiate processor, passing the unit test as param
167 $pr = new mock_auto_parser_processor($this);
168 $this->assertTrue($pr instanceof progressive_parser_processor);
169 // Assign processor to parser
170 $pp->set_processor($pr);
171 // Set file from fixtures
172 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test3.xml');
173 // Process the file, the autotest processor will perform a bunch of automatic tests
174 $pp->process();
175 // Get processor debug info
176 $debug = $pr->debug_info();
177 $this->assertTrue(is_array($debug));
178 $this->assertTrue(array_key_exists('chunks', $debug));
179 // Check the number of chunks is correct for the file
180 $this->assertEqual($debug['chunks'], 10);
181 }
182
183 /*
184 * test progressive_parser parsing results using simplified_parser_processor and test4.xml
185 * (one simple glossary backup file example)
186 */
187 function test_simplified_parser_results() {
188 global $CFG;
189 // Instantiate progressive_parser
190 $pp = new progressive_parser();
191 // Instantiate simplified_parser_processor declaring the interesting paths
192 $pr = new mock_simplified_parser_processor(array(
193 '/activity',
194 '/activity/glossary',
195 '/activity/glossary/entries/entry',
196 '/activity/glossary/entries/entry/aliases/alias',
197 '/activity/glossary/entries/entry/ratings/rating',
4c7f6ac6
EL
198 '/activity/glossary/categories/category',
199 '/activity/glossary/onetest',
200 '/activity/glossary/othertest'));
be866f9d
EL
201 $this->assertTrue($pr instanceof progressive_parser_processor);
202 // Assign processor to parser
203 $pp->set_processor($pr);
204 // Set file from fixtures
205 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test4.xml');
206 // Process the file
207 $pp->process();
208 // Get processor debug info
209 $debug = $pr->debug_info();
210 $this->assertTrue(is_array($debug));
211 $this->assertTrue(array_key_exists('chunks', $debug));
212
213 // Check the number of chunks is correct for the file
4c7f6ac6 214 $this->assertEqual($debug['chunks'], 12);
be866f9d
EL
215 // Get all the simplified chunks and perform various validations
216 $chunks = $pr->get_chunks();
4c7f6ac6
EL
217 // Check we have received the correct number of chunks
218 $this->assertEqual(count($chunks), 12);
be866f9d
EL
219
220 // chunk[0] (/activity) tests
221 $this->assertEqual(count($chunks[0]), 3);
222 $this->assertEqual($chunks[0]['path'], '/activity');
223 $this->assertEqual($chunks[0]['level'],'2');
224 $tags = $chunks[0]['tags'];
225 $this->assertEqual(count($tags), 4);
226 $this->assertEqual($tags['id'], 1);
227 $this->assertEqual($tags['moduleid'], 5);
228 $this->assertEqual($tags['modulename'], 'glossary');
229 $this->assertEqual($tags['contextid'], 26);
230 $this->assertEqual($chunks[0]['level'],'2');
231
232 // chunk[1] (/activity/glossary) tests
233 $this->assertEqual(count($chunks[1]), 3);
234 $this->assertEqual($chunks[1]['path'], '/activity/glossary');
235 $this->assertEqual($chunks[1]['level'],'3');
236 $tags = $chunks[1]['tags'];
237 $this->assertEqual(count($tags), 24);
238 $this->assertEqual($tags['id'], 1);
239 $this->assertEqual($tags['intro'], '<p>One simple glossary to test backup &amp; restore. Here it\'s the standard image:</p>'.
240 "\n".
241 '<p><img src="@@PLUGINFILE@@/88_31.png" alt="pwd by moodle" width="88" height="31" /></p>');
242 $this->assertEqual($tags['timemodified'], 1275639747);
243 $this->assertTrue(!isset($tags['categories']));
244
245 // chunk[5] (second /activity/glossary/entries/entry) tests
246 $this->assertEqual(count($chunks[5]), 3);
247 $this->assertEqual($chunks[5]['path'], '/activity/glossary/entries/entry');
248 $this->assertEqual($chunks[5]['level'],'5');
249 $tags = $chunks[5]['tags'];
250 $this->assertEqual(count($tags), 15);
251 $this->assertEqual($tags['id'], 2);
252 $this->assertEqual($tags['concept'], 'cat');
253 $this->assertTrue(!isset($tags['aliases']));
254 $this->assertTrue(!isset($tags['entries']));
255
256 // chunk[6] (second /activity/glossary/entries/entry/aliases/alias) tests
257 $this->assertEqual(count($chunks[6]), 3);
258 $this->assertEqual($chunks[6]['path'], '/activity/glossary/entries/entry/aliases/alias');
259 $this->assertEqual($chunks[6]['level'],'7');
260 $tags = $chunks[6]['tags'];
261 $this->assertEqual(count($tags), 2);
262 $this->assertEqual($tags['id'], 2);
263 $this->assertEqual($tags['alias_text'], 'cats');
264
4c7f6ac6 265 // chunk[7] (second /activity/glossary/entries/entry/aliases/alias) tests
be866f9d 266 $this->assertEqual(count($chunks[7]), 3);
4c7f6ac6 267 $this->assertEqual($chunks[7]['path'], '/activity/glossary/entries/entry/aliases/alias');
be866f9d
EL
268 $this->assertEqual($chunks[7]['level'],'7');
269 $tags = $chunks[7]['tags'];
4c7f6ac6
EL
270 $this->assertEqual(count($tags), 2);
271 $this->assertEqual($tags['id'], 3);
272 $this->assertEqual($tags['alias_text'], 'felines');
273
274 // chunk[8] (second /activity/glossary/entries/entry/ratings/rating) tests
275 $this->assertEqual(count($chunks[8]), 3);
276 $this->assertEqual($chunks[8]['path'], '/activity/glossary/entries/entry/ratings/rating');
277 $this->assertEqual($chunks[8]['level'],'7');
278 $tags = $chunks[8]['tags'];
be866f9d
EL
279 $this->assertEqual(count($tags), 6);
280 $this->assertEqual($tags['id'], 1);
281 $this->assertEqual($tags['timemodified'], '1275639779');
4c7f6ac6
EL
282
283 // chunk[9] (first /activity/glossary/onetest) tests
284 $this->assertEqual(count($chunks[9]), 3);
285 $this->assertEqual($chunks[9]['path'], '/activity/glossary/onetest');
286 $this->assertEqual($chunks[9]['level'],'4');
287 $tags = $chunks[9]['tags'];
288 $this->assertEqual(count($tags), 2);
289 $this->assertEqual($tags['name'], 1);
290 $this->assertEqual($tags['value'], 1);
291
292 // chunk[10] (second /activity/glossary/onetest) tests
293 $this->assertEqual(count($chunks[10]), 3);
294 $this->assertEqual($chunks[10]['path'], '/activity/glossary/onetest');
295 $this->assertEqual($chunks[10]['level'],'4');
296 $tags = $chunks[10]['tags'];
297 $this->assertEqual(count($tags), 2);
298 $this->assertEqual($tags['name'], 2);
299 $this->assertEqual($tags['value'], 2);
300
301 // chunk[11] (first /activity/glossary/othertest) tests
302 // note we don't allow repeated "final" element, so we only return the last one
303 $this->assertEqual(count($chunks[11]), 3);
304 $this->assertEqual($chunks[11]['path'], '/activity/glossary/othertest');
305 $this->assertEqual($chunks[11]['level'],'4');
306 $tags = $chunks[11]['tags'];
307 $this->assertEqual(count($tags), 2);
308 $this->assertEqual($tags['name'], 4);
309 $this->assertEqual($tags['value'], 5);
14e6710d
EL
310
311 // Now check start notifications
312 $snotifs = $pr->get_start_notifications();
313 // Check we have received the correct number of notifications
314 $this->assertEqual(count($snotifs), 12);
315 // Check first, sixth and last notifications
316 $this->assertEqual($snotifs[0], '/activity');
317 $this->assertEqual($snotifs[5], '/activity/glossary/entries/entry');
318 $this->assertEqual($snotifs[11], '/activity/glossary/othertest');
319
320 // Now check end notifications
321 $enotifs = $pr->get_end_notifications();
322 // Check we have received the correct number of notifications
323 $this->assertEqual(count($snotifs), 12);
324 // Check first, sixth and last notifications
325 $this->assertEqual($enotifs[0], '/activity/glossary/entries/entry/aliases/alias');
326 $this->assertEqual($enotifs[5], '/activity/glossary/entries/entry/ratings/rating');
327 $this->assertEqual($enotifs[11], '/activity');
328
329 // Check start and end notifications are balanced
330 sort($snotifs);
331 sort($enotifs);
332 $this->assertEqual($snotifs, $enotifs);
8298beda
EL
333
334 // Now verify that the start/process/end order is correct
335 $allnotifs = $pr->get_all_notifications();
336 $this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count
337 // Check integrity of the notifications
338 $errcount = $this->helper_check_notifications_order_integrity($allnotifs);
339 $this->assertEqual($errcount, 0); // No errors found, plz
4c7f6ac6
EL
340 }
341
54b8f334
EL
342 /**
343 * test how the simplified processor and the order of start/process/end events happens
344 * with one real fragment of one backup 1.9 file, where some problems
345 * were found by David, hence we honor him in the name of the test ;-)
346 */
347 function test_simplified_david_backup19_file_fragment() {
348 global $CFG;
349 // Instantiate progressive_parser
350 $pp = new progressive_parser();
351 // Instantiate grouped_parser_processor
352 $pr = new mock_simplified_parser_processor();
353 // Add interesting paths
354 $pr->add_path('/MOODLE_BACKUP/COURSE');
355 $pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION');
356 $pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
357 $pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD/ROLES_OVERRIDES');
358 $this->assertTrue($pr instanceof progressive_parser_processor);
359 // Assign processor to parser
360 $pp->set_processor($pr);
361 // Set file from fixtures
362 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test5.xml');
363 // Process the file
364 $pp->process();
365
366 // Get all the simplified chunks and perform various validations
367 $chunks = $pr->get_chunks();
368 $this->assertEqual(count($chunks), 3); // Only 3, because 7 (COURSE, ROLES_OVERRIDES and 5 MOD) are empty, aka no chunk
369
370 // Now check start notifications
371 $snotifs = $pr->get_start_notifications();
372 // Check we have received the correct number of notifications
373 $this->assertEqual(count($snotifs), 10); // Start tags are dispatched for empties (ROLES_OVERRIDES)
374 // Check first and last notifications
375 $this->assertEqual($snotifs[0], '/MOODLE_BACKUP/COURSE');
376 $this->assertEqual($snotifs[1], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION');
377 $this->assertEqual($snotifs[2], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
378 $this->assertEqual($snotifs[3], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD/ROLES_OVERRIDES');
379 $this->assertEqual($snotifs[7], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
380 $this->assertEqual($snotifs[8], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
381 $this->assertEqual($snotifs[9], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
382
383 // Now check end notifications
384 $enotifs = $pr->get_end_notifications();
385 // Check we have received the correct number of notifications
386 $this->assertEqual(count($snotifs), 10); // End tags are dispatched for empties (ROLES_OVERRIDES)
387 // Check first, and last notifications
388 $this->assertEqual($enotifs[0], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD/ROLES_OVERRIDES');
389 $this->assertEqual($enotifs[1], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
390 $this->assertEqual($enotifs[2], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
391 $this->assertEqual($enotifs[3], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
392 $this->assertEqual($enotifs[7], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
393 $this->assertEqual($enotifs[8], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION');
394 $this->assertEqual($enotifs[9], '/MOODLE_BACKUP/COURSE');
395
396 // Check start and end notifications are balanced
397 sort($snotifs);
398 sort($enotifs);
399 $this->assertEqual($snotifs, $enotifs);
400
401 // Now verify that the start/process/end order is correct
402 $allnotifs = $pr->get_all_notifications();
403 $this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count
404 // Check integrity of the notifications
405 $errcount = $this->helper_check_notifications_order_integrity($allnotifs);
406 $this->assertEqual($errcount, 0); // No errors found, plz
407 }
408
4c7f6ac6
EL
409 /*
410 * test progressive_parser parsing results using grouped_parser_processor and test4.xml
411 * (one simple glossary backup file example)
412 */
413 function test_grouped_parser_results() {
414 global $CFG;
415 // Instantiate progressive_parser
416 $pp = new progressive_parser();
417 // Instantiate grouped_parser_processor
418 $pr = new mock_grouped_parser_processor();
419 // Add interesting paths
420 $pr->add_path('/activity');
421 $pr->add_path('/activity/glossary', true);
422 $pr->add_path('/activity/glossary/entries/entry');
423 $pr->add_path('/activity/glossary/entries/entry/aliases/alias');
424 $pr->add_path('/activity/glossary/entries/entry/ratings/rating');
425 $pr->add_path('/activity/glossary/categories/category');
426 $pr->add_path('/activity/glossary/onetest');
427 $pr->add_path('/activity/glossary/othertest');
428 $this->assertTrue($pr instanceof progressive_parser_processor);
429 // Assign processor to parser
430 $pp->set_processor($pr);
431 // Set file from fixtures
432 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test4.xml');
433 // Process the file
434 $pp->process();
435 // Get processor debug info
436 $debug = $pr->debug_info();
437 $this->assertTrue(is_array($debug));
438 $this->assertTrue(array_key_exists('chunks', $debug));
439
440 // Check the number of chunks is correct for the file
441 $this->assertEqual($debug['chunks'], 2);
442 // Get all the simplified chunks and perform various validations
443 $chunks = $pr->get_chunks();
444 // Check we have received the correct number of chunks
445 $this->assertEqual(count($chunks), 2);
446
447 // chunk[0] (/activity) tests
448 $this->assertEqual(count($chunks[0]), 3);
449 $this->assertEqual($chunks[0]['path'], '/activity');
450 $this->assertEqual($chunks[0]['level'],'2');
451 $tags = $chunks[0]['tags'];
452 $this->assertEqual(count($tags), 4);
453 $this->assertEqual($tags['id'], 1);
454 $this->assertEqual($tags['moduleid'], 5);
455 $this->assertEqual($tags['modulename'], 'glossary');
456 $this->assertEqual($tags['contextid'], 26);
457 $this->assertEqual($chunks[0]['level'],'2');
458
459 // chunk[1] (grouped /activity/glossary tests)
460 $this->assertEqual(count($chunks[1]), 3);
461 $this->assertEqual($chunks[1]['path'], '/activity/glossary');
462 $this->assertEqual($chunks[1]['level'],'3');
463 $tags = $chunks[1]['tags'];
464 $this->assertEqual(count($tags), 27);
465 $this->assertEqual($tags['id'], 1);
466 $this->assertEqual($tags['intro'], '<p>One simple glossary to test backup &amp; restore. Here it\'s the standard image:</p>'.
467 "\n".
468 '<p><img src="@@PLUGINFILE@@/88_31.png" alt="pwd by moodle" width="88" height="31" /></p>');
469 $this->assertEqual($tags['timemodified'], 1275639747);
470 $this->assertTrue(!isset($tags['categories']));
471 $this->assertTrue(isset($tags['entries']));
472 $this->assertTrue(isset($tags['onetest']));
473 $this->assertTrue(isset($tags['othertest']));
474
475 // Various tests under the entries
476 $entries = $chunks[1]['tags']['entries']['entry'];
477 $this->assertEqual(count($entries), 2);
478
479 // First entry
480 $entry1 = $entries[0];
481 $this->assertEqual(count($entry1), 17);
482 $this->assertEqual($entry1['id'], 1);
483 $this->assertEqual($entry1['userid'], 2);
484 $this->assertEqual($entry1['concept'], 'dog');
485 $this->assertEqual($entry1['definition'], '<p>Traditional enemies of cats</p>');
486 $this->assertTrue(isset($entry1['aliases']));
487 $this->assertTrue(isset($entry1['ratings']));
488 // aliases of first entry
489 $aliases = $entry1['aliases']['alias'];
490 $this->assertEqual(count($aliases), 1);
491 // first alias
492 $alias1 = $aliases[0];
493 $this->assertEqual(count($alias1), 2);
494 $this->assertEqual($alias1['id'], 1);
495 $this->assertEqual($alias1['alias_text'], 'dogs');
496 // ratings of first entry
497 $ratings = $entry1['ratings']['rating'];
498 $this->assertEqual(count($ratings), 1);
499 // first rating
500 $rating1 = $ratings[0];
501 $this->assertEqual(count($rating1), 6);
502 $this->assertEqual($rating1['id'], 2);
503 $this->assertEqual($rating1['value'], 6);
504 $this->assertEqual($rating1['timemodified'], '1275639797');
505
506 // Second entry
507 $entry2 = $entries[1];
508 $this->assertEqual(count($entry2), 17);
509 $this->assertEqual($entry2['id'], 2);
510 $this->assertEqual($entry2['userid'], 2);
511 $this->assertEqual($entry2['concept'], 'cat');
512 $this->assertEqual($entry2['definition'], '<p>traditional enemies of dogs</p>');
513 $this->assertTrue(isset($entry2['aliases']));
514 $this->assertTrue(isset($entry2['ratings']));
515 // aliases of first entry
516 $aliases = $entry2['aliases']['alias'];
517 $this->assertEqual(count($aliases), 2);
518 // first alias
519 $alias1 = $aliases[0];
520 $this->assertEqual(count($alias1), 2);
521 $this->assertEqual($alias1['id'], 2);
522 $this->assertEqual($alias1['alias_text'], 'cats');
523 // second alias
524 $alias2 = $aliases[1];
525 $this->assertEqual(count($alias2), 2);
526 $this->assertEqual($alias2['id'], 3);
527 $this->assertEqual($alias2['alias_text'], 'felines');
528 // ratings of first entry
529 $ratings = $entry2['ratings']['rating'];
530 $this->assertEqual(count($ratings), 1);
531 // first rating
532 $rating1 = $ratings[0];
533 $this->assertEqual(count($rating1), 6);
534 $this->assertEqual($rating1['id'], 1);
535 $this->assertEqual($rating1['value'], 5);
536 $this->assertEqual($rating1['scaleid'], 10);
537
538 // Onetest test (only 1 level nested)
539 $onetest = $tags['onetest'];
540 $this->assertEqual(count($onetest), 2);
541 $this->assertEqual(count($onetest[0]), 2);
542 $this->assertEqual($onetest[0]['name'], 1);
543 $this->assertEqual($onetest[0]['value'], 1);
544 $this->assertEqual(count($onetest[1]), 2);
545 $this->assertEqual($onetest[1]['name'], 2);
546 $this->assertEqual($onetest[1]['value'], 2);
547
548 // Other test (0 level nested, only last one is retrieved)
549 $othertest = $tags['othertest'];
550 $this->assertEqual(count($othertest), 1);
551 $this->assertEqual(count($othertest[0]), 2);
552 $this->assertEqual($othertest[0]['name'], 4);
553 $this->assertEqual($othertest[0]['value'], 5);
14e6710d
EL
554
555 // Now check start notifications
556 $snotifs = $pr->get_start_notifications();
557 // Check we have received the correct number of notifications
558 $this->assertEqual(count($snotifs), 2);
559 // Check first and last notifications
560 $this->assertEqual($snotifs[0], '/activity');
561 $this->assertEqual($snotifs[1], '/activity/glossary');
562
563 // Now check end notifications
564 $enotifs = $pr->get_end_notifications();
565 // Check we have received the correct number of notifications
566 $this->assertEqual(count($snotifs), 2);
567 // Check first, and last notifications
568 $this->assertEqual($enotifs[0], '/activity/glossary');
569 $this->assertEqual($enotifs[1], '/activity');
570
571 // Check start and end notifications are balanced
572 sort($snotifs);
573 sort($enotifs);
574 $this->assertEqual($snotifs, $enotifs);
8298beda
EL
575
576 // Now verify that the start/process/end order is correct
577 $allnotifs = $pr->get_all_notifications();
578 $this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count
579 // Check integrity of the notifications
580 $errcount = $this->helper_check_notifications_order_integrity($allnotifs);
581 $this->assertEqual($errcount, 0); // No errors found, plz
582 }
583
54b8f334
EL
584 /**
585 * test how the grouped processor and the order of start/process/end events happens
586 * with one real fragment of one backup 1.9 file, where some problems
587 * were found by David, hence we honor him in the name of the test ;-)
588 */
589 function test_grouped_david_backup19_file_fragment() {
590 global $CFG;
591 // Instantiate progressive_parser
592 $pp = new progressive_parser();
593 // Instantiate grouped_parser_processor
594 $pr = new mock_grouped_parser_processor();
595 // Add interesting paths
596 $pr->add_path('/MOODLE_BACKUP/COURSE');
597 $pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION', true);
598 $pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
599 $pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD/ROLES_OVERRIDES');
600 $this->assertTrue($pr instanceof progressive_parser_processor);
601 // Assign processor to parser
602 $pp->set_processor($pr);
603 // Set file from fixtures
604 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test5.xml');
605 // Process the file
606 $pp->process();
607
608 // Get all the simplified chunks and perform various validations
609 $chunks = $pr->get_chunks();
610 $this->assertEqual(count($chunks), 1); // Only 1, the SECTION one
611
612 // Now check start notifications
613 $snotifs = $pr->get_start_notifications();
614 // Check we have received the correct number of notifications
615 $this->assertEqual(count($snotifs), 2);
616 // Check first and last notifications
617 $this->assertEqual($snotifs[0], '/MOODLE_BACKUP/COURSE');
618 $this->assertEqual($snotifs[1], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION');
619
620 // Now check end notifications
621 $enotifs = $pr->get_end_notifications();
622 // Check we have received the correct number of notifications
623 $this->assertEqual(count($snotifs), 2); // End tags are dispatched for empties (ROLES_OVERRIDES)
624 // Check first, and last notifications
625 $this->assertEqual($enotifs[0], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION');
626 $this->assertEqual($enotifs[1], '/MOODLE_BACKUP/COURSE');
627
628 // Check start and end notifications are balanced
629 sort($snotifs);
630 sort($enotifs);
631 $this->assertEqual($snotifs, $enotifs);
632
633 // Now verify that the start/process/end order is correct
634 $allnotifs = $pr->get_all_notifications();
635 $this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count
636 // Check integrity of the notifications
637 $errcount = $this->helper_check_notifications_order_integrity($allnotifs);
638 $this->assertEqual($errcount, 0); // No errors found, plz
639 }
640
641
8298beda
EL
642 /**
643 * Helper function that given one array of ordered start/process/end notifications will
644 * check it of integrity like:
645 * - process only happens if start is the previous notification
646 * - end only happens if dispatch is the previous notification
647 * - start only happen with level > than last one and if there is no already started like that
648 *
649 * @param array $notifications ordered array of notifications with format [start|process|end]:path
650 * @return int number of integrity problems found (errors)
651 */
652 function helper_check_notifications_order_integrity($notifications) {
653 $numerrors = 0;
654 $notifpile = array('pilebase' => 'start');
d4dd0659 655 $lastnotif = 'start:pilebase';
8298beda 656 foreach ($notifications as $notif) {
8298beda 657
d4dd0659
EL
658 $lastpiletype = end($notifpile);
659 $lastpilepath = key($notifpile);
660 $lastpilelevel = strlen(preg_replace('/[^\/]/', '', $lastpilepath));
661
662 $lastnotiftype = preg_replace('/:.*/', '', $lastnotif);
663 $lastnotifpath = preg_replace('/.*:/', '', $lastnotif);
664 $lastnotiflevel = strlen(preg_replace('/[^\/]/', '', $lastnotifpath));
665
8298beda
EL
666 $notiftype = preg_replace('/:.*/', '', $notif);
667 $notifpath = preg_replace('/.*:/', '', $notif);
d4dd0659 668 $notiflevel = strlen(preg_replace('/[^\/]/', '', $notifpath));
8298beda
EL
669
670 switch ($notiftype) {
671 case 'process':
d4dd0659
EL
672 if ($lastnotifpath != $notifpath or $lastnotiftype != 'start') {
673 $numerrors++; // Only start for same path from last notification is allowed before process
8298beda
EL
674 }
675 $notifpile[$notifpath] = 'process'; // Update the status in the pile
676 break;
677 case 'end':
54b8f334 678 if ($lastpilepath != $notifpath or ($lastpiletype != 'process' and $lastpiletype != 'start')) {
d4dd0659 679 $numerrors++; // Only process and start for same path from last pile is allowed before end
8298beda
EL
680 }
681 unset($notifpile[$notifpath]); // Delete from the pile
682 break;
683 case 'start':
684 if (array_key_exists($notifpath, $notifpile) or $notiflevel <= $lastpilelevel) {
d4dd0659 685 $numerrors++; // Only non existing in pile and with level > last pile is allowed on start
8298beda
EL
686 }
687 $notifpile[$notifpath] = 'start'; // Add to the pile
688 break;
689 default:
690 $numerrors++; // Incorrect type of notification => error
691 }
d4dd0659
EL
692 // Update lastnotif
693 $lastnotif = $notif;
8298beda
EL
694 }
695 return $numerrors;
be866f9d
EL
696 }
697}
698
699/*
700 * helper processor able to perform various auto-cheks based on attributes while processing
701 * the test1.xml file available in the fixtures dir. It performs these checks:
702 * - name equal to "name" attribute of the tag (if present)
703 * - level equal to "level" attribute of the tag (if present)
704 * - path + tagname equal to "path" attribute of the tag (if present)
705 * - cdata, if not empty is:
706 * - equal to "value" attribute of the tag (if present)
707 * - else, equal to tag name
708 *
709 * We pass the whole UnitTestCase object to the processor in order to be
710 * able to perform the tests in the straight in the process
711 */
712class mock_auto_parser_processor extends progressive_parser_processor {
713
714 private $utc = null; // To store the unit test case
715
716 public function __construct($unit_test_case) {
717 parent::__construct();
718 $this->utc = $unit_test_case;
719 }
720
721 public function process_chunk($data) {
722 // Perform auto-checks based in the rules above
723 if (isset($data['tags'])) {
724 foreach ($data['tags'] as $tag) {
725 if (isset($tag['attrs']['name'])) { // name tests
726 $this->utc->assertEqual($tag['name'], $tag['attrs']['name']);
727 }
728 if (isset($tag['attrs']['level'])) { // level tests
729 $this->utc->assertEqual($data['level'], $tag['attrs']['level']);
730 }
731 if (isset($tag['attrs']['path'])) { // path tests
732 $this->utc->assertEqual(rtrim($data['path'], '/') . '/' . $tag['name'], $tag['attrs']['path']);
733 }
734 if (!empty($tag['cdata'])) { // cdata tests
735 if (isset($tag['attrs']['value'])) {
736 $this->utc->assertEqual($tag['cdata'], $tag['attrs']['value']);
737 } else {
738 $this->utc->assertEqual($tag['cdata'], $tag['name']);
739 }
740 }
741 }
742 }
743 }
744}
745
746/*
747 * helper processor that accumulates all the chunks, resturning them with the get_chunks() method
748 */
749class mock_parser_processor extends progressive_parser_processor {
750
751 private $chunksarr = array(); // To accumulate the found chunks
752
753 public function process_chunk($data) {
754 $this->chunksarr[] = $data;
755 }
756
757 public function get_chunks() {
758 return $this->chunksarr;
759 }
760}
761
762/*
763 * helper processor that accumulates simplified chunks, returning them with the get_chunks() method
764 */
765class mock_simplified_parser_processor extends simplified_parser_processor {
766
767 private $chunksarr = array(); // To accumulate the found chunks
14e6710d
EL
768 private $startarr = array(); // To accumulate all the notified path starts
769 private $endarr = array(); // To accumulate all the notified path ends
8298beda 770 private $allnotif = array(); // To accumulate all the notified and dispatched events in an ordered way
be866f9d
EL
771
772 public function dispatch_chunk($data) {
773 $this->chunksarr[] = $data;
8298beda 774 $this->allnotif[] = 'process:' . $data['path'];
be866f9d
EL
775 }
776
14e6710d
EL
777 public function notify_path_start($path) {
778 $this->startarr[] = $path;
8298beda 779 $this->allnotif[] = 'start:' . $path;
14e6710d
EL
780 }
781
782 public function notify_path_end($path) {
783 $this->endarr[] = $path;
8298beda 784 $this->allnotif[] = 'end:' . $path;
14e6710d
EL
785 }
786
be866f9d
EL
787 public function get_chunks() {
788 return $this->chunksarr;
789 }
14e6710d
EL
790
791 public function get_start_notifications() {
792 return $this->startarr;
793 }
794
795 public function get_end_notifications() {
796 return $this->endarr;
797 }
8298beda
EL
798
799 public function get_all_notifications() {
800 return $this->allnotif;
801 }
be866f9d 802}
4c7f6ac6
EL
803
804/*
805 * helper processor that accumulates grouped chunks, returning them with the get_chunks() method
806 */
807class mock_grouped_parser_processor extends grouped_parser_processor {
808
809 private $chunksarr = array(); // To accumulate the found chunks
14e6710d
EL
810 private $startarr = array(); // To accumulate all the notified path starts
811 private $endarr = array(); // To accumulate all the notified path ends
8298beda 812 private $allnotif = array(); // To accumulate all the notified and dispatched events in an ordered way
4c7f6ac6
EL
813
814 public function dispatch_chunk($data) {
815 $this->chunksarr[] = $data;
8298beda 816 $this->allnotif[] = 'process:' . $data['path'];
4c7f6ac6
EL
817 }
818
14e6710d
EL
819 public function notify_path_start($path) {
820 $this->startarr[] = $path;
8298beda 821 $this->allnotif[] = 'start:' . $path;
14e6710d
EL
822 }
823
824 public function notify_path_end($path) {
825 $this->endarr[] = $path;
8298beda 826 $this->allnotif[] = 'end:' . $path;
14e6710d
EL
827 }
828
4c7f6ac6
EL
829 public function get_chunks() {
830 return $this->chunksarr;
831 }
14e6710d
EL
832
833 public function get_start_notifications() {
834 return $this->startarr;
835 }
836
837 public function get_end_notifications() {
838 return $this->endarr;
839 }
8298beda
EL
840
841 public function get_all_notifications() {
842 return $this->allnotif;
843 }
4c7f6ac6 844}