Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
    /**
3
     *	base include file for SimpleTest
4
     *	@package	SimpleTest
5
     *	@subpackage	UnitTester
6
     *	@version	$Id: xml.php 1398 2006-09-08 19:31:03Z xue $
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
        protected $_indent;
23
        protected $_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 paintError($message) {
175
            parent::paintError($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
        protected $_name;
263
        protected $_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
        protected $_listener;
445
        protected $_expat;
446
        protected $_tag_stack;
447
        protected $_in_content_tag;
448
        protected $_content;
449
        protected $_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($tag, array(
534
                    'NAME', 'PASS', 'FAIL', 'EXCEPTION', 'MESSAGE', 'FORMATTED', 'SIGNAL'));
535
        }
536
 
537
        /**
538
         *    Handler for start of event element.
539
         *    @param resource $expat     Parser handle.
540
         *    @param string $tag         Element name.
541
         *    @param hash $attributes    Name value pairs.
542
         *                               Attributes without content
543
         *                               are marked as true.
544
         *    @access protected
545
         */
546
        function _startElement($expat, $tag, $attributes) {
547
            $this->_attributes = $attributes;
548
            if ($tag == 'GROUP') {
549
                $this->_pushNestingTag(new NestingGroupTag($attributes));
550
            } elseif ($tag == 'CASE') {
551
                $this->_pushNestingTag(new NestingCaseTag($attributes));
552
            } elseif ($tag == 'TEST') {
553
                $this->_pushNestingTag(new NestingMethodTag($attributes));
554
            } elseif ($this->_isLeaf($tag)) {
555
                $this->_in_content_tag = true;
556
                $this->_content = '';
557
            }
558
        }
559
 
560
        /**
561
         *    End of element event.
562
         *    @param resource $expat     Parser handle.
563
         *    @param string $tag         Element name.
564
         *    @access protected
565
         */
566
        function _endElement($expat, $tag) {
567
            $this->_in_content_tag = false;
568
            if (in_array($tag, array('GROUP', 'CASE', 'TEST'))) {
569
                $nesting_tag = $this->_popNestingTag();
570
                $nesting_tag->paintEnd($this->_listener);
571
            } elseif ($tag == 'NAME') {
572
                $nesting_tag = $this->_getCurrentNestingTag();
573
                $nesting_tag->setName($this->_content);
574
                $nesting_tag->paintStart($this->_listener);
575
            } elseif ($tag == 'PASS') {
576
                $this->_listener->paintPass($this->_content);
577
            } elseif ($tag == 'FAIL') {
578
                $this->_listener->paintFail($this->_content);
579
            } elseif ($tag == 'EXCEPTION') {
580
                $this->_listener->paintError($this->_content);
581
            } elseif ($tag == 'SIGNAL') {
582
                $this->_listener->paintSignal(
583
                        $this->_attributes['TYPE'],
584
                        unserialize($this->_content));
585
            } elseif ($tag == 'MESSAGE') {
586
                $this->_listener->paintMessage($this->_content);
587
            } elseif ($tag == 'FORMATTED') {
588
                $this->_listener->paintFormattedMessage($this->_content);
589
            }
590
        }
591
 
592
        /**
593
         *    Content between start and end elements.
594
         *    @param resource $expat     Parser handle.
595
         *    @param string $text        Usually output messages.
596
         *    @access protected
597
         */
598
        function _addContent($expat, $text) {
599
            if ($this->_in_content_tag) {
600
                $this->_content .= $text;
601
            }
602
            return true;
603
        }
604
 
605
        /**
606
         *    XML and Doctype handler. Discards all such content.
607
         *    @param resource $expat     Parser handle.
608
         *    @param string $default     Text of default content.
609
         *    @access protected
610
         */
611
        function _default($expat, $default) {
612
        }
613
    }
614
?>