dramatic changes are in the alpha releases. Here is a list of possible
problems and their fixes...
+No method _getTest() on mocks
+-----------------------------
+This has finally been removed. It was a pretty esoteric
+flex point anyway. It was there to allow the mocks to
+work with other test tools, but no one does this anyway.
+
+No method assertError(), assertNoErrors(), swallowErrors()
+----------------------------------------------------------
+These have been deprecated in 1.0.1beta in favour of
+expectError() and expectException(). assertNoErrors() is
+redundant if you use expectError() as failures are now reporterted
+immediately.
+
+No method TestCase::signal()
+----------------------------
+This has been deprecated in favour of triggering an error or
+throwing an exception. Deprecated as of 1.0.1beta.
+
+No method TestCase::sendMessage()
+---------------------------------
+This has been deprecated as of 1.0.1beta.
+
Failure to connect now emits failures
-------------------------------------
It used to be that you would have to use the
------------------------------
The ability to insert arbitrary partial mock code
has been removed. This was a low value feature
-causing needless complications.It was removed
+causing needless complications. It was removed
in the 1.0.1beta release.
No method setMockBaseClass()
The _assertTrue method has had it's signature changed due to a bug
in the PHP 5.0.1 release. You must now use getTest() from within
that method to get the test case. Mock compatibility with other
-unit testers is now deprecated as of 1.0.1alpha as PEAR::PHUnit2
+unit testers is now deprecated as of 1.0.1alpha as PEAR::PHPUnit2
should soon have mock support of it's own.
Broken code extending SimpleRunner
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
SimpleTest
==========
You probably got this package from...
-http://sourceforge.net/projects/simpletest/
+http://simpletest.sourceforge.net/projects/simpletest/
If there is no licence agreement with this package please download
a version from the location above. You must read and accept that
-1.0.1alpha3
\ No newline at end of file
+1.0.1beta
\ No newline at end of file
$form->submitButton(new SimpleById($id), $additional));
return ($success ? $this->getContent() : $success);
}
+
+ /**
+ * Tests to see if a submit button exists with this
+ * label.
+ * @param string $label Button label.
+ * @return boolean True if present.
+ * @access public
+ */
+ function isSubmit($label) {
+ return (boolean)$this->_page->getFormBySubmit(new SimpleByLabel($label));
+ }
/**
* Clicks the submit image by some kind of label. Usually
$form->submitImage(new SimpleById($id), $x, $y, $additional));
return ($success ? $this->getContent() : $success);
}
+
+ /**
+ * Tests to see if an image exists with this
+ * title or alt text.
+ * @param string $label Image text.
+ * @return boolean True if present.
+ * @access public
+ */
+ function isImage($label) {
+ return (boolean)$this->_page->getFormByImage(new SimpleByLabel($label));
+ }
/**
* Submits a form by the ID.
}
/**
- * Follows a link by label. Will click the first link
+ * Finds a URL by label. Will find the first link
* found with this link text by default, or a later
* one if an index is given. The match ignores case and
* white space issues.
* @param string $label Text between the anchor tags.
* @param integer $index Link position counting from zero.
- * @return string/boolean Page on success.
+ * @return string/boolean URL on success.
* @access public
*/
- function clickLink($label, $index = 0) {
+ function getLink($label, $index = 0) {
$urls = $this->_page->getUrlsByLabel($label);
if (count($urls) == 0) {
return false;
if (count($urls) < $index + 1) {
return false;
}
- $this->_load($urls[$index], new SimpleGetEncoding());
- return $this->getContent();
+ return $urls[$index];
}
/**
- * Tests to see if a link is present by label.
- * @param string $label Text of value attribute.
- * @return boolean True if link present.
+ * Follows a link by label. Will click the first link
+ * found with this link text by default, or a later
+ * one if an index is given. The match ignores case and
+ * white space issues.
+ * @param string $label Text between the anchor tags.
+ * @param integer $index Link position counting from zero.
+ * @return string/boolean Page on success.
+ * @access public
+ */
+ function clickLink($label, $index = 0) {
+ $url = $this->getLink($label, $index);
+ if ($url === false) {
+ return false;
+ }
+ $this->_load($url, new SimpleGetEncoding());
+ return $this->getContent();
+ }
+
+ /**
+ * Finds a link by id attribute.
+ * @param string $id ID attribute value.
+ * @return string/boolean URL on success.
* @access public
*/
- function isLink($label) {
- return (count($this->_page->getUrlsByLabel($label)) > 0);
+ function getLinkById($id) {
+ return $this->_page->getUrlById($id);
}
/**
* @access public
*/
function clickLinkById($id) {
- if (! ($url = $this->_page->getUrlById($id))) {
+ if (! ($url = $this->getLinkById($id))) {
return false;
}
$this->_load($url, new SimpleGetEncoding());
return $this->getContent();
}
- /**
- * Tests to see if a link is present by ID attribute.
- * @param string $id Text of id attribute.
- * @return boolean True if link present.
- * @access public
- */
- function isLinkById($id) {
- return (boolean)$this->_page->getUrlById($id);
- }
-
/**
* Clicks a visible text item. Will first try buttons,
* then links and then images.
}
return $raw;
}
+
+ /**
+ * Tests to see if a click target exists.
+ * @param string $label Visible text or alt text.
+ * @return boolean True if target present.
+ * @access public
+ */
+ function isClickable($label) {
+ return $this->isSubmit($label) || ($this->getLink($label) !== false) || $this->isImage($label);
+ }
}
?>
\ No newline at end of file
<?php
-/**
- * This file contains the following classes: {@link SimpleCollector},
- * {@link SimplePatternCollector}.
- *
- * @author Travis Swicegood <development@domain51.com>
- * @package SimpleTest
- * @subpackage UnitTester
- * @version $Id$
- */
-
-/**
- * The basic collector for {@link GroupTest}
- *
- * @see collect(), GroupTest::collect()
- * @package SimpleTest
- * @subpackage UnitTester
- */
-class SimpleCollector {
-
/**
- * Strips off any kind of slash at the end so as to normalise the path
+ * This file contains the following classes: {@link SimpleCollector},
+ * {@link SimplePatternCollector}.
*
- * @param string $path Path to normalise.
+ * @author Travis Swicegood <development@domain51.com>
+ * @package SimpleTest
+ * @subpackage UnitTester
+ * @version $Id$
*/
- function _removeTrailingSlash($path) {
- return preg_replace('|[\\/]$|', '', $path);
-
- /**
- * @internal
- * Try benchmarking the following. It's more code, but by not using the
- * regex, it may be faster? Also, shouldn't be looking for
- * DIRECTORY_SEPERATOR instead of a manual "/"?
- */
- if (substr($path, -1) == DIRECTORY_SEPERATOR) {
- return substr($path, 0, -1);
- } else {
- return $path;
- }
- }
-
+
/**
- * Scans the directory and adds what it can.
- * @param object $test Group test with {@link GroupTest::addTestFile()} method.
- * @param string $path Directory to scan.
- * @see _attemptToAdd()
+ * The basic collector for {@link GroupTest}
+ *
+ * @see collect(), GroupTest::collect()
+ * @package SimpleTest
+ * @subpackage UnitTester
*/
- function collect(&$test, $path) {
- $path = $this->_removeTrailingSlash($path);
- if ($handle = opendir($path)) {
- while (($entry = readdir($handle)) !== false) {
- $this->_handle($test, $path . DIRECTORY_SEPARATOR . $entry);
+ class SimpleCollector {
+
+ /**
+ * Strips off any kind of slash at the end so as to normalise the path.
+ * @param string $path Path to normalise.
+ * @return string Path without trailing slash.
+ */
+ function _removeTrailingSlash($path) {
+ if (substr($path, -1) == DIRECTORY_SEPARATOR) {
+ return substr($path, 0, -1);
+ } elseif (substr($path, -1) == '/') {
+ return substr($path, 0, -1);
+ } else {
+ return $path;
}
- closedir($handle);
}
- }
- /**
- * This method determines what should be done with a given file and adds
- * it via {@link GroupTest::addTestFile()} if necessary.
- *
- * This method should be overriden to provide custom matching criteria,
- * such as pattern matching, recursive matching, etc. For an example, see
- * {@link SimplePatternCollector::_handle()}.
- *
- * @param object $test Group test with {@link GroupTest::addTestFile()} method.
- * @param string $filename A filename as generated by {@link collect()}
- * @see collect()
- * @access protected
- */
- function _handle(&$test, $file) {
- if (!is_dir($file)) {
- $test->addTestFile($file);
+ /**
+ * Scans the directory and adds what it can.
+ * @param object $test Group test with {@link GroupTest::addTestFile()} method.
+ * @param string $path Directory to scan.
+ * @see _attemptToAdd()
+ */
+ function collect(&$test, $path) {
+ $path = $this->_removeTrailingSlash($path);
+ if ($handle = opendir($path)) {
+ while (($entry = readdir($handle)) !== false) {
+ $this->_handle($test, $path . DIRECTORY_SEPARATOR . $entry);
+ }
+ closedir($handle);
+ }
}
- }
-}
-
-/**
- * An extension to {@link SimpleCollector} that only adds files matching a
- * given pattern.
- *
- * @package SimpleTest
- * @subpackage UnitTester
- * @see SimpleCollector
- */
-class SimplePatternCollector extends SimpleCollector {
- var $_pattern;
+ /**
+ * This method determines what should be done with a given file and adds
+ * it via {@link GroupTest::addTestFile()} if necessary.
+ *
+ * This method should be overriden to provide custom matching criteria,
+ * such as pattern matching, recursive matching, etc. For an example, see
+ * {@link SimplePatternCollector::_handle()}.
+ *
+ * @param object $test Group test with {@link GroupTest::addTestFile()} method.
+ * @param string $filename A filename as generated by {@link collect()}
+ * @see collect()
+ * @access protected
+ */
+ function _handle(&$test, $file) {
+ if (! is_dir($file)) {
+ $test->addTestFile($file);
+ }
+ }
+ }
/**
+ * An extension to {@link SimpleCollector} that only adds files matching a
+ * given pattern.
*
- * @param string $pattern Perl compatible regex to test name against
- * See {@link http://us4.php.net/manual/en/reference.pcre.pattern.syntax.php PHP's PCRE}
- * for full documentation of valid pattern.s
+ * @package SimpleTest
+ * @subpackage UnitTester
+ * @see SimpleCollector
*/
- function SimplePatternCollector($pattern = '/php$/i') {
- $this->_pattern = $pattern;
- }
+ class SimplePatternCollector extends SimpleCollector {
+ var $_pattern;
+ /**
+ *
+ * @param string $pattern Perl compatible regex to test name against
+ * See {@link http://us4.php.net/manual/en/reference.pcre.pattern.syntax.php PHP's PCRE}
+ * for full documentation of valid pattern.s
+ */
+ function SimplePatternCollector($pattern = '/php$/i') {
+ $this->_pattern = $pattern;
+ }
- /**
- * Attempts to add files that match a given pattern.
- *
- * @see SimpleCollector::_handle()
- * @param object $test Group test with {@link GroupTest::addTestFile()} method.
- * @param string $path Directory to scan.
- * @access protected
- */
- function _handle(&$test, $filename) {
- if (preg_match($this->_pattern, $filename)) {
- parent::_handle($test, $filename);
+ /**
+ * Attempts to add files that match a given pattern.
+ *
+ * @see SimpleCollector::_handle()
+ * @param object $test Group test with {@link GroupTest::addTestFile()} method.
+ * @param string $path Directory to scan.
+ * @access protected
+ */
+ function _handle(&$test, $filename) {
+ if (preg_match($this->_pattern, $filename)) {
+ parent::_handle($test, $filename);
+ }
}
}
-}
?>
\ No newline at end of file
if (is_array($first) && is_array($second)) {
return SimpleTestCompatibility::_isArrayOfIdenticalTypes($first, $second);
}
+ if ($first !== $second) {
+ return false;
+ }
return true;
}
* @static
*/
function isReference(&$first, &$second) {
- if (version_compare(phpversion(), '5', '>=')
- && is_object($first)) {
+ if (version_compare(phpversion(), '5', '>=') && is_object($first)) {
return ($first === $second);
}
if (is_object($first) && is_object($second)) {
* @static
*/
function isA($object, $class) {
- if (function_exists('is_a')) {
- return is_a($object, $class);
- }
if (version_compare(phpversion(), '5') >= 0) {
if (! class_exists($class, false)) {
if (function_exists('interface_exists')) {
eval("\$is_a = \$object instanceof $class;");
return $is_a;
}
+ if (function_exists('is_a')) {
+ return is_a($object, $class);
+ }
return ((strtolower($class) == get_class($object))
or (is_subclass_of($object, $class)));
}
set_socket_timeout($handle, $timeout, 0);
}
}
-
- /**
- * Gets the current stack trace topmost first.
- * @return array List of stack frames.
- * @access public
- * @static
- */
- function getStackTrace() {
- if (function_exists('debug_backtrace')) {
- return array_reverse(debug_backtrace());
- }
- return array();
- }
}
-?>
+?>
\ No newline at end of file
ob_end_clean();
return $formatted;
}
-
- /**
- * Extracts the last assertion that was not within
- * Simpletest itself. The name must start with "assert".
- * @param array $stack List of stack frames.
- * @access public
- * @static
- */
- function getFormattedAssertionLine($stack) {
- foreach ($stack as $frame) {
- if (isset($frame['file'])) {
- if (strpos($frame['file'], SIMPLE_TEST) !== false) {
- if (dirname($frame['file']) . '/' == SIMPLE_TEST) {
- continue;
- }
- }
- }
- if (SimpleDumper::_stackFrameIsAnAssertion($frame)) {
- return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ']';
- }
- }
- return '';
- }
-
- /**
- * Tries to determine if the method call is an assertion.
- * @param array $frame PHP stack frame.
- * @access private
- * @static
- */
- function _stackFrameIsAnAssertion($frame) {
- if (($frame['function'] == 'fail') || ($frame['function'] == 'pass')) {
- return true;
- }
- if (strncmp($frame['function'], 'assert', 6) == 0) {
- return true;
- }
- if (strncmp($frame['function'], 'expect', 6) == 0) {
- return true;
- }
- return false;
- }
}
?>
\ No newline at end of file
* @access public
*/
function asRequest() {
- return $this->_key . '=' . urlencode($this->_value);
+ return urlencode($this->_key) . '=' . urlencode($this->_value);
}
/**
* Includes SimpleTest files.
*/
require_once(dirname(__FILE__) . '/invoker.php');
+ require_once(dirname(__FILE__) . '/test_case.php');
+ require_once(dirname(__FILE__) . '/expectation.php');
/**
* Extension that traps errors into an error queue.
* @access public
*/
function invoke($method) {
- set_error_handler('simpleTestErrorHandler');
+ $context = &SimpleTest::getContext();
+ $queue = &$context->get('SimpleErrorQueue');
+ $queue->setTestCase($this->GetTestCase());
+ set_error_handler('SimpleTestErrorHandler');
parent::invoke($method);
- $queue = &SimpleErrorQueue::instance();
- while (list($severity, $message, $file, $line, $globals) = $queue->extract()) {
+ while (list($severity, $message, $file, $line) = $queue->extract()) {
$severity = SimpleErrorQueue::getSeverityAsString($severity);
- $test_case = &$this->getTestCase();
- $test_case->error($severity, $message, $file, $line);
+ $test = &$this->getTestCase();
+ $test->error($severity, $message, $file, $line);
}
restore_error_handler();
}
*/
class SimpleErrorQueue {
var $_queue;
+ var $_expectation_queue;
+ var $_test;
/**
* Starts with an empty queue.
- * @access public
*/
function SimpleErrorQueue() {
$this->clear();
}
+ /**
+ * Sets the currently running test case.
+ * @param SimpleTestCase $test Test case to send messages to.
+ * @access public
+ */
+ function setTestCase(&$test) {
+ $this->_test = &$test;
+ }
+
/**
* Adds an error to the front of the queue.
- * @param $severity PHP error code.
- * @param $message Text of error.
- * @param $filename File error occoured in.
- * @param $line Line number of error.
- * @param $super_globals Hash of PHP super global arrays.
+ * @param integer $severity PHP error code.
+ * @param string $content Text of error.
+ * @param string $filename File error occoured in.
+ * @param integer $line Line number of error.
* @access public
*/
- function add($severity, $message, $filename, $line, $super_globals) {
- array_push(
- $this->_queue,
- array($severity, $message, $filename, $line, $super_globals));
+ function add($severity, $content, $filename, $line) {
+ $content = str_replace('%', '%%', $content);
+ if (count($this->_expectation_queue)) {
+ $this->_testLatestError($severity, $content, $filename, $line);
+ } else {
+ array_push(
+ $this->_queue,
+ array($severity, $content, $filename, $line));
+ }
+ }
+
+ /**
+ * Tests the error against the most recent expected
+ * error.
+ * @param integer $severity PHP error code.
+ * @param string $content Text of error.
+ * @param string $filename File error occoured in.
+ * @param integer $line Line number of error.
+ * @access private
+ */
+ function _testLatestError($severity, $content, $filename, $line) {
+ list($expected, $message) = array_shift($this->_expectation_queue);
+ $severity = $this->getSeverityAsString($severity);
+ $is_match = $this->_test->assert(
+ $expected,
+ $content,
+ sprintf($message, "%s -> PHP error [$content] severity [$severity] in [$filename] line [$line]"));
+ if (! $is_match) {
+ $this->_test->error($severity, $content, $filename, $line);
+ }
}
/**
*/
function clear() {
$this->_queue = array();
+ $this->_expectation_queue = array();
}
/**
- * Tests to see if the queue is empty.
- * @return True if empty.
+ * @deprecated
*/
- function isEmpty() {
- return (count($this->_queue) == 0);
+ function assertNoErrors($message) {
+ return $this->_test->assert(
+ new TrueExpectation(),
+ count($this->_queue) == 0,
+ sprintf($message, 'Should be no errors'));
}
/**
- * Global access to a single error queue.
- * @return Global error queue object.
- * @access public
- * @static
+ * @deprecated
*/
- function &instance() {
- static $queue = false;
- if (! $queue) {
- $queue = new SimpleErrorQueue();
+ function assertError($expected, $message) {
+ if (count($this->_queue) == 0) {
+ $this->_test->fail(sprintf($message, 'Expected error not found'));
+ return false;
}
- return $queue;
+ list($severity, $content, $file, $line) = $this->extract();
+ $severity = $this->getSeverityAsString($severity);
+ return $this->_test->assert(
+ $expected,
+ $content,
+ sprintf($message, "Expected PHP error [$content] severity [$severity] in [$file] line [$line]"));
+ }
+
+ /**
+ * Sets up an expectation of an error. If this is
+ * not fulfilled at the end of the test, a failure
+ * will occour. If the error does happen, then this
+ * will cancel it out and send a pass message.
+ * @param SimpleExpectation $expected Expected error match.
+ * @param string $message Message to display.
+ * @access public
+ */
+ function expectError($expected, $message) {
+ array_push(
+ $this->_expectation_queue,
+ array($expected, $message));
}
/**
- * Converst an error code into it's string
+ * Converts an error code into it's string
* representation.
* @param $severity PHP integer error code.
* @return String version of error code.
* @static
* @access public
*/
- function simpleTestErrorHandler($severity, $message, $filename, $line, $super_globals) {
+ function SimpleTestErrorHandler($severity, $message, $filename, $line, $super_globals) {
if ($severity = $severity & error_reporting()) {
restore_error_handler();
if (ini_get('log_errors')) {
$label = SimpleErrorQueue::getSeverityAsString($severity);
error_log("$label: $message in $filename on line $line");
}
- $queue = &SimpleErrorQueue::instance();
- $queue->add($severity, $message, $filename, $line, $super_globals);
- set_error_handler('simpleTestErrorHandler');
+ $context = &SimpleTest::getContext();
+ $queue = &$context->get('SimpleErrorQueue');
+ $queue->add($severity, $message, $filename, $line);
+ set_error_handler('SimpleTestErrorHandler');
}
}
?>
\ No newline at end of file
* for dependent libraries.
*/
require_once(dirname(__FILE__) . '/invoker.php');
+ require_once(dirname(__FILE__) . '/expectation.php');
/**
* Extension that traps exceptions and turns them into
- * an error message.
+ * an error message. PHP5 only.
* @package SimpleTest
* @subpackage UnitTester
*/
}
/**
- * Invokes a test method and dispatches any
- * untrapped errors.
+ * Invokes a test method whilst trapping expected
+ * exceptions. Any left over unthrown exceptions
+ * are then reported as failures.
* @param string $method Test method to call.
- * @access public
*/
function invoke($method) {
+ $trap = SimpleTest::getContext()->get('SimpleExceptionTrap');
+ $trap->clear();
try {
parent::invoke($method);
} catch (Exception $exception) {
- $test_case = &$this->getTestCase();
- $test_case->tearDown(); // Added by T.J.Hunt@open.ac.uk.
- $test_case->exception($exception);
+ if (! $trap->isExpected($this->getTestCase(), $exception)) {
+ $this->getTestCase()->exception($exception);
+ }
+ $trap->clear();
+ }
+ if ($message = $trap->getOutstanding()) {
+ $this->getTestCase()->fail($message);
+ }
+ }
+ }
+
+ /**
+ * Tests exceptions either by type or the exact
+ * exception. This could be improved to accept
+ * a pattern expectation to test the error
+ * message, but that will have to come later.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+ class ExceptionExpectation extends SimpleExpectation {
+ private $expected;
+
+ /**
+ * Sets up the conditions to test against.
+ * If the expected value is a string, then
+ * it will act as a test of the class name.
+ * An exception as the comparison will
+ * trigger an identical match. Writing this
+ * down now makes it look doubly dumb. I hope
+ * come up with a better scheme later.
+ * @param mixed $expected A class name or an actual
+ * exception to compare with.
+ * @param string $message Message to display.
+ */
+ function __construct($expected, $message = '%s') {
+ $this->expected = $expected;
+ parent::__construct($message);
+ }
+
+ /**
+ * Carry out the test.
+ * @param Exception $compare Value to check.
+ * @return boolean True if matched.
+ */
+ function test($compare) {
+ if (is_string($this->expected)) {
+ return ($compare instanceof $this->expected);
+ }
+ if (get_class($compare) != get_class($this->expected)) {
+ return false;
}
+ return $compare->getMessage() == $this->expected->getMessage();
+ }
+
+ /**
+ * Create the message to display describing the test.
+ * @param Exception $compare Exception to match.
+ * @return string Final message.
+ */
+ function testMessage($compare) {
+ if (is_string($this->expected)) {
+ return "Exception [" . $this->describeException($compare) .
+ "] should be type [" . $this->expected . "]";
+ }
+ return "Exception [" . $this->describeException($compare) .
+ "] should match [" .
+ $this->describeException($this->expected) . "]";
+ }
+
+ /**
+ * Summary of an Exception object.
+ * @param Exception $compare Exception to describe.
+ * @return string Text description.
+ */
+ protected function describeException($exception) {
+ return get_class($exception) . ": " . $exception->getMessage();
+ }
+ }
+
+ /**
+ * Stores expected exceptions for when they
+ * get thrown. Saves the irritating try...catch
+ * block.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+ class SimpleExceptionTrap {
+ private $expected;
+ private $message;
+
+ /**
+ * Clears down the queue ready for action.
+ */
+ function __construct() {
+ $this->clear();
+ }
+
+ /**
+ * Sets up an expectation of an exception.
+ * This has the effect of intercepting an
+ * exception that matches.
+ * @param SimpleExpectation $expected Expected exception to match.
+ * @param string $message Message to display.
+ * @access public
+ */
+ function expectException($expected = false, $message = '%s') {
+ if ($expected === false) {
+ $expected = new AnythingExpectation();
+ }
+ if (! SimpleExpectation::isExpectation($expected)) {
+ $expected = new ExceptionExpectation($expected);
+ }
+ $this->expected = $expected;
+ $this->message = $message;
+ }
+
+ /**
+ * Compares the expected exception with any
+ * in the queue. Issues a pass or fail and
+ * returns the state of the test.
+ * @param SimpleTestCase $test Test case to send messages to.
+ * @param Exception $exception Exception to compare.
+ * @return boolean False on no match.
+ */
+ function isExpected($test, $exception) {
+ if ($this->expected) {
+ return $test->assert($this->expected, $exception, $this->message);
+ }
+ return false;
+ }
+
+ /**
+ * Tests for any left over exception.
+ * @return string/false The failure message or false if none.
+ */
+ function getOutstanding() {
+ return sprintf($this->message, 'Failed to trap exception');
+ }
+
+ /**
+ * Discards the contents of the error queue.
+ */
+ function clear() {
+ $this->expected = false;
+ $this->message = false;
}
}
?>
\ No newline at end of file
* @param string $message Customised message on failure.
*/
function SimpleExpectation($message = '%s') {
- $this->_dumper = &new SimpleDumper();
$this->_message = $message;
}
/**
* Overlays the generated message onto the stored user
* message. An additional message can be interjected.
- * @param mixed $compare Comparison value.
- * @return string Description of success
- * or failure.
+ * @param mixed $compare Comparison value.
+ * @param SimpleDumper $dumper For formatting the results.
+ * @return string Description of success
+ * or failure.
* @access public
*/
- function overlayMessage($compare) {
+ function overlayMessage($compare, $dumper) {
+ $this->_dumper = $dumper;
return sprintf($this->_message, $this->testMessage($compare));
}
SimpleTestCompatibility::isA($expectation, 'SimpleExpectation');
}
}
+
+ /**
+ * A wildcard expectation always matches.
+ * @package SimpleTest
+ * @subpackage MockObjects
+ */
+ class AnythingExpectation extends SimpleExpectation {
+
+ /**
+ * Tests the expectation. Always true.
+ * @param mixed $compare Ignored.
+ * @return boolean True.
+ * @access public
+ */
+ function test($compare) {
+ return true;
+ }
+
+ /**
+ * Returns a human readable test message.
+ * @param mixed $compare Comparison value.
+ * @return string Description of success
+ * or failure.
+ * @access public
+ */
+ function testMessage($compare) {
+ $dumper = &$this->_getDumper();
+ return 'Anything always matches [' . $dumper->describeValue($compare) . ']';
+ }
+ }
+
+ /**
+ * An expectation that passes on boolean true.
+ * @package SimpleTest
+ * @subpackage MockObjects
+ */
+ class TrueExpectation extends SimpleExpectation {
+
+ /**
+ * Tests the expectation.
+ * @param mixed $compare Should be true.
+ * @return boolean True on match.
+ * @access public
+ */
+ function test($compare) {
+ return (boolean)$compare;
+ }
+
+ /**
+ * Returns a human readable test message.
+ * @param mixed $compare Comparison value.
+ * @return string Description of success
+ * or failure.
+ * @access public
+ */
+ function testMessage($compare) {
+ $dumper = &$this->_getDumper();
+ return 'Expected true, got [' . $dumper->describeValue($compare) . ']';
+ }
+ }
+
+ /**
+ * An expectation that passes on boolean false.
+ * @package SimpleTest
+ * @subpackage MockObjects
+ */
+ class FalseExpectation extends SimpleExpectation {
+
+ /**
+ * Tests the expectation.
+ * @param mixed $compare Should be false.
+ * @return boolean True on match.
+ * @access public
+ */
+ function test($compare) {
+ return ! (boolean)$compare;
+ }
+
+ /**
+ * Returns a human readable test message.
+ * @param mixed $compare Comparison value.
+ * @return string Description of success
+ * or failure.
+ * @access public
+ */
+ function testMessage($compare) {
+ $dumper = &$this->_getDumper();
+ return 'Expected false, got [' . $dumper->describeValue($compare) . ']';
+ }
+ }
/**
* Test for equality.
/**
* Describes a pattern match including the string
* found and it's position.
- * @package SimpleTest
- * @subpackage UnitTester
+ * @package SimpleTest
+ * @subpackage UnitTester
* @param string $pattern Regex to match against.
* @param string $subject Subject to search.
* @access protected
function _describePatternMatch($pattern, $subject) {
preg_match($pattern, $subject, $matches);
$position = strpos($subject, $matches[0]);
- $dumper = &$this->_getDumper();
+ $dumper = $this->_getDumper();
return "Pattern [$pattern] detected at character [$position] in [" .
$dumper->describeValue($subject) . "] as [" .
$matches[0] . "] in region [" .
"] should contain method [$method]";
}
}
-?>
+?>
\ No newline at end of file
* @public
*/
function assertNotNull($value, $message = "%s") {
- parent::assertTrue(isset($value), $message);
+ parent::assert(new TrueExpectation(), isset($value), $message);
}
/**
* @public
*/
function assertNull($value, $message = "%s") {
- parent::assertTrue(!isset($value), $message);
+ parent::assert(new TrueExpectation(), !isset($value), $message);
}
/**
"[" . $dumper->describeValue($first) .
"] and [" . $dumper->describeValue($second) .
"] should reference the same object");
- return $this->assertTrue(
+ return $this->assert(
+ new TrueExpectation(),
SimpleTestCompatibility::isReference($first, $second),
$message);
}
"[" . $dumper->describeValue($first) .
"] and [" . $dumper->describeValue($second) .
"] should not be the same object");
- return $this->assertFalse(
+ return $this->assert(
+ new falseExpectation(),
SimpleTestCompatibility::isReference($first, $second),
$message);
}
* @public
*/
function assertTrue($condition, $message = "%s") {
- parent::assertTrue($condition, $message);
+ parent::assert(new TrueExpectation(), $condition, $message);
}
/**
* @public
*/
function assertFalse($condition, $message = "%s") {
- parent::assertTrue(!$condition, $message);
+ parent::assert(new FalseExpectation(), $condition, $message);
}
/**
* @public
*/
function assertType($value, $type, $message = "%s") {
- parent::assertTrue(gettype($value) == strtolower($type), $message);
+ parent::assert(new TrueExpectation(), gettype($value) == strtolower($type), $message);
}
/**
* @public
*/
function assert($condition, $message = false) {
- parent::assertTrue($condition, $message);
+ parent::assert(new TrueExpectation(), $condition, $message);
}
/**
define('MOCK_ANYTHING', '*');
}
- /**
- * A wildcard expectation always matches.
- * @package SimpleTest
- * @subpackage MockObjects
- */
- class AnythingExpectation extends SimpleExpectation {
-
- /**
- * Tests the expectation. Always true.
- * @param mixed $compare Ignored.
- * @return boolean True.
- * @access public
- */
- function test($compare) {
- return true;
- }
-
- /**
- * Returns a human readable test message.
- * @param mixed $compare Comparison value.
- * @return string Description of success
- * or failure.
- * @access public
- */
- function testMessage($compare) {
- $dumper = &$this->_getDumper();
- return 'Anything always matches [' . $dumper->describeValue($compare) . ']';
- }
- }
-
/**
* Parameter comparison assertion.
* @package SimpleTest
* those that are wildcarded.
* If the value is not an array
* then it is considered to match any.
- * @param mixed $wildcard Any parameter matching this
- * will always match.
* @param string $message Customised message on failure.
* @access public
*/
$comparison = $this->_coerceToExpectation($expected[$i]);
if (! $comparison->test($parameters[$i])) {
$messages[] = "parameter " . ($i + 1) . " with [" .
- $comparison->overlayMessage($parameters[$i]) . "]";
+ $comparison->overlayMessage($parameters[$i], $this->_getDumper()) . "]";
}
}
return "Parameter expectation differs at " . implode(" and ", $messages);
* @access protected
*/
function &_getCurrentTestCase() {
- return SimpleTest::getCurrent();
+ $context = &SimpleTest::getContext();
+ return $context->getTest();
}
/**
* test method has finished. Totals up the call
* counts and triggers a test assertion if a test
* is present for expected call counts.
- * @param string $method Current method name.
+ * @param string $test_method Current method name.
+ * @param SimpleTestCase $test Test to send message to.
* @access public
*/
- function atTestEnd($method) {
+ function atTestEnd($test_method, &$test) {
foreach ($this->_expected_counts as $method => $expectation) {
- $this->_assertTrue(
- $expectation->test($this->getCallCount($method)),
- $expectation->overlayMessage($this->getCallCount($method)));
+ $test->assert($expectation, $this->getCallCount($method));
}
foreach ($this->_max_counts as $method => $expectation) {
if ($expectation->test($this->getCallCount($method))) {
- $this->_assertTrue(
- true,
- $expectation->overlayMessage($this->getCallCount($method)));
+ $test->assert($expectation, $this->getCallCount($method));
}
}
}
* @access private
*/
function _checkExpectations($method, $args, $timing) {
+ $test = &$this->_getCurrentTestCase();
if (isset($this->_max_counts[$method])) {
if (! $this->_max_counts[$method]->test($timing + 1)) {
- $this->_assertTrue(
- false,
- $this->_max_counts[$method]->overlayMessage($timing + 1));
+ $test->assert($this->_max_counts[$method], $timing + 1);
}
}
if (isset($this->_expected_args_at[$timing][$method])) {
- $this->_assertTrue(
- $this->_expected_args_at[$timing][$method]->test($args),
- "Mock method [$method] at [$timing] -> " .
- $this->_expected_args_at[$timing][$method]->overlayMessage($args));
+ $test->assert(
+ $this->_expected_args_at[$timing][$method],
+ $args,
+ "Mock method [$method] at [$timing] -> %s");
} elseif (isset($this->_expected_args[$method])) {
- $this->_assertTrue(
- $this->_expected_args[$method]->test($args),
- "Mock method [$method] -> " . $this->_expected_args[$method]->overlayMessage($args));
+ $test->assert(
+ $this->_expected_args[$method],
+ $args,
+ "Mock method [$method] -> %s");
}
}
-
- /**
- * Triggers an assertion on the held test case.
- * Should be overridden when using another test
- * framework other than the SimpleTest one if the
- * assertion method has a different name.
- * @param boolean $assertion True will pass.
- * @param string $message Message that will go with
- * the test event.
- * @access protected
- */
- function _assertTrue($assertion, $message) {
- $test = &$this->_getCurrentTestCase();
- $test->assertTrue($assertion, $message);
- }
}
/**
* @access public
*/
function Mock() {
- trigger_error('Mock factory methods are class only.');
+ trigger_error('Mock factory methods are static.');
}
/**
/**
* Uses a stack trace to find the line of an assertion.
- * @param array $stack Stack frames top most first. Only
- * needed if not using the PHP
- * backtrace function.
- * @return string Location of first expect*
- * method embedded in format string.
* @access public
* @static
*/
- function getExpectationLine($stack = false) {
- if ($stack === false) {
- $stack = SimpleTestCompatibility::getStackTrace();
- }
- return SimpleDumper::getFormattedAssertionLine($stack);
+ function getExpectationLine() {
+ $trace = new SimpleStackTrace(array('expect'));
+ return $trace->traceMethod();
}
}
}
$mock_reflection = new SimpleReflection($this->_mock_class);
if ($mock_reflection->classExistsSansAutoload()) {
- trigger_error("Partial mock class [$mock_class] already exists");
+ trigger_error('Partial mock class [' . $this->_mock_class . '] already exists');
return false;
}
return eval($this->_extendClassCode($methods));
* @access public
*/
function acceptAttributeToken($token, $event) {
- if ($event == LEXER_UNMATCHED) {
- $this->_attributes[$this->_current_attribute] .=
- SimpleHtmlSaxParser::decodeHtml($token);
- }
- if ($event == LEXER_SPECIAL) {
- $this->_attributes[$this->_current_attribute] .=
- preg_replace('/^=\s*/' , '', SimpleHtmlSaxParser::decodeHtml($token));
+ if ($this->_current_attribute) {
+ if ($event == LEXER_UNMATCHED) {
+ $this->_attributes[$this->_current_attribute] .=
+ SimpleHtmlSaxParser::decodeHtml($token);
+ }
+ if ($event == LEXER_SPECIAL) {
+ $this->_attributes[$this->_current_attribute] .=
+ preg_replace('/^=\s*/' , '', SimpleHtmlSaxParser::decodeHtml($token));
+ }
}
return true;
}
/**
* Version specific reflection API.
- * @package SimpleTest
- * @subpackage UnitTester
+ * @package SimpleTest
+ * @subpackage UnitTester
*/
class SimpleReflection {
var $_interface;
* @access public
*/
function getSignature($name) {
- if ($name == '__get') {
- return 'function __get($key)';
- }
if ($name == '__set') {
return 'function __set($key, $value)';
}
+ if ($name == '__call') {
+ return 'function __call($method, $arguments)';
+ }
+ if (version_compare(phpversion(), '5.1.0', '>=')) {
+ if (in_array($name, array('__get', '__isset', $name == '__unset'))) {
+ return "function {$name}(\$key)";
+ }
+ }
if (! is_callable(array($this->_interface, $name))) {
return "function $name()";
}
* @access private
*/
function _getFullSignature($name) {
- $interface = new ReflectionClass($this->_interface);
- $method = $interface->getMethod($name);
- $reference = $method->returnsReference() ? '&' : '';
- return "function $reference$name(" .
- implode(', ', $this->_getParameterSignatures($method)) .
- ")";
+ $interface = new ReflectionClass($this->_interface);
+ $method = $interface->getMethod($name);
+ $reference = $method->returnsReference() ? '&' : '';
+ return "function $reference$name(" .
+ implode(', ', $this->_getParameterSignatures($method)) .
+ ")";
}
/**
* Gets the source code for each parameter.
* @param ReflectionMethod $method Method object from
- * reflection API
+ * reflection API
* @return array List of strings, each
* a snippet of code.
* @access private
*/
function _getParameterSignatures($method) {
- $signatures = array();
+ $signatures = array();
foreach ($method->getParameters() as $parameter) {
$type = $parameter->getClass();
$signatures[] =
- (! is_null($type) ? $type->getName() . ' ' : '') .
- ($parameter->isPassedByReference() ? '&' : '') .
- '$' . $this->_suppressSpurious($parameter->getName()) .
- ($this->_isOptional($parameter) ? ' = null' : '');
+ (! is_null($type) ? $type->getName() . ' ' : '') .
+ ($parameter->isPassedByReference() ? '&' : '') .
+ '$' . $this->_suppressSpurious($parameter->getName()) .
+ ($this->_isOptional($parameter) ? ' = null' : '');
}
return $signatures;
}
* @access protected
*/
function &_createBrowser() {
- return new SimpleBrowser();
+ $browser = &new SimpleBrowser();
+ return $browser;
}
/**
* @access protected
*/
function &_createParser(&$reporter) {
- return new SimpleTestXmlParser($reporter);
+ $parser = &new SimpleTestXmlParser($reporter);
+ return $parser;
}
/**
*/
function paintHeader($test_name) {
$this->sendNoCacheHeaders();
+ print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">";
print "<html>\n<head>\n<title>$test_name</title>\n";
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=" .
$this->_character_set . "\">\n";
* @access protected
*/
function _getCss() {
- return ".fail { color: red; } pre { background-color: lightgray; }";
+ return ".fail { background-color: inherit; color: red; }" .
+ ".pass { background-color: inherit; color: green; }" .
+ " pre { background-color: lightgray; color: inherit; }";
}
/**
}
/**
- * Paints a PHP error or exception.
+ * Paints a PHP error.
* @param string $message Message is ignored.
* @access public
- * @abstract
*/
function paintError($message) {
parent::paintError($message);
print " -> <strong>" . $this->_htmlEntities($message) . "</strong><br />\n";
}
+ /**
+ * Paints a PHP exception.
+ * @param Exception $exception Exception to display.
+ * @access public
+ */
+ function paintException($exception) {
+ parent::paintException($exception);
+ print "<span class=\"fail\">Exception</span>: ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ $message = 'Unexpected exception of type [' . get_class($exception) .
+ '] with message ['. $exception->getMessage() .
+ '] in ['. $exception->getFile() .
+ ' line ' . $exception->getLine() . ']';
+ print " -> <strong>" . $this->_htmlEntities($message) . "</strong><br />\n";
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ parent::paintSkip($message);
+ print "<span class=\"pass\">Skipped</span>: ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ print " -> " . $this->_htmlEntities($message) . "<br />\n";
+ }
+
/**
* Paints formatted text such as dumped variables.
* @param string $message Text to show.
/**
* Paints a PHP error or exception.
- * @param string $message Message is ignored.
+ * @param string $message Message to be shown.
* @access public
* @abstract
*/
print "Exception " . $this->getExceptionCount() . "!\n$message\n";
}
+ /**
+ * Paints a PHP error or exception.
+ * @param Exception $exception Exception to describe.
+ * @access public
+ * @abstract
+ */
+ function paintException($exception) {
+ parent::paintException($exception);
+ $message = 'Unexpected exception of type [' . get_class($exception) .
+ '] with message ['. $exception->getMessage() .
+ '] in ['. $exception->getFile() .
+ ' line ' . $exception->getLine() . ']';
+ print "Exception " . $this->getExceptionCount() . "!\n$message\n";
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ parent::paintSkip($message);
+ print "Skip: $message\n";
+ }
+
/**
* Paints formatted text such as dumped variables.
* @param string $message Text to show.
}
/**
- * Deals with PHP 4 throwing an error or PHP 5
- * throwing an exception.
+ * Deals with PHP 4 throwing an error.
* @param string $message Text of error formatted by
* the test case.
* @access public
$this->_exceptions++;
}
+ /**
+ * Deals with PHP 5 throwing an exception.
+ * @param Exception $exception The actual exception thrown.
+ * @access public
+ */
+ function paintException($exception) {
+ $this->_exceptions++;
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ }
+
/**
* Accessor for the number of passes so far.
* @return integer Number of passes.
$this->_size = null;
$this->_progress = 0;
}
+
+ /**
+ * Gets the formatter for variables and other small
+ * generic data items.
+ * @return SimpleDumper Formatter.
+ * @access public
+ */
+ function getDumper() {
+ return new SimpleDumper();
+ }
/**
* Paints the start of a group test. Will also paint
var $_reporter;
/**
- * Mediates between teh reporter and the test case.
+ * Mediates between the reporter and the test case.
* @param SimpleScorer $reporter Reporter to receive events.
*/
function SimpleReporterDecorator(&$reporter) {
function &createInvoker(&$invoker) {
return $this->_reporter->createInvoker($invoker);
}
+
+ /**
+ * Gets the formatter for variables and other small
+ * generic data items.
+ * @return SimpleDumper Formatter.
+ * @access public
+ */
+ function getDumper() {
+ return $this->_reporter->getDumper();
+ }
/**
* Paints the start of a group test.
$this->_reporter->paintError($message);
}
+ /**
+ * Chains to the wrapped reporter.
+ * @param Exception $exception Exception to show.
+ * @access public
+ */
+ function paintException($exception) {
+ $this->_reporter->paintException($exception);
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ $this->_reporter->paintSkip($message);
+ }
+
/**
* Chains to the wrapped reporter.
* @param string $message Text to display.
}
return $invoker;
}
+
+ /**
+ * Gets the formatter for variables and other small
+ * generic data items.
+ * @return SimpleDumper Formatter.
+ * @access public
+ */
+ function getDumper() {
+ return new SimpleDumper();
+ }
/**
* Paints the start of a group test.
$this->_reporters[$i]->paintError($message);
}
}
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param Exception $exception Exception to display.
+ * @access public
+ */
+ function paintException($exception) {
+ for ($i = 0; $i < count($this->_reporters); $i++) {
+ $this->_reporters[$i]->paintException($exception);
+ }
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ for ($i = 0; $i < count($this->_reporters); $i++) {
+ $this->_reporters[$i]->paintSkip($message);
+ }
+ }
/**
* Chains to the wrapped reporter.
/**
* Test case for testing of command line scripts and
- * utilities. Usually scripts taht are external to the
+ * utilities. Usually scripts that are external to the
* PHP code, but support it in some way.
* @package SimpleTest
* @subpackage UnitTester
$shell = &$this->_getShell();
return $shell->getOutputAsList();
}
+
+ /**
+ * Called from within the test methods to register
+ * passes and failures.
+ * @param boolean $result Pass on true.
+ * @param string $message Message to display describing
+ * the test state.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertTrue($result, $message = false) {
+ return $this->assert(new TrueExpectation(), $result, $message);
+ }
+
+ /**
+ * Will be true on false and vice versa. False
+ * is the PHP definition of false, so that null,
+ * empty strings, zero and an empty array all count
+ * as false.
+ * @param boolean $result Pass on false.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertFalse($result, $message = '%s') {
+ return $this->assert(new FalseExpectation(), $result, $message);
+ }
/**
* Will trigger a pass if the two parameters have
return $shell;
}
}
-?>
\ No newline at end of file
+?>
/**#@-*/
/**
- * Static global directives and options. I hate this
- * class. It's a mixture of reference hacks, configuration
- * and previous design screw-ups that I have to maintain
- * to keep backward compatibility.
+ * Registry and test context. Includes a few
+ * global options that I'm slowly getting rid of.
* @package SimpleTest
*/
class SimpleTest {
* missing abstract declarations. This cannot
* be done whilst loading classes wiithout forcing
* a particular order on the class declarations and
- * the ignore() calls. It's nice to havethe ignore()
- * calls at the top of teh file.
+ * the ignore() calls. It's just nice to have the ignore()
+ * calls at the top of the file before the actual declarations.
* @param array $classes Class names of interest.
* @static
* @access public
return $registry['DefaultProxyPassword'];
}
- /**
- * Sets the current test case instance. This
- * global instance can be used by the mock objects
- * to send message to the test cases.
- * @param SimpleTestCase $test Test case to register.
- * @access public
- * @static
- */
- function setCurrent(&$test) {
- $registry = &SimpleTest::_getRegistry();
- $registry['CurrentTestCase'] = &$test;
- }
-
- /**
- * Accessor for current test instance.
- * @return SimpleTEstCase Currently running test.
- * @access public
- * @static
- */
- function &getCurrent() {
- $registry = &SimpleTest::_getRegistry();
- return $registry['CurrentTestCase'];
- }
-
/**
* Accessor for global registry of options.
* @return hash All stored values.
return $registry;
}
+ /**
+ * Accessor for the context of the current
+ * test run.
+ * @return SimpleTestContext Current test run.
+ * @access public
+ * @static
+ */
+ function &getContext() {
+ static $context = false;
+ if (! $context) {
+ $context = new SimpleTestContext();
+ }
+ return $context;
+ }
+
/**
* Constant default values.
* @return hash All registry defaults.
}
}
+ /**
+ * Container for all components for a specific
+ * test run. Makes things like error queues
+ * available to PHP event handlers, and also
+ * gets around some nasty reference issues in
+ * the mocks.
+ * @package SimpleTest
+ */
+ class SimpleTestContext {
+ var $_test;
+ var $_reporter;
+ var $_resources;
+
+ /**
+ * Clears down the current context.
+ * @access public
+ */
+ function clear() {
+ $this->_resources = array();
+ }
+
+ /**
+ * Sets the current test case instance. This
+ * global instance can be used by the mock objects
+ * to send message to the test cases.
+ * @param SimpleTestCase $test Test case to register.
+ * @access public
+ */
+ function setTest(&$test) {
+ $this->clear();
+ $this->_test = &$test;
+ }
+
+ /**
+ * Accessor for currently running test case.
+ * @return SimpleTestCase Current test.
+ * @acess pubic
+ */
+ function &getTest() {
+ return $this->_test;
+ }
+
+ /**
+ * Sets the current reporter. This
+ * global instance can be used by the mock objects
+ * to send messages.
+ * @param SimpleReporter $reporter Reporter to register.
+ * @access public
+ */
+ function setReporter(&$reporter) {
+ $this->clear();
+ $this->_reporter = &$reporter;
+ }
+
+ /**
+ * Accessor for current reporter.
+ * @return SimpleReporter Current reporter.
+ * @acess pubic
+ */
+ function &getReporter() {
+ return $this->_reporter;
+ }
+
+ /**
+ * Accessor for the Singleton resource.
+ * @return object Global resource.
+ * @access public
+ * @static
+ */
+ function &get($resource) {
+ if (! isset($this->_resources[$resource])) {
+ $this->_resources[$resource] = &new $resource();
+ }
+ return $this->_resources[$resource];
+ }
+ }
+
+ /**
+ * Interrogates the stack trace to recover the
+ * failure point.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+ class SimpleStackTrace {
+ var $_prefixes;
+
+ /**
+ * Stashes the list of target prefixes.
+ * @param array $prefixes List of method prefixes
+ * to search for.
+ */
+ function SimpleStackTrace($prefixes) {
+ $this->_prefixes = $prefixes;
+ }
+
+ /**
+ * Extracts the last method name that was not within
+ * Simpletest itself. Captures a stack trace if none given.
+ * @param array $stack List of stack frames.
+ * @return string Snippet of test report with line
+ * number and file.
+ * @access public
+ */
+ function traceMethod($stack = false) {
+ $stack = $stack ? $stack : $this->_captureTrace();
+ foreach ($stack as $frame) {
+ if ($this->_frameLiesWithinSimpleTestFolder($frame)) {
+ continue;
+ }
+ if ($this->_frameMatchesPrefix($frame)) {
+ return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ']';
+ }
+ }
+ return '';
+ }
+
+ /**
+ * Test to see if error is generated by SimpleTest itself.
+ * @param array $frame PHP stack frame.
+ * @return boolean True if a SimpleTest file.
+ * @access private
+ */
+ function _frameLiesWithinSimpleTestFolder($frame) {
+ if (isset($frame['file'])) {
+ $path = substr(SIMPLE_TEST, 0, -1);
+ if (strpos($frame['file'], $path) === 0) {
+ if (dirname($frame['file']) == $path) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tries to determine if the method call is an assert, etc.
+ * @param array $frame PHP stack frame.
+ * @return boolean True if matches a target.
+ * @access private
+ */
+ function _frameMatchesPrefix($frame) {
+ foreach ($this->_prefixes as $prefix) {
+ if (strncmp($frame['function'], $prefix, strlen($prefix)) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Grabs a current stack trace.
+ * @return array Fulle trace.
+ * @access private
+ */
+ function _captureTrace() {
+ if (function_exists('debug_backtrace')) {
+ return array_reverse(debug_backtrace());
+ }
+ return array();
+ }
+ }
+
/**
* @deprecated
*/
return Simpletest::getDefaultProxyPassword();
}
}
-?>
\ No newline at end of file
+?>
require_once(dirname(__FILE__) . '/reflection_php4.php');
}
if (! defined('SIMPLE_TEST')) {
- /**
- * @ignore
- */
- define('SIMPLE_TEST', dirname(__FILE__) . '/');
+ /** @ignore */
+ define('SIMPLE_TEST', dirname(__FILE__) . DIRECTORY_SEPARATOR);
}
/**#@-*/
var $_label = false;
var $_reporter;
var $_observers;
+ var $_should_skip = false;
/**
* Sets up the test with no display.
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.
* 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) {
- SimpleTest::setCurrent($this);
+ $context = &SimpleTest::getContext();
+ $context->setTest($this);
+ $context->setReporter($reporter);
$this->_reporter = &$reporter;
- $this->_reporter->paintCaseStart($this->getLabel());
- foreach ($this->getTests() as $method) {
- if ($this->_reporter->shouldInvoke($this->getLabel(), $method)) {
- $invoker = &$this->_reporter->createInvoker($this->createInvoker());
- $invoker->before($method);
- $invoker->invoke($method);
- $invoker->after($method);
+ $reporter->paintCaseStart($this->getLabel());
+ $this->skip();
+ if (! $this->_should_skip) {
+ foreach ($this->getTests() as $method) {
+ if ($reporter->shouldInvoke($this->getLabel(), $method)) {
+ $invoker = &$this->_reporter->createInvoker($this->createInvoker());
+ $invoker->before($method);
+ $invoker->invoke($method);
+ $invoker->after($method);
+ }
}
}
- $this->_reporter->paintCaseEnd($this->getLabel());
+ $reporter->paintCaseEnd($this->getLabel());
unset($this->_reporter);
return $reporter->getStatus();
}
*/
function after($method) {
for ($i = 0; $i < count($this->_observers); $i++) {
- $this->_observers[$i]->atTestEnd($method);
+ $this->_observers[$i]->atTestEnd($method, $this);
}
$this->_reporter->paintMethodEnd($method);
}
}
/**
- * Sends a pass event with a message.
- * @param string $message Message to send.
- * @access public
+ * @deprecated
*/
function pass($message = "Pass") {
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]");
+ "Unexpected PHP error [$message] severity [$severity] in [$file line $line]");
}
/**
* @access public
*/
function exception($exception) {
- $this->_reporter->paintError(
- 'Unexpected exception of type [' . get_class($exception) .
- '] with message ['. $exception->getMessage() .
- '] in ['. $exception->getFile() .
- '] line [' . $exception->getLine() . ']');
+ $this->_reporter->paintException($exception);
}
/**
- * Sends a user defined event to the test reporter.
- * This is for small scale extension where
- * both the test case and either the reporter or
- * display are subclassed.
- * @param string $type Type of event.
- * @param mixed $payload Object or message to deliver.
- * @access public
+ * @deprecated
*/
function signal($type, &$payload) {
if (! isset($this->_reporter)) {
$this->_reporter->paintSignal($type, $payload);
}
- /**
- * Cancels any outstanding errors.
- * @access public
- */
- function swallowErrors() {
- $queue = &SimpleErrorQueue::instance();
- $queue->clear();
- }
-
/**
* Runs an expectation directly, for extending the
* tests with new expectation classes.
* @access public
*/
function assert(&$expectation, $compare, $message = '%s') {
- return $this->assertTrue(
- $expectation->test($compare),
- sprintf($message, $expectation->overlayMessage($compare)));
+ 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())));
+ }
}
/**
return $this->assert($expectation, $compare, $message);
}
- /**
- * Called from within the test methods to register
- * passes and failures.
- * @param boolean $result Pass on true.
- * @param string $message Message to display describing
- * the test state.
- * @return boolean True on pass
- * @access public
- */
- function assertTrue($result, $message = false) {
- if (! $message) {
- $message = 'True assertion got ' . ($result ? 'True' : 'False');
- }
- if ($result) {
- return $this->pass($message);
- } else {
- return $this->fail($message);
- }
- }
-
- /**
- * Will be true on false and vice versa. False
- * is the PHP definition of false, so that null,
- * empty strings, zero and an empty array all count
- * as false.
- * @param boolean $result Pass on false.
- * @param string $message Message to display.
- * @return boolean True on pass
- * @access public
- */
- function assertFalse($result, $message = false) {
- if (! $message) {
- $message = 'False assertion got ' . ($result ? 'True' : 'False');
- }
- return $this->assertTrue(! $result, $message);
- }
-
/**
* Uses a stack trace to find the line of an assertion.
- * @param string $format String formatting.
- * @param array $stack Stack frames top most first. Only
- * needed if not using the PHP
- * backtrace function.
* @return string Line number of first assert*
* method embedded in format string.
* @access public
*/
- function getAssertionLine($stack = false) {
- if ($stack === false) {
- $stack = SimpleTestCompatibility::getStackTrace();
- }
- return SimpleDumper::getFormattedAssertionLine($stack);
+ function getAssertionLine() {
+ $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip'));
+ return $trace->traceMethod();
}
/**
* @access public
*/
function dump($variable, $message = false) {
- $formatted = SimpleDumper::dump($variable);
+ $dumper = $this->_reporter->getDumper();
+ $formatted = $dumper->dump($variable);
if ($message) {
$formatted = $message . "\n" . $formatted;
}
}
/**
- * Dispatches a text message straight to the
- * test suite. Useful for status bar displays.
- * @param string $message Message to show.
- * @access public
+ * @deprecated
*/
function sendMessage($message) {
$this->_reporter->PaintMessage($message);
* @package SimpleTest
* @subpackage UnitTester
*/
- class GroupTest {
+ class TestSuite {
var $_label;
var $_test_cases;
var $_old_track_errors;
* of the test.
* @access public
*/
- function GroupTest($label = false) {
+ function TestSuite($label = false) {
$this->_label = $label ? $label : get_class($this);
$this->_test_cases = array();
$this->_old_track_errors = ini_get('track_errors');
* @access public
*/
function addTestClass($class) {
- if ($this->_getBaseTestCase($class) == 'grouptest') {
+ if ($this->_getBaseTestCase($class) == 'testsuite' || $this->_getBaseTestCase($class) == 'grouptest') {
$this->_test_cases[] = &new $class();
} else {
$this->_test_cases[] = $class;
function addTestFile($test_file) {
$existing_classes = get_declared_classes();
if ($error = $this->_requireWithError($test_file)) {
- $this->addTestCase(new BadGroupTest($test_file, $error));
+ $this->addTestCase(new BadTestSuite($test_file, $error));
return;
}
$classes = $this->_selectRunnableTests($existing_classes, get_declared_classes());
if (count($classes) == 0) {
- $this->addTestCase(new BadGroupTest($test_file, "No runnable test cases in [$test_file]"));
+ $this->addTestCase(new BadTestSuite($test_file, "No runnable test cases in [$test_file]"));
return;
}
$group = &$this->_createGroupFromClasses($test_file, $classes);
$error = isset($php_errormsg) ? $php_errormsg : false;
$this->_disableErrorReporting();
$self_inflicted_errors = array(
- 'Assigning the return value of new by reference is deprecated',
- 'var: Deprecated. Please use the public/private/protected modifiers');
- if (in_array($error, $self_inflicted_errors)) {
- return false;
- }
+ '/Assigning the return value of new by reference/i',
+ '/var: Deprecated/i',
+ '/Non-static method/i');
+ foreach ($self_inflicted_errors as $pattern) {
+ if (preg_match($pattern, $error)) {
+ return false;
+ }
+ }
return $error;
}
* Builds a group test from a class list.
* @param string $title Title of new group.
* @param array $classes Test classes.
- * @return GroupTest Group loaded with the new
+ * @return TestSuite Group loaded with the new
* test cases.
* @access private
*/
function &_createGroupFromClasses($title, $classes) {
SimpleTest::ignoreParentsIfIgnored($classes);
- $group = &new GroupTest($title);
+ $group = &new TestSuite($title);
foreach ($classes as $class) {
if (! SimpleTest::isIgnored($class)) {
$group->addTestClass($class);
function _getBaseTestCase($class) {
while ($class = get_parent_class($class)) {
$class = strtolower($class);
- if ($class == "simpletestcase" || $class == "grouptest") {
+ if ($class == 'simpletestcase' || $class == 'testsuite' || $class == 'grouptest') {
return $class;
}
}
$class = $this->_test_cases[$i];
$test = &new $class();
$test->run($reporter);
+ unset($test);
} else {
$this->_test_cases[$i]->run($reporter);
}
return $count;
}
}
+
+ /**
+ * @deprecated
+ */
+ class GroupTest extends TestSuite { }
/**
* This is a failing group test for when a test suite hasn't
* @package SimpleTest
* @subpackage UnitTester
*/
- class BadGroupTest {
+ class BadTestSuite {
var $_label;
var $_error;
* of the test.
* @access public
*/
- function BadGroupTest($label, $error) {
+ function BadTestSuite($label, $error) {
$this->_label = $label;
$this->_error = $error;
}
*/
function run(&$reporter) {
$reporter->paintGroupStart($this->getLabel(), $this->getSize());
- $reporter->paintFail('Bad GroupTest [' . $this->getLabel() .
+ $reporter->paintFail('Bad TestSuite [' . $this->getLabel() .
'] with error [' . $this->_error . ']');
$reporter->paintGroupEnd($this->getLabel());
return $reporter->getStatus();
return 0;
}
}
-?>
+
+ /**
+ * @deprecated
+ */
+ class BadGroupTest extends BadTestSuite { }
+?>
\ No newline at end of file
$this->SimpleTestCase($label);
}
+ /**
+ * Called from within the test methods to register
+ * passes and failures.
+ * @param boolean $result Pass on true.
+ * @param string $message Message to display describing
+ * the test state.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertTrue($result, $message = false) {
+ return $this->assert(new TrueExpectation(), $result, $message);
+ }
+
+ /**
+ * Will be true on false and vice versa. False
+ * is the PHP definition of false, so that null,
+ * empty strings, zero and an empty array all count
+ * as false.
+ * @param boolean $result Pass on false.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertFalse($result, $message = '%s') {
+ return $this->assert(new FalseExpectation(), $result, $message);
+ }
+
/**
* Will be true if the value is null.
* @param null $value Supposedly null value.
* @return boolean True on pass
* @access public
*/
- function assertNull($value, $message = "%s") {
+ function assertNull($value, $message = '%s') {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
- "[" . $dumper->describeValue($value) . "] should be null");
+ '[' . $dumper->describeValue($value) . '] should be null');
return $this->assertTrue(! isset($value), $message);
}
* @return boolean True on pass.
* @access public
*/
- function assertNotNull($value, $message = "%s") {
+ function assertNotNull($value, $message = '%s') {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
- "[" . $dumper->describeValue($value) . "] should not be null");
+ '[' . $dumper->describeValue($value) . '] should not be null');
return $this->assertTrue(isset($value), $message);
}
* @return boolean True on pass.
* @access public
*/
- function assertIsA($object, $type, $message = "%s") {
+ function assertIsA($object, $type, $message = '%s') {
return $this->assert(
new IsAExpectation($type),
$object,
* @return boolean True on pass.
* @access public
*/
- function assertNotA($object, $type, $message = "%s") {
+ function assertNotA($object, $type, $message = '%s') {
return $this->assert(
new NotAExpectation($type),
$object,
* @return boolean True on pass
* @access public
*/
- function assertEqual($first, $second, $message = "%s") {
+ function assertEqual($first, $second, $message = '%s') {
return $this->assert(
new EqualExpectation($first),
$second,
* @return boolean True on pass
* @access public
*/
- function assertNotEqual($first, $second, $message = "%s") {
+ function assertNotEqual($first, $second, $message = '%s') {
return $this->assert(
new NotEqualExpectation($first),
$second,
* @return boolean True on pass
* @access public
*/
- function assertWithinMargin($first, $second, $margin, $message = "%s") {
+ function assertWithinMargin($first, $second, $margin, $message = '%s') {
return $this->assert(
new WithinMarginExpectation($first, $margin),
$second,
* @return boolean True on pass
* @access public
*/
- function assertOutsideMargin($first, $second, $margin, $message = "%s") {
+ function assertOutsideMargin($first, $second, $margin, $message = '%s') {
return $this->assert(
new OutsideMarginExpectation($first, $margin),
$second,
* @return boolean True on pass
* @access public
*/
- function assertIdentical($first, $second, $message = "%s") {
+ function assertIdentical($first, $second, $message = '%s') {
return $this->assert(
new IdenticalExpectation($first),
$second,
* @return boolean True on pass
* @access public
*/
- function assertNotIdentical($first, $second, $message = "%s") {
+ function assertNotIdentical($first, $second, $message = '%s') {
return $this->assert(
new NotIdenticalExpectation($first),
$second,
* @return boolean True on pass
* @access public
*/
- function assertReference(&$first, &$second, $message = "%s") {
+ function assertReference(&$first, &$second, $message = '%s') {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
- "[" . $dumper->describeValue($first) .
- "] and [" . $dumper->describeValue($second) .
- "] should reference the same object");
+ '[' . $dumper->describeValue($first) .
+ '] and [' . $dumper->describeValue($second) .
+ '] should reference the same object');
return $this->assertTrue(
SimpleTestCompatibility::isReference($first, $second),
$message);
* @return boolean True on pass
* @access public
*/
- function assertClone(&$first, &$second, $message = "%s") {
+ function assertClone(&$first, &$second, $message = '%s') {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
- "[" . $dumper->describeValue($first) .
- "] and [" . $dumper->describeValue($second) .
- "] should not be the same object");
+ '[' . $dumper->describeValue($first) .
+ '] and [' . $dumper->describeValue($second) .
+ '] should not be the same object');
$identical = &new IdenticalExpectation($first);
return $this->assertTrue(
$identical->test($second) &&
* @return boolean True on pass
* @access public
*/
- function assertPattern($pattern, $subject, $message = "%s") {
+ function assertPattern($pattern, $subject, $message = '%s') {
return $this->assert(
new PatternExpectation($pattern),
$subject,
/**
* @deprecated
*/
- function assertWantedPattern($pattern, $subject, $message = "%s") {
+ function assertWantedPattern($pattern, $subject, $message = '%s') {
return $this->assertPattern($pattern, $subject, $message);
}
* @return boolean True on pass
* @access public
*/
- function assertNoPattern($pattern, $subject, $message = "%s") {
+ function assertNoPattern($pattern, $subject, $message = '%s') {
return $this->assert(
new NoPatternExpectation($pattern),
$subject,
/**
* @deprecated
*/
- function assertNoUnwantedPattern($pattern, $subject, $message = "%s") {
+ function assertNoUnwantedPattern($pattern, $subject, $message = '%s') {
return $this->assertNoPattern($pattern, $subject, $message);
}
/**
- * Confirms that no errors have occoured so
- * far in the test method.
- * @param string $message Message to display.
- * @return boolean True on pass
+ * @deprecated
+ */
+ function swallowErrors() {
+ $context = &SimpleTest::getContext();
+ $queue = &$context->get('SimpleErrorQueue');
+ $queue->clear();
+ }
+
+ /**
+ * @deprecated
+ */
+ function assertNoErrors($message = '%s') {
+ $context = &SimpleTest::getContext();
+ $queue = &$context->get('SimpleErrorQueue');
+ return $queue->assertNoErrors($message);
+ }
+
+ /**
+ * @deprecated
+ */
+ function assertError($expected = false, $message = '%s') {
+ $context = &SimpleTest::getContext();
+ $queue = &$context->get('SimpleErrorQueue');
+ return $queue->assertError($this->_coerceExpectation($expected), $message);
+ }
+
+ /**
+ * Prepares for an error. If the error mismatches it
+ * passes through, otherwise it is swallowed. Any
+ * left over errors trigger failures.
+ * @param SimpleExpectation/string $expected The error to match.
+ * @param string $message Message on failure.
* @access public
*/
- function assertNoErrors($message = "%s") {
- $queue = &SimpleErrorQueue::instance();
- return $this->assertTrue(
- $queue->isEmpty(),
- sprintf($message, "Should be no errors"));
+ function expectError($expected = false, $message = '%s') {
+ $context = &SimpleTest::getContext();
+ $queue = &$context->get('SimpleErrorQueue');
+ $queue->expectError($this->_coerceExpectation($expected), $message);
}
/**
- * Confirms that an error has occoured and
- * optionally that the error text matches exactly.
- * @param string $expected Expected error text or
- * false for no check.
- * @param string $message Message to display.
- * @return boolean True on pass
+ * Prepares for an exception. If the error mismatches it
+ * passes through, otherwise it is swallowed. Any
+ * left over errors trigger failures.
+ * @param SimpleExpectation/Exception $expected The error to match.
+ * @param string $message Message on failure.
* @access public
*/
- function assertError($expected = false, $message = "%s") {
- $queue = &SimpleErrorQueue::instance();
- if ($queue->isEmpty()) {
- $this->fail(sprintf($message, "Expected error not found"));
- return;
- }
- list($severity, $content, $file, $line, $globals) = $queue->extract();
- $severity = SimpleErrorQueue::getSeverityAsString($severity);
- if (! $expected) {
- return $this->pass(
- "Captured a PHP error of [$content] severity [$severity] in [$file] line [$line] -> %s");
- }
- $expected = $this->_coerceToExpectation($expected);
- return $this->assert(
- $expected,
- $content,
- "Expected PHP error [$content] severity [$severity] in [$file] line [$line] -> %s");
+ function expectException($expected = false, $message = '%s') {
+ $context = &SimpleTest::getContext();
+ $queue = &$context->get('SimpleExceptionTrap');
+ $queue->expectException($expected, $message . $this->getAssertionLine());
}
/**
* @return SimpleExpectation Expectation object.
* @access private
*/
- function _coerceToExpectation($expected) {
+ function _coerceExpectation($expected) {
+ if ($expected == false) {
+ return new AnythingExpectation();
+ }
if (SimpleTestCompatibility::isA($expected, 'SimpleExpectation')) {
return $expected;
}
+ if(is_string($expected)) {
+ $expected = str_replace('%', '%%', $expected);
+ }
return new EqualExpectation($expected);
}
/**
* @deprecated
*/
- function assertErrorPattern($pattern, $message = "%s") {
+ function assertErrorPattern($pattern, $message = '%s') {
return $this->assertError(new PatternExpectation($pattern), $message);
}
}
-?>
+?>
\ No newline at end of file
* @access public
*/
function normalisePath($path) {
- $path = preg_replace('|/[^/]+/\.\./|', '/', $path);
- return preg_replace('|/\./|', '/', $path);
+ $path = preg_replace('|/\./|', '/', $path);
+ return preg_replace('|/[^/]+/\.\./|', '/', $path);
}
/**
} else {
return "Field expectation [" . $dumper->describeValue($this->_value) .
"] fails with [" .
- $this->_dumper->describeValue($compare) . "] " .
- $this->_dumper->describeDifference($this->_value, $compare);
+ $dumper->describeValue($compare) . "] " .
+ $dumper->describeDifference($this->_value, $compare);
}
}
}
*/
function testMessage($compare) {
if (SimpleExpectation::isExpectation($this->_expected_value)) {
- $message = $this->_expected_value->testMessage($compare);
+ $message = $this->_expected_value->overlayMessage($compare, $this->_getDumper());
} else {
$message = $this->_expected_header .
($this->_expected_value ? ': ' . $this->_expected_value : '');
* @param string $expiry Expiry date.
* @access public
*/
- function setCookie($name, $value, $host = false, $path = "/", $expiry = false) {
+ function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
$this->_browser->setCookie($name, $value, $host, $path, $expiry);
}
return $this->_failOnError($this->_browser->click($label));
}
+ /**
+ * Checks for a click target.
+ * @param string $label Visible text or alt text.
+ * @return boolean True if click target.
+ * @access public
+ */
+ function assertClickable($label, $message = '%s') {
+ return $this->assertTrue(
+ $this->_browser->isClickable($label),
+ sprintf($message, "Click target [$label] should exist"));
+ }
+
/**
* Clicks the submit button by label. The owning
* form will be submitted by this.
$this->_browser->clickSubmitById($id, $additional));
}
+ /**
+ * Checks for a valid button label.
+ * @param string $label Visible text.
+ * @return boolean True if click target.
+ * @access public
+ */
+ function assertSubmit($label, $message = '%s') {
+ return $this->assertTrue(
+ $this->_browser->isSubmit($label),
+ sprintf($message, "Submit button [$label] should exist"));
+ }
+
/**
* Clicks the submit image by some kind of label. Usually
* the alt tag or the nearest equivalent. The owning
$this->_browser->clickImageById($id, $x, $y, $additional));
}
+ /**
+ * Checks for a valid image with atht alt text or title.
+ * @param string $label Visible text.
+ * @return boolean True if click target.
+ * @access public
+ */
+ function assertImage($label, $message = '%s') {
+ return $this->assertTrue(
+ $this->_browser->isImage($label),
+ sprintf($message, "Image with text [$label] should exist"));
+ }
+
/**
* Submits a form by the ID.
* @param string $id Form ID. No button information
return $this->_failOnError($this->_browser->clickLinkById($id));
}
- /**
- * Will trigger a pass if the two parameters have
- * the same value only. Otherwise a fail. This
- * is for testing hand extracted text, etc.
- * @param mixed $first Value to compare.
- * @param mixed $second Value to compare.
- * @param string $message Message to display.
- * @return boolean True on pass
- * @access public
- */
- function assertEqual($first, $second, $message = "%s") {
- return $this->assert(
- new EqualExpectation($first),
- $second,
- $message);
- }
-
- /**
- * Will trigger a pass if the two parameters have
- * a different value. Otherwise a fail. This
- * is for testing hand extracted text, etc.
- * @param mixed $first Value to compare.
- * @param mixed $second Value to compare.
- * @param string $message Message to display.
- * @return boolean True on pass
- * @access public
- */
- function assertNotEqual($first, $second, $message = "%s") {
- return $this->assert(
- new NotEqualExpectation($first),
- $second,
- $message);
- }
-
/**
* Tests for the presence of a link label. Match is
* case insensitive with normalised space.
* @param string $label Text between the anchor tags.
+ * @param mixed $expected Expected URL or expectation object.
* @param string $message Message to display. Default
* can be embedded with %s.
* @return boolean True if link present.
* @access public
*/
- function assertLink($label, $message = "%s") {
- return $this->assertTrue(
- $this->_browser->isLink($label),
- sprintf($message, "Link [$label] should exist"));
+ function assertLink($label, $expected = true, $message = '%s') {
+ $url = $this->_browser->getLink($label);
+ if ($expected === true) {
+ return $this->assertTrue($url !== false, sprintf($message, "Link [$label] should exist"));
+ }
+ if (! SimpleExpectation::isExpectation($expected)) {
+ $expected = new IdenticalExpectation($expected);
+ }
+ return $this->assert($expected, $url->asString(), sprintf($message, "Link [$label] should match"));
}
/**
* @return boolean True if link missing.
* @access public
*/
- function assertNoLink($label, $message = "%s") {
- return $this->assertFalse(
- $this->_browser->isLink($label),
+ function assertNoLink($label, $message = '%s') {
+ return $this->assertTrue(
+ $this->_browser->getLink($label) === false,
sprintf($message, "Link [$label] should not exist"));
}
/**
* Tests for the presence of a link id attribute.
* @param string $id Id attribute value.
+ * @param mixed $expected Expected URL or expectation object.
* @param string $message Message to display. Default
* can be embedded with %s.
* @return boolean True if link present.
* @access public
*/
- function assertLinkById($id, $message = "%s") {
- return $this->assertTrue(
- $this->_browser->isLinkById($id),
- sprintf($message, "Link ID [$id] should exist"));
+ function assertLinkById($id, $expected = true, $message = '%s') {
+ $url = $this->_browser->getLinkById($id);
+ if ($expected === true) {
+ return $this->assertTrue($url !== false, sprintf($message, "Link ID [$id] should exist"));
+ }
+ if (! SimpleExpectation::isExpectation($expected)) {
+ $expected = new IdenticalExpectation($expected);
+ }
+ return $this->assert($expected, $url->asString(), sprintf($message, "Link ID [$id] should match"));
}
/**
* @return boolean True if link missing.
* @access public
*/
- function assertNoLinkById($id, $message = "%s") {
- return $this->assertFalse(
- $this->_browser->isLinkById($id),
+ function assertNoLinkById($id, $message = '%s') {
+ return $this->assertTrue(
+ $this->_browser->getLinkById($id) === false,
sprintf($message, "Link ID [$id] should not exist"));
}
/**
* Tests the text between the title tags.
- * @param string $title Expected title.
- * @param string $message Message to display.
- * @return boolean True if pass.
+ * @param string/SimpleExpectation $title Expected title.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
* @access public
*/
function assertTitle($title = false, $message = '%s') {
$this->getCookie($name) === false,
sprintf($message, "Not expecting cookie [$name]"));
}
+
+ /**
+ * Called from within the test methods to register
+ * passes and failures.
+ * @param boolean $result Pass on true.
+ * @param string $message Message to display describing
+ * the test state.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertTrue($result, $message = false) {
+ return $this->assert(new TrueExpectation(), $result, $message);
+ }
+
+ /**
+ * Will be true on false and vice versa. False
+ * is the PHP definition of false, so that null,
+ * empty strings, zero and an empty array all count
+ * as false.
+ * @param boolean $result Pass on false.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertFalse($result, $message = '%s') {
+ return $this->assert(new FalseExpectation(), $result, $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters have
+ * the same value only. Otherwise a fail. This
+ * is for testing hand extracted text, etc.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertEqual($first, $second, $message = '%s') {
+ return $this->assert(
+ new EqualExpectation($first),
+ $second,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters have
+ * a different value. Otherwise a fail. This
+ * is for testing hand extracted text, etc.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertNotEqual($first, $second, $message = '%s') {
+ return $this->assert(
+ new NotEqualExpectation($first),
+ $second,
+ $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', 'click', 'pass', 'fail'));
+ return $trace->traceMethod();
+ }
}
?>
\ No newline at end of file
var $_namespace;
/**
- * Does nothing yet.
+ * Sets up indentation and namespace.
+ * @param string $namespace Namespace to add to each tag.
+ * @param string $indent Indenting to add on each nesting.
* @access public
*/
function XmlReporter($namespace = false, $indent = ' ') {
}
/**
- * Increments the pass count.
- * @param string $message Message is ignored.
+ * Paints pass as XML.
+ * @param string $message Message to encode.
* @access public
*/
function paintPass($message) {
}
/**
- * Increments the fail count.
- * @param string $message Message is ignored.
+ * Paints failure as XML.
+ * @param string $message Message to encode.
* @access public
*/
function paintFail($message) {
}
/**
- * Paints a PHP error or exception.
- * @param string $message Message is ignored.
+ * Paints error as XML.
+ * @param string $message Message to encode.
* @access public
- * @abstract
*/
function paintError($message) {
parent::paintError($message);
print "</" . $this->_namespace . "exception>\n";
}
+ /**
+ * Paints exception as XML.
+ * @param Exception $exception Exception to encode.
+ * @access public
+ */
+ function paintException($exception) {
+ parent::paintException($exception);
+ print $this->_getIndent(1);
+ print "<" . $this->_namespace . "exception>";
+ $message = 'Unexpected exception of type [' . get_class($exception) .
+ '] with message ['. $exception->getMessage() .
+ '] in ['. $exception->getFile() .
+ ' line ' . $exception->getLine() . ']';
+ print $this->toParsedXml($message);
+ print "</" . $this->_namespace . "exception>\n";
+ }
+
+ /**
+ * Paints the skipping message and tag.
+ * @param string $message Text to display in skip tag.
+ * @access public
+ */
+ function paintSkip($message) {
+ parent::paintSkip($message);
+ print $this->_getIndent(1);
+ print "<" . $this->_namespace . "skip>";
+ print $this->toParsedXml($message);
+ print "</" . $this->_namespace . "skip>\n";
+ }
+
/**
* Paints a simple supplementary message.
* @param string $message Text to display.
*/
function _isLeaf($tag) {
return in_array($tag, array(
- 'NAME', 'PASS', 'FAIL', 'EXCEPTION', 'MESSAGE', 'FORMATTED', 'SIGNAL'));
+ 'NAME', 'PASS', 'FAIL', 'EXCEPTION', 'SKIP', 'MESSAGE', 'FORMATTED', 'SIGNAL'));
}
/**
$this->_listener->paintFail($this->_content);
} elseif ($tag == 'EXCEPTION') {
$this->_listener->paintError($this->_content);
+ } elseif ($tag == 'SKIP') {
+ $this->_listener->paintSkip($this->_content);
} elseif ($tag == 'SIGNAL') {
$this->_listener->paintSignal(
$this->_attributes['TYPE'],