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