[ Index ]

PHP Cross Reference of Limb3

title

Body

[close]

/tests_runner/lib/simpletest/ -> test_case.php (source)

   1  <?php
   2      /**

   3       *    Base include file for SimpleTest

   4       *    @package    SimpleTest

   5       *    @subpackage    UnitTester

   6       *    @version    $Id: test_case.php 5999 2007-06-18 13:13:08Z pachanga $

   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          /**

  28           * @ignore

  29           */
  30          define('SIMPLE_TEST', dirname(__FILE__) . DIRECTORY_SEPARATOR);
  31      }
  32      /**#@-*/

  33  
  34      /**

  35       *    Basic test case. This is the smallest unit of a test

  36       *    suite. It searches for

  37       *    all methods that start with the the string "test" and

  38       *    runs them. Working test cases extend this class.

  39       *    @package        SimpleTest

  40       *    @subpackage    UnitTester

  41       */
  42      class SimpleTestCase {
  43          var $_label = false;
  44          var $_reporter;
  45          var $_observers;
  46          var $_should_skip = false;
  47  
  48          /**

  49           *    Sets up the test with no display.

  50           *    @param string $label    If no test name is given then

  51           *                            the class name is used.

  52           *    @access public

  53           */
  54          function SimpleTestCase($label = false) {
  55              if ($label) {
  56                  $this->_label = $label;
  57              }
  58          }
  59  
  60          /**

  61           *    Accessor for the test name for subclasses.

  62           *    @return string           Name of the test.

  63           *    @access public

  64           */
  65          function getLabel() {
  66              return $this->_label ? $this->_label : get_class($this);
  67          }
  68  
  69          /**

  70           *    This is a placeholder for skipping tests. In this

  71           *    method you place skipIf() and skipUnless() calls to

  72           *    set the skipping state.

  73           *    @access public

  74           */
  75          function skip() {
  76          }
  77  
  78          /**

  79           *    Will issue a message to the reporter and tell the test

  80           *    case to skip if the incoming flag is true.

  81           *    @param string $should_skip    Condition causing the tests to be skipped.

  82           *    @param string $message        Text of skip condition.

  83           *    @access public

  84           */
  85          function skipIf($should_skip, $message = '%s') {
  86              if ($should_skip && ! $this->_should_skip) {
  87                  $this->_should_skip = true;
  88                  $message = sprintf($message, 'Skipping [' . get_class($this) . ']');
  89                  $this->_reporter->paintSkip($message . $this->getAssertionLine());
  90              }
  91          }
  92  
  93          /**

  94           *    Will issue a message to the reporter and tell the test

  95           *    case to skip if the incoming flag is false.

  96           *    @param string $shouldnt_skip  Condition causing the tests to be run.

  97           *    @param string $message        Text of skip condition.

  98           *    @access public

  99           */
 100          function skipUnless($shouldnt_skip, $message = false) {
 101              $this->skipIf(! $shouldnt_skip, $message);
 102          }
 103  
 104          /**

 105           *    Used to invoke the single tests.

 106           *    @return SimpleInvoker        Individual test runner.

 107           *    @access public

 108           */
 109          function &createInvoker() {
 110              $invoker = &new SimpleErrorTrappingInvoker(new SimpleInvoker($this));
 111              if (version_compare(phpversion(), '5') >= 0) {
 112                  $invoker = &new SimpleExceptionTrappingInvoker($invoker);
 113              }
 114              return $invoker;
 115          }
 116  
 117          /**

 118           *    Uses reflection to run every method within itself

 119           *    starting with the string "test" unless a method

 120           *    is specified.

 121           *    @param SimpleReporter $reporter    Current test reporter.

 122           *    @return boolean                    True if all tests passed.

 123           *    @access public

 124           */
 125          function run(&$reporter) {
 126              $context = &SimpleTest::getContext();
 127              $context->setTest($this);
 128              $context->setReporter($reporter);
 129              $this->_reporter = &$reporter;
 130              $started = false;
 131              foreach ($this->getTests() as $method) {
 132                  if ($reporter->shouldInvoke($this->getLabel(), $method)) {
 133                      $this->skip();
 134                      if ($this->_should_skip) {
 135                          break;
 136                      }
 137                      if (! $started) {
 138                          $reporter->paintCaseStart($this->getLabel());
 139                          $started = true;
 140                      }
 141                      $invoker = &$this->_reporter->createInvoker($this->createInvoker());
 142                      $invoker->before($method);
 143                      $invoker->invoke($method);
 144                      $invoker->after($method);
 145                  }
 146              }
 147              if ($started) {
 148                  $reporter->paintCaseEnd($this->getLabel());
 149              }
 150              unset($this->_reporter);
 151              return $reporter->getStatus();
 152          }
 153  
 154          /**

 155           *    Gets a list of test names. Normally that will

 156           *    be all internal methods that start with the

 157           *    name "test". This method should be overridden

 158           *    if you want a different rule.

 159           *    @return array        List of test names.

 160           *    @access public

 161           */
 162          function getTests() {
 163              $methods = array();
 164              foreach (get_class_methods(get_class($this)) as $method) {
 165                  if ($this->_isTest($method)) {
 166                      $methods[] = $method;
 167                  }
 168              }
 169              return $methods;
 170          }
 171  
 172          /**

 173           *    Tests to see if the method is a test that should

 174           *    be run. Currently any method that starts with 'test'

 175           *    is a candidate unless it is the constructor.

 176           *    @param string $method        Method name to try.

 177           *    @return boolean              True if test method.

 178           *    @access protected

 179           */
 180          function _isTest($method) {
 181              if (strtolower(substr($method, 0, 4)) == 'test') {
 182                  return ! SimpleTestCompatibility::isA($this, strtolower($method));
 183              }
 184              return false;
 185          }
 186  
 187          /**

 188           *    Announces the start of the test.

 189           *    @param string $method    Test method just started.

 190           *    @access public

 191           */
 192          function before($method) {
 193              $this->_reporter->paintMethodStart($method);
 194              $this->_observers = array();
 195          }
 196  
 197          /**

 198           *    Sets up unit test wide variables at the start

 199           *    of each test method. To be overridden in

 200           *    actual user test cases.

 201           *    @access public

 202           */
 203          function setUp() {
 204          }
 205  
 206          /**

 207           *    Clears the data set in the setUp() method call.

 208           *    To be overridden by the user in actual user test cases.

 209           *    @access public

 210           */
 211          function tearDown() {
 212          }
 213  
 214          /**

 215           *    Announces the end of the test. Includes private clean up.

 216           *    @param string $method    Test method just finished.

 217           *    @access public

 218           */
 219          function after($method) {
 220              for ($i = 0; $i < count($this->_observers); $i++) {
 221                  $this->_observers[$i]->atTestEnd($method, $this);
 222              }
 223              $this->_reporter->paintMethodEnd($method);
 224          }
 225  
 226          /**

 227           *    Sets up an observer for the test end.

 228           *    @param object $observer    Must have atTestEnd()

 229           *                               method.

 230           *    @access public

 231           */
 232          function tell(&$observer) {
 233              $this->_observers[] = &$observer;
 234          }
 235  
 236          /**

 237           *    @deprecated

 238           */
 239          function pass($message = "Pass") {
 240              if (! isset($this->_reporter)) {
 241                  trigger_error('Can only make assertions within test methods');
 242              }
 243              $this->_reporter->paintPass(
 244                      $message . $this->getAssertionLine());
 245              return true;
 246          }
 247  
 248          /**

 249           *    Sends a fail event with a message.

 250           *    @param string $message        Message to send.

 251           *    @access public

 252           */
 253          function fail($message = "Fail") {
 254              if (! isset($this->_reporter)) {
 255                  trigger_error('Can only make assertions within test methods');
 256              }
 257              $this->_reporter->paintFail(
 258                      $message . $this->getAssertionLine());
 259              return false;
 260          }
 261  
 262          /**

 263           *    Formats a PHP error and dispatches it to the

 264           *    reporter.

 265           *    @param integer $severity  PHP error code.

 266           *    @param string $message    Text of error.

 267           *    @param string $file       File error occoured in.

 268           *    @param integer $line      Line number of error.

 269           *    @access public

 270           */
 271          function error($severity, $message, $file, $line) {
 272              if (! isset($this->_reporter)) {
 273                  trigger_error('Can only make assertions within test methods');
 274              }
 275              $this->_reporter->paintError(
 276                      "Unexpected PHP error [$message] severity [$severity] in [$file line $line]");
 277          }
 278  
 279          /**

 280           *    Formats an exception and dispatches it to the

 281           *    reporter.

 282           *    @param Exception $exception    Object thrown.

 283           *    @access public

 284           */
 285          function exception($exception) {
 286              $this->_reporter->paintException($exception);
 287          }
 288  
 289          /**

 290           *    @deprecated

 291           */
 292          function signal($type, &$payload) {
 293              if (! isset($this->_reporter)) {
 294                  trigger_error('Can only make assertions within test methods');
 295              }
 296              $this->_reporter->paintSignal($type, $payload);
 297          }
 298  
 299          /**

 300           *    Runs an expectation directly, for extending the

 301           *    tests with new expectation classes.

 302           *    @param SimpleExpectation $expectation  Expectation subclass.

 303           *    @param mixed $compare               Value to compare.

 304           *    @param string $message                 Message to display.

 305           *    @return boolean                        True on pass

 306           *    @access public

 307           */
 308          function assert(&$expectation, $compare, $message = '%s') {
 309              if ($expectation->test($compare)) {
 310                  return $this->pass(sprintf(
 311                          $message,
 312                          $expectation->overlayMessage($compare, $this->_reporter->getDumper())));
 313              } else {
 314                  return $this->fail(sprintf(
 315                          $message,
 316                          $expectation->overlayMessage($compare, $this->_reporter->getDumper())));
 317              }
 318          }
 319  
 320          /**

 321           *      @deprecated

 322           */
 323          function assertExpectation(&$expectation, $compare, $message = '%s') {
 324              return $this->assert($expectation, $compare, $message);
 325          }
 326  
 327          /**

 328           *    Uses a stack trace to find the line of an assertion.

 329           *    @return string           Line number of first assert*

 330           *                             method embedded in format string.

 331           *    @access public

 332           */
 333          function getAssertionLine() {
 334              $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip'));
 335              return $trace->traceMethod();
 336          }
 337  
 338          /**

 339           *    Sends a formatted dump of a variable to the

 340           *    test suite for those emergency debugging

 341           *    situations.

 342           *    @param mixed $variable    Variable to display.

 343           *    @param string $message    Message to display.

 344           *    @return mixed             The original variable.

 345           *    @access public

 346           */
 347          function dump($variable, $message = false) {
 348              $dumper = $this->_reporter->getDumper();
 349              $formatted = $dumper->dump($variable);
 350              if ($message) {
 351                  $formatted = $message . "\n" . $formatted;
 352              }
 353              $this->_reporter->paintFormattedMessage($formatted);
 354              return $variable;
 355          }
 356  
 357          /**

 358           *    @deprecated

 359           */
 360          function sendMessage($message) {
 361              $this->_reporter->PaintMessage($message);
 362          }
 363  
 364          /**

 365           *    Accessor for the number of subtests.

 366           *    @return integer           Number of test cases.

 367           *    @access public

 368           *    @static

 369           */
 370          function getSize() {
 371              return 1;
 372          }
 373      }
 374  
 375      /**

 376       *  Helps to extract test cases automatically from a file.

 377       */
 378      class SimpleFileLoader {
 379  
 380          /**

 381           *    Builds a test suite from a library of test cases.

 382           *    The new suite is composed into this one.

 383           *    @param string $test_file        File name of library with

 384           *                                    test case classes.

 385           *    @return TestSuite               The new test suite.

 386           *    @access public

 387           */
 388          function &load($test_file) {
 389              $existing_classes = get_declared_classes();
 390              include_once($test_file);
 391              $classes = $this->selectRunnableTests(
 392                      array_diff(get_declared_classes(), $existing_classes));
 393              $suite = &$this->createSuiteFromClasses($test_file, $classes);
 394              return $suite;
 395          }
 396  
 397          /**

 398           *    Calculates the incoming test cases. Skips abstract

 399           *    and ignored classes.

 400           *    @param array $candidates   Candidate classes.

 401           *    @return array              New classes which are test

 402           *                               cases that shouldn't be ignored.

 403           *    @access public

 404           */
 405          function selectRunnableTests($candidates) {
 406              $classes = array();
 407              foreach ($candidates as $class) {
 408                  if (TestSuite::getBaseTestCase($class)) {
 409                      $reflection = new SimpleReflection($class);
 410                      if ($reflection->isAbstract()) {
 411                          SimpleTest::ignore($class);
 412                      }
 413                      $classes[] = $class;
 414                  }
 415              }
 416              return $classes;
 417          }
 418  
 419          /**

 420           *    Builds a test suite from a class list.

 421           *    @param string $title       Title of new group.

 422           *    @param array $classes      Test classes.

 423           *    @return TestSuite          Group loaded with the new

 424           *                               test cases.

 425           *    @access public

 426           */
 427          function &createSuiteFromClasses($title, $classes) {
 428              if (count($classes) == 0) {
 429                  $suite = &new BadTestSuite($title, "No runnable test cases in [$title]");
 430                  return $suite;
 431              }
 432              SimpleTest::ignoreParentsIfIgnored($classes);
 433              $suite = &new TestSuite($title);
 434              foreach ($classes as $class) {
 435                  if (! SimpleTest::isIgnored($class)) {
 436                      $suite->addTestClass($class);
 437                  }
 438              }
 439              return $suite;
 440          }
 441      }
 442  
 443      /**

 444       *    This is a composite test class for combining

 445       *    test cases and other RunnableTest classes into

 446       *    a group test.

 447       *    @package        SimpleTest

 448       *    @subpackage    UnitTester

 449       */
 450      class TestSuite {
 451          var $_label;
 452          var $_test_cases;
 453  
 454          /**

 455           *    Sets the name of the test suite.

 456           *    @param string $label    Name sent at the start and end

 457           *                            of the test.

 458           *    @access public

 459           */
 460          function TestSuite($label = false) {
 461              $this->_label = $label;
 462              $this->_test_cases = array();
 463          }
 464  
 465          /**

 466           *    Accessor for the test name for subclasses. If the suite

 467           *    wraps a single test case the label defaults to the name of that test.

 468           *    @return string           Name of the test.

 469           *    @access public

 470           */
 471          function getLabel() {
 472              if (! $this->_label) {
 473                  return ($this->getSize() == 1) ?
 474                          get_class($this->_test_cases[0]) : get_class($this);
 475              } else {
 476                  return $this->_label;
 477              }
 478          }
 479  
 480          /**

 481           *    @deprecated

 482           */
 483          function addTestCase(&$test_case) {
 484              $this->_test_cases[] = &$test_case;
 485          }
 486  
 487          /**

 488           *    @deprecated

 489           */
 490          function addTestClass($class) {
 491              if (TestSuite::getBaseTestCase($class) == 'testsuite') {
 492                  $this->_test_cases[] = &new $class();
 493              } else {
 494                  $this->_test_cases[] = $class;
 495              }
 496          }
 497  
 498          /**

 499           *    Adds a test into the suite by instance or class. The class will

 500           *    be instantiated if it's a test suite.

 501           *    @param SimpleTestCase $test_case  Suite or individual test

 502           *                                      case implementing the

 503           *                                      runnable test interface.

 504           *    @access public

 505           */
 506          function add(&$test_case) {
 507              if (! is_string($test_case)) {
 508                  $this->_test_cases[] = &$test_case;
 509              } elseif (TestSuite::getBaseTestCase($class) == 'testsuite') {
 510                  $this->_test_cases[] = &new $class();
 511              } else {
 512                  $this->_test_cases[] = $class;
 513              }
 514          }
 515  
 516          /**

 517           *    @deprecated

 518           */
 519          function addTestFile($test_file) {
 520              $this->addFile($test_file);
 521          }
 522  
 523          /**

 524           *    Builds a test suite from a library of test cases.

 525           *    The new suite is composed into this one.

 526           *    @param string $test_file        File name of library with

 527           *                                    test case classes.

 528           *    @access public

 529           */
 530          function addFile($test_file) {
 531              $extractor = new SimpleFileLoader();
 532              $this->add($extractor->load($test_file));
 533          }
 534  
 535          /**

 536           *    Delegates to a visiting collector to add test

 537           *    files.

 538           *    @param string $path                  Path to scan from.

 539           *    @param SimpleCollector $collector    Directory scanner.

 540           *    @access public

 541           */
 542          function collect($path, &$collector) {
 543              $collector->collect($this, $path);
 544          }
 545  
 546          /**

 547           *    Invokes run() on all of the held test cases, instantiating

 548           *    them if necessary.

 549           *    @param SimpleReporter $reporter    Current test reporter.

 550           *    @access public

 551           */
 552          function run(&$reporter) {
 553              $reporter->paintGroupStart($this->getLabel(), $this->getSize());
 554              for (