first reimport from platal
[platal.git] / htdocs / TESTS / simpletest / simple_test.php
1 <?php
2 /**
3 * Base include file for SimpleTest
4 * @package SimpleTest
5 * @subpackage UnitTester
6 * @version $Id: simple_test.php,v 1.71 2004/08/21 00:38:04 lastcraft Exp $
7 */
8
9 /**#@+
10 * Includes SimpleTest files and defined the root constant
11 * for dependent libraries.
12 */
13 require_once(dirname(__FILE__) . '/errors.php');
14 require_once(dirname(__FILE__) . '/options.php');
15 require_once(dirname(__FILE__) . '/scorer.php');
16 require_once(dirname(__FILE__) . '/expectation.php');
17 require_once(dirname(__FILE__) . '/dumper.php');
18 if (! defined('SIMPLE_TEST')) {
19 define('SIMPLE_TEST', dirname(__FILE__) . '/');
20 }
21 /**#@-*/
22
23 /**
24 * The standard runner. Will run every method starting
25 * with test as well as the setUp() and tearDown()
26 * before and after each test method. Basically the
27 * Mediator pattern.
28 * @package SimpleTest
29 * @subpackage UnitTester
30 */
31 class SimpleRunner {
32 var $_test_case;
33 var $_scorer;
34
35 /**
36 * Takes in the test case and reporter to mediate between.
37 * @param SimpleTestCase $test_case Test case to run.
38 * @param SimpleScorer $scorer Reporter to receive events.
39 */
40 function SimpleRunner(&$test_case, &$scorer) {
41 $this->_test_case = &$test_case;
42 $this->_scorer = &$scorer;
43 }
44
45 /**
46 * Accessor for test case being run.
47 * @return SimpleTestCase Test case.
48 * @access protected
49 */
50 function &_getTestCase() {
51 return $this->_test_case;
52 }
53
54 /**
55 * Runs the test methods in the test case.
56 * @param SimpleTest $test_case Test case to run test on.
57 * @param string $method Name of test method.
58 * @access public
59 */
60 function run() {
61 $methods = get_class_methods(get_class($this->_test_case));
62 foreach ($methods as $method) {
63 if (! $this->_isTest($method)) {
64 continue;
65 }
66 if ($this->_isConstructor($method)) {
67 continue;
68 }
69 $this->_scorer->paintMethodStart($method);
70 $this->_scorer->invoke($this, $method);
71 $this->_scorer->paintMethodEnd($method);
72 }
73 }
74
75 /**
76 * Tests to see if the method is the constructor and
77 * so should be ignored.
78 * @param string $method Method name to try.
79 * @return boolean True if constructor.
80 * @access protected
81 */
82 function _isConstructor($method) {
83 return SimpleTestCompatibility::isA(
84 $this->_test_case,
85 strtolower($method));
86 }
87
88 /**
89 * Tests to see if the method is a test that should
90 * be run. Currently any method that starts with 'test'
91 * is a candidate.
92 * @param string $method Method name to try.
93 * @return boolean True if test method.
94 * @access protected
95 */
96 function _isTest($method) {
97 return strtolower(substr($method, 0, 4)) == 'test';
98 }
99
100 /**
101 * Invokes a test method and buffered with setUp()
102 * and tearDown() calls.
103 * @param string $method Test method to call.
104 * @access public
105 */
106 function invoke($method) {
107 $this->_test_case->before();
108 $this->_test_case->setUp();
109 $this->_test_case->$method();
110 $this->_test_case->tearDown();
111 $this->_test_case->after();
112 }
113
114 /**
115 * Paints the start of a test method.
116 * @param string $test_name Name of test or other label.
117 * @access public
118 */
119 function paintMethodStart($test_name) {
120 $this->_scorer->paintMethodStart($test_name);
121 }
122
123 /**
124 * Paints the end of a test method.
125 * @param string $test_name Name of test or other label.
126 * @access public
127 */
128 function paintMethodEnd($test_name) {
129 $this->_scorer->paintMethodEnd($test_name);
130 }
131
132 /**
133 * Chains to the wrapped reporter.
134 * @param string $message Message is ignored.
135 * @access public
136 */
137 function paintPass($message) {
138 $this->_scorer->paintPass($message);
139 }
140
141 /**
142 * Chains to the wrapped reporter.
143 * @param string $message Message is ignored.
144 * @access public
145 */
146 function paintFail($message) {
147 $this->_scorer->paintFail($message);
148 }
149
150 /**
151 * Chains to the wrapped reporter.
152 * @param string $message Text of error formatted by
153 * the test case.
154 * @access public
155 */
156 function paintError($message) {
157 $this->_scorer->paintError($message);
158 }
159
160 /**
161 * Chains to the wrapped reporter.
162 * @param Exception $exception Object thrown.
163 * @access public
164 */
165 function paintException($exception) {
166 $this->_scorer->paintException($exception);
167 }
168
169 /**
170 * Chains to the wrapped reporter.
171 * @param string $message Text to display.
172 * @access public
173 */
174 function paintMessage($message) {
175 $this->_scorer->paintMessage($message);
176 }
177
178 /**
179 * Chains to the wrapped reporter.
180 * @param string $message Text to display.
181 * @access public
182 */
183 function paintFormattedMessage($message) {
184 $this->_scorer->paintFormattedMessage($message);
185 }
186
187 /**
188 * Chains to the wrapped reporter.
189 * @param string $type Event type as text.
190 * @param mixed $payload Message or object.
191 * @return boolean Should return false if this
192 * type of signal should fail the
193 * test suite.
194 * @access public
195 */
196 function paintSignal($type, &$payload) {
197 $this->_scorer->paintSignal($type, $payload);
198 }
199 }
200
201 /**
202 * Extension that traps errors into an error queue.
203 * @package SimpleTest
204 * @subpackage UnitTester
205 */
206 class SimpleErrorTrappingRunner extends SimpleRunner {
207
208 /**
209 * Takes in the test case and reporter to mediate between.
210 * @param SimpleTestCase $test_case Test case to run.
211 * @param SimpleScorer $scorer Reporter to receive events.
212 */
213 function SimpleErrorTrappingRunner(&$test_case, &$scorer) {
214 $this->SimpleRunner($test_case, $scorer);
215 }
216
217 /**
218 * Invokes a test method and dispatches any
219 * untrapped errors. Called back from
220 * the visiting runner.
221 * @param string $method Test method to call.
222 * @access public
223 */
224 function invoke($method) {
225 set_error_handler('simpleTestErrorHandler');
226 parent::invoke($method);
227 $queue = &SimpleErrorQueue::instance();
228 while (list($severity, $message, $file, $line, $globals) = $queue->extract()) {
229 $test_case = &$this->_getTestCase();
230 $test_case->error($severity, $message, $file, $line, $globals);
231 }
232 restore_error_handler();
233 }
234 }
235
236 /**
237 * Basic test case. This is the smallest unit of a test
238 * suite. It searches for
239 * all methods that start with the the string "test" and
240 * runs them. Working test cases extend this class.
241 * @package SimpleTest
242 * @subpackage UnitTester
243 */
244 class SimpleTestCase {
245 var $_label;
246 var $_runner;
247
248 /**
249 * Sets up the test with no display.
250 * @param string $label If no test name is given then
251 * the class name is used.
252 * @access public
253 */
254 function SimpleTestCase($label = false) {
255 $this->_label = $label ? $label : get_class($this);
256 $this->_runner = false;
257 }
258
259 /**
260 * Accessor for the test name for subclasses.
261 * @return string Name of the test.
262 * @access public
263 * @static
264 */
265 function getLabel() {
266 return $this->_label;
267 }
268
269 /**
270 * Can modify the incoming reporter so as to run
271 * the tests differently. This version simply
272 * passes it straight through.
273 * @param SimpleReporter $reporter Incoming observer.
274 * @return SimpleReporter
275 * @access protected
276 */
277 function &_createRunner(&$reporter) {
278 return new SimpleErrorTrappingRunner($this, $reporter);
279 }
280
281 /**
282 * Uses reflection to run every method within itself
283 * starting with the string "test".
284 * @param SimpleReporter $reporter Current test reporter.
285 * @access public
286 */
287 function run(&$reporter) {
288 $reporter->paintCaseStart($this->getLabel());
289 $this->_runner = &$this->_createRunner($reporter);
290 $this->_runner->run();
291 $reporter->paintCaseEnd($this->getLabel());
292 return $reporter->getStatus();
293 }
294
295 /**
296 * Runs test case specific code before the user setUp().
297 * For extension writers not wanting to interfere with setUp().
298 * @access protected
299 */
300 function before() {
301 }
302
303 /**
304 * Runs test case specific code after the user tearDown().
305 * For extension writers not wanting to interfere with user tests.
306 * @access protected
307 */
308 function after() {
309 }
310
311 /**
312 * Sets up unit test wide variables at the start
313 * of each test method. To be overridden in
314 * actual user test cases.
315 * @access public
316 */
317 function setUp() {
318 }
319
320 /**
321 * Clears the data set in the setUp() method call.
322 * To be overridden by the user in actual user test cases.
323 * @access public
324 */
325 function tearDown() {
326 }
327
328 /**
329 * Sends a pass event with a message.
330 * @param string $message Message to send.
331 * @access public
332 */
333 function pass($message = "Pass") {
334 $this->_runner->paintPass($message . $this->getAssertionLine(' at line [%d]'));
335 }
336
337 /**
338 * Sends a fail event with a message.
339 * @param string $message Message to send.
340 * @access public
341 */
342 function fail($message = "Fail") {
343 $this->_runner->paintFail($message . $this->getAssertionLine(' at line [%d]'));
344 }
345
346 /**
347 * Formats a PHP error and dispatches it to the
348 * runner.
349 * @param integer $severity PHP error code.
350 * @param string $message Text of error.
351 * @param string $file File error occoured in.
352 * @param integer $line Line number of error.
353 * @param hash $globals PHP super global arrays.
354 * @access public
355 */
356 function error($severity, $message, $file, $line, $globals) {
357 $severity = SimpleErrorQueue::getSeverityAsString($severity);
358 $this->_runner->paintError(
359 "Unexpected PHP error [$message] severity [$severity] in [$file] line [$line]");
360 }
361
362 /**
363 * Sends a user defined event to the test runner.
364 * This is for small scale extension where
365 * both the test case and either the runner or
366 * display are subclassed.
367 * @param string $type Type of event.
368 * @param mixed $payload Object or message to deliver.
369 * @access public
370 */
371 function signal($type, &$payload) {
372 $this->_runner->paintSignal($type, $payload);
373 }
374
375 /**
376 * Cancels any outstanding errors.
377 * @access public
378 */
379 function swallowErrors() {
380 $queue = &SimpleErrorQueue::instance();
381 $queue->clear();
382 }
383
384 /**
385 * Runs an expectation directly, for extending the
386 * tests with new expectation classes.
387 * @param SimpleExpectation $expectation Expectation subclass.
388 * @param mixed $test_value Value to compare.
389 * @param string $message Message to display.
390 * @return boolean True on pass
391 * @access public
392 */
393 function assertExpectation(&$expectation, $test_value, $message = '%s') {
394 return $this->assertTrue(
395 $expectation->test($test_value),
396 sprintf($message, $expectation->overlayMessage($test_value)));
397 }
398
399 /**
400 * Called from within the test methods to register
401 * passes and failures.
402 * @param boolean $result Pass on true.
403 * @param string $message Message to display describing
404 * the test state.
405 * @return boolean True on pass
406 * @access public
407 */
408 function assertTrue($result, $message = false) {
409 if (! $message) {
410 $message = 'True assertion got ' . ($result ? 'True' : 'False');
411 }
412 if ($result) {
413 $this->pass($message);
414 return true;
415 } else {
416 $this->fail($message);
417 return false;
418 }
419 }
420
421 /**
422 * Will be true on false and vice versa. False
423 * is the PHP definition of false, so that null,
424 * empty strings, zero and an empty array all count
425 * as false.
426 * @param boolean $result Pass on false.
427 * @param string $message Message to display.
428 * @return boolean True on pass
429 * @access public
430 */
431 function assertFalse($result, $message = false) {
432 if (! $message) {
433 $message = 'False assertion got ' . ($result ? 'True' : 'False');
434 }
435 return ! $this->assertTrue(! $result, $message);
436 }
437
438 /**
439 * Uses a stack trace to find the line of an assertion.
440 * @param string $format String formatting.
441 * @param array $stack Stack frames top most first. Only
442 * needed if not using the PHP
443 * backtrace function.
444 * @return string Line number of first assert*
445 * method embedded in format string.
446 * @access public
447 */
448 function getAssertionLine($format = '%d', $stack = false) {
449 if ($stack === false) {
450 $stack = SimpleTestCompatibility::getStackTrace();
451 }
452 return SimpleDumper::getFormattedAssertionLine($stack, $format);
453 }
454
455 /**
456 * Sends a formatted dump of a variable to the
457 * test suite for those emergency debugging
458 * situations.
459 * @param mixed $variable Variable to display.
460 * @param string $message Message to display.
461 * @return mixed The original variable.
462 * @access public
463 */
464 function dump($variable, $message = false) {
465 $formatted = SimpleDumper::dump($variable);
466 if ($message) {
467 $formatted = $message . "\n" . $formatted;
468 }
469 $this->_runner->paintFormattedMessage($formatted);
470 return $variable;
471 }
472
473 /**
474 * Dispatches a text message straight to the
475 * test suite. Useful for status bar displays.
476 * @param string $message Message to show.
477 * @access public
478 */
479 function sendMessage($message) {
480 $this->_runner->PaintMessage($message);
481 }
482
483 /**
484 * Accessor for the number of subtests.
485 * @return integer Number of test cases.
486 * @access public
487 * @static
488 */
489 function getSize() {
490 return 1;
491 }
492 }
493
494 /**
495 * This is a composite test class for combining
496 * test cases and other RunnableTest classes into
497 * a group test.
498 * @package SimpleTest
499 * @subpackage UnitTester
500 */
501 class GroupTest {
502 var $_label;
503 var $_test_cases;
504
505 /**
506 * Sets the name of the test suite.
507 * @param string $label Name sent at the start and end
508 * of the test.
509 * @access public
510 */
511 function GroupTest($label) {
512 $this->_label = $label;
513 $this->_test_cases = array();
514 }
515
516 /**
517 * Accessor for the test name for subclasses.
518 * @return string Name of the test.
519 * @access public
520 */
521 function getLabel() {
522 return $this->_label;
523 }
524
525 /**
526 * Adds a test into the suite. Can be either a group
527 * test or some other unit test.
528 * @param SimpleTestCase $test_case Suite or individual test
529 * case implementing the
530 * runnable test interface.
531 * @access public
532 */
533 function addTestCase(&$test_case) {
534 $this->_test_cases[] = &$test_case;
535 }
536
537 /**
538 * Adds a test into the suite by class name. The class will
539 * be instantiated as needed.
540 * @param SimpleTestCase $test_case Suite or individual test
541 * case implementing the
542 * runnable test interface.
543 * @access public
544 */
545 function addTestClass($class) {
546 $this->_test_cases[] = $class;
547 }
548
549 /**
550 * Builds a group test from a library of test cases.
551 * The new group is composed into this one.
552 * @param string $test_file File name of library with
553 * test case classes.
554 * @access public
555 */
556 function addTestFile($test_file) {
557 $existing_classes = get_declared_classes();
558 require($test_file);
559 $group = new GroupTest($test_file);
560 foreach (get_declared_classes() as $class) {
561 if (in_array($class, $existing_classes)) {
562 continue;
563 }
564 if (! $this->_isTestCase($class)) {
565 continue;
566 }
567 if (SimpleTestOptions::isIgnored($class)) {
568 continue;
569 }
570 $group->addTestClass($class);
571 }
572 $this->addTestCase($group);
573 }
574
575 /**
576 * Test to see if a class is derived from the
577 * TestCase class.
578 * @param string $class Class name.
579 * @access private
580 */
581 function _isTestCase($class) {
582 while ($class = get_parent_class($class)) {
583 if (strtolower($class) == "simpletestcase") {
584 return true;
585 }
586 }
587 return false;
588 }
589
590 /**
591 * Invokes run() on all of the held test cases, instantiating
592 * them if necessary.
593 * @param SimpleReporter $reporter Current test reporter.
594 * @access public
595 */
596 function run(&$reporter) {
597 $reporter->paintGroupStart($this->getLabel(), $this->getSize());
598 for ($i = 0; $i < count($this->_test_cases); $i++) {
599 if (is_string($this->_test_cases[$i])) {
600 $class = $this->_test_cases[$i];
601 $test = &new $class();
602 $test->run($reporter);
603 } else {
604 $this->_test_cases[$i]->run($reporter);
605 }
606 }
607 $reporter->paintGroupEnd($this->getLabel());
608 return $reporter->getStatus();
609 }
610
611 /**
612 * Number of contained test cases.
613 * @return integer Total count of cases in the group.
614 * @access public
615 */
616 function getSize() {
617 $count = 0;
618 foreach ($this->_test_cases as $case) {
619 if (is_string($case)) {
620 $count++;
621 } else {
622 $count += $case->getSize();
623 }
624 }
625 return $count;
626 }
627 }
628 ?>