weekly release 2.1dev
[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
342 /*
343 * test progressive_parser parsing results using grouped_parser_processor and test4.xml
344 * (one simple glossary backup file example)
345 */
346 function test_grouped_parser_results() {
347 global $CFG;
348 // Instantiate progressive_parser
349 $pp = new progressive_parser();
350 // Instantiate grouped_parser_processor
351 $pr = new mock_grouped_parser_processor();
352 // Add interesting paths
353 $pr->add_path('/activity');
354 $pr->add_path('/activity/glossary', true);
355 $pr->add_path('/activity/glossary/entries/entry');
356 $pr->add_path('/activity/glossary/entries/entry/aliases/alias');
357 $pr->add_path('/activity/glossary/entries/entry/ratings/rating');
358 $pr->add_path('/activity/glossary/categories/category');
359 $pr->add_path('/activity/glossary/onetest');
360 $pr->add_path('/activity/glossary/othertest');
361 $this->assertTrue($pr instanceof progressive_parser_processor);
362 // Assign processor to parser
363 $pp->set_processor($pr);
364 // Set file from fixtures
365 $pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test4.xml');
366 // Process the file
367 $pp->process();
368 // Get processor debug info
369 $debug = $pr->debug_info();
370 $this->assertTrue(is_array($debug));
371 $this->assertTrue(array_key_exists('chunks', $debug));
372
373 // Check the number of chunks is correct for the file
374 $this->assertEqual($debug['chunks'], 2);
375 // Get all the simplified chunks and perform various validations
376 $chunks = $pr->get_chunks();
377 // Check we have received the correct number of chunks
378 $this->assertEqual(count($chunks), 2);
379
380 // chunk[0] (/activity) tests
381 $this->assertEqual(count($chunks[0]), 3);
382 $this->assertEqual($chunks[0]['path'], '/activity');
383 $this->assertEqual($chunks[0]['level'],'2');
384 $tags = $chunks[0]['tags'];
385 $this->assertEqual(count($tags), 4);
386 $this->assertEqual($tags['id'], 1);
387 $this->assertEqual($tags['moduleid'], 5);
388 $this->assertEqual($tags['modulename'], 'glossary');
389 $this->assertEqual($tags['contextid'], 26);
390 $this->assertEqual($chunks[0]['level'],'2');
391
392 // chunk[1] (grouped /activity/glossary tests)
393 $this->assertEqual(count($chunks[1]), 3);
394 $this->assertEqual($chunks[1]['path'], '/activity/glossary');
395 $this->assertEqual($chunks[1]['level'],'3');
396 $tags = $chunks[1]['tags'];
397 $this->assertEqual(count($tags), 27);
398 $this->assertEqual($tags['id'], 1);
399 $this->assertEqual($tags['intro'], '<p>One simple glossary to test backup &amp; restore. Here it\'s the standard image:</p>'.
400 "\n".
401 '<p><img src="@@PLUGINFILE@@/88_31.png" alt="pwd by moodle" width="88" height="31" /></p>');
402 $this->assertEqual($tags['timemodified'], 1275639747);
403 $this->assertTrue(!isset($tags['categories']));
404 $this->assertTrue(isset($tags['entries']));
405 $this->assertTrue(isset($tags['onetest']));
406 $this->assertTrue(isset($tags['othertest']));
407
408 // Various tests under the entries
409 $entries = $chunks[1]['tags']['entries']['entry'];
410 $this->assertEqual(count($entries), 2);
411
412 // First entry
413 $entry1 = $entries[0];
414 $this->assertEqual(count($entry1), 17);
415 $this->assertEqual($entry1['id'], 1);
416 $this->assertEqual($entry1['userid'], 2);
417 $this->assertEqual($entry1['concept'], 'dog');
418 $this->assertEqual($entry1['definition'], '<p>Traditional enemies of cats</p>');
419 $this->assertTrue(isset($entry1['aliases']));
420 $this->assertTrue(isset($entry1['ratings']));
421 // aliases of first entry
422 $aliases = $entry1['aliases']['alias'];
423 $this->assertEqual(count($aliases), 1);
424 // first alias
425 $alias1 = $aliases[0];
426 $this->assertEqual(count($alias1), 2);
427 $this->assertEqual($alias1['id'], 1);
428 $this->assertEqual($alias1['alias_text'], 'dogs');
429 // ratings of first entry
430 $ratings = $entry1['ratings']['rating'];
431 $this->assertEqual(count($ratings), 1);
432 // first rating
433 $rating1 = $ratings[0];
434 $this->assertEqual(count($rating1), 6);
435 $this->assertEqual($rating1['id'], 2);
436 $this->assertEqual($rating1['value'], 6);
437 $this->assertEqual($rating1['timemodified'], '1275639797');
438
439 // Second entry
440 $entry2 = $entries[1];
441 $this->assertEqual(count($entry2), 17);
442 $this->assertEqual($entry2['id'], 2);
443 $this->assertEqual($entry2['userid'], 2);
444 $this->assertEqual($entry2['concept'], 'cat');
445 $this->assertEqual($entry2['definition'], '<p>traditional enemies of dogs</p>');
446 $this->assertTrue(isset($entry2['aliases']));
447 $this->assertTrue(isset($entry2['ratings']));
448 // aliases of first entry
449 $aliases = $entry2['aliases']['alias'];
450 $this->assertEqual(count($aliases), 2);
451 // first alias
452 $alias1 = $aliases[0];
453 $this->assertEqual(count($alias1), 2);
454 $this->assertEqual($alias1['id'], 2);
455 $this->assertEqual($alias1['alias_text'], 'cats');
456 // second alias
457 $alias2 = $aliases[1];
458 $this->assertEqual(count($alias2), 2);
459 $this->assertEqual($alias2['id'], 3);
460 $this->assertEqual($alias2['alias_text'], 'felines');
461 // ratings of first entry
462 $ratings = $entry2['ratings']['rating'];
463 $this->assertEqual(count($ratings), 1);
464 // first rating
465 $rating1 = $ratings[0];
466 $this->assertEqual(count($rating1), 6);
467 $this->assertEqual($rating1['id'], 1);
468 $this->assertEqual($rating1['value'], 5);
469 $this->assertEqual($rating1['scaleid'], 10);
470
471 // Onetest test (only 1 level nested)
472 $onetest = $tags['onetest'];
473 $this->assertEqual(count($onetest), 2);
474 $this->assertEqual(count($onetest[0]), 2);
475 $this->assertEqual($onetest[0]['name'], 1);
476 $this->assertEqual($onetest[0]['value'], 1);
477 $this->assertEqual(count($onetest[1]), 2);
478 $this->assertEqual($onetest[1]['name'], 2);
479 $this->assertEqual($onetest[1]['value'], 2);
480
481 // Other test (0 level nested, only last one is retrieved)
482 $othertest = $tags['othertest'];
483 $this->assertEqual(count($othertest), 1);
484 $this->assertEqual(count($othertest[0]), 2);
485 $this->assertEqual($othertest[0]['name'], 4);
486 $this->assertEqual($othertest[0]['value'], 5);
14e6710d
EL
487
488 // Now check start notifications
489 $snotifs = $pr->get_start_notifications();
490 // Check we have received the correct number of notifications
491 $this->assertEqual(count($snotifs), 2);
492 // Check first and last notifications
493 $this->assertEqual($snotifs[0], '/activity');
494 $this->assertEqual($snotifs[1], '/activity/glossary');
495
496 // Now check end notifications
497 $enotifs = $pr->get_end_notifications();
498 // Check we have received the correct number of notifications
499 $this->assertEqual(count($snotifs), 2);
500 // Check first, and last notifications
501 $this->assertEqual($enotifs[0], '/activity/glossary');
502 $this->assertEqual($enotifs[1], '/activity');
503
504 // Check start and end notifications are balanced
505 sort($snotifs);
506 sort($enotifs);
507 $this->assertEqual($snotifs, $enotifs);
8298beda
EL
508
509 // Now verify that the start/process/end order is correct
510 $allnotifs = $pr->get_all_notifications();
511 $this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count
512 // Check integrity of the notifications
513 $errcount = $this->helper_check_notifications_order_integrity($allnotifs);
514 $this->assertEqual($errcount, 0); // No errors found, plz
515 }
516
517 /**
518 * Helper function that given one array of ordered start/process/end notifications will
519 * check it of integrity like:
520 * - process only happens if start is the previous notification
521 * - end only happens if dispatch is the previous notification
522 * - start only happen with level > than last one and if there is no already started like that
523 *
524 * @param array $notifications ordered array of notifications with format [start|process|end]:path
525 * @return int number of integrity problems found (errors)
526 */
527 function helper_check_notifications_order_integrity($notifications) {
528 $numerrors = 0;
529 $notifpile = array('pilebase' => 'start');
530 $lastpile = 'start:pilebase';
531 foreach ($notifications as $notif) {
532 $lastpilelevel = strlen(preg_replace('/[^\/]/', '', $lastpile));
533 $lastpiletype = preg_replace('/:.*/', '', $lastpile);
534 $lastpilepath = preg_replace('/.*:/', '', $lastpile);
535
536 $notiflevel = strlen(preg_replace('/[^\/]/', '', $notif));
537 $notiftype = preg_replace('/:.*/', '', $notif);
538 $notifpath = preg_replace('/.*:/', '', $notif);
539
540 switch ($notiftype) {
541 case 'process':
542 if ($lastpilepath != $notifpath or $lastpiletype != 'start') {
543 $numerrors++; // Only start for same path is allowed before process
544 }
545 $notifpile[$notifpath] = 'process'; // Update the status in the pile
546 break;
547 case 'end':
548 if ($lastpilepath != $notifpath or $lastpiletype != 'process') {
549 $numerrors++; // Only process for same path is allowed before end
550 }
551 unset($notifpile[$notifpath]); // Delete from the pile
552 break;
553 case 'start':
554 if (array_key_exists($notifpath, $notifpile) or $notiflevel <= $lastpilelevel) {
555 $numerrors++; // If same path exists or the level is < than the last one
556 }
557 $notifpile[$notifpath] = 'start'; // Add to the pile
558 break;
559 default:
560 $numerrors++; // Incorrect type of notification => error
561 }
562 // Update lastpile
563 end($notifpile);
564 $path = key($notifpile);
565 $type = $notifpile[$path];
566 $lastpile = $type. ':' . $path;
567 }
568 return $numerrors;
be866f9d
EL
569 }
570}
571
572/*
573 * helper processor able to perform various auto-cheks based on attributes while processing
574 * the test1.xml file available in the fixtures dir. It performs these checks:
575 * - name equal to "name" attribute of the tag (if present)
576 * - level equal to "level" attribute of the tag (if present)
577 * - path + tagname equal to "path" attribute of the tag (if present)
578 * - cdata, if not empty is:
579 * - equal to "value" attribute of the tag (if present)
580 * - else, equal to tag name
581 *
582 * We pass the whole UnitTestCase object to the processor in order to be
583 * able to perform the tests in the straight in the process
584 */
585class mock_auto_parser_processor extends progressive_parser_processor {
586
587 private $utc = null; // To store the unit test case
588
589 public function __construct($unit_test_case) {
590 parent::__construct();
591 $this->utc = $unit_test_case;
592 }
593
594 public function process_chunk($data) {
595 // Perform auto-checks based in the rules above
596 if (isset($data['tags'])) {
597 foreach ($data['tags'] as $tag) {
598 if (isset($tag['attrs']['name'])) { // name tests
599 $this->utc->assertEqual($tag['name'], $tag['attrs']['name']);
600 }
601 if (isset($tag['attrs']['level'])) { // level tests
602 $this->utc->assertEqual($data['level'], $tag['attrs']['level']);
603 }
604 if (isset($tag['attrs']['path'])) { // path tests
605 $this->utc->assertEqual(rtrim($data['path'], '/') . '/' . $tag['name'], $tag['attrs']['path']);
606 }
607 if (!empty($tag['cdata'])) { // cdata tests
608 if (isset($tag['attrs']['value'])) {
609 $this->utc->assertEqual($tag['cdata'], $tag['attrs']['value']);
610 } else {
611 $this->utc->assertEqual($tag['cdata'], $tag['name']);
612 }
613 }
614 }
615 }
616 }
617}
618
619/*
620 * helper processor that accumulates all the chunks, resturning them with the get_chunks() method
621 */
622class mock_parser_processor extends progressive_parser_processor {
623
624 private $chunksarr = array(); // To accumulate the found chunks
625
626 public function process_chunk($data) {
627 $this->chunksarr[] = $data;
628 }
629
630 public function get_chunks() {
631 return $this->chunksarr;
632 }
633}
634
635/*
636 * helper processor that accumulates simplified chunks, returning them with the get_chunks() method
637 */
638class mock_simplified_parser_processor extends simplified_parser_processor {
639
640 private $chunksarr = array(); // To accumulate the found chunks
14e6710d
EL
641 private $startarr = array(); // To accumulate all the notified path starts
642 private $endarr = array(); // To accumulate all the notified path ends
8298beda 643 private $allnotif = array(); // To accumulate all the notified and dispatched events in an ordered way
be866f9d
EL
644
645 public function dispatch_chunk($data) {
646 $this->chunksarr[] = $data;
8298beda 647 $this->allnotif[] = 'process:' . $data['path'];
be866f9d
EL
648 }
649
14e6710d
EL
650 public function notify_path_start($path) {
651 $this->startarr[] = $path;
8298beda 652 $this->allnotif[] = 'start:' . $path;
14e6710d
EL
653 }
654
655 public function notify_path_end($path) {
656 $this->endarr[] = $path;
8298beda 657 $this->allnotif[] = 'end:' . $path;
14e6710d
EL
658 }
659
be866f9d
EL
660 public function get_chunks() {
661 return $this->chunksarr;
662 }
14e6710d
EL
663
664 public function get_start_notifications() {
665 return $this->startarr;
666 }
667
668 public function get_end_notifications() {
669 return $this->endarr;
670 }
8298beda
EL
671
672 public function get_all_notifications() {
673 return $this->allnotif;
674 }
be866f9d 675}
4c7f6ac6
EL
676
677/*
678 * helper processor that accumulates grouped chunks, returning them with the get_chunks() method
679 */
680class mock_grouped_parser_processor extends grouped_parser_processor {
681
682 private $chunksarr = array(); // To accumulate the found chunks
14e6710d
EL
683 private $startarr = array(); // To accumulate all the notified path starts
684 private $endarr = array(); // To accumulate all the notified path ends
8298beda 685 private $allnotif = array(); // To accumulate all the notified and dispatched events in an ordered way
4c7f6ac6
EL
686
687 public function dispatch_chunk($data) {
688 $this->chunksarr[] = $data;
8298beda 689 $this->allnotif[] = 'process:' . $data['path'];
4c7f6ac6
EL
690 }
691
14e6710d
EL
692 public function notify_path_start($path) {
693 $this->startarr[] = $path;
8298beda 694 $this->allnotif[] = 'start:' . $path;
14e6710d
EL
695 }
696
697 public function notify_path_end($path) {
698 $this->endarr[] = $path;
8298beda 699 $this->allnotif[] = 'end:' . $path;
14e6710d
EL
700 }
701
4c7f6ac6
EL
702 public function get_chunks() {
703 return $this->chunksarr;
704 }
14e6710d
EL
705
706 public function get_start_notifications() {
707 return $this->startarr;
708 }
709
710 public function get_end_notifications() {
711 return $this->endarr;
712 }
8298beda
EL
713
714 public function get_all_notifications() {
715 return $this->allnotif;
716 }
4c7f6ac6 717}