aboutsummaryrefslogtreecommitdiff
path: root/vendors/simpletest/test_case.php
diff options
context:
space:
mode:
Diffstat (limited to 'vendors/simpletest/test_case.php')
-rw-r--r--vendors/simpletest/test_case.php708
1 files changed, 708 insertions, 0 deletions
diff --git a/vendors/simpletest/test_case.php b/vendors/simpletest/test_case.php
new file mode 100644
index 000000000..e5b229833
--- /dev/null
+++ b/vendors/simpletest/test_case.php
@@ -0,0 +1,708 @@
+<?php
+/**
+ * Base include file for SimpleTest
+ * @package SimpleTest
+ * @subpackage UnitTester
+ * @version $Id: test_case.php 1726 2008-04-08 01:20:10Z lastcraft $
+ */
+
+/**#@+
+ * Includes SimpleTest files and defined the root constant
+ * for dependent libraries.
+ */
+require_once(dirname(__FILE__) . '/invoker.php');
+require_once(dirname(__FILE__) . '/errors.php');
+require_once(dirname(__FILE__) . '/compatibility.php');
+require_once(dirname(__FILE__) . '/scorer.php');
+require_once(dirname(__FILE__) . '/expectation.php');
+require_once(dirname(__FILE__) . '/dumper.php');
+require_once(dirname(__FILE__) . '/simpletest.php');
+if (version_compare(phpversion(), '5') >= 0) {
+ require_once(dirname(__FILE__) . '/exceptions.php');
+ require_once(dirname(__FILE__) . '/reflection_php5.php');
+} else {
+ require_once(dirname(__FILE__) . '/reflection_php4.php');
+}
+if (! defined('SIMPLE_TEST')) {
+ /**
+ * @ignore
+ */
+ define('SIMPLE_TEST', dirname(__FILE__) . DIRECTORY_SEPARATOR);
+}
+/**#@-*/
+
+/**
+ * Basic test case. This is the smallest unit of a test
+ * suite. It searches for
+ * all methods that start with the the string "test" and
+ * runs them. Working test cases extend this class.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class SimpleTestCase {
+ var $_label = false;
+ var $_reporter;
+ var $_observers;
+ var $_should_skip = false;
+
+ /**
+ * Sets up the test with no display.
+ * @param string $label If no test name is given then
+ * the class name is used.
+ * @access public
+ */
+ function SimpleTestCase($label = false) {
+ if ($label) {
+ $this->_label = $label;
+ }
+ }
+
+ /**
+ * Accessor for the test name for subclasses.
+ * @return string Name of the test.
+ * @access public
+ */
+ function getLabel() {
+ return $this->_label ? $this->_label : get_class($this);
+ }
+
+ /**
+ * This is a placeholder for skipping tests. In this
+ * method you place skipIf() and skipUnless() calls to
+ * set the skipping state.
+ * @access public
+ */
+ function skip() {
+ }
+
+ /**
+ * Will issue a message to the reporter and tell the test
+ * case to skip if the incoming flag is true.
+ * @param string $should_skip Condition causing the tests to be skipped.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function skipIf($should_skip, $message = '%s') {
+ if ($should_skip && ! $this->_should_skip) {
+ $this->_should_skip = true;
+ $message = sprintf($message, 'Skipping [' . get_class($this) . ']');
+ $this->_reporter->paintSkip($message . $this->getAssertionLine());
+ }
+ }
+
+ /**
+ * Will issue a message to the reporter and tell the test
+ * case to skip if the incoming flag is false.
+ * @param string $shouldnt_skip Condition causing the tests to be run.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function skipUnless($shouldnt_skip, $message = false) {
+ $this->skipIf(! $shouldnt_skip, $message);
+ }
+
+ /**
+ * Used to invoke the single tests.
+ * @return SimpleInvoker Individual test runner.
+ * @access public
+ */
+ function &createInvoker() {
+ $invoker = &new SimpleErrorTrappingInvoker(new SimpleInvoker($this));
+ if (version_compare(phpversion(), '5') >= 0) {
+ $invoker = &new SimpleExceptionTrappingInvoker($invoker);
+ }
+ return $invoker;
+ }
+
+ /**
+ * Uses reflection to run every method within itself
+ * starting with the string "test" unless a method
+ * is specified.
+ * @param SimpleReporter $reporter Current test reporter.
+ * @return boolean True if all tests passed.
+ * @access public
+ */
+ function run(&$reporter) {
+ $context = &SimpleTest::getContext();
+ $context->setTest($this);
+ $context->setReporter($reporter);
+ $this->_reporter = &$reporter;
+ $started = false;
+ foreach ($this->getTests() as $method) {
+ if ($reporter->shouldInvoke($this->getLabel(), $method)) {
+ $this->skip();
+ if ($this->_should_skip) {
+ break;
+ }
+ if (! $started) {
+ $reporter->paintCaseStart($this->getLabel());
+ $started = true;
+ }
+ $invoker = &$this->_reporter->createInvoker($this->createInvoker());
+ $invoker->before($method);
+ $invoker->invoke($method);
+ $invoker->after($method);
+ }
+ }
+ if ($started) {
+ $reporter->paintCaseEnd($this->getLabel());
+ }
+ unset($this->_reporter);
+ return $reporter->getStatus();
+ }
+
+ /**
+ * Gets a list of test names. Normally that will
+ * be all internal methods that start with the
+ * name "test". This method should be overridden
+ * if you want a different rule.
+ * @return array List of test names.
+ * @access public
+ */
+ function getTests() {
+ $methods = array();
+ foreach (get_class_methods(get_class($this)) as $method) {
+ if ($this->_isTest($method)) {
+ $methods[] = $method;
+ }
+ }
+ return $methods;
+ }
+
+ /**
+ * Tests to see if the method is a test that should
+ * be run. Currently any method that starts with 'test'
+ * is a candidate unless it is the constructor.
+ * @param string $method Method name to try.
+ * @return boolean True if test method.
+ * @access protected
+ */
+ function _isTest($method) {
+ if (strtolower(substr($method, 0, 4)) == 'test') {
+ return ! SimpleTestCompatibility::isA($this, strtolower($method));
+ }
+ return false;
+ }
+
+ /**
+ * Announces the start of the test.
+ * @param string $method Test method just started.
+ * @access public
+ */
+ function before($method) {
+ $this->_reporter->paintMethodStart($method);
+ $this->_observers = array();
+ }
+
+ /**
+ * Sets up unit test wide variables at the start
+ * of each test method. To be overridden in
+ * actual user test cases.
+ * @access public
+ */
+ function setUp() {
+ }
+
+ /**
+ * Clears the data set in the setUp() method call.
+ * To be overridden by the user in actual user test cases.
+ * @access public
+ */
+ function tearDown() {
+ }
+
+ /**
+ * Announces the end of the test. Includes private clean up.
+ * @param string $method Test method just finished.
+ * @access public
+ */
+ function after($method) {
+ for ($i = 0; $i < count($this->_observers); $i++) {
+ $this->_observers[$i]->atTestEnd($method, $this);
+ }
+ $this->_reporter->paintMethodEnd($method);
+ }
+
+ /**
+ * Sets up an observer for the test end.
+ * @param object $observer Must have atTestEnd()
+ * method.
+ * @access public
+ */
+ function tell(&$observer) {
+ $this->_observers[] = &$observer;
+ }
+
+ /**
+ * @deprecated
+ */
+ function pass($message = "Pass") {
+ if (! isset($this->_reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->_reporter->paintPass(
+ $message . $this->getAssertionLine());
+ return true;
+ }
+
+ /**
+ * Sends a fail event with a message.
+ * @param string $message Message to send.
+ * @access public
+ */
+ function fail($message = "Fail") {
+ if (! isset($this->_reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->_reporter->paintFail(
+ $message . $this->getAssertionLine());
+ return false;
+ }
+
+ /**
+ * Formats a PHP error and dispatches it to the
+ * reporter.
+ * @param integer $severity PHP error code.
+ * @param string $message Text of error.
+ * @param string $file File error occoured in.
+ * @param integer $line Line number of error.
+ * @access public
+ */
+ function error($severity, $message, $file, $line) {
+ if (! isset($this->_reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->_reporter->paintError(
+ "Unexpected PHP error [$message] severity [$severity] in [$file line $line]");
+ }
+
+ /**
+ * Formats an exception and dispatches it to the
+ * reporter.
+ * @param Exception $exception Object thrown.
+ * @access public
+ */
+ function exception($exception) {
+ $this->_reporter->paintException($exception);
+ }
+
+ /**
+ * @deprecated
+ */
+ function signal($type, &$payload) {
+ if (! isset($this->_reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->_reporter->paintSignal($type, $payload);
+ }
+
+ /**
+ * Runs an expectation directly, for extending the
+ * tests with new expectation classes.
+ * @param SimpleExpectation $expectation Expectation subclass.
+ * @param mixed $compare Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assert(&$expectation, $compare, $message = '%s') {
+ if ($expectation->test($compare)) {
+ return $this->pass(sprintf(
+ $message,
+ $expectation->overlayMessage($compare, $this->_reporter->getDumper())));
+ } else {
+ return $this->fail(sprintf(
+ $message,
+ $expectation->overlayMessage($compare, $this->_reporter->getDumper())));
+ }
+ }
+
+ /**
+ * @deprecated
+ */
+ function assertExpectation(&$expectation, $compare, $message = '%s') {
+ return $this->assert($expectation, $compare, $message);
+ }
+
+ /**
+ * Uses a stack trace to find the line of an assertion.
+ * @return string Line number of first assert*
+ * method embedded in format string.
+ * @access public
+ */
+ function getAssertionLine() {
+ $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip'));
+ return $trace->traceMethod();
+ }
+
+ /**
+ * Sends a formatted dump of a variable to the
+ * test suite for those emergency debugging
+ * situations.
+ * @param mixed $variable Variable to display.
+ * @param string $message Message to display.
+ * @return mixed The original variable.
+ * @access public
+ */
+ function dump($variable, $message = false) {
+ $dumper = $this->_reporter->getDumper();
+ $formatted = $dumper->dump($variable);
+ if ($message) {
+ $formatted = $message . "\n" . $formatted;
+ }
+ $this->_reporter->paintFormattedMessage($formatted);
+ return $variable;
+ }
+
+ /**
+ * @deprecated
+ */
+ function sendMessage($message) {
+ $this->_reporter->PaintMessage($message);
+ }
+
+ /**
+ * Accessor for the number of subtests including myelf.
+ * @return integer Number of test cases.
+ * @access public
+ * @static
+ */
+ function getSize() {
+ return 1;
+ }
+}
+
+/**
+ * Helps to extract test cases automatically from a file.
+ */
+class SimpleFileLoader {
+
+ /**
+ * Builds a test suite from a library of test cases.
+ * The new suite is composed into this one.
+ * @param string $test_file File name of library with
+ * test case classes.
+ * @return TestSuite The new test suite.
+ * @access public
+ */
+ function &load($test_file) {
+ $existing_classes = get_declared_classes();
+ $existing_globals = get_defined_vars();
+ include_once($test_file);
+ $new_globals = get_defined_vars();
+ $this->_makeFileVariablesGlobal($existing_globals, $new_globals);
+ $new_classes = array_diff(get_declared_classes(), $existing_classes);
+ if (empty($new_classes)) {
+ $new_classes = $this->_scrapeClassesFromFile($test_file);
+ }
+ $classes = $this->selectRunnableTests($new_classes);
+ $suite = &$this->createSuiteFromClasses($test_file, $classes);
+ return $suite;
+ }
+
+ /**
+ * Imports new variables into the global namespace.
+ * @param hash $existing Variables before the file was loaded.
+ * @param hash $new Variables after the file was loaded.
+ * @access private
+ */
+ function _makeFileVariablesGlobal($existing, $new) {
+ $globals = array_diff(array_keys($new), array_keys($existing));
+ foreach ($globals as $global) {
+ $_GLOBALS[$global] = $new[$global];
+ }
+ }
+
+ /**
+ * Lookup classnames from file contents, in case the
+ * file may have been included before.
+ * Note: This is probably too clever by half. Figuring this
+ * out after a failed test case is going to be tricky for us,
+ * never mind the user. A test case should not be included
+ * twice anyway.
+ * @param string $test_file File name with classes.
+ * @access private
+ */
+ function _scrapeClassesFromFile($test_file) {
+ preg_match_all('~^\s*class\s+(\w+)(\s+(extends|implements)\s+\w+)*\s*\{~mi',
+ file_get_contents($test_file),
+ $matches );
+ return $matches[1];
+ }
+
+ /**
+ * Calculates the incoming test cases. Skips abstract
+ * and ignored classes.
+ * @param array $candidates Candidate classes.
+ * @return array New classes which are test
+ * cases that shouldn't be ignored.
+ * @access public
+ */
+ function selectRunnableTests($candidates) {
+ $classes = array();
+ foreach ($candidates as $class) {
+ if (TestSuite::getBaseTestCase($class)) {
+ $reflection = new SimpleReflection($class);
+ if ($reflection->isAbstract()) {
+ SimpleTest::ignore($class);
+ } else {
+ $classes[] = $class;
+ }
+ }
+ }
+ return $classes;
+ }
+
+ /**
+ * Builds a test suite from a class list.
+ * @param string $title Title of new group.
+ * @param array $classes Test classes.
+ * @return TestSuite Group loaded with the new
+ * test cases.
+ * @access public
+ */
+ function &createSuiteFromClasses($title, $classes) {
+ if (count($classes) == 0) {
+ $suite = &new BadTestSuite($title, "No runnable test cases in [$title]");
+ return $suite;
+ }
+ SimpleTest::ignoreParentsIfIgnored($classes);
+ $suite = &new TestSuite($title);
+ foreach ($classes as $class) {
+ if (! SimpleTest::isIgnored($class)) {
+ $suite->addTestClass($class);
+ }
+ }
+ return $suite;
+ }
+}
+
+/**
+ * This is a composite test class for combining
+ * test cases and other RunnableTest classes into
+ * a group test.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class TestSuite {
+ var $_label;
+ var $_test_cases;
+
+ /**
+ * Sets the name of the test suite.
+ * @param string $label Name sent at the start and end
+ * of the test.
+ * @access public
+ */
+ function TestSuite($label = false) {
+ $this->_label = $label;
+ $this->_test_cases = array();
+ }
+
+ /**
+ * Accessor for the test name for subclasses. If the suite
+ * wraps a single test case the label defaults to the name of that test.
+ * @return string Name of the test.
+ * @access public
+ */
+ function getLabel() {
+ if (! $this->_label) {
+ return ($this->getSize() == 1) ?
+ get_class($this->_test_cases[0]) : get_class($this);
+ } else {
+ return $this->_label;
+ }
+ }
+
+ /**
+ * @deprecated
+ */
+ function addTestCase(&$test_case) {
+ $this->_test_cases[] = &$test_case;
+ }
+
+ /**
+ * @deprecated
+ */
+ function addTestClass($class) {
+ if (TestSuite::getBaseTestCase($class) == 'testsuite') {
+ $this->_test_cases[] = &new $class();
+ } else {
+ $this->_test_cases[] = $class;
+ }
+ }
+
+ /**
+ * Adds a test into the suite by instance or class. The class will
+ * be instantiated if it's a test suite.
+ * @param SimpleTestCase $test_case Suite or individual test
+ * case implementing the
+ * runnable test interface.
+ * @access public
+ */
+ function add(&$test_case) {
+ if (! is_string($test_case)) {
+ $this->_test_cases[] = &$test_case;
+ } elseif (TestSuite::getBaseTestCase($class) == 'testsuite') {
+ $this->_test_cases[] = &new $class();
+ } else {
+ $this->_test_cases[] = $class;
+ }
+ }
+
+ /**
+ * @deprecated
+ */
+ function addTestFile($test_file) {
+ $this->addFile($test_file);
+ }
+
+ /**
+ * Builds a test suite from a library of test cases.
+ * The new suite is composed into this one.
+ * @param string $test_file File name of library with
+ * test case classes.
+ * @access public
+ */
+ function addFile($test_file) {
+ $extractor = new SimpleFileLoader();
+ $this->add($extractor->load($test_file));
+ }
+
+ /**
+ * Delegates to a visiting collector to add test
+ * files.
+ * @param string $path Path to scan from.
+ * @param SimpleCollector $collector Directory scanner.
+ * @access public
+ */
+ function collect($path, &$collector) {
+ $collector->collect($this, $path);
+ }
+
+ /**
+ * Invokes run() on all of the held test cases, instantiating
+ * them if necessary.
+ * @param SimpleReporter $reporter Current test reporter.
+ * @access public
+ */
+ function run(&$reporter) {
+ $reporter->paintGroupStart($this->getLabel(), $this->getSize());
+ for ($i = 0, $count = count($this->_test_cases); $i < $count; $i++) {
+ if (is_string($this->_test_cases[$i])) {
+ $class = $this->_test_cases[$i];
+ $test = &new $class();
+ $test->run($reporter);
+ unset($test);
+ } else {
+ $this->_test_cases[$i]->run($reporter);
+ }
+ }
+ $reporter->paintGroupEnd($this->getLabel());
+ return $reporter->getStatus();
+ }
+
+ /**
+ * Number of contained test cases.
+ * @return integer Total count of cases in the group.
+ * @access public
+ */
+ function getSize() {
+ $count = 0;
+ foreach ($this->_test_cases as $case) {
+ if (is_string($case)) {
+ if (! SimpleTest::isIgnored($case)) {
+ $count++;
+ }
+ } else {
+ $count += $case->getSize();
+ }
+ }
+ return $count;
+ }
+
+ /**
+ * Test to see if a class is derived from the
+ * SimpleTestCase class.
+ * @param string $class Class name.
+ * @access public
+ * @static
+ */
+ function getBaseTestCase($class) {
+ while ($class = get_parent_class($class)) {
+ $class = strtolower($class);
+ if ($class == 'simpletestcase' || $class == 'testsuite') {
+ return $class;
+ }
+ }
+ return false;
+ }
+}
+
+/**
+ * @package SimpleTest
+ * @subpackage UnitTester
+ * @deprecated
+ */
+class GroupTest extends TestSuite { }
+
+/**
+ * This is a failing group test for when a test suite hasn't
+ * loaded properly.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class BadTestSuite {
+ var $_label;
+ var $_error;
+
+ /**
+ * Sets the name of the test suite and error message.
+ * @param string $label Name sent at the start and end
+ * of the test.
+ * @access public
+ */
+ function BadTestSuite($label, $error) {
+ $this->_label = $label;
+ $this->_error = $error;
+ }
+
+ /**
+ * Accessor for the test name for subclasses.
+ * @return string Name of the test.
+ * @access public
+ */
+ function getLabel() {
+ return $this->_label;
+ }
+
+ /**
+ * Sends a single error to the reporter.
+ * @param SimpleReporter $reporter Current test reporter.
+ * @access public
+ */
+ function run(&$reporter) {
+ $reporter->paintGroupStart($this->getLabel(), $this->getSize());
+ $reporter->paintFail('Bad TestSuite [' . $this->getLabel() .
+ '] with error [' . $this->_error . ']');
+ $reporter->paintGroupEnd($this->getLabel());
+ return $reporter->getStatus();
+ }
+
+ /**
+ * Number of contained test cases. Always zero.
+ * @return integer Total count of cases in the group.
+ * @access public
+ */
+ function getSize() {
+ return 0;
+ }
+}
+
+/**
+ * @package SimpleTest
+ * @subpackage UnitTester
+ * @deprecated
+ */
+class BadGroupTest extends BadTestSuite { }
+?>