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: test_case.php 2309 2007-10-08 03:24:07Z wei $
7
     */
8
 
9
    /**#@+
10
     * Includes SimpleTest files and defined the root constant
11
     * for dependent libraries.
12
     */
13
    require_once(dirname(__FILE__) . '/invoker.php');
14
    require_once(dirname(__FILE__) . '/errors.php');
15
    require_once(dirname(__FILE__) . '/compatibility.php');
16
    require_once(dirname(__FILE__) . '/scorer.php');
17
    require_once(dirname(__FILE__) . '/expectation.php');
18
    require_once(dirname(__FILE__) . '/dumper.php');
19
    require_once(dirname(__FILE__) . '/simpletest.php');
20
    if (version_compare(phpversion(), '5') >= 0) {
21
        require_once(dirname(__FILE__) . '/exceptions.php');
22
        require_once(dirname(__FILE__) . '/reflection_php5.php');
23
    } else {
24
        require_once(dirname(__FILE__) . '/reflection_php4.php');
25
    }
26
    if (! defined('SIMPLE_TEST')) {
27
        /**
28
         * @ignore
29
         */
30
        define('SIMPLE_TEST', dirname(__FILE__) . '/');
31
    }
32
    /**#@-*/
33
 
34
    /**
35
     *    Basic test case. This is the smallest unit of a test
36
     *    suite. It searches for
37
     *    all methods that start with the the string "test" and
38
     *    runs them. Working test cases extend this class.
39
	 *    @package		SimpleTest
40
	 *    @subpackage	UnitTester
41
     */
42
    class SimpleTestCase {
43
        protected $_label = false;
44
        protected $_reporter;
45
        protected $_observers;
46
 
47
        /**
48
         *    Sets up the test with no display.
49
         *    @param string $label    If no test name is given then
50
         *                            the class name is used.
51
         *    @access public
52
         */
53
        function SimpleTestCase($label = false) {
54
            if ($label) {
55
                $this->_label = $label;
56
            }
57
        }
58
 
59
        /**
60
         *    Accessor for the test name for subclasses.
61
         *    @return string           Name of the test.
62
         *    @access public
63
         */
64
        function getLabel() {
65
            return $this->_label ? $this->_label : get_class($this);
66
        }
67
 
68
        /**
69
         *    Used to invoke the single tests.
70
         *    @return SimpleInvoker        Individual test runner.
71
         *    @access public
72
         */
73
        function createInvoker() {
74
            $invoker = new SimpleErrorTrappingInvoker(new SimpleInvoker($this));
75
            if (version_compare(phpversion(), '5') >= 0) {
76
                $invoker = new SimpleExceptionTrappingInvoker($invoker);
77
            }
78
            return $invoker;
79
        }
80
 
81
        /**
82
         *    Uses reflection to run every method within itself
83
         *    starting with the string "test" unless a method
84
         *    is specified.
85
         *    @param SimpleReporter $reporter    Current test reporter.
86
         *    @access public
87
         */
88
        function run($reporter) {
89
            SimpleTest::setCurrent($this);
90
            $this->_reporter = $reporter;
91
            $this->_reporter->paintCaseStart($this->getLabel());
92
            foreach ($this->getTests() as $method) {
93
                if ($this->_reporter->shouldInvoke($this->getLabel(), $method)) {
94
                    $invoker = $this->_reporter->createInvoker($this->createInvoker());
95
                    $invoker->before($method);
96
                    $invoker->invoke($method);
97
                    $invoker->after($method);
98
                }
99
            }
100
            $this->_reporter->paintCaseEnd($this->getLabel());
101
            unset($this->_reporter);
102
            return $reporter->getStatus();
103
        }
104
 
105
        /**
106
         *    Gets a list of test names. Normally that will
107
         *    be all internal methods that start with the
108
         *    name "test". This method should be overridden
109
         *    if you want a different rule.
110
         *    @return array        List of test names.
111
         *    @access public
112
         */
113
        function getTests() {
114
            $methods = array();
115
            foreach (get_class_methods(get_class($this)) as $method) {
116
                if ($this->_isTest($method)) {
117
                    $methods[] = $method;
118
                }
119
            }
120
            return $methods;
121
        }
122
 
123
        /**
124
         *    Tests to see if the method is a test that should
125
         *    be run. Currently any method that starts with 'test'
126
         *    is a candidate unless it is the constructor.
127
         *    @param string $method        Method name to try.
128
         *    @return boolean              True if test method.
129
         *    @access protected
130
         */
131
        function _isTest($method) {
132
            if (strtolower(substr($method, 0, 4)) == 'test') {
133
                return ! SimpleTestCompatibility::isA($this, strtolower($method));
134
            }
135
            return false;
136
        }
137
 
138
        /**
139
         *    Announces the start of the test.
140
         *    @param string $method    Test method just started.
141
         *    @access public
142
         */
143
        function before($method) {
144
            $this->_reporter->paintMethodStart($method);
145
            $this->_observers = array();
146
        }
147
 
148
        /**
149
         *    Sets up unit test wide variables at the start
150
         *    of each test method. To be overridden in
151
         *    actual user test cases.
152
         *    @access public
153
         */
154
        function setUp() {
155
        }
156
 
157
        /**
158
         *    Clears the data set in the setUp() method call.
159
         *    To be overridden by the user in actual user test cases.
160
         *    @access public
161
         */
162
        function tearDown() {
163
        }
164
 
165
        /**
166
         *    Announces the end of the test. Includes private clean up.
167
         *    @param string $method    Test method just finished.
168
         *    @access public
169
         */
170
        function after($method) {
171
            for ($i = 0; $i < count($this->_observers); $i++) {
172
                $this->_observers[$i]->atTestEnd($method);
173
            }
174
            $this->_reporter->paintMethodEnd($method);
175
        }
176
 
177
        /**
178
         *    Sets up an observer for the test end.
179
         *    @param object $observer    Must have atTestEnd()
180
         *                               method.
181
         *    @access public
182
         */
183
        function tell($observer) {
184
            $this->_observers[] = $observer;
185
        }
186
 
187
        /**
188
         *    Sends a pass event with a message.
189
         *    @param string $message        Message to send.
190
         *    @access public
191
         */
192
        function pass($message = "Pass") {
193
            if (! isset($this->_reporter)) {
194
                trigger_error('Can only make assertions within test methods');
195
            }
196
            $this->_reporter->paintPass(
197
                    $message . $this->getAssertionLine());
198
            return true;
199
        }
200
 
201
        /**
202
         *    Sends a fail event with a message.
203
         *    @param string $message        Message to send.
204
         *    @access public
205
         */
206
        function fail($message = "Fail") {
207
            if (! isset($this->_reporter)) {
208
                trigger_error('Can only make assertions within test methods');
209
            }
210
            $this->_reporter->paintFail(
211
                    $message . $this->getAssertionLine());
212
            return false;
213
        }
214
 
215
        /**
216
         *    Formats a PHP error and dispatches it to the
217
         *    reporter.
218
         *    @param integer $severity  PHP error code.
219
         *    @param string $message    Text of error.
220
         *    @param string $file       File error occoured in.
221
         *    @param integer $line      Line number of error.
222
         *    @access public
223
         */
224
        function error($severity, $message, $file, $line) {
225
            if (! isset($this->_reporter)) {
226
                trigger_error('Can only make assertions within test methods');
227
            }
228
            $this->_reporter->paintError(
229
                    "Unexpected PHP error [$message] severity [$severity] in [$file] line [$line]");
230
        }
231
 
232
        /**
233
         *    Formats an exception and dispatches it to the
234
         *    reporter.
235
         *    @param Exception $exception    Object thrown.
236
         *    @access public
237
         */
238
        function exception($exception) {
239
            $this->_reporter->paintError(
240
                    'Unexpected exception of type [' . get_class($exception) .
241
                    '] with message ['. $exception->getMessage() .
242
                    '] in ['. $exception->getFile() .
243
                    '] line [' . $exception->getLine() .
244
					'] stack [' . $exception->getTraceAsString() .']');
245
        }
246
 
247
        /**
248
         *    Sends a user defined event to the test reporter.
249
         *    This is for small scale extension where
250
         *    both the test case and either the reporter or
251
         *    display are subclassed.
252
         *    @param string $type       Type of event.
253
         *    @param mixed $payload     Object or message to deliver.
254
         *    @access public
255
         */
256
        function signal($type, $payload) {
257
            if (! isset($this->_reporter)) {
258
                trigger_error('Can only make assertions within test methods');
259
            }
260
            $this->_reporter->paintSignal($type, $payload);
261
        }
262
 
263
        /**
264
         *    Cancels any outstanding errors.
265
         *    @access public
266
         */
267
        function swallowErrors() {
268
            $queue = &SimpleErrorQueue::instance();
269
            $queue->clear();
270
        }
271
 
272
        /**
273
         *    Runs an expectation directly, for extending the
274
         *    tests with new expectation classes.
275
         *    @param SimpleExpectation $expectation  Expectation subclass.
276
         *    @param mixed $compare               Value to compare.
277
         *    @param string $message                 Message to display.
278
         *    @return boolean                        True on pass
279
         *    @access public
280
         */
281
        function assert($expectation, $compare, $message = '%s') {
282
            return $this->assertTrue(
283
                    $expectation->test($compare),
284
                    sprintf($message, $expectation->overlayMessage($compare)));
285
        }
286
 
287
        /**
288
         *	  @deprecated
289
         */
290
        function assertExpectation($expectation, $compare, $message = '%s') {
291
        	return $this->assert($expectation, $compare, $message);
292
        }
293
 
294
        /**
295
         *    Called from within the test methods to register
296
         *    passes and failures.
297
         *    @param boolean $result    Pass on true.
298
         *    @param string $message    Message to display describing
299
         *                              the test state.
300
         *    @return boolean           True on pass
301
         *    @access public
302
         */
303
        function assertTrue($result, $message = false) {
304
            if (! $message) {
305
                $message = 'True assertion got ' . ($result ? 'True' : 'False');
306
            }
307
            if ($result) {
308
                return $this->pass($message);
309
            } else {
310
                return $this->fail($message);
311
            }
312
        }
313
 
314
        /**
315
         *    Will be true on false and vice versa. False
316
         *    is the PHP definition of false, so that null,
317
         *    empty strings, zero and an empty array all count
318
         *    as false.
319
         *    @param boolean $result    Pass on false.
320
         *    @param string $message    Message to display.
321
         *    @return boolean           True on pass
322
         *    @access public
323
         */
324
        function assertFalse($result, $message = false) {
325
            if (! $message) {
326
                $message = 'False assertion got ' . ($result ? 'True' : 'False');
327
            }
328
            return $this->assertTrue(! $result, $message);
329
        }
330
 
331
        /**
332
         *    Uses a stack trace to find the line of an assertion.
333
         *    @param string $format    String formatting.
334
         *    @param array $stack      Stack frames top most first. Only
335
         *                             needed if not using the PHP
336
         *                             backtrace function.
337
         *    @return string           Line number of first assert*
338
         *                             method embedded in format string.
339
         *    @access public
340
         */
341
        function getAssertionLine($stack = false) {
342
            if ($stack === false) {
343
                $stack = SimpleTestCompatibility::getStackTrace();
344
            }
345
            return SimpleDumper::getFormattedAssertionLine($stack);
346
        }
347
 
348
        /**
349
         *    Sends a formatted dump of a variable to the
350
         *    test suite for those emergency debugging
351
         *    situations.
352
         *    @param mixed $variable    Variable to display.
353
         *    @param string $message    Message to display.
354
         *    @return mixed             The original variable.
355
         *    @access public
356
         */
357
        function dump($variable, $message = false) {
358
            $formatted = SimpleDumper::dump($variable);
359
            if ($message) {
360
                $formatted = $message . "\n" . $formatted;
361
            }
362
            $this->_reporter->paintFormattedMessage($formatted);
363
            return $variable;
364
        }
365
 
366
        /**
367
         *    Dispatches a text message straight to the
368
         *    test suite. Useful for status bar displays.
369
         *    @param string $message        Message to show.
370
         *    @access public
371
         */
372
        function sendMessage($message) {
373
            $this->_reporter->PaintMessage($message);
374
        }
375
 
376
        /**
377
         *    Accessor for the number of subtests.
378
         *    @return integer           Number of test cases.
379
         *    @access public
380
         *    @static
381
         */
382
        static function getSize() {
383
            return 1;
384
        }
385
    }
386
 
387
    /**
388
     *    This is a composite test class for combining
389
     *    test cases and other RunnableTest classes into
390
     *    a group test.
391
	 *    @package		SimpleTest
392
	 *    @subpackage	UnitTester
393
     */
394
    class GroupTest {
395
        protected $_label;
396
        protected $_test_cases;
397
        protected $_old_track_errors;
398
        protected $_xdebug_is_enabled;
399
 
400
        /**
401
         *    Sets the name of the test suite.
402
         *    @param string $label    Name sent at the start and end
403
         *                            of the test.
404
         *    @access public
405
         */
406
        function GroupTest($label = false) {
407
            $this->_label = $label ? $label : get_class($this);
408
            $this->_test_cases = array();
409
            $this->_old_track_errors = ini_get('track_errors');
410
            $this->_xdebug_is_enabled = function_exists('xdebug_is_enabled') ?
411
                    xdebug_is_enabled() : false;
412
        }
413
 
414
        /**
415
         *    Accessor for the test name for subclasses.
416
         *    @return string           Name of the test.
417
         *    @access public
418
         */
419
        function getLabel() {
420
            return $this->_label;
421
        }
422
 
423
		function setLabel($value)
424
		{
425
			$this->_label = $value;
426
		}
427
 
428
        /**
429
         *    Adds a test into the suite. Can be either a group
430
         *    test or some other unit test.
431
         *    @param SimpleTestCase $test_case  Suite or individual test
432
         *                                      case implementing the
433
         *                                      runnable test interface.
434
         *    @access public
435
         */
436
        function addTestCase($test_case) {
437
            $this->_test_cases[] = $test_case;
438
        }
439
 
440
        /**
441
         *    Adds a test into the suite by class name. The class will
442
         *    be instantiated as needed.
443
         *    @param SimpleTestCase $test_case  Suite or individual test
444
         *                                      case implementing the
445
         *                                      runnable test interface.
446
         *    @access public
447
         */
448
        function addTestClass($class) {
449
            if ($this->_getBaseTestCase($class) == 'grouptest') {
450
                $this->_test_cases[] = new $class();
451
            } else {
452
                $this->_test_cases[] = $class;
453
            }
454
        }
455
 
456
        /**
457
         *    Builds a group test from a library of test cases.
458
         *    The new group is composed into this one.
459
         *    @param string $test_file        File name of library with
460
         *                                    test case classes.
461
         *    @access public
462
         */
463
        function addTestFile($test_file) {
464
            $existing_classes = get_declared_classes();
465
            if ($error = $this->_requireWithError($test_file)) {
466
                $this->addTestCase(new BadGroupTest($test_file, $error));
467
                return;
468
            }
469
            $classes = $this->_selectRunnableTests($existing_classes, get_declared_classes());
470
            if (count($classes) == 0) {
471
                $this->addTestCase(new BadGroupTest($test_file, "No runnable test cases in [$test_file]"));
472
                return;
473
            }
474
            $group = $this->_createGroupFromClasses($test_file, $classes);
475
            $this->addTestCase($group);
476
        }
477
 
478
        /**
479
         *    Requires a source file recording any syntax errors.
480
         *    @param string $file        File name to require in.
481
         *    @return string/boolean     An error message on failure or false
482
         *                               if no errors.
483
         *    @access private
484
         */
485
        function _requireWithError($file) {
486
            $this->_enableErrorReporting();
487
            include_once($file);
488
            $error = isset($php_errormsg) ? $php_errormsg : false;
489
            $this->_disableErrorReporting();
490
            $self_inflicted_errors = array(
491
                    'Assigning the return value of new by reference is deprecated',
492
                    'var: Deprecated. Please use the public/private/protected modifiers');
493
            if (in_array($error, $self_inflicted_errors)) {
494
                return false;
495
            }
496
            return $error;
497
        }
498
 
499
        /**
500
         *    Sets up detection of parse errors. Note that XDebug
501
         *    interferes with this and has to be disabled. This is
502
         *    to make sure the correct error code is returned
503
         *    from unattended scripts.
504
         *    @access private
505
         */
506
        function _enableErrorReporting() {
507
            if ($this->_xdebug_is_enabled) {
508
                xdebug_disable();
509
            }
510
            ini_set('track_errors', true);
511
        }
512
 
513
        /**
514
         *    Resets detection of parse errors to their old values.
515
         *    This is to make sure the correct error code is returned
516
         *    from unattended scripts.
517
         *    @access private
518
         */
519
        function _disableErrorReporting() {
520
            ini_set('track_errors', $this->_old_track_errors);
521
            if ($this->_xdebug_is_enabled) {
522
                xdebug_enable();
523
            }
524
        }
525
 
526
        /**
527
         *    Calculates the incoming test cases from a before
528
         *    and after list of loaded classes. Skips abstract
529
         *    classes.
530
         *    @param array $existing_classes   Classes before require().
531
         *    @param array $new_classes        Classes after require().
532
         *    @return array                    New classes which are test
533
         *                                     cases that shouldn't be ignored.
534
         *    @access private
535
         */
536
        function _selectRunnableTests($existing_classes, $new_classes) {
537
            $classes = array();
538
            foreach ($new_classes as $class) {
539
                if (in_array($class, $existing_classes)) {
540
                    continue;
541
                }
542
                if ($this->_getBaseTestCase($class)) {
543
                    $reflection = new SimpleReflection($class);
544
                    if ($reflection->isAbstract()) {
545
                        SimpleTest::ignore($class);
546
                    }
547
                    $classes[] = $class;
548
                }
549
            }
550
            return $classes;
551
        }
552
 
553
        /**
554
         *    Builds a group test from a class list.
555
         *    @param string $title       Title of new group.
556
         *    @param array $classes      Test classes.
557
         *    @return GroupTest          Group loaded with the new
558
         *                               test cases.
559
         *    @access private
560
         */
561
        function &_createGroupFromClasses($title, $classes) {
562
            SimpleTest::ignoreParentsIfIgnored($classes);
563
            $group = new GroupTest($title);
564
            foreach ($classes as $class) {
565
                if (! SimpleTest::isIgnored($class)) {
566
                    $group->addTestClass($class);
567
                }
568
            }
569
            return $group;
570
        }
571
 
572
        /**
573
         *    Test to see if a class is derived from the
574
         *    SimpleTestCase class.
575
         *    @param string $class     Class name.
576
         *    @access private
577
         */
578
        function _getBaseTestCase($class) {
579
            while ($class = get_parent_class($class)) {
580
                $class = strtolower($class);
581
                if ($class == "simpletestcase" || $class == "grouptest") {
582
                    return $class;
583
                }
584
            }
585
            return false;
586
        }
587
 
588
        /**
589
         *    Delegates to a visiting collector to add test
590
         *    files.
591
         *    @param string $path                  Path to scan from.
592
         *    @param SimpleCollector $collector    Directory scanner.
593
         *    @access public
594
         */
595
        function collect($path, $collector) {
596
            $collector->collect($this, $path);
597
        }
598
 
599
        /**
600
         *    Invokes run() on all of the held test cases, instantiating
601
         *    them if necessary.
602
         *    @param SimpleReporter $reporter    Current test reporter.
603
         *    @access public
604
         */
605
        function run($reporter) {
606
            $reporter->paintGroupStart($this->getLabel(), $this->getSize());
607
            for ($i = 0, $count = count($this->_test_cases); $i < $count; $i++) {
608
                if (is_string($this->_test_cases[$i])) {
609
                    $class = $this->_test_cases[$i];
610
                    $test = new $class();
611
                    $test->run($reporter);
612
                } else {
613
                    $this->_test_cases[$i]->run($reporter);
614
                }
615
            }
616
            $reporter->paintGroupEnd($this->getLabel());
617
            return $reporter->getStatus();
618
        }
619
 
620
        /**
621
         *    Number of contained test cases.
622
         *    @return integer     Total count of cases in the group.
623
         *    @access public
624
         */
625
        function getSize() {
626
            $count = 0;
627
            foreach ($this->_test_cases as $case) {
628
                if (is_string($case)) {
629
                    $count++;
630
                } else {
631
                    $count += $case->getSize();
632
                }
633
            }
634
            return $count;
635
        }
636
    }
637
 
638
    /**
639
     *    This is a failing group test for when a test suite hasn't
640
     *    loaded properly.
641
	 *    @package		SimpleTest
642
	 *    @subpackage	UnitTester
643
     */
644
    class BadGroupTest {
645
        protected $_label;
646
        protected $_error;
647
 
648
        /**
649
         *    Sets the name of the test suite and error message.
650
         *    @param string $label    Name sent at the start and end
651
         *                            of the test.
652
         *    @access public
653
         */
654
        function BadGroupTest($label, $error) {
655
            $this->_label = $label;
656
            $this->_error = $error;
657
        }
658
 
659
        /**
660
         *    Accessor for the test name for subclasses.
661
         *    @return string           Name of the test.
662
         *    @access public
663
         */
664
        function getLabel() {
665
            return $this->_label;
666
        }
667
 
668
        /**
669
         *    Sends a single error to the reporter.
670
         *    @param SimpleReporter $reporter    Current test reporter.
671
         *    @access public
672
         */
673
        function run($reporter) {
674
            $reporter->paintGroupStart($this->getLabel(), $this->getSize());
675
            $reporter->paintFail('Bad GroupTest [' . $this->getLabel() .
676
                    '] with error [' . $this->_error . ']');
677
            $reporter->paintGroupEnd($this->getLabel());
678
            return $reporter->getStatus();
679
        }
680
 
681
        /**
682
         *    Number of contained test cases. Always zero.
683
         *    @return integer     Total count of cases in the group.
684
         *    @access public
685
         */
686
        function getSize() {
687
            return 0;
688
        }
689
    }
690
?>