00001 <?php
00002
00003
00010 class SimpleTestCase {
00011 var $_label = false;
00012 var $_reporter;
00013 var $_observers;
00014 var $_should_skip = false;
00015
00022 function SimpleTestCase($label = false) {
00023 if ($label) {
00024 $this->_label = $label;
00025 }
00026 }
00027
00033 function getLabel() {
00034 return $this->_label ? $this->_label : get_class($this);
00035 }
00036
00043 function skip() {}
00044
00052 function skipIf($should_skip, $message = '%s') {
00053 if ($should_skip && !$this->_should_skip) {
00054 $this->_should_skip = true;
00055 $message = sprintf($message, 'Skipping [' . get_class($this) . ']');
00056 $this->_reporter->paintSkip($message . $this->getAssertionLine());
00057 }
00058 }
00059
00067 function skipUnless($shouldnt_skip, $message = false) {
00068 $this->skipIf(!$shouldnt_skip, $message);
00069 }
00070
00076 function & createInvoker() {
00077 $invoker = &new SimpleErrorTrappingInvoker(new SimpleInvoker($this));
00078 if (version_compare(phpversion(), '5') >= 0) {
00079 $invoker = &new SimpleExceptionTrappingInvoker($invoker);
00080 }
00081 return $invoker;
00082 }
00083
00092 function run(&$reporter) {
00093 $context = &SimpleTest::getContext();
00094 $context->setTest($this);
00095 $context->setReporter($reporter);
00096 $this->_reporter = &$reporter;
00097 $started = false;
00098 foreach ($this->getTests() as $method) {
00099 if ($reporter->shouldInvoke($this->getLabel(), $method)) {
00100 $this->skip();
00101 if ($this->_should_skip) {
00102 break;
00103 }
00104 if (!$started) {
00105 $reporter->paintCaseStart($this->getLabel());
00106 $started = true;
00107 }
00108 $invoker = &$this->_reporter->createInvoker($this->createInvoker());
00109 $invoker->before($method);
00110 $invoker->invoke($method);
00111 $invoker->after($method);
00112 }
00113 }
00114 if ($started) {
00115 $reporter->paintCaseEnd($this->getLabel());
00116 }
00117 unset($this->_reporter);
00118 return $reporter->getStatus();
00119 }
00120
00129 function getTests() {
00130 $methods = array();
00131 foreach (get_class_methods(get_class($this)) as $method) {
00132 if ($this->_isTest($method)) {
00133 $methods[] = $method;
00134 }
00135 }
00136 return $methods;
00137 }
00138
00147 function _isTest($method) {
00148 if (strtolower(substr($method, 0, 4)) == 'test') {
00149 return !is_a($this, strtolower($method));
00150 }
00151 return false;
00152 }
00153
00159 function before($method) {
00160 $this->_reporter->paintMethodStart($method);
00161 $this->_observers = array();
00162 }
00163
00170 function setUp() {}
00171
00177 function tearDown() {}
00178
00184 function after($method) {
00185 for ($i = 0; $i < count($this->_observers); $i++) {
00186 $this->_observers[$i]->atTestEnd($method, $this);
00187 }
00188 $this->_reporter->paintMethodEnd($method);
00189 }
00190
00197 function tell(&$observer) {
00198 $this->_observers[] = &$observer;
00199 }
00200
00204 function pass($message = 'Pass', $group = 'Other') {
00205 if (!isset($this->_reporter)) {
00206 trigger_error('Can only make assertions within test methods');
00207 }
00208 $this->_reporter->paintPass($message . $this->getAssertionLine(), $group);
00209 return TRUE;
00210 }
00211
00217 function fail($message = 'Fail', $group = 'Other') {
00218 if (!isset($this->_reporter)) {
00219 trigger_error('Can only make assertions within test methods');
00220 }
00221 $this->_reporter->paintFail($message . $this->getAssertionLine(), $group);
00222 return FALSE;
00223 }
00224
00234 function error($severity, $message, $file, $line) {
00235 if (!isset($this->_reporter)) {
00236 trigger_error('Can only make assertions within test methods');
00237 }
00238 $this->_reporter->paintError("Unexpected PHP error [$message] severity [$severity] in [$file line $line]");
00239 }
00240
00247 function exception($exception) {
00248 $this->_reporter->paintException($exception);
00249 }
00250
00254 function signal($type, &$payload) {
00255 if (!isset($this->_reporter)) {
00256 trigger_error('Can only make assertions within test methods');
00257 }
00258 $this->_reporter->paintSignal($type, $payload);
00259 }
00260
00270 function assert(&$expectation, $compare, $message = '%s', $group = 'Other') {
00271 if ($expectation->test($compare)) {
00272 return $this->pass(sprintf($message, $expectation->overlayMessage($compare, $this->_reporter->getDumper())), $group);
00273 }
00274 else {
00275 return $this->fail(sprintf($message, $expectation->overlayMessage($compare, $this->_reporter->getDumper())), $group);
00276 }
00277 }
00278
00282 function assertExpectation(&$expectation, $compare, $message = '%s', $group = 'Other') {
00283 return $this->assert($expectation, $compare, $message, $group);
00284 }
00285
00292 function getAssertionLine() {
00293 $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip'));
00294 return $trace->traceMethod();
00295 }
00296
00300 function sendMessage($message) {
00301 $this->_reporter->PaintMessage($message);
00302 }
00303
00310 function getSize() {
00311 return 1;
00312 }
00313 }
00314
00318 class SimpleFileLoader {
00319
00328 function &load($test_file) {
00329 $existing_classes = get_declared_classes();
00330 include_once ($test_file);
00331 $classes = $this->selectRunnableTests(
00332 array_diff(get_declared_classes(), $existing_classes));
00333 $suite = &$this->createSuiteFromClasses($test_file, $classes);
00334 return $suite;
00335 }
00336
00345 function selectRunnableTests($candidates) {
00346 $classes = array();
00347 foreach ($candidates as $class) {
00348 if (TestSuite::getBaseTestCase($class)) {
00349 $reflection = new ReflectionClass($class);
00350 if ($reflection->isAbstract()) {
00351 SimpleTest::ignore($class);
00352 }
00353 $classes[] = $class;
00354 }
00355 }
00356 return $classes;
00357 }
00358
00367 function &createSuiteFromClasses($title, $classes) {
00368 if (count($classes) == 0) {
00369 $suite = &new BadTestSuite($title, "No runnable test cases in [$title]");
00370 return $suite;
00371 }
00372 SimpleTest::ignoreParentsIfIgnored($classes);
00373 $suite = &new TestSuite($title);
00374 foreach ($classes as $class) {
00375 if (!SimpleTest::isIgnored($class)) {
00376 $suite->addTestClass($class);
00377 }
00378 }
00379 return $suite;
00380 }
00381 }
00382
00390 class TestSuite {
00391 var $_label;
00392 var $_test_cases;
00393
00400 function TestSuite($label = false) {
00401 $this->_label = $label;
00402 $this->_test_cases = array();
00403 }
00404
00411 function getLabel() {
00412 if (!$this->_label) {
00413 return ($this->getSize() == 1) ? get_class($this->_test_cases[0]) : get_class($this);
00414 }
00415 else {
00416 return $this->_label;
00417 }
00418 }
00419
00423 function addTestCase(&$test_case) {
00424 $this->_test_cases[] = &$test_case;
00425 }
00426
00430 function addTestClass($class) {
00431 if (TestSuite::getBaseTestCase($class) == 'testsuite') {
00432 $this->_test_cases[] = &new $class();
00433 }
00434 else {
00435 $this->_test_cases[] = $class;
00436 }
00437 }
00438
00447 function add(&$test_case) {
00448 if (!is_string($test_case)) {
00449 $this->_test_cases[] = &$test_case;
00450 }
00451 elseif (TestSuite::getBaseTestCase($class) == 'testsuite') {
00452 $this->_test_cases[] = &new $class();
00453 }
00454 else {
00455 $this->_test_cases[] = $class;
00456 }
00457 }
00458
00462 function addTestFile($test_file) {
00463 $this->addFile($test_file);
00464 }
00465
00473 function addFile($test_file) {
00474 $extractor = new SimpleFileLoader();
00475 $this->add($extractor->load($test_file));
00476 }
00477
00485 function collect($path, &$collector) {
00486 $collector->collect($this, $path);
00487 }
00488
00495 function run(&$reporter) {
00496 $reporter->paintGroupStart($this->getLabel(), $this->getSize());
00497 for ($i = 0, $count = count($this->_test_cases); $i < $count; $i++) {
00498 if (is_string($this->_test_cases[$i])) {
00499 $class = $this->_test_cases[$i];
00500 $test = &new $class();
00501 $test->run($reporter);
00502 unset($test);
00503 }
00504 else {
00505 $this->_test_cases[$i]->run($reporter);
00506 }
00507 }
00508 $reporter->paintGroupEnd($this->getLabel());
00509 return $reporter->getStatus();
00510 }
00511
00517 function getSize() {
00518 $count = 0;
00519 foreach ($this->_test_cases as $case) {
00520 if (is_string($case)) {
00521 $count++;
00522 }
00523 else {
00524 $count += $case->getSize();
00525 }
00526 }
00527 return $count;
00528 }
00529
00537 function getBaseTestCase($class) {
00538 while ($class = get_parent_class($class)) {
00539 $class = strtolower($class);
00540 if ($class == 'simpletestcase' || $class == 'testsuite') {
00541 return $class;
00542 }
00543 }
00544 return false;
00545 }
00546 }
00547
00553 class GroupTest extends TestSuite {}
00554
00561 class BadTestSuite {
00562 var $_label;
00563 var $_error;
00564
00571 function BadTestSuite($label, $error) {
00572 $this->_label = $label;
00573 $this->_error = $error;
00574 }
00575
00581 function getLabel() {
00582 return $this->_label;
00583 }
00584
00590 function run(&$reporter) {
00591 $reporter->paintGroupStart($this->getLabel(), $this->getSize());
00592 $reporter->paintFail('Bad TestSuite [' . $this->getLabel() .
00593 '] with error [' . $this->_error . ']');
00594 $reporter->paintGroupEnd($this->getLabel());
00595 return $reporter->getStatus();
00596 }
00597
00603 function getSize() {
00604 return 0;
00605 }
00606 }
00607
00613 class BadGroupTest extends BadTestSuite {}
00614
00615