first reimport from platal
[platal.git] / htdocs / TESTS / simpletest / xml.php
1 <?php
2 /**
3 * base include file for SimpleTest
4 * @package SimpleTest
5 * @subpackage UnitTester
6 * @version $Id: xml.php,v 1.20 2004/08/04 22:09:39 lastcraft Exp $
7 */
8
9 /**#@+
10 * include other SimpleTest class files
11 */
12 require_once(dirname(__FILE__) . '/scorer.php');
13 /**#@-*/
14
15 /**
16 * Creates the XML needed for remote communication
17 * by SimpleTest.
18 * @package SimpleTest
19 * @subpackage UnitTester
20 */
21 class XmlReporter extends SimpleReporter {
22 var $_indent;
23 var $_namespace;
24
25 /**
26 * Does nothing yet.
27 * @access public
28 */
29 function XmlReporter($namespace = false, $indent = ' ') {
30 $this->SimpleReporter();
31 $this->_namespace = ($namespace ? $namespace . ':' : '');
32 $this->_indent = $indent;
33 }
34
35 /**
36 * Calculates the pretty printing indent level
37 * from the current level of nesting.
38 * @param integer $offset Extra indenting level.
39 * @return string Leading space.
40 * @access protected
41 */
42 function _getIndent($offset = 0) {
43 return str_repeat(
44 $this->_indent,
45 count($this->getTestList()) + $offset);
46 }
47
48 /**
49 * Converts character string to parsed XML
50 * entities string.
51 * @param string text Unparsed character data.
52 * @return string Parsed character data.
53 * @access public
54 */
55 function toParsedXml($text) {
56 return str_replace(
57 array('&', '<', '>', '"', '\''),
58 array('&amp;', '&lt;', '&gt;', '&quot;', '&apos;'),
59 $text);
60 }
61
62 /**
63 * Paints the start of a group test.
64 * @param string $test_name Name of test that is starting.
65 * @param integer $size Number of test cases starting.
66 * @access public
67 */
68 function paintGroupStart($test_name, $size) {
69 parent::paintGroupStart($test_name, $size);
70 print $this->_getIndent();
71 print "<" . $this->_namespace . "group size=\"$size\">\n";
72 print $this->_getIndent(1);
73 print "<" . $this->_namespace . "name>" .
74 $this->toParsedXml($test_name) .
75 "</" . $this->_namespace . "name>\n";
76 }
77
78 /**
79 * Paints the end of a group test.
80 * @param string $test_name Name of test that is ending.
81 * @access public
82 */
83 function paintGroupEnd($test_name) {
84 print $this->_getIndent();
85 print "</" . $this->_namespace . "group>\n";
86 parent::paintGroupEnd($test_name);
87 }
88
89 /**
90 * Paints the start of a test case.
91 * @param string $test_name Name of test that is starting.
92 * @access public
93 */
94 function paintCaseStart($test_name) {
95 parent::paintCaseStart($test_name);
96 print $this->_getIndent();
97 print "<" . $this->_namespace . "case>\n";
98 print $this->_getIndent(1);
99 print "<" . $this->_namespace . "name>" .
100 $this->toParsedXml($test_name) .
101 "</" . $this->_namespace . "name>\n";
102 }
103
104 /**
105 * Paints the end of a test case.
106 * @param string $test_name Name of test that is ending.
107 * @access public
108 */
109 function paintCaseEnd($test_name) {
110 print $this->_getIndent();
111 print "</" . $this->_namespace . "case>\n";
112 parent::paintCaseEnd($test_name);
113 }
114
115 /**
116 * Paints the start of a test method.
117 * @param string $test_name Name of test that is starting.
118 * @access public
119 */
120 function paintMethodStart($test_name) {
121 parent::paintMethodStart($test_name);
122 print $this->_getIndent();
123 print "<" . $this->_namespace . "test>\n";
124 print $this->_getIndent(1);
125 print "<" . $this->_namespace . "name>" .
126 $this->toParsedXml($test_name) .
127 "</" . $this->_namespace . "name>\n";
128 }
129
130 /**
131 * Paints the end of a test method.
132 * @param string $test_name Name of test that is ending.
133 * @param integer $progress Number of test cases ending.
134 * @access public
135 */
136 function paintMethodEnd($test_name) {
137 print $this->_getIndent();
138 print "</" . $this->_namespace . "test>\n";
139 parent::paintMethodEnd($test_name);
140 }
141
142 /**
143 * Increments the pass count.
144 * @param string $message Message is ignored.
145 * @access public
146 */
147 function paintPass($message) {
148 parent::paintPass($message);
149 print $this->_getIndent(1);
150 print "<" . $this->_namespace . "pass>";
151 print $this->toParsedXml($message);
152 print "</" . $this->_namespace . "pass>\n";
153 }
154
155 /**
156 * Increments the fail count.
157 * @param string $message Message is ignored.
158 * @access public
159 */
160 function paintFail($message) {
161 parent::paintFail($message);
162 print $this->_getIndent(1);
163 print "<" . $this->_namespace . "fail>";
164 print $this->toParsedXml($message);
165 print "</" . $this->_namespace . "fail>\n";
166 }
167
168 /**
169 * Paints a PHP error or exception.
170 * @param string $message Message is ignored.
171 * @access public
172 * @abstract
173 */
174 function paintException($message) {
175 parent::paintException($message);
176 print $this->_getIndent(1);
177 print "<" . $this->_namespace . "exception>";
178 print $this->toParsedXml($message);
179 print "</" . $this->_namespace . "exception>\n";
180 }
181
182 /**
183 * Paints a simple supplementary message.
184 * @param string $message Text to display.
185 * @access public
186 */
187 function paintMessage($message) {
188 parent::paintMessage($message);
189 print $this->_getIndent(1);
190 print "<" . $this->_namespace . "message>";
191 print $this->toParsedXml($message);
192 print "</" . $this->_namespace . "message>\n";
193 }
194
195 /**
196 * Paints a formatted ASCII message such as a
197 * variable dump.
198 * @param string $message Text to display.
199 * @access public
200 */
201 function paintFormattedMessage($message) {
202 parent::paintFormattedMessage($message);
203 print $this->_getIndent(1);
204 print "<" . $this->_namespace . "formatted>";
205 print "<![CDATA[$message]]>";
206 print "</" . $this->_namespace . "formatted>\n";
207 }
208
209 /**
210 * Serialises the event object.
211 * @param string $type Event type as text.
212 * @param mixed $payload Message or object.
213 * @access public
214 */
215 function paintSignal($type, &$payload) {
216 parent::paintSignal($type, $payload);
217 print $this->_getIndent(1);
218 print "<" . $this->_namespace . "signal type=\"$type\">";
219 print "<![CDATA[" . serialize($payload) . "]]>";
220 print "</" . $this->_namespace . "signal>\n";
221 }
222
223 /**
224 * Paints the test document header.
225 * @param string $test_name First test top level
226 * to start.
227 * @access public
228 * @abstract
229 */
230 function paintHeader($test_name) {
231 if (! SimpleReporter::inCli()) {
232 header('Content-type: text/xml');
233 }
234 print "<?xml version=\"1.0\"";
235 if ($this->_namespace) {
236 print " xmlns:" . $this->_namespace .
237 "=\"www.lastcraft.com/SimpleTest/Beta3/Report\"";
238 }
239 print "?>\n";
240 print "<" . $this->_namespace . "run>\n";
241 }
242
243 /**
244 * Paints the test document footer.
245 * @param string $test_name The top level test.
246 * @access public
247 * @abstract
248 */
249 function paintFooter($test_name) {
250 print "</" . $this->_namespace . "run>\n";
251 }
252 }
253
254 /**
255 * Accumulator for incoming tag. Holds the
256 * incoming test structure information for
257 * later dispatch to the reporter.
258 * @package SimpleTest
259 * @subpackage UnitTester
260 */
261 class NestingXmlTag {
262 var $_name;
263 var $_attributes;
264
265 /**
266 * Sets the basic test information except
267 * the name.
268 * @param hash $attributes Name value pairs.
269 * @access public
270 */
271 function NestingXmlTag($attributes) {
272 $this->_name = false;
273 $this->_attributes = $attributes;
274 }
275
276 /**
277 * Sets the test case/method name.
278 * @param string $name Name of test.
279 * @access public
280 */
281 function setName($name) {
282 $this->_name = $name;
283 }
284
285 /**
286 * Accessor for name.
287 * @return string Name of test.
288 * @access public
289 */
290 function getName() {
291 return $this->_name;
292 }
293
294 /**
295 * Accessor for attributes.
296 * @return hash All attributes.
297 * @access protected
298 */
299 function _getAttributes() {
300 return $this->_attributes;
301 }
302 }
303
304 /**
305 * Accumulator for incoming method tag. Holds the
306 * incoming test structure information for
307 * later dispatch to the reporter.
308 * @package SimpleTest
309 * @subpackage UnitTester
310 */
311 class NestingMethodTag extends NestingXmlTag {
312
313 /**
314 * Sets the basic test information except
315 * the name.
316 * @param hash $attributes Name value pairs.
317 * @access public
318 */
319 function NestingMethodTag($attributes) {
320 $this->NestingXmlTag($attributes);
321 }
322
323 /**
324 * Signals the appropriate start event on the
325 * listener.
326 * @param SimpleReporter $listener Target for events.
327 * @access public
328 */
329 function paintStart(&$listener) {
330 $listener->paintMethodStart($this->getName());
331 }
332
333 /**
334 * Signals the appropriate end event on the
335 * listener.
336 * @param SimpleReporter $listener Target for events.
337 * @access public
338 */
339 function paintEnd(&$listener) {
340 $listener->paintMethodEnd($this->getName());
341 }
342 }
343
344 /**
345 * Accumulator for incoming case tag. Holds the
346 * incoming test structure information for
347 * later dispatch to the reporter.
348 * @package SimpleTest
349 * @subpackage UnitTester
350 */
351 class NestingCaseTag extends NestingXmlTag {
352
353 /**
354 * Sets the basic test information except
355 * the name.
356 * @param hash $attributes Name value pairs.
357 * @access public
358 */
359 function NestingCaseTag($attributes) {
360 $this->NestingXmlTag($attributes);
361 }
362
363 /**
364 * Signals the appropriate start event on the
365 * listener.
366 * @param SimpleReporter $listener Target for events.
367 * @access public
368 */
369 function paintStart(&$listener) {
370 $listener->paintCaseStart($this->getName());
371 }
372
373 /**
374 * Signals the appropriate end event on the
375 * listener.
376 * @param SimpleReporter $listener Target for events.
377 * @access public
378 */
379 function paintEnd(&$listener) {
380 $listener->paintCaseEnd($this->getName());
381 }
382 }
383
384 /**
385 * Accumulator for incoming group tag. Holds the
386 * incoming test structure information for
387 * later dispatch to the reporter.
388 * @package SimpleTest
389 * @subpackage UnitTester
390 */
391 class NestingGroupTag extends NestingXmlTag {
392
393 /**
394 * Sets the basic test information except
395 * the name.
396 * @param hash $attributes Name value pairs.
397 * @access public
398 */
399 function NestingGroupTag($attributes) {
400 $this->NestingXmlTag($attributes);
401 }
402
403 /**
404 * Signals the appropriate start event on the
405 * listener.
406 * @param SimpleReporter $listener Target for events.
407 * @access public
408 */
409 function paintStart(&$listener) {
410 $listener->paintGroupStart($this->getName(), $this->getSize());
411 }
412
413 /**
414 * Signals the appropriate end event on the
415 * listener.
416 * @param SimpleReporter $listener Target for events.
417 * @access public
418 */
419 function paintEnd(&$listener) {
420 $listener->paintGroupEnd($this->getName());
421 }
422
423 /**
424 * The size in the attributes.
425 * @return integer Value of size attribute or zero.
426 * @access public
427 */
428 function getSize() {
429 $attributes = $this->_getAttributes();
430 if (isset($attributes['SIZE'])) {
431 return (integer)$attributes['SIZE'];
432 }
433 return 0;
434 }
435 }
436
437 /**
438 * Parser for importing the output of the XmlReporter.
439 * Dispatches that output to another reporter.
440 * @package SimpleTest
441 * @subpackage UnitTester
442 */
443 class SimpleTestXmlParser {
444 var $_listener;
445 var $_expat;
446 var $_tag_stack;
447 var $_in_content_tag;
448 var $_content;
449 var $_attributes;
450
451 /**
452 * Loads a listener with the SimpleReporter
453 * interface.
454 * @param SimpleReporter $listener Listener of tag events.
455 * @access public
456 */
457 function SimpleTestXmlParser(&$listener) {
458 $this->_listener = &$listener;
459 $this->_expat = &$this->_createParser();
460 $this->_tag_stack = array();
461 $this->_in_content_tag = false;
462 $this->_content = '';
463 $this->_attributes = array();
464 }
465
466 /**
467 * Parses a block of XML sending the results to
468 * the listener.
469 * @param string $chunk Block of text to read.
470 * @return boolean True if valid XML.
471 * @access public
472 */
473 function parse($chunk) {
474 if (! xml_parse($this->_expat, $chunk)) {
475 trigger_error('XML parse error with ' .
476 xml_error_string(xml_get_error_code($this->_expat)));
477 return false;
478 }
479 return true;
480 }
481
482 /**
483 * Sets up expat as the XML parser.
484 * @return resource Expat handle.
485 * @access protected
486 */
487 function &_createParser() {
488 $expat = xml_parser_create();
489 xml_set_object($expat, $this);
490 xml_set_element_handler($expat, '_startElement', '_endElement');
491 xml_set_character_data_handler($expat, '_addContent');
492 xml_set_default_handler($expat, '_default');
493 return $expat;
494 }
495
496 /**
497 * Opens a new test nesting level.
498 * @return NestedXmlTag The group, case or method tag
499 * to start.
500 * @access private
501 */
502 function _pushNestingTag($nested) {
503 array_unshift($this->_tag_stack, $nested);
504 }
505
506 /**
507 * Accessor for current test structure tag.
508 * @return NestedXmlTag The group, case or method tag
509 * being parsed.
510 * @access private
511 */
512 function &_getCurrentNestingTag() {
513 return $this->_tag_stack[0];
514 }
515
516 /**
517 * Ends a nesting tag.
518 * @return NestedXmlTag The group, case or method tag
519 * just finished.
520 * @access private
521 */
522 function _popNestingTag() {
523 return array_shift($this->_tag_stack);
524 }
525
526 /**
527 * Test if tag is a leaf node with only text content.
528 * @param string $tag XML tag name.
529 * @return @boolean True if leaf, false if nesting.
530 * @private
531 */
532 function _isLeaf($tag) {
533 return in_array(
534 $tag,
535 array('NAME', 'PASS', 'FAIL', 'EXCEPTION', 'MESSAGE', 'FORMATTED', 'SIGNAL'));
536 }
537
538 /**
539 * Handler for start of event element.
540 * @param resource $expat Parser handle.
541 * @param string $tag Element name.
542 * @param hash $attributes Name value pairs.
543 * Attributes without content
544 * are marked as true.
545 * @access protected
546 */
547 function _startElement($expat, $tag, $attributes) {
548 $this->_attributes = $attributes;
549 if ($tag == 'GROUP') {
550 $this->_pushNestingTag(new NestingGroupTag($attributes));
551 } elseif ($tag == 'CASE') {
552 $this->_pushNestingTag(new NestingCaseTag($attributes));
553 } elseif ($tag == 'TEST') {
554 $this->_pushNestingTag(new NestingMethodTag($attributes));
555 } elseif ($this->_isLeaf($tag)) {
556 $this->_in_content_tag = true;
557 $this->_content = '';
558 }
559 }
560
561 /**
562 * End of element event.
563 * @param resource $expat Parser handle.
564 * @param string $tag Element name.
565 * @access protected
566 */
567 function _endElement($expat, $tag) {
568 $this->_in_content_tag = false;
569 if (in_array($tag, array('GROUP', 'CASE', 'TEST'))) {
570 $nesting_tag = $this->_popNestingTag();
571 $nesting_tag->paintEnd($this->_listener);
572 } elseif ($tag == 'NAME') {
573 $nesting_tag = &$this->_getCurrentNestingTag();
574 $nesting_tag->setName($this->_content);
575 $nesting_tag->paintStart($this->_listener);
576 } elseif ($tag == 'PASS') {
577 $this->_listener->paintPass($this->_content);
578 } elseif ($tag == 'FAIL') {
579 $this->_listener->paintFail($this->_content);
580 } elseif ($tag == 'EXCEPTION') {
581 $this->_listener->paintException($this->_content);
582 } elseif ($tag == 'SIGNAL') {
583 $this->_listener->paintSignal(
584 $this->_attributes['TYPE'],
585 unserialize($this->_content));
586 } elseif ($tag == 'MESSAGE') {
587 $this->_listener->paintMessage($this->_content);
588 } elseif ($tag == 'FORMATTED') {
589 $this->_listener->paintFormattedMessage($this->_content);
590 }
591 }
592
593 /**
594 * Content between start and end elements.
595 * @param resource $expat Parser handle.
596 * @param string $text Usually output messages.
597 * @access protected
598 */
599 function _addContent($expat, $text) {
600 if ($this->_in_content_tag) {
601 $this->_content .= $text;
602 }
603 return true;
604 }
605
606 /**
607 * XML and Doctype handler. Discards all such content.
608 * @param resource $expat Parser handle.
609 * @param string $default Text of default content.
610 * @access protected
611 */
612 function _default($expat, $default) {
613 }
614 }
615 ?>