|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00013 require_once(dirname(__FILE__) . '/invoker.php'); 00014 require_once(dirname(__FILE__) . '/errors.php'); 00015 require_once(dirname(__FILE__) . '/compatibility.php'); 00016 require_once(dirname(__FILE__) . '/scorer.php'); 00017 require_once(dirname(__FILE__) . '/expectation.php'); 00018 require_once(dirname(__FILE__) . '/dumper.php'); 00019 require_once(dirname(__FILE__) . '/simpletest.php'); 00020 if (version_compare(phpversion(), '5') >= 0) { 00021 require_once(dirname(__FILE__) . '/exceptions.php'); 00022 require_once(dirname(__FILE__) . '/reflection_php5.php'); 00023 } else { 00024 require_once(dirname(__FILE__) . '/reflection_php4.php'); 00025 } 00026 if (! defined('SIMPLE_TEST')) { 00030 define('SIMPLE_TEST', dirname(__FILE__) . DIRECTORY_SEPARATOR); 00031 } 00042 class SimpleTestCase { 00043 var $_label = false; 00044 var $_reporter; 00045 var $_observers; 00046 var $_should_skip = false; 00047 00054 function SimpleTestCase($label = false) { 00055 if ($label) { 00056 $this->_label = $label; 00057 } 00058 } 00059 00065 function getLabel() { 00066 return $this->_label ? $this->_label : get_class($this); 00067 } 00068 00075 function skip() { 00076 } 00077 00085 function skipIf($should_skip, $message = '%s') { 00086 if ($should_skip && ! $this->_should_skip) { 00087 $this->_should_skip = true; 00088 $message = sprintf($message, 'Skipping [' . get_class($this) . ']'); 00089 $this->_reporter->paintSkip($message . $this->getAssertionLine()); 00090 } 00091 } 00092 00100 function skipUnless($shouldnt_skip, $message = false) { 00101 $this->skipIf(! $shouldnt_skip, $message); 00102 } 00103 00109 function &createInvoker() { 00110 $invoker = new SimpleErrorTrappingInvoker(new SimpleInvoker($this)); 00111 if (version_compare(phpversion(), '5') >= 0) { 00112 $invoker = new SimpleExceptionTrappingInvoker($invoker); 00113 } 00114 return $invoker; 00115 } 00116 00125 function run(&$reporter) { 00126 $context = &SimpleTest::getContext(); 00127 $context->setTest($this); 00128 $context->setReporter($reporter); 00129 $this->_reporter = &$reporter; 00130 $started = false; 00131 foreach ($this->getTests() as $method) { 00132 if ($reporter->shouldInvoke($this->getLabel(), $method)) { 00133 $this->skip(); 00134 if ($this->_should_skip) { 00135 break; 00136 } 00137 if (! $started) { 00138 $reporter->paintCaseStart($this->getLabel()); 00139 $started = true; 00140 } 00141 //moodlefix begins 00142 if (defined('TIME_ALLOWED_PER_UNIT_TEST')) { 00143 set_time_limit(TIME_ALLOWED_PER_UNIT_TEST); 00144 } 00145 //moodlefix ends 00146 $invoker = &$this->_reporter->createInvoker($this->createInvoker()); 00147 $invoker->before($method); 00148 $invoker->invoke($method); 00149 $invoker->after($method); 00150 } 00151 } 00152 if ($started) { 00153 $reporter->paintCaseEnd($this->getLabel()); 00154 } 00155 unset($this->_reporter); 00156 //moodlefix begins 00157 $context->unsetTest(); 00158 //moodlefix ends 00159 return $reporter->getStatus(); 00160 } 00161 00170 function getTests() { 00171 $methods = array(); 00172 foreach (get_class_methods(get_class($this)) as $method) { 00173 if ($this->_isTest($method)) { 00174 $methods[] = $method; 00175 } 00176 } 00177 return $methods; 00178 } 00179 00188 function _isTest($method) { 00189 if (strtolower(substr($method, 0, 4)) == 'test') { 00190 return ! SimpleTestCompatibility::isA($this, strtolower($method)); 00191 } 00192 return false; 00193 } 00194 00200 function before($method) { 00201 $this->_reporter->paintMethodStart($method); 00202 $this->_observers = array(); 00203 } 00204 00211 function setUp() { 00212 } 00213 00219 function tearDown() { 00220 } 00221 00227 function after($method) { 00228 for ($i = 0; $i < count($this->_observers); $i++) { 00229 $this->_observers[$i]->atTestEnd($method, $this); 00230 } 00231 $this->_reporter->paintMethodEnd($method); 00232 } 00233 00240 function tell(&$observer) { 00241 $this->_observers[] = &$observer; 00242 } 00243 00247 function pass($message = "Pass") { 00248 if (! isset($this->_reporter)) { 00249 trigger_error('Can only make assertions within test methods'); 00250 } 00251 $this->_reporter->paintPass( 00252 $message . $this->getAssertionLine()); 00253 return true; 00254 } 00255 00261 function fail($message = "Fail") { 00262 if (! isset($this->_reporter)) { 00263 trigger_error('Can only make assertions within test methods'); 00264 } 00265 $this->_reporter->paintFail( 00266 $message . $this->getAssertionLine()); 00267 return false; 00268 } 00269 00279 function error($severity, $message, $file, $line) { 00280 if (! isset($this->_reporter)) { 00281 trigger_error('Can only make assertions within test methods'); 00282 } 00283 $this->_reporter->paintError( 00284 "Unexpected PHP error [$message] severity [$severity] in [$file line $line]"); 00285 } 00286 00293 function exception($exception) { 00294 $this->_reporter->paintException($exception); 00295 } 00296 00300 function signal($type, &$payload) { 00301 if (! isset($this->_reporter)) { 00302 trigger_error('Can only make assertions within test methods'); 00303 } 00304 $this->_reporter->paintSignal($type, $payload); 00305 } 00306 00316 function assert(&$expectation, $compare, $message = '%s') { 00317 if ($expectation->test($compare)) { 00318 return $this->pass(sprintf( 00319 $message, 00320 $expectation->overlayMessage($compare, $this->_reporter->getDumper()))); 00321 } else { 00322 return $this->fail(sprintf( 00323 $message, 00324 $expectation->overlayMessage($compare, $this->_reporter->getDumper()))); 00325 } 00326 } 00327 00331 function assertExpectation(&$expectation, $compare, $message = '%s') { 00332 return $this->assert($expectation, $compare, $message); 00333 } 00334 00341 function getAssertionLine() { 00342 $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip')); 00343 return $trace->traceMethod(); 00344 } 00345 00355 function dump($variable, $message = false) { 00356 $dumper = $this->_reporter->getDumper(); 00357 $formatted = $dumper->dump($variable); 00358 if ($message) { 00359 $formatted = $message . "\n" . $formatted; 00360 } 00361 $this->_reporter->paintFormattedMessage($formatted); 00362 return $variable; 00363 } 00364 00368 function sendMessage($message) { 00369 $this->_reporter->PaintMessage($message); 00370 } 00371 00378 function getSize() { 00379 return 1; 00380 } 00381 } 00382 00386 class SimpleFileLoader { 00387 00396 function &load($test_file) { 00397 $existing_classes = get_declared_classes(); 00398 $existing_globals = get_defined_vars(); 00399 global $CFG; 00400 include_once($test_file); 00401 $new_globals = get_defined_vars(); 00402 $this->_makeFileVariablesGlobal($existing_globals, $new_globals); 00403 $new_classes = array_diff(get_declared_classes(), $existing_classes); 00404 if (empty($new_classes)) { 00405 $new_classes = $this->_scrapeClassesFromFile($test_file); 00406 } 00407 $classes = $this->selectRunnableTests($new_classes); 00408 $suite = &$this->createSuiteFromClasses($test_file, $classes); 00409 return $suite; 00410 } 00411 00418 function _makeFileVariablesGlobal($existing, $new) { 00419 $globals = array_diff(array_keys($new), array_keys($existing)); 00420 foreach ($globals as $global) { 00421 $_GLOBALS[$global] = $new[$global]; 00422 } 00423 } 00424 00435 function _scrapeClassesFromFile($test_file) { 00436 preg_match_all('~^\s*class\s+(\w+)(\s+(extends|implements)\s+\w+)*\s*\{~mi', 00437 file_get_contents($test_file), 00438 $matches ); 00439 return $matches[1]; 00440 } 00441 00450 function selectRunnableTests($candidates) { 00451 $classes = array(); 00452 foreach ($candidates as $class) { 00453 if (TestSuite::getBaseTestCase($class)) { 00454 $reflection = new SimpleReflection($class); 00455 if ($reflection->isAbstract()) { 00456 SimpleTest::ignore($class); 00457 } else { 00458 $classes[] = $class; 00459 } 00460 } 00461 } 00462 return $classes; 00463 } 00464 00473 function &createSuiteFromClasses($title, $classes) { 00474 if (count($classes) == 0) { 00475 $suite = new BadTestSuite($title, "No runnable test cases in [$title]"); 00476 return $suite; 00477 } 00478 SimpleTest::ignoreParentsIfIgnored($classes); 00479 $suite = new TestSuite($title); 00480 foreach ($classes as $class) { 00481 if (! SimpleTest::isIgnored($class)) { 00482 $suite->addTestClass($class); 00483 } 00484 } 00485 return $suite; 00486 } 00487 } 00488 00496 class TestSuite { 00497 var $_label; 00498 var $_test_cases; 00499 00506 function TestSuite($label = false) { 00507 $this->_label = $label; 00508 $this->_test_cases = array(); 00509 } 00510 00517 function getLabel() { 00518 if (! $this->_label) { 00519 return ($this->getSize() == 1) ? 00520 get_class($this->_test_cases[0]) : get_class($this); 00521 } else { 00522 return $this->_label; 00523 } 00524 } 00525 00529 function addTestCase(&$test_case) { 00530 $this->_test_cases[] = &$test_case; 00531 } 00532 00536 function addTestClass($class) { 00537 if (TestSuite::getBaseTestCase($class) == 'testsuite') { 00538 $this->_test_cases[] = new $class(); 00539 } else { 00540 $this->_test_cases[] = $class; 00541 } 00542 } 00543 00552 function add(&$test_case) { 00553 if (! is_string($test_case)) { 00554 $this->_test_cases[] = &$test_case; 00555 } elseif (TestSuite::getBaseTestCase($class) == 'testsuite') { 00556 $this->_test_cases[] = new $class(); 00557 } else { 00558 $this->_test_cases[] = $class; 00559 } 00560 } 00561 00565 function addTestFile($test_file) { 00566 $this->addFile($test_file); 00567 } 00568 00576 function addFile($test_file) { 00577 $extractor = new SimpleFileLoader(); 00578 $this->add($extractor->load($test_file)); 00579 } 00580 00588 function collect($path, &$collector) { 00589 $collector->collect($this, $path); 00590 } 00591 00598 function run(&$reporter) { 00599 $reporter->paintGroupStart($this->getLabel(), $this->getSize()); 00600 for ($i = 0, $count = count($this->_test_cases); $i < $count; $i++) { 00601 if (is_string($this->_test_cases[$i])) { 00602 $class = $this->_test_cases[$i]; 00603 // moodle hack start - need to do this before the constructor call, because of FakeDBUnitTestCase. 00604 global $CFG; 00605 if (is_subclass_of($class, 'FakeDBUnitTestCase')) { 00606 // Do not execute this test because the test tables system no longer works, reporting it as exception 00607 $reporter->paintError("Unit test \"{$class}\" of type FakeDBUnitTestCase no longer supported. Must be migrated to UnitTestCaseUsingDatabase."); 00608 continue; 00609 } 00610 if (is_subclass_of($class, 'UnitTestCaseUsingDatabase') && empty($CFG->unittestprefix)) { 00611 // Do not execute this test because $CFG->unittestprefix is not set, but it will be required. 00612 $reporter->paintSkip("Unit test \"{$class}\" of type UnitTestCaseUsingDatabase skipped. Must define different, non-conflicting \$CFG->unittestprefix to be runnable."); 00613 continue; 00614 } 00615 // moodle hack end 00616 $test = new $class(); 00617 $test->run($reporter); 00618 unset($test); 00619 } else { 00620 $this->_test_cases[$i]->run($reporter); 00621 } 00622 } 00623 $reporter->paintGroupEnd($this->getLabel()); 00624 return $reporter->getStatus(); 00625 } 00626 00632 function getSize() { 00633 $count = 0; 00634 foreach ($this->_test_cases as $case) { 00635 if (is_string($case)) { 00636 if (! SimpleTest::isIgnored($case)) { 00637 $count++; 00638 } 00639 } else { 00640 $count += $case->getSize(); 00641 } 00642 } 00643 return $count; 00644 } 00645 00653 function getBaseTestCase($class) { 00654 while ($class = get_parent_class($class)) { 00655 $class = strtolower($class); 00656 if ($class == 'simpletestcase' || $class == 'testsuite') { 00657 return $class; 00658 } 00659 } 00660 return false; 00661 } 00662 } 00663 00669 class GroupTest extends TestSuite { 00670 // moodle fix: adding old style constructor to make it compatible with PHP 5.3 00671 function GroupTest($label = false) { 00672 parent::TestSuite($label); 00673 } 00674 } 00675 00682 class BadTestSuite { 00683 var $_label; 00684 var $_error; 00685 00692 function BadTestSuite($label, $error) { 00693 $this->_label = $label; 00694 $this->_error = $error; 00695 } 00696 00702 function getLabel() { 00703 return $this->_label; 00704 } 00705 00711 function run(&$reporter) { 00712 $reporter->paintGroupStart($this->getLabel(), $this->getSize()); 00713 $reporter->paintFail('Bad TestSuite [' . $this->getLabel() . 00714 '] with error [' . $this->_error . ']'); 00715 $reporter->paintGroupEnd($this->getLabel()); 00716 return $reporter->getStatus(); 00717 } 00718 00724 function getSize() { 00725 return 0; 00726 } 00727 } 00728 00734 class BadGroupTest extends BadTestSuite { } 00735 ?>