3 * Base include file for SimpleTest
5 * @subpackage UnitTester
6 * @version $Id: simple_test.php,v 1.71 2004/08/21 00:38:04 lastcraft Exp $
10 * Includes SimpleTest files and defined the root constant
11 * for dependent libraries.
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__
) . '/');
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
29 * @subpackage UnitTester
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.
40 function SimpleRunner(&$test_case, &$scorer) {
41 $this->_test_case
= &$test_case;
42 $this->_scorer
= &$scorer;
46 * Accessor for test case being run.
47 * @return SimpleTestCase Test case.
50 function &_getTestCase() {
51 return $this->_test_case
;
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.
61 $methods = get_class_methods(get_class($this->_test_case
));
62 foreach ($methods as $method) {
63 if (! $this->_isTest($method)) {
66 if ($this->_isConstructor($method)) {
69 $this->_scorer
->paintMethodStart($method);
70 $this->_scorer
->invoke($this, $method);
71 $this->_scorer
->paintMethodEnd($method);
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.
82 function _isConstructor($method) {
83 return SimpleTestCompatibility
::isA(
89 * Tests to see if the method is a test that should
90 * be run. Currently any method that starts with 'test'
92 * @param string $method Method name to try.
93 * @return boolean True if test method.
96 function _isTest($method) {
97 return strtolower(substr($method, 0, 4)) == 'test';
101 * Invokes a test method and buffered with setUp()
102 * and tearDown() calls.
103 * @param string $method Test method to call.
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();
115 * Paints the start of a test method.
116 * @param string $test_name Name of test or other label.
119 function paintMethodStart($test_name) {
120 $this->_scorer
->paintMethodStart($test_name);
124 * Paints the end of a test method.
125 * @param string $test_name Name of test or other label.
128 function paintMethodEnd($test_name) {
129 $this->_scorer
->paintMethodEnd($test_name);
133 * Chains to the wrapped reporter.
134 * @param string $message Message is ignored.
137 function paintPass($message) {
138 $this->_scorer
->paintPass($message);
142 * Chains to the wrapped reporter.
143 * @param string $message Message is ignored.
146 function paintFail($message) {
147 $this->_scorer
->paintFail($message);
151 * Chains to the wrapped reporter.
152 * @param string $message Text of error formatted by
156 function paintError($message) {
157 $this->_scorer
->paintError($message);
161 * Chains to the wrapped reporter.
162 * @param Exception $exception Object thrown.
165 function paintException($exception) {
166 $this->_scorer
->paintException($exception);
170 * Chains to the wrapped reporter.
171 * @param string $message Text to display.
174 function paintMessage($message) {
175 $this->_scorer
->paintMessage($message);
179 * Chains to the wrapped reporter.
180 * @param string $message Text to display.
183 function paintFormattedMessage($message) {
184 $this->_scorer
->paintFormattedMessage($message);
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
196 function paintSignal($type, &$payload) {
197 $this->_scorer
->paintSignal($type, $payload);
202 * Extension that traps errors into an error queue.
203 * @package SimpleTest
204 * @subpackage UnitTester
206 class SimpleErrorTrappingRunner
extends SimpleRunner
{
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.
213 function SimpleErrorTrappingRunner(&$test_case, &$scorer) {
214 $this->SimpleRunner($test_case, $scorer);
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.
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);
232 restore_error_handler();
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
244 class SimpleTestCase
{
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.
254 function SimpleTestCase($label = false
) {
255 $this->_label
= $label ?
$label : get_class($this);
256 $this->_runner
= false
;
260 * Accessor for the test name for subclasses.
261 * @return string Name of the test.
265 function getLabel() {
266 return $this->_label
;
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
277 function &_createRunner(&$reporter) {
278 return new SimpleErrorTrappingRunner($this, $reporter);
282 * Uses reflection to run every method within itself
283 * starting with the string "test".
284 * @param SimpleReporter $reporter Current test reporter.
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();
296 * Runs test case specific code before the user setUp().
297 * For extension writers not wanting to interfere with setUp().
304 * Runs test case specific code after the user tearDown().
305 * For extension writers not wanting to interfere with user tests.
312 * Sets up unit test wide variables at the start
313 * of each test method. To be overridden in
314 * actual user test cases.
321 * Clears the data set in the setUp() method call.
322 * To be overridden by the user in actual user test cases.
325 function tearDown() {
329 * Sends a pass event with a message.
330 * @param string $message Message to send.
333 function pass($message = "Pass") {
334 $this->_runner
->paintPass($message . $this->getAssertionLine(' at line [%d]'));
338 * Sends a fail event with a message.
339 * @param string $message Message to send.
342 function fail($message = "Fail") {
343 $this->_runner
->paintFail($message . $this->getAssertionLine(' at line [%d]'));
347 * Formats a PHP error and dispatches it to the
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.
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]");
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.
371 function signal($type, &$payload) {
372 $this->_runner
->paintSignal($type, $payload);
376 * Cancels any outstanding errors.
379 function swallowErrors() {
380 $queue = &SimpleErrorQueue
::instance();
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
393 function assertExpectation(&$expectation, $test_value, $message = '%s') {
394 return $this->assertTrue(
395 $expectation->test($test_value),
396 sprintf($message, $expectation->overlayMessage($test_value)));
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
405 * @return boolean True on pass
408 function assertTrue($result, $message = false
) {
410 $message = 'True assertion got ' . ($result ?
'True' : 'False');
413 $this->pass($message);
416 $this->fail($message);
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
426 * @param boolean $result Pass on false.
427 * @param string $message Message to display.
428 * @return boolean True on pass
431 function assertFalse($result, $message = false
) {
433 $message = 'False assertion got ' . ($result ?
'True' : 'False');
435 return ! $this->assertTrue(! $result, $message);
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.
448 function getAssertionLine($format = '%d', $stack = false
) {
449 if ($stack === false
) {
450 $stack = SimpleTestCompatibility
::getStackTrace();
452 return SimpleDumper
::getFormattedAssertionLine($stack, $format);
456 * Sends a formatted dump of a variable to the
457 * test suite for those emergency debugging
459 * @param mixed $variable Variable to display.
460 * @param string $message Message to display.
461 * @return mixed The original variable.
464 function dump($variable, $message = false
) {
465 $formatted = SimpleDumper
::dump($variable);
467 $formatted = $message . "\n" . $formatted;
469 $this->_runner
->paintFormattedMessage($formatted);
474 * Dispatches a text message straight to the
475 * test suite. Useful for status bar displays.
476 * @param string $message Message to show.
479 function sendMessage($message) {
480 $this->_runner
->PaintMessage($message);
484 * Accessor for the number of subtests.
485 * @return integer Number of test cases.
495 * This is a composite test class for combining
496 * test cases and other RunnableTest classes into
498 * @package SimpleTest
499 * @subpackage UnitTester
506 * Sets the name of the test suite.
507 * @param string $label Name sent at the start and end
511 function GroupTest($label) {
512 $this->_label
= $label;
513 $this->_test_cases
= array();
517 * Accessor for the test name for subclasses.
518 * @return string Name of the test.
521 function getLabel() {
522 return $this->_label
;
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.
533 function addTestCase(&$test_case) {
534 $this->_test_cases
[] = &$test_case;
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.
545 function addTestClass($class) {
546 $this->_test_cases
[] = $class;
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
556 function addTestFile($test_file) {
557 $existing_classes = get_declared_classes();
559 $group = new GroupTest($test_file);
560 foreach (get_declared_classes() as $class) {
561 if (in_array($class, $existing_classes)) {
564 if (! $this->_isTestCase($class)) {
567 if (SimpleTestOptions
::isIgnored($class)) {
570 $group->addTestClass($class);
572 $this->addTestCase($group);
576 * Test to see if a class is derived from the
578 * @param string $class Class name.
581 function _isTestCase($class) {
582 while ($class = get_parent_class($class)) {
583 if (strtolower($class) == "simpletestcase") {
591 * Invokes run() on all of the held test cases, instantiating
593 * @param SimpleReporter $reporter Current test reporter.
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);
604 $this->_test_cases
[$i]->run($reporter);
607 $reporter->paintGroupEnd($this->getLabel());
608 return $reporter->getStatus();
612 * Number of contained test cases.
613 * @return integer Total count of cases in the group.
618 foreach ($this->_test_cases
as $case) {
619 if (is_string($case)) {
622 $count +
= $case->getSize();