MDL-15204 Update complete

This commit is contained in:
nicolasconnault
2008-06-10 20:10:50 +00:00
parent 0b00c4ce59
commit f80efd77e7
45 changed files with 17908 additions and 16584 deletions
-46
View File
@@ -1,46 +0,0 @@
BACKLOG
This is backed up stuff that defines the 1.0.1 release.
$Id$
Unit tester
-----------
Add skip facility (4).
Reporter
--------
Add a repeating reporter (2).
Split and refactor dumpers by type (2).
Mock objects
------------
Parser
------
Add U flag to regexes to allow unicode (3).
Parse fieldsets correctly with labels (5).
Browser
-------
Change getUrls() to return more information (2).
Add a file() loading command (2).
Investigate bug, clicking keeps encoding again and again (3).
Fix bug URL losing spaces (3).
Setting an option by id attribute should only toggle that option (3).
Add additional parameters to click() method (1).
Allow index selection of controls (3).
Web tester
----------
Add assertClickable() method (1).
Add assertSubmit() method (1).
Documentation
-------------
Extension docs (1).
Replace all deprecated methods (3).
Split mock objects off fromtutorial (4).
Add page for projects that use or extend SimpleTest (2).
Build
-----
@@ -5,17 +5,31 @@ written with earlier versions will fail with the newest ones. The most
dramatic changes are in the alpha releases. Here is a list of possible
problems and their fixes...
No method getRelativeUrls() or getAbsoluteUrls()
------------------------------------------------
These methods were always a bit weird anyway, and
the new parsing of the base tag makes them more so.
They have been replaced with getUrls() instead. If
you want the old functionality then simply chop
off the current domain from getUrl().
Method setWildcard() removed in mocks
-------------------------------------
Even setWildcard() has been removed in 1.0.1beta now.
If you want to test explicitely for a '*' string, then
simply pass in new IdenticalExpectation('*') instead.
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.
work with other test tools, but no one does this.
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
redundant if you use expectError() as failures are now reported
immediately.
No method TestCase::signal()
+12 -12
View File
@@ -8,9 +8,9 @@ a version from the location above. You must read and accept that
licence to use this software. The file is titled simply LICENSE.
What is it? It's a framework for unit testing, web site testing and
mock objects for PHP 4.2.0+.
mock objects for PHP 4.2.0+ (and PHP 5.0 to 5.3 without E_STRICT).
If you have used JUnit you will find this PHP unit testing version very
If you have used JUnit, you will find this PHP unit testing version very
similar. Also included is a mock objects and server stubs generator.
The stubs can have return values set for different arguments, can have
sequences set also by arguments and can return items by reference.
@@ -31,9 +31,9 @@ in the extreme, but a lot of information flows from the test suite.
After version 1.0 we will release a better web UI, but we are leaving XUL
and GTk versions to volunteers as everybody has their own opinion
on a good GUI, and we don't want to discourage development by shipping
one with the toolkit.
one with the toolkit. YOucan download an Eclipse plug-in separately.
You are looking at a first full release. The unit tests for SimpleTest
You are looking at a second full release. The unit tests for SimpleTest
itself can be run here...
simpletest/test/unit_tests.php
@@ -42,7 +42,7 @@ And tests involving live network connections as well are here...
simpletest/test/all_tests.php
The full tests will typically overrun the 8Mb limit usually allowed
The full tests will typically overrun the 8Mb limit often allowed
to a PHP process. A workaround is to run the tests on the command
with a custom php.ini file if you do not have access to your server
version.
@@ -55,7 +55,7 @@ The full tests read some test data from the LastCraft site. If the site
is down or has been modified for a later version then you will get
spurious errors. A unit_tests.php failure on the other hand would be
very serious. As far as we know we haven't yet managed to check in any
unit test failures so please correct us if you find one.
unit test failures, so please correct us if you find one.
Even if all of the tests run please verify that your existing test suites
also function as expected. If they don't see the file...
@@ -63,7 +63,7 @@ also function as expected. If they don't see the file...
HELP_MY_TESTS_DONT_WORK_ANYMORE
This contains information on interface changes. It also points out
deprecated interfaces so you should read this even if all of
deprecated interfaces, so you should read this even if all of
your current tests appear to run.
There is a documentation folder which contains the core reference information
@@ -77,7 +77,7 @@ with the project documentation. A French translation exists at...
http://www.onpk.net/index.php/2005/01/12/254-tutoriel-simpletest-decouvrir-les-tests-unitaires.
If you download and use and possibly even extend this tool, please let us
If you download and use, and possibly even extend this tool, please let us
know. Any feedback, even bad, is always welcome and we will work to get
your suggestions into the next release. Ideally please send your
comments to...
@@ -87,10 +87,10 @@ [email protected]
...so that others can read them too. We usually try to respond within 48
hours.
There is no change log as yet except at Sourceforge. You can visit the
There is no change log except at Sourceforge. You can visit the
release notes to see the completed TODO list after each cycle and also the
status of any bugs, but if the bug is recent then it will be fixed in CVS only.
The CVS check-ins always have all the tests passing and so CVS snapshots should
status of any bugs, but if the bug is recent then it will be fixed in SVN only.
The SVN check-ins always have all the tests passing and so SVN snapshots should
be pretty usable, although the code may not look so good internally.
Oh, yes. It is called "Simple" because it should be simple to
@@ -103,6 +103,6 @@ really are invaluable, but sadly you are too many to mention in full.
Thanks to all on the advanced PHP forum on SitePoint, especially Harry
Feucks. Early adopters are always an inspiration.
yours Marcus Baker, Jason Sweat, Travis Swicegood and Perrick Penet.
Marcus Baker, Jason Sweat, Travis Swicegood, Perrick Penet and Edward Z. Yang.
--
[email protected]
-53
View File
@@ -1,53 +0,0 @@
TODO
This is immediate stuff only for this iteration (1.0.1alpha3) of 44 hours (60 actual).
$Id$
Unit tester
-----------
Change assertCopy() to assertClone() and add identical check (1/1) - done.
The ignore() directive should ignore parent classes as well (1/3) - done.
The fail() method should issue a line number (2/1) - done.
Abstract test cases should be ignored automatically (2/2) - done.
More meaningful message when trying a test in the constructor (1/1) - done.
Add exception trap (2/2) - done.
Reporter
--------
Allow multiple reporters (2/1) - done.
Add a test case selecting ReporterDecorator (2/4) - done.
Can we get rid of that useless runner class? yes! (1/2) - done.
Test case should say what tests are available (1/1) - done.
Mock objects
------------
Confirm mocking of SPL classes and derivatives (3/4) - done.
Optional parameters generate spurious warnings in PHP 5.0.2 (1/2) - done.
Parser
------
Browser
-------
Allow ignoring of cookies as per feature request (2/8) - done.
Setting a radio button with value 0 just doesn't happen (1/10) - done.
Fix quoting issue with fields as in bug report (2/2) - done.
Fix bug with encoded GET parameters not being transmitted in form action (3/2) - done.
Confirm that button with no name has no value transmitted (2/4) - done.
Allow setting of checkboxes by setting them to true (1/1) - done.
Add memory fixes to builder (1/1) - done.
Web tester
----------
Failure to connect should be reported unless suppressed (2/2) - done.
Message bug in web header pattern assertions (2/1) - done.
Documentation
-------------
Build
-----
Fix fatal error in PHP 5.1 (3/0) - done.
Fix fatal error in PHP 5.0.5 (3/2) - done.
Test with PHP 4.4.2 (1/1) - done.
Fix error in PHP 5.0.2 (2/2) - done.
+1 -1
View File
@@ -1 +1 @@
1.0.1beta
1.0.1
+218 -218
View File
@@ -1,238 +1,238 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id$
*/
/**
* include http class
*/
require_once(dirname(__FILE__) . '/http.php');
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id$
*/
/**
* include http class
*/
require_once(dirname(__FILE__) . '/http.php');
/**
* Represents a single security realm's identity.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleRealm {
var $_type;
var $_root;
var $_username;
var $_password;
/**
* Represents a single security realm's identity.
* @package SimpleTest
* @subpackage WebTester
* Starts with the initial entry directory.
* @param string $type Authentication type for this
* realm. Only Basic authentication
* is currently supported.
* @param SimpleUrl $url Somewhere in realm.
* @access public
*/
class SimpleRealm {
var $_type;
var $_root;
var $_username;
var $_password;
/**
* Starts with the initial entry directory.
* @param string $type Authentication type for this
* realm. Only Basic authentication
* is currently supported.
* @param SimpleUrl $url Somewhere in realm.
* @access public
*/
function SimpleRealm($type, $url) {
$this->_type = $type;
$this->_root = $url->getBasePath();
$this->_username = false;
$this->_password = false;
}
/**
* Adds another location to the realm.
* @param SimpleUrl $url Somewhere in realm.
* @access public
*/
function stretch($url) {
$this->_root = $this->_getCommonPath($this->_root, $url->getPath());
}
/**
* Finds the common starting path.
* @param string $first Path to compare.
* @param string $second Path to compare.
* @return string Common directories.
* @access private
*/
function _getCommonPath($first, $second) {
$first = explode('/', $first);
$second = explode('/', $second);
for ($i = 0; $i < min(count($first), count($second)); $i++) {
if ($first[$i] != $second[$i]) {
return implode('/', array_slice($first, 0, $i)) . '/';
}
function SimpleRealm($type, $url) {
$this->_type = $type;
$this->_root = $url->getBasePath();
$this->_username = false;
$this->_password = false;
}
/**
* Adds another location to the realm.
* @param SimpleUrl $url Somewhere in realm.
* @access public
*/
function stretch($url) {
$this->_root = $this->_getCommonPath($this->_root, $url->getPath());
}
/**
* Finds the common starting path.
* @param string $first Path to compare.
* @param string $second Path to compare.
* @return string Common directories.
* @access private
*/
function _getCommonPath($first, $second) {
$first = explode('/', $first);
$second = explode('/', $second);
for ($i = 0; $i < min(count($first), count($second)); $i++) {
if ($first[$i] != $second[$i]) {
return implode('/', array_slice($first, 0, $i)) . '/';
}
return implode('/', $first) . '/';
}
/**
* Sets the identity to try within this realm.
* @param string $username Username in authentication dialog.
* @param string $username Password in authentication dialog.
* @access public
*/
function setIdentity($username, $password) {
$this->_username = $username;
$this->_password = $password;
return implode('/', $first) . '/';
}
/**
* Sets the identity to try within this realm.
* @param string $username Username in authentication dialog.
* @param string $username Password in authentication dialog.
* @access public
*/
function setIdentity($username, $password) {
$this->_username = $username;
$this->_password = $password;
}
/**
* Accessor for current identity.
* @return string Last succesful username.
* @access public
*/
function getUsername() {
return $this->_username;
}
/**
* Accessor for current identity.
* @return string Last succesful password.
* @access public
*/
function getPassword() {
return $this->_password;
}
/**
* Test to see if the URL is within the directory
* tree of the realm.
* @param SimpleUrl $url URL to test.
* @return boolean True if subpath.
* @access public
*/
function isWithin($url) {
if ($this->_isIn($this->_root, $url->getBasePath())) {
return true;
}
/**
* Accessor for current identity.
* @return string Last succesful username.
* @access public
*/
function getUsername() {
return $this->_username;
if ($this->_isIn($this->_root, $url->getBasePath() . $url->getPage() . '/')) {
return true;
}
/**
* Accessor for current identity.
* @return string Last succesful password.
* @access public
*/
function getPassword() {
return $this->_password;
}
/**
* Test to see if the URL is within the directory
* tree of the realm.
* @param SimpleUrl $url URL to test.
* @return boolean True if subpath.
* @access public
*/
function isWithin($url) {
if ($this->_isIn($this->_root, $url->getBasePath())) {
return true;
}
if ($this->_isIn($this->_root, $url->getBasePath() . $url->getPage() . '/')) {
return true;
}
return false;
}
/**
* Tests to see if one string is a substring of
* another.
* @param string $part Small bit.
* @param string $whole Big bit.
* @return boolean True if the small bit is
* in the big bit.
* @access private
*/
function _isIn($part, $whole) {
return strpos($whole, $part) === 0;
return false;
}
/**
* Tests to see if one string is a substring of
* another.
* @param string $part Small bit.
* @param string $whole Big bit.
* @return boolean True if the small bit is
* in the big bit.
* @access private
*/
function _isIn($part, $whole) {
return strpos($whole, $part) === 0;
}
}
/**
* Manages security realms.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleAuthenticator {
var $_realms;
/**
* Clears the realms.
* @access public
*/
function SimpleAuthenticator() {
$this->restartSession();
}
/**
* Starts with no realms set up.
* @access public
*/
function restartSession() {
$this->_realms = array();
}
/**
* Adds a new realm centered the current URL.
* Browsers vary wildly on their behaviour in this
* regard. Mozilla ignores the realm and presents
* only when challenged, wasting bandwidth. IE
* just carries on presenting until a new challenge
* occours. SimpleTest tries to follow the spirit of
* the original standards committee and treats the
* base URL as the root of a file tree shaped realm.
* @param SimpleUrl $url Base of realm.
* @param string $type Authentication type for this
* realm. Only Basic authentication
* is currently supported.
* @param string $realm Name of realm.
* @access public
*/
function addRealm($url, $type, $realm) {
$this->_realms[$url->getHost()][$realm] = new SimpleRealm($type, $url);
}
/**
* Sets the current identity to be presented
* against that realm.
* @param string $host Server hosting realm.
* @param string $realm Name of realm.
* @param string $username Username for realm.
* @param string $password Password for realm.
* @access public
*/
function setIdentityForRealm($host, $realm, $username, $password) {
if (isset($this->_realms[$host][$realm])) {
$this->_realms[$host][$realm]->setIdentity($username, $password);
}
}
/**
* Manages security realms.
* @package SimpleTest
* @subpackage WebTester
* Finds the name of the realm by comparing URLs.
* @param SimpleUrl $url URL to test.
* @return SimpleRealm Name of realm.
* @access private
*/
class SimpleAuthenticator {
var $_realms;
/**
* Clears the realms.
* @access public
*/
function SimpleAuthenticator() {
$this->restartSession();
}
/**
* Starts with no realms set up.
* @access public
*/
function restartSession() {
$this->_realms = array();
}
/**
* Adds a new realm centered the current URL.
* Browsers vary wildly on their behaviour in this
* regard. Mozilla ignores the realm and presents
* only when challenged, wasting bandwidth. IE
* just carries on presenting until a new challenge
* occours. SimpleTest tries to follow the spirit of
* the original standards committee and treats the
* base URL as the root of a file tree shaped realm.
* @param SimpleUrl $url Base of realm.
* @param string $type Authentication type for this
* realm. Only Basic authentication
* is currently supported.
* @param string $realm Name of realm.
* @access public
*/
function addRealm($url, $type, $realm) {
$this->_realms[$url->getHost()][$realm] = new SimpleRealm($type, $url);
}
/**
* Sets the current identity to be presented
* against that realm.
* @param string $host Server hosting realm.
* @param string $realm Name of realm.
* @param string $username Username for realm.
* @param string $password Password for realm.
* @access public
*/
function setIdentityForRealm($host, $realm, $username, $password) {
if (isset($this->_realms[$host][$realm])) {
$this->_realms[$host][$realm]->setIdentity($username, $password);
}
}
/**
* Finds the name of the realm by comparing URLs.
* @param SimpleUrl $url URL to test.
* @return SimpleRealm Name of realm.
* @access private
*/
function _findRealmFromUrl($url) {
if (! isset($this->_realms[$url->getHost()])) {
return false;
}
foreach ($this->_realms[$url->getHost()] as $name => $realm) {
if ($realm->isWithin($url)) {
return $realm;
}
}
function _findRealmFromUrl($url) {
if (! isset($this->_realms[$url->getHost()])) {
return false;
}
/**
* Presents the appropriate headers for this location.
* @param SimpleHttpRequest $request Request to modify.
* @param SimpleUrl $url Base of realm.
* @access public
*/
function addHeaders(&$request, $url) {
if ($url->getUsername() && $url->getPassword()) {
$username = $url->getUsername();
$password = $url->getPassword();
} elseif ($realm = $this->_findRealmFromUrl($url)) {
$username = $realm->getUsername();
$password = $realm->getPassword();
} else {
return;
foreach ($this->_realms[$url->getHost()] as $name => $realm) {
if ($realm->isWithin($url)) {
return $realm;
}
$this->addBasicHeaders($request, $username, $password);
}
/**
* Presents the appropriate headers for this
* location for basic authentication.
* @param SimpleHttpRequest $request Request to modify.
* @param string $username Username for realm.
* @param string $password Password for realm.
* @access public
* @static
*/
function addBasicHeaders(&$request, $username, $password) {
if ($username && $password) {
$request->addHeaderLine(
'Authorization: Basic ' . base64_encode("$username:$password"));
}
return false;
}
/**
* Presents the appropriate headers for this location.
* @param SimpleHttpRequest $request Request to modify.
* @param SimpleUrl $url Base of realm.
* @access public
*/
function addHeaders(&$request, $url) {
if ($url->getUsername() && $url->getPassword()) {
$username = $url->getUsername();
$password = $url->getPassword();
} elseif ($realm = $this->_findRealmFromUrl($url)) {
$username = $realm->getUsername();
$password = $realm->getPassword();
} else {
return;
}
$this->addBasicHeaders($request, $username, $password);
}
/**
* Presents the appropriate headers for this
* location for basic authentication.
* @param SimpleHttpRequest $request Request to modify.
* @param string $username Username for realm.
* @param string $password Password for realm.
* @access public
* @static
*/
function addBasicHeaders(&$request, $username, $password) {
if ($username && $password) {
$request->addHeaderLine(
'Authorization: Basic ' . base64_encode("$username:$password"));
}
}
}
?>
+87
View File
@@ -0,0 +1,87 @@
<?php
/**
* Autorunner which runs all tests cases found in a file
* that includes this module.
* @package SimpleTest
* @version $Id$
*/
require_once dirname(__FILE__) . '/unit_tester.php';
require_once dirname(__FILE__) . '/mock_objects.php';
require_once dirname(__FILE__) . '/collector.php';
require_once dirname(__FILE__) . '/default_reporter.php';
$GLOBALS['SIMPLETEST_AUTORUNNER_INITIAL_CLASSES'] = get_declared_classes();
register_shutdown_function('simpletest_autorun');
/**
* Exit handler to run all recent test cases if no test has
* so far been run. Uses the DefaultReporter which can have
* it's output controlled with SimpleTest::prefer().
*/
function simpletest_autorun() {
if (tests_have_run()) {
return;
}
$candidates = array_intersect(
capture_new_classes(),
classes_defined_in_initial_file());
$loader = new SimpleFileLoader();
$suite = $loader->createSuiteFromClasses(
basename(initial_file()),
$loader->selectRunnableTests($candidates));
$result = $suite->run(new DefaultReporter());
if (SimpleReporter::inCli()) {
exit($result ? 0 : 1);
}
}
/**
* Checks the current test context to see if a test has
* ever been run.
* @return boolean True if tests have run.
*/
function tests_have_run() {
if ($context = SimpleTest::getContext()) {
return (boolean)$context->getTest();
}
return false;
}
/**
* The first autorun file.
* @return string Filename of first autorun script.
*/
function initial_file() {
static $file = false;
if (! $file) {
$file = reset(get_included_files());
}
return $file;
}
/**
* Just the classes from the first autorun script. May
* get a few false positives, as it just does a regex based
* on following the word "class".
* @return array List of all possible classes in first
* autorun script.
*/
function classes_defined_in_initial_file() {
if (preg_match_all('/\bclass\s+(\w+)/i', file_get_contents(initial_file()), $matches)) {
return array_map('strtolower', $matches[1]);
}
return array();
}
/**
* Every class since the first autorun include. This
* is safe enough if require_once() is alwyas used.
* @return array Class names.
*/
function capture_new_classes() {
global $SIMPLETEST_AUTORUNNER_INITIAL_CLASSES;
return array_map('strtolower', array_diff(get_declared_classes(),
$SIMPLETEST_AUTORUNNER_INITIAL_CLASSES ?
$SIMPLETEST_AUTORUNNER_INITIAL_CLASSES : array()));
}
?>
+1063 -1062
View File
File diff suppressed because it is too large Load Diff
+107 -92
View File
@@ -1,107 +1,122 @@
<?php
/**
* This file contains the following classes: {@link SimpleCollector},
* {@link SimplePatternCollector}.
*
* @author Travis Swicegood <[email protected]>
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* The basic collector for {@link GroupTest}
*
* @see collect(), GroupTest::collect()
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleCollector {
/**
* This file contains the following classes: {@link SimpleCollector},
* {@link SimplePatternCollector}.
*
* @author Travis Swicegood <[email protected]>
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
* 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.
*/
/**
* 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.
* @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;
}
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;
}
/**
* 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);
}
/**
* 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) {
if ($this->_isHidden($entry)) {
continue;
}
closedir($handle);
$this->_handle($test, $path . DIRECTORY_SEPARATOR . $entry);
}
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);
}
}
/**
* 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)) {
return;
}
$test->addTestFile($file);
}
/**
* An extension to {@link SimpleCollector} that only adds files matching a
* given pattern.
*
* @package SimpleTest
* @subpackage UnitTester
* @see SimpleCollector
* Tests for hidden files so as to skip them. Currently
* only tests for Unix hidden files.
* @param string $filename Plain filename.
* @return boolean True if hidden file.
* @access private
*/
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);
}
function _isHidden($filename) {
return strncmp($filename, '.', 1) == 0;
}
}
/**
* 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;
/**
*
* @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);
}
}
}
?>
+155 -155
View File
@@ -1,173 +1,173 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @version $Id$
*/
/**
* Static methods for compatibility between different
* PHP versions.
* @package SimpleTest
*/
class SimpleTestCompatibility {
/**
* Static methods for compatibility between different
* PHP versions.
* @package SimpleTest
* Creates a copy whether in PHP5 or PHP4.
* @param object $object Thing to copy.
* @return object A copy.
* @access public
* @static
*/
class SimpleTestCompatibility {
/**
* Creates a copy whether in PHP5 or PHP4.
* @param object $object Thing to copy.
* @return object A copy.
* @access public
* @static
*/
function copy($object) {
if (version_compare(phpversion(), '5') >= 0) {
eval('$copy = clone $object;');
return $copy;
}
return $object;
}
/**
* Identity test. Drops back to equality + types for PHP5
* objects as the === operator counts as the
* stronger reference constraint.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if identical.
* @access public
* @static
*/
function isIdentical($first, $second) {
if ($first != $second) {
function copy($object) {
if (version_compare(phpversion(), '5') >= 0) {
eval('$copy = clone $object;');
return $copy;
}
return $object;
}
/**
* Identity test. Drops back to equality + types for PHP5
* objects as the === operator counts as the
* stronger reference constraint.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if identical.
* @access public
* @static
*/
function isIdentical($first, $second) {
if (version_compare(phpversion(), '5') >= 0) {
return SimpleTestCompatibility::_isIdenticalType($first, $second);
}
if ($first != $second) {
return false;
}
return ($first === $second);
}
/**
* Recursive type test.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if same type.
* @access private
* @static
*/
function _isIdenticalType($first, $second) {
if (gettype($first) != gettype($second)) {
return false;
}
if (is_object($first) && is_object($second)) {
if (get_class($first) != get_class($second)) {
return false;
}
if (version_compare(phpversion(), '5') >= 0) {
return SimpleTestCompatibility::_isIdenticalType($first, $second);
return SimpleTestCompatibility::_isArrayOfIdenticalTypes(
get_object_vars($first),
get_object_vars($second));
}
if (is_array($first) && is_array($second)) {
return SimpleTestCompatibility::_isArrayOfIdenticalTypes($first, $second);
}
if ($first !== $second) {
return false;
}
return true;
}
/**
* Recursive type test for each element of an array.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if identical.
* @access private
* @static
*/
function _isArrayOfIdenticalTypes($first, $second) {
if (array_keys($first) != array_keys($second)) {
return false;
}
foreach (array_keys($first) as $key) {
$is_identical = SimpleTestCompatibility::_isIdenticalType(
$first[$key],
$second[$key]);
if (! $is_identical) {
return false;
}
}
return true;
}
/**
* Test for two variables being aliases.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if same.
* @access public
* @static
*/
function isReference(&$first, &$second) {
if (version_compare(phpversion(), '5', '>=') && is_object($first)) {
return ($first === $second);
}
/**
* Recursive type test.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if same type.
* @access private
* @static
*/
function _isIdenticalType($first, $second) {
if (gettype($first) != gettype($second)) {
return false;
}
if (is_object($first) && is_object($second)) {
if (get_class($first) != get_class($second)) {
return false;
}
return SimpleTestCompatibility::_isArrayOfIdenticalTypes(
get_object_vars($first),
get_object_vars($second));
}
if (is_array($first) && is_array($second)) {
return SimpleTestCompatibility::_isArrayOfIdenticalTypes($first, $second);
}
if ($first !== $second) {
return false;
}
return true;
}
/**
* Recursive type test for each element of an array.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if identical.
* @access private
* @static
*/
function _isArrayOfIdenticalTypes($first, $second) {
if (array_keys($first) != array_keys($second)) {
return false;
}
foreach (array_keys($first) as $key) {
$is_identical = SimpleTestCompatibility::_isIdenticalType(
$first[$key],
$second[$key]);
if (! $is_identical) {
return false;
}
}
return true;
}
/**
* Test for two variables being aliases.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if same.
* @access public
* @static
*/
function isReference(&$first, &$second) {
if (version_compare(phpversion(), '5', '>=') && is_object($first)) {
return ($first === $second);
}
if (is_object($first) && is_object($second)) {
$id = uniqid("test");
$first->$id = true;
$is_ref = isset($second->$id);
unset($first->$id);
return $is_ref;
}
$temp = $first;
$first = uniqid("test");
$is_ref = ($first === $second);
$first = $temp;
if (is_object($first) && is_object($second)) {
$id = uniqid("test");
$first->$id = true;
$is_ref = isset($second->$id);
unset($first->$id);
return $is_ref;
}
/**
* Test to see if an object is a member of a
* class hiearchy.
* @param object $object Object to test.
* @param string $class Root name of hiearchy.
* @return boolean True if class in hiearchy.
* @access public
* @static
*/
function isA($object, $class) {
if (version_compare(phpversion(), '5') >= 0) {
if (! class_exists($class, false)) {
if (function_exists('interface_exists')) {
if (! interface_exists($class, false)) {
return false;
}
$temp = $first;
$first = uniqid("test");
$is_ref = ($first === $second);
$first = $temp;
return $is_ref;
}
/**
* Test to see if an object is a member of a
* class hiearchy.
* @param object $object Object to test.
* @param string $class Root name of hiearchy.
* @return boolean True if class in hiearchy.
* @access public
* @static
*/
function isA($object, $class) {
if (version_compare(phpversion(), '5') >= 0) {
if (! class_exists($class, false)) {
if (function_exists('interface_exists')) {
if (! interface_exists($class, false)) {
return false;
}
}
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)));
eval("\$is_a = \$object instanceof $class;");
return $is_a;
}
/**
* Sets a socket timeout for each chunk.
* @param resource $handle Socket handle.
* @param integer $timeout Limit in seconds.
* @access public
* @static
*/
function setTimeout($handle, $timeout) {
if (function_exists('stream_set_timeout')) {
stream_set_timeout($handle, $timeout, 0);
} elseif (function_exists('socket_set_timeout')) {
socket_set_timeout($handle, $timeout, 0);
} elseif (function_exists('set_socket_timeout')) {
set_socket_timeout($handle, $timeout, 0);
}
if (function_exists('is_a')) {
return is_a($object, $class);
}
return ((strtolower($class) == get_class($object))
or (is_subclass_of($object, $class)));
}
/**
* Sets a socket timeout for each chunk.
* @param resource $handle Socket handle.
* @param integer $timeout Limit in seconds.
* @access public
* @static
*/
function setTimeout($handle, $timeout) {
if (function_exists('stream_set_timeout')) {
stream_set_timeout($handle, $timeout, 0);
} elseif (function_exists('socket_set_timeout')) {
socket_set_timeout($handle, $timeout, 0);
} elseif (function_exists('set_socket_timeout')) {
set_socket_timeout($handle, $timeout, 0);
}
}
}
?>
+365 -365
View File
@@ -1,380 +1,380 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id$
*/
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id$
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/url.php');
/**#@-*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/url.php');
/**#@-*/
/**
* Cookie data holder. Cookie rules are full of pretty
* arbitary stuff. I have used...
* http://wp.netscape.com/newsref/std/cookie_spec.html
* http://www.cookiecentral.com/faq/
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleCookie {
var $_host;
var $_name;
var $_value;
var $_path;
var $_expiry;
var $_is_secure;
/**
* Cookie data holder. Cookie rules are full of pretty
* arbitary stuff. I have used...
* http://wp.netscape.com/newsref/std/cookie_spec.html
* http://www.cookiecentral.com/faq/
* @package SimpleTest
* @subpackage WebTester
* Constructor. Sets the stored values.
* @param string $name Cookie key.
* @param string $value Value of cookie.
* @param string $path Cookie path if not host wide.
* @param string $expiry Expiry date as string.
* @param boolean $is_secure Currently ignored.
*/
class SimpleCookie {
var $_host;
var $_name;
var $_value;
var $_path;
var $_expiry;
var $_is_secure;
/**
* Constructor. Sets the stored values.
* @param string $name Cookie key.
* @param string $value Value of cookie.
* @param string $path Cookie path if not host wide.
* @param string $expiry Expiry date as string.
* @param boolean $is_secure Currently ignored.
*/
function SimpleCookie($name, $value = false, $path = false, $expiry = false, $is_secure = false) {
$this->_host = false;
$this->_name = $name;
$this->_value = $value;
$this->_path = ($path ? $this->_fixPath($path) : "/");
$this->_expiry = false;
if (is_string($expiry)) {
$this->_expiry = strtotime($expiry);
} elseif (is_integer($expiry)) {
$this->_expiry = $expiry;
}
$this->_is_secure = $is_secure;
}
/**
* Sets the host. The cookie rules determine
* that the first two parts are taken for
* certain TLDs and three for others. If the
* new host does not match these rules then the
* call will fail.
* @param string $host New hostname.
* @return boolean True if hostname is valid.
* @access public
*/
function setHost($host) {
if ($host = $this->_truncateHost($host)) {
$this->_host = $host;
return true;
}
return false;
}
/**
* Accessor for the truncated host to which this
* cookie applies.
* @return string Truncated hostname.
* @access public
*/
function getHost() {
return $this->_host;
}
/**
* Test for a cookie being valid for a host name.
* @param string $host Host to test against.
* @return boolean True if the cookie would be valid
* here.
*/
function isValidHost($host) {
return ($this->_truncateHost($host) === $this->getHost());
}
/**
* Extracts just the domain part that determines a
* cookie's host validity.
* @param string $host Host name to truncate.
* @return string Domain or false on a bad host.
* @access private
*/
function _truncateHost($host) {
$tlds = SimpleUrl::getAllTopLevelDomains();
if (preg_match('/[a-z\-]+\.(' . $tlds . ')$/i', $host, $matches)) {
return $matches[0];
} elseif (preg_match('/[a-z\-]+\.[a-z\-]+\.[a-z\-]+$/i', $host, $matches)) {
return $matches[0];
}
return false;
}
/**
* Accessor for name.
* @return string Cookie key.
* @access public
*/
function getName() {
return $this->_name;
}
/**
* Accessor for value. A deleted cookie will
* have an empty string for this.
* @return string Cookie value.
* @access public
*/
function getValue() {
return $this->_value;
}
/**
* Accessor for path.
* @return string Valid cookie path.
* @access public
*/
function getPath() {
return $this->_path;
}
/**
* Tests a path to see if the cookie applies
* there. The test path must be longer or
* equal to the cookie path.
* @param string $path Path to test against.
* @return boolean True if cookie valid here.
* @access public
*/
function isValidPath($path) {
return (strncmp(
$this->_fixPath($path),
$this->getPath(),
strlen($this->getPath())) == 0);
}
/**
* Accessor for expiry.
* @return string Expiry string.
* @access public
*/
function getExpiry() {
if (! $this->_expiry) {
return false;
}
return gmdate("D, d M Y H:i:s", $this->_expiry) . " GMT";
}
/**
* Test to see if cookie is expired against
* the cookie format time or timestamp.
* Will give true for a session cookie.
* @param integer/string $now Time to test against. Result
* will be false if this time
* is later than the cookie expiry.
* Can be either a timestamp integer
* or a cookie format date.
* @access public
*/
function isExpired($now) {
if (! $this->_expiry) {
return true;
}
if (is_string($now)) {
$now = strtotime($now);
}
return ($this->_expiry < $now);
}
/**
* Ages the cookie by the specified number of
* seconds.
* @param integer $interval In seconds.
* @public
*/
function agePrematurely($interval) {
if ($this->_expiry) {
$this->_expiry -= $interval;
}
}
/**
* Accessor for the secure flag.
* @return boolean True if cookie needs SSL.
* @access public
*/
function isSecure() {
return $this->_is_secure;
}
/**
* Adds a trailing and leading slash to the path
* if missing.
* @param string $path Path to fix.
* @access private
*/
function _fixPath($path) {
if (substr($path, 0, 1) != '/') {
$path = '/' . $path;
}
if (substr($path, -1, 1) != '/') {
$path .= '/';
}
return $path;
function SimpleCookie($name, $value = false, $path = false, $expiry = false, $is_secure = false) {
$this->_host = false;
$this->_name = $name;
$this->_value = $value;
$this->_path = ($path ? $this->_fixPath($path) : "/");
$this->_expiry = false;
if (is_string($expiry)) {
$this->_expiry = strtotime($expiry);
} elseif (is_integer($expiry)) {
$this->_expiry = $expiry;
}
$this->_is_secure = $is_secure;
}
/**
* Repository for cookies. This stuff is a
* tiny bit browser dependent.
* @package SimpleTest
* @subpackage WebTester
* Sets the host. The cookie rules determine
* that the first two parts are taken for
* certain TLDs and three for others. If the
* new host does not match these rules then the
* call will fail.
* @param string $host New hostname.
* @return boolean True if hostname is valid.
* @access public
*/
class SimpleCookieJar {
var $_cookies;
/**
* Constructor. Jar starts empty.
* @access public
*/
function SimpleCookieJar() {
$this->_cookies = array();
}
/**
* Removes expired and temporary cookies as if
* the browser was closed and re-opened.
* @param string/integer $now Time to test expiry against.
* @access public
*/
function restartSession($date = false) {
$surviving_cookies = array();
for ($i = 0; $i < count($this->_cookies); $i++) {
if (! $this->_cookies[$i]->getValue()) {
continue;
}
if (! $this->_cookies[$i]->getExpiry()) {
continue;
}
if ($date && $this->_cookies[$i]->isExpired($date)) {
continue;
}
$surviving_cookies[] = $this->_cookies[$i];
}
$this->_cookies = $surviving_cookies;
}
/**
* Ages all cookies in the cookie jar.
* @param integer $interval The old session is moved
* into the past by this number
* of seconds. Cookies now over
* age will be removed.
* @access public
*/
function agePrematurely($interval) {
for ($i = 0; $i < count($this->_cookies); $i++) {
$this->_cookies[$i]->agePrematurely($interval);
}
}
/**
* Sets an additional cookie. If a cookie has
* the same name and path it is replaced.
* @param string $name Cookie key.
* @param string $value Value of cookie.
* @param string $host Host upon which the cookie is valid.
* @param string $path Cookie path if not host wide.
* @param string $expiry Expiry date.
* @access public
*/
function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
$cookie = new SimpleCookie($name, $value, $path, $expiry);
if ($host) {
$cookie->setHost($host);
}
$this->_cookies[$this->_findFirstMatch($cookie)] = $cookie;
}
/**
* Finds a matching cookie to write over or the
* first empty slot if none.
* @param SimpleCookie $cookie Cookie to write into jar.
* @return integer Available slot.
* @access private
*/
function _findFirstMatch($cookie) {
for ($i = 0; $i < count($this->_cookies); $i++) {
$is_match = $this->_isMatch(
$cookie,
$this->_cookies[$i]->getHost(),
$this->_cookies[$i]->getPath(),
$this->_cookies[$i]->getName());
if ($is_match) {
return $i;
}
}
return count($this->_cookies);
}
/**
* Reads the most specific cookie value from the
* browser cookies. Looks for the longest path that
* matches.
* @param string $host Host to search.
* @param string $path Applicable path.
* @param string $name Name of cookie to read.
* @return string False if not present, else the
* value as a string.
* @access public
*/
function getCookieValue($host, $path, $name) {
$longest_path = '';
foreach ($this->_cookies as $cookie) {
if ($this->_isMatch($cookie, $host, $path, $name)) {
if (strlen($cookie->getPath()) > strlen($longest_path)) {
$value = $cookie->getValue();
$longest_path = $cookie->getPath();
}
}
}
return (isset($value) ? $value : false);
}
/**
* Tests cookie for matching against search
* criteria.
* @param SimpleTest $cookie Cookie to test.
* @param string $host Host must match.
* @param string $path Cookie path must be shorter than
* this path.
* @param string $name Name must match.
* @return boolean True if matched.
* @access private
*/
function _isMatch($cookie, $host, $path, $name) {
if ($cookie->getName() != $name) {
return false;
}
if ($host && $cookie->getHost() && ! $cookie->isValidHost($host)) {
return false;
}
if (! $cookie->isValidPath($path)) {
return false;
}
function setHost($host) {
if ($host = $this->_truncateHost($host)) {
$this->_host = $host;
return true;
}
/**
* Uses a URL to sift relevant cookies by host and
* path. Results are list of strings of form "name=value".
* @param SimpleUrl $url Url to select by.
* @return array Valid name and value pairs.
* @access public
*/
function selectAsPairs($url) {
$pairs = array();
foreach ($this->_cookies as $cookie) {
if ($this->_isMatch($cookie, $url->getHost(), $url->getPath(), $cookie->getName())) {
$pairs[] = $cookie->getName() . '=' . $cookie->getValue();
}
}
return $pairs;
return false;
}
/**
* Accessor for the truncated host to which this
* cookie applies.
* @return string Truncated hostname.
* @access public
*/
function getHost() {
return $this->_host;
}
/**
* Test for a cookie being valid for a host name.
* @param string $host Host to test against.
* @return boolean True if the cookie would be valid
* here.
*/
function isValidHost($host) {
return ($this->_truncateHost($host) === $this->getHost());
}
/**
* Extracts just the domain part that determines a
* cookie's host validity.
* @param string $host Host name to truncate.
* @return string Domain or false on a bad host.
* @access private
*/
function _truncateHost($host) {
$tlds = SimpleUrl::getAllTopLevelDomains();
if (preg_match('/[a-z\-]+\.(' . $tlds . ')$/i', $host, $matches)) {
return $matches[0];
} elseif (preg_match('/[a-z\-]+\.[a-z\-]+\.[a-z\-]+$/i', $host, $matches)) {
return $matches[0];
}
return false;
}
/**
* Accessor for name.
* @return string Cookie key.
* @access public
*/
function getName() {
return $this->_name;
}
/**
* Accessor for value. A deleted cookie will
* have an empty string for this.
* @return string Cookie value.
* @access public
*/
function getValue() {
return $this->_value;
}
/**
* Accessor for path.
* @return string Valid cookie path.
* @access public
*/
function getPath() {
return $this->_path;
}
/**
* Tests a path to see if the cookie applies
* there. The test path must be longer or
* equal to the cookie path.
* @param string $path Path to test against.
* @return boolean True if cookie valid here.
* @access public
*/
function isValidPath($path) {
return (strncmp(
$this->_fixPath($path),
$this->getPath(),
strlen($this->getPath())) == 0);
}
/**
* Accessor for expiry.
* @return string Expiry string.
* @access public
*/
function getExpiry() {
if (! $this->_expiry) {
return false;
}
return gmdate("D, d M Y H:i:s", $this->_expiry) . " GMT";
}
/**
* Test to see if cookie is expired against
* the cookie format time or timestamp.
* Will give true for a session cookie.
* @param integer/string $now Time to test against. Result
* will be false if this time
* is later than the cookie expiry.
* Can be either a timestamp integer
* or a cookie format date.
* @access public
*/
function isExpired($now) {
if (! $this->_expiry) {
return true;
}
if (is_string($now)) {
$now = strtotime($now);
}
return ($this->_expiry < $now);
}
/**
* Ages the cookie by the specified number of
* seconds.
* @param integer $interval In seconds.
* @public
*/
function agePrematurely($interval) {
if ($this->_expiry) {
$this->_expiry -= $interval;
}
}
/**
* Accessor for the secure flag.
* @return boolean True if cookie needs SSL.
* @access public
*/
function isSecure() {
return $this->_is_secure;
}
/**
* Adds a trailing and leading slash to the path
* if missing.
* @param string $path Path to fix.
* @access private
*/
function _fixPath($path) {
if (substr($path, 0, 1) != '/') {
$path = '/' . $path;
}
if (substr($path, -1, 1) != '/') {
$path .= '/';
}
return $path;
}
}
/**
* Repository for cookies. This stuff is a
* tiny bit browser dependent.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleCookieJar {
var $_cookies;
/**
* Constructor. Jar starts empty.
* @access public
*/
function SimpleCookieJar() {
$this->_cookies = array();
}
/**
* Removes expired and temporary cookies as if
* the browser was closed and re-opened.
* @param string/integer $now Time to test expiry against.
* @access public
*/
function restartSession($date = false) {
$surviving_cookies = array();
for ($i = 0; $i < count($this->_cookies); $i++) {
if (! $this->_cookies[$i]->getValue()) {
continue;
}
if (! $this->_cookies[$i]->getExpiry()) {
continue;
}
if ($date && $this->_cookies[$i]->isExpired($date)) {
continue;
}
$surviving_cookies[] = $this->_cookies[$i];
}
$this->_cookies = $surviving_cookies;
}
/**
* Ages all cookies in the cookie jar.
* @param integer $interval The old session is moved
* into the past by this number
* of seconds. Cookies now over
* age will be removed.
* @access public
*/
function agePrematurely($interval) {
for ($i = 0; $i < count($this->_cookies); $i++) {
$this->_cookies[$i]->agePrematurely($interval);
}
}
/**
* Sets an additional cookie. If a cookie has
* the same name and path it is replaced.
* @param string $name Cookie key.
* @param string $value Value of cookie.
* @param string $host Host upon which the cookie is valid.
* @param string $path Cookie path if not host wide.
* @param string $expiry Expiry date.
* @access public
*/
function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
$cookie = new SimpleCookie($name, $value, $path, $expiry);
if ($host) {
$cookie->setHost($host);
}
$this->_cookies[$this->_findFirstMatch($cookie)] = $cookie;
}
/**
* Finds a matching cookie to write over or the
* first empty slot if none.
* @param SimpleCookie $cookie Cookie to write into jar.
* @return integer Available slot.
* @access private
*/
function _findFirstMatch($cookie) {
for ($i = 0; $i < count($this->_cookies); $i++) {
$is_match = $this->_isMatch(
$cookie,
$this->_cookies[$i]->getHost(),
$this->_cookies[$i]->getPath(),
$this->_cookies[$i]->getName());
if ($is_match) {
return $i;
}
}
return count($this->_cookies);
}
/**
* Reads the most specific cookie value from the
* browser cookies. Looks for the longest path that
* matches.
* @param string $host Host to search.
* @param string $path Applicable path.
* @param string $name Name of cookie to read.
* @return string False if not present, else the
* value as a string.
* @access public
*/
function getCookieValue($host, $path, $name) {
$longest_path = '';
foreach ($this->_cookies as $cookie) {
if ($this->_isMatch($cookie, $host, $path, $name)) {
if (strlen($cookie->getPath()) > strlen($longest_path)) {
$value = $cookie->getValue();
$longest_path = $cookie->getPath();
}
}
}
return (isset($value) ? $value : false);
}
/**
* Tests cookie for matching against search
* criteria.
* @param SimpleTest $cookie Cookie to test.
* @param string $host Host must match.
* @param string $path Cookie path must be shorter than
* this path.
* @param string $name Name must match.
* @return boolean True if matched.
* @access private
*/
function _isMatch($cookie, $host, $path, $name) {
if ($cookie->getName() != $name) {
return false;
}
if ($host && $cookie->getHost() && ! $cookie->isValidHost($host)) {
return false;
}
if (! $cookie->isValidPath($path)) {
return false;
}
return true;
}
/**
* Uses a URL to sift relevant cookies by host and
* path. Results are list of strings of form "name=value".
* @param SimpleUrl $url Url to select by.
* @return array Valid name and value pairs.
* @access public
*/
function selectAsPairs($url) {
$pairs = array();
foreach ($this->_cookies as $cookie) {
if ($this->_isMatch($cookie, $url->getHost(), $url->getPath(), $cookie->getName())) {
$pairs[] = $cookie->getName() . '=' . $cookie->getValue();
}
}
return $pairs;
}
}
?>
+133
View File
@@ -0,0 +1,133 @@
<?php
/**
* Optional include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/simpletest.php');
require_once(dirname(__FILE__) . '/scorer.php');
require_once(dirname(__FILE__) . '/reporter.php');
require_once(dirname(__FILE__) . '/xml.php');
/**#@-*/
/**
* Parser for command line arguments. Extracts
* the a specific test to run and engages XML
* reporting when necessary.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleCommandLineParser {
var $_to_property = array(
'case' => '_case', 'c' => '_case',
'test' => '_test', 't' => '_test',
'xml' => '_xml', 'x' => '_xml');
var $_case = '';
var $_test = '';
var $_xml = false;
var $_no_skips = false;
/**
* Parses raw command line arguments into object properties.
* @param string $arguments Raw commend line arguments.
*/
function SimpleCommandLineParser($arguments) {
if (! is_array($arguments)) {
return;
}
foreach ($arguments as $i => $argument) {
if (preg_match('/^--?(test|case|t|c)=(.+)$/', $argument, $matches)) {
$property = $this->_to_property[$matches[1]];
$this->$property = $matches[2];
} elseif (preg_match('/^--?(test|case|t|c)$/', $argument, $matches)) {
$property = $this->_to_property[$matches[1]];
if (isset($arguments[$i + 1])) {
$this->$property = $arguments[$i + 1];
}
} elseif (preg_match('/^--?(xml|x)$/', $argument)) {
$this->_xml = true;
} elseif (preg_match('/^--?(no-skip|no-skips|s)$/', $argument)) {
$this->_no_skips = true;
}
}
}
/**
* Run only this test.
* @return string Test name to run.
* @access public
*/
function getTest() {
return $this->_test;
}
/**
* Run only this test suite.
* @return string Test class name to run.
* @access public
*/
function getTestCase() {
return $this->_case;
}
/**
* Output should be XML or not.
* @return boolean True if XML desired.
* @access public
*/
function isXml() {
return $this->_xml;
}
/**
* Output should suppress skip messages.
* @return boolean True for no skips.
* @access public
*/
function noSkips() {
return $this->_no_skips;
}
}
/**
* The default reporter used by SimpleTest's autorun
* feature. The actual reporters used are dependency
* injected and can be overridden.
* @package SimpleTest
* @subpackage UnitTester
*/
class DefaultReporter extends SimpleReporterDecorator {
/**
* Assembles the appopriate reporter for the environment.
*/
function DefaultReporter() {
if (SimpleReporter::inCli()) {
global $argv;
$parser = new SimpleCommandLineParser($argv);
$interfaces = $parser->isXml() ? array('XmlReporter') : array('TextReporter');
$reporter = &new SelectiveReporter(
SimpleTest::preferred($interfaces),
$parser->getTestCase(),
$parser->getTest());
if ($parser->noSkips()) {
$reporter = &new NoSkipsReporter($reporter);
}
} else {
$reporter = &new SelectiveReporter(
SimpleTest::preferred('HtmlReporter'),
@$_GET['c'],
@$_GET['t']);
if (@$_GET['skips'] == 'no' || @$_GET['show-skips'] == 'no') {
$reporter = &new NoSkipsReporter($reporter);
}
}
$this->SimpleReporterDecorator($reporter);
}
}
?>
+81 -81
View File
@@ -1,96 +1,96 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/xml.php');
require_once(dirname(__FILE__) . '/shell_tester.php');
/**#@-*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/xml.php');
require_once(dirname(__FILE__) . '/shell_tester.php');
/**#@-*/
/**
* Runs an XML formated test in a separate process.
* @package SimpleTest
* @subpackage UnitTester
*/
class DetachedTestCase {
var $_command;
var $_dry_command;
var $_size;
/**
* Runs an XML formated test in a separate process.
* @package SimpleTest
* @subpackage UnitTester
* Sets the location of the remote test.
* @param string $command Test script.
* @param string $dry_command Script for dry run.
* @access public
*/
class DetachedTestCase {
var $_command;
var $_dry_command;
var $_size;
function DetachedTestCase($command, $dry_command = false) {
$this->_command = $command;
$this->_dry_command = $dry_command ? $dry_command : $command;
$this->_size = false;
}
/**
* Sets the location of the remote test.
* @param string $command Test script.
* @param string $dry_command Script for dry run.
* @access public
*/
function DetachedTestCase($command, $dry_command = false) {
$this->_command = $command;
$this->_dry_command = $dry_command ? $dry_command : $command;
$this->_size = false;
/**
* Accessor for the test name for subclasses.
* @return string Name of the test.
* @access public
*/
function getLabel() {
return $this->_command;
}
/**
* Runs the top level test for this class. Currently
* reads the data as a single chunk. I'll fix this
* once I have added iteration to the browser.
* @param SimpleReporter $reporter Target of test results.
* @returns boolean True if no failures.
* @access public
*/
function run(&$reporter) {
$shell = &new SimpleShell();
$shell->execute($this->_command);
$parser = &$this->_createParser($reporter);
if (! $parser->parse($shell->getOutput())) {
trigger_error('Cannot parse incoming XML from [' . $this->_command . ']');
return false;
}
return true;
}
/**
* Accessor for the test name for subclasses.
* @return string Name of the test.
* @access public
*/
function getLabel() {
return $this->_command;
}
/**
* Runs the top level test for this class. Currently
* reads the data as a single chunk. I'll fix this
* once I have added iteration to the browser.
* @param SimpleReporter $reporter Target of test results.
* @returns boolean True if no failures.
* @access public
*/
function run(&$reporter) {
$shell = &new SimpleShell();
$shell->execute($this->_command);
/**
* Accessor for the number of subtests.
* @return integer Number of test cases.
* @access public
*/
function getSize() {
if ($this->_size === false) {
$shell = &new SimpleShell();
$shell->execute($this->_dry_command);
$reporter = &new SimpleReporter();
$parser = &$this->_createParser($reporter);
if (! $parser->parse($shell->getOutput())) {
trigger_error('Cannot parse incoming XML from [' . $this->_command . ']');
trigger_error('Cannot parse incoming XML from [' . $this->_dry_command . ']');
return false;
}
return true;
}
/**
* Accessor for the number of subtests.
* @return integer Number of test cases.
* @access public
*/
function getSize() {
if ($this->_size === false) {
$shell = &new SimpleShell();
$shell->execute($this->_dry_command);
$reporter = &new SimpleReporter();
$parser = &$this->_createParser($reporter);
if (! $parser->parse($shell->getOutput())) {
trigger_error('Cannot parse incoming XML from [' . $this->_dry_command . ']');
return false;
}
$this->_size = $reporter->getTestCaseCount();
}
return $this->_size;
}
/**
* Creates the XML parser.
* @param SimpleReporter $reporter Target of test results.
* @return SimpleTestXmlListener XML reader.
* @access protected
*/
function &_createParser(&$reporter) {
return new SimpleTestXmlParser($reporter);
$this->_size = $reporter->getTestCaseCount();
}
return $this->_size;
}
/**
* Creates the XML parser.
* @param SimpleReporter $reporter Target of test results.
* @return SimpleTestXmlListener XML reader.
* @access protected
*/
function &_createParser(&$reporter) {
return new SimpleTestXmlParser($reporter);
}
}
?>
+334 -334
View File
@@ -1,360 +1,360 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* does type matter
*/
if (! defined('TYPE_MATTERS')) {
define('TYPE_MATTERS', true);
}
/**
* Displays variables as text and does diffs.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleDumper {
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
* Renders a variable in a shorter form than print_r().
* @param mixed $value Variable to render as a string.
* @return string Human readable string form.
* @access public
*/
/**
* does type matter
*/
if (! defined('TYPE_MATTERS')) {
define('TYPE_MATTERS', true);
function describeValue($value) {
$type = $this->getType($value);
switch($type) {
case "Null":
return "NULL";
case "Boolean":
return "Boolean: " . ($value ? "true" : "false");
case "Array":
return "Array: " . count($value) . " items";
case "Object":
return "Object: of " . get_class($value);
case "String":
return "String: " . $this->clipString($value, 200);
default:
return "$type: $value";
}
return "Unknown";
}
/**
* Displays variables as text and does diffs.
* @package SimpleTest
* @subpackage UnitTester
* Gets the string representation of a type.
* @param mixed $value Variable to check against.
* @return string Type.
* @access public
*/
class SimpleDumper {
/**
* Renders a variable in a shorter form than print_r().
* @param mixed $value Variable to render as a string.
* @return string Human readable string form.
* @access public
*/
function describeValue($value) {
$type = $this->getType($value);
switch($type) {
case "Null":
return "NULL";
case "Boolean":
return "Boolean: " . ($value ? "true" : "false");
case "Array":
return "Array: " . count($value) . " items";
case "Object":
return "Object: of " . get_class($value);
case "String":
return "String: " . $this->clipString($value, 200);
default:
return "$type: $value";
}
return "Unknown";
}
/**
* Gets the string representation of a type.
* @param mixed $value Variable to check against.
* @return string Type.
* @access public
*/
function getType($value) {
if (! isset($value)) {
return "Null";
} elseif (is_bool($value)) {
return "Boolean";
} elseif (is_string($value)) {
return "String";
} elseif (is_integer($value)) {
return "Integer";
} elseif (is_float($value)) {
return "Float";
} elseif (is_array($value)) {
return "Array";
} elseif (is_resource($value)) {
return "Resource";
} elseif (is_object($value)) {
return "Object";
}
return "Unknown";
function getType($value) {
if (! isset($value)) {
return "Null";
} elseif (is_bool($value)) {
return "Boolean";
} elseif (is_string($value)) {
return "String";
} elseif (is_integer($value)) {
return "Integer";
} elseif (is_float($value)) {
return "Float";
} elseif (is_array($value)) {
return "Array";
} elseif (is_resource($value)) {
return "Resource";
} elseif (is_object($value)) {
return "Object";
}
return "Unknown";
}
/**
* Creates a human readable description of the
* difference between two variables. Uses a
* dynamic call.
* @param mixed $first First variable.
* @param mixed $second Value to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Description of difference.
* @access public
*/
function describeDifference($first, $second, $identical = false) {
if ($identical) {
if (! $this->_isTypeMatch($first, $second)) {
return "with type mismatch as [" . $this->describeValue($first) .
"] does not match [" . $this->describeValue($second) . "]";
}
/**
* Creates a human readable description of the
* difference between two variables. Uses a
* dynamic call.
* @param mixed $first First variable.
* @param mixed $second Value to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Description of difference.
* @access public
*/
function describeDifference($first, $second, $identical = false) {
if ($identical) {
if (! $this->_isTypeMatch($first, $second)) {
return "with type mismatch as [" . $this->describeValue($first) .
"] does not match [" . $this->describeValue($second) . "]";
}
$type = $this->getType($first);
if ($type == "Unknown") {
return "with unknown type";
}
$method = '_describe' . $type . 'Difference';
return $this->$method($first, $second, $identical);
}
/**
* Tests to see if types match.
* @param mixed $first First variable.
* @param mixed $second Value to compare with.
* @return boolean True if matches.
* @access private
*/
function _isTypeMatch($first, $second) {
return ($this->getType($first) == $this->getType($second));
$type = $this->getType($first);
if ($type == "Unknown") {
return "with unknown type";
}
$method = '_describe' . $type . 'Difference';
return $this->$method($first, $second, $identical);
}
/**
* Tests to see if types match.
* @param mixed $first First variable.
* @param mixed $second Value to compare with.
* @return boolean True if matches.
* @access private
*/
function _isTypeMatch($first, $second) {
return ($this->getType($first) == $this->getType($second));
}
/**
* Clips a string to a maximum length.
* @param string $value String to truncate.
* @param integer $size Minimum string size to show.
* @param integer $position Centre of string section.
* @return string Shortened version.
* @access public
*/
function clipString($value, $size, $position = 0) {
$length = strlen($value);
if ($length <= $size) {
return $value;
}
$position = min($position, $length);
$start = ($size/2 > $position ? 0 : $position - $size/2);
if ($start + $size > $length) {
$start = $length - $size;
}
$value = substr($value, $start, $size);
return ($start > 0 ? "..." : "") . $value . ($start + $size < $length ? "..." : "");
/**
* Clips a string to a maximum length.
* @param string $value String to truncate.
* @param integer $size Minimum string size to show.
* @param integer $position Centre of string section.
* @return string Shortened version.
* @access public
*/
function clipString($value, $size, $position = 0) {
$length = strlen($value);
if ($length <= $size) {
return $value;
}
/**
* Creates a human readable description of the
* difference between two variables. The minimal
* version.
* @param null $first First value.
* @param mixed $second Value to compare with.
* @return string Human readable description.
* @access private
*/
function _describeGenericDifference($first, $second) {
return "as [" . $this->describeValue($first) .
"] does not match [" .
$this->describeValue($second) . "]";
$position = min($position, $length);
$start = ($size/2 > $position ? 0 : $position - $size/2);
if ($start + $size > $length) {
$start = $length - $size;
}
/**
* Creates a human readable description of the
* difference between a null and another variable.
* @param null $first First null.
* @param mixed $second Null to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeNullDifference($first, $second, $identical) {
$value = substr($value, $start, $size);
return ($start > 0 ? "..." : "") . $value . ($start + $size < $length ? "..." : "");
}
/**
* Creates a human readable description of the
* difference between two variables. The minimal
* version.
* @param null $first First value.
* @param mixed $second Value to compare with.
* @return string Human readable description.
* @access private
*/
function _describeGenericDifference($first, $second) {
return "as [" . $this->describeValue($first) .
"] does not match [" .
$this->describeValue($second) . "]";
}
/**
* Creates a human readable description of the
* difference between a null and another variable.
* @param null $first First null.
* @param mixed $second Null to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeNullDifference($first, $second, $identical) {
return $this->_describeGenericDifference($first, $second);
}
/**
* Creates a human readable description of the
* difference between a boolean and another variable.
* @param boolean $first First boolean.
* @param mixed $second Boolean to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeBooleanDifference($first, $second, $identical) {
return $this->_describeGenericDifference($first, $second);
}
/**
* Creates a human readable description of the
* difference between a string and another variable.
* @param string $first First string.
* @param mixed $second String to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeStringDifference($first, $second, $identical) {
if (is_object($second) || is_array($second)) {
return $this->_describeGenericDifference($first, $second);
}
/**
* Creates a human readable description of the
* difference between a boolean and another variable.
* @param boolean $first First boolean.
* @param mixed $second Boolean to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeBooleanDifference($first, $second, $identical) {
$position = $this->_stringDiffersAt($first, $second);
$message = "at character $position";
$message .= " with [" .
$this->clipString($first, 200, $position) . "] and [" .
$this->clipString($second, 200, $position) . "]";
return $message;
}
/**
* Creates a human readable description of the
* difference between an integer and another variable.
* @param integer $first First number.
* @param mixed $second Number to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeIntegerDifference($first, $second, $identical) {
if (is_object($second) || is_array($second)) {
return $this->_describeGenericDifference($first, $second);
}
/**
* Creates a human readable description of the
* difference between a string and another variable.
* @param string $first First string.
* @param mixed $second String to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeStringDifference($first, $second, $identical) {
if (is_object($second) || is_array($second)) {
return $this->_describeGenericDifference($first, $second);
}
$position = $this->_stringDiffersAt($first, $second);
$message = "at character $position";
$message .= " with [" .
$this->clipString($first, 200, $position) . "] and [" .
$this->clipString($second, 200, $position) . "]";
return $message;
}
/**
* Creates a human readable description of the
* difference between an integer and another variable.
* @param integer $first First number.
* @param mixed $second Number to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeIntegerDifference($first, $second, $identical) {
if (is_object($second) || is_array($second)) {
return $this->_describeGenericDifference($first, $second);
}
return "because [" . $this->describeValue($first) .
"] differs from [" .
$this->describeValue($second) . "] by " .
abs($first - $second);
}
/**
* Creates a human readable description of the
* difference between two floating point numbers.
* @param float $first First float.
* @param mixed $second Float to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeFloatDifference($first, $second, $identical) {
if (is_object($second) || is_array($second)) {
return $this->_describeGenericDifference($first, $second);
}
return "because [" . $this->describeValue($first) .
"] differs from [" .
$this->describeValue($second) . "] by " .
abs($first - $second);
}
/**
* Creates a human readable description of the
* difference between two arrays.
* @param array $first First array.
* @param mixed $second Array to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeArrayDifference($first, $second, $identical) {
if (! is_array($second)) {
return $this->_describeGenericDifference($first, $second);
}
if (! $this->_isMatchingKeys($first, $second, $identical)) {
return "as key list [" .
implode(", ", array_keys($first)) . "] does not match key list [" .
implode(", ", array_keys($second)) . "]";
}
foreach (array_keys($first) as $key) {
if ($identical && ($first[$key] === $second[$key])) {
continue;
}
if (! $identical && ($first[$key] == $second[$key])) {
continue;
}
return "with member [$key] " . $this->describeDifference(
$first[$key],
$second[$key],
$identical);
}
return "";
}
/**
* Compares two arrays to see if their key lists match.
* For an identical match, the ordering and types of the keys
* is significant.
* @param array $first First array.
* @param array $second Array to compare with.
* @param boolean $identical If true then type anomolies count.
* @return boolean True if matching.
* @access private
*/
function _isMatchingKeys($first, $second, $identical) {
$first_keys = array_keys($first);
$second_keys = array_keys($second);
if ($identical) {
return ($first_keys === $second_keys);
}
sort($first_keys);
sort($second_keys);
return ($first_keys == $second_keys);
}
/**
* Creates a human readable description of the
* difference between a resource and another variable.
* @param resource $first First resource.
* @param mixed $second Resource to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeResourceDifference($first, $second, $identical) {
return "because [" . $this->describeValue($first) .
"] differs from [" .
$this->describeValue($second) . "] by " .
abs($first - $second);
}
/**
* Creates a human readable description of the
* difference between two floating point numbers.
* @param float $first First float.
* @param mixed $second Float to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeFloatDifference($first, $second, $identical) {
if (is_object($second) || is_array($second)) {
return $this->_describeGenericDifference($first, $second);
}
/**
* Creates a human readable description of the
* difference between two objects.
* @param object $first First object.
* @param mixed $second Object to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeObjectDifference($first, $second, $identical) {
if (! is_object($second)) {
return $this->_describeGenericDifference($first, $second);
return "because [" . $this->describeValue($first) .
"] differs from [" .
$this->describeValue($second) . "] by " .
abs($first - $second);
}
/**
* Creates a human readable description of the
* difference between two arrays.
* @param array $first First array.
* @param mixed $second Array to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeArrayDifference($first, $second, $identical) {
if (! is_array($second)) {
return $this->_describeGenericDifference($first, $second);
}
if (! $this->_isMatchingKeys($first, $second, $identical)) {
return "as key list [" .
implode(", ", array_keys($first)) . "] does not match key list [" .
implode(", ", array_keys($second)) . "]";
}
foreach (array_keys($first) as $key) {
if ($identical && ($first[$key] === $second[$key])) {
continue;
}
return $this->_describeArrayDifference(
get_object_vars($first),
get_object_vars($second),
if (! $identical && ($first[$key] == $second[$key])) {
continue;
}
return "with member [$key] " . $this->describeDifference(
$first[$key],
$second[$key],
$identical);
}
/**
* Find the first character position that differs
* in two strings by binary chop.
* @param string $first First string.
* @param string $second String to compare with.
* @return integer Position of first differing
* character.
* @access private
*/
function _stringDiffersAt($first, $second) {
if (! $first || ! $second) {
return 0;
}
if (strlen($first) < strlen($second)) {
list($first, $second) = array($second, $first);
}
$position = 0;
$step = strlen($first);
while ($step > 1) {
$step = (integer)(($step + 1) / 2);
if (strncmp($first, $second, $position + $step) == 0) {
$position += $step;
}
}
return $position;
}
/**
* Sends a formatted dump of a variable to a string.
* @param mixed $variable Variable to display.
* @return string Output from print_r().
* @access public
* @static
*/
function dump($variable) {
ob_start();
print_r($variable);
$formatted = ob_get_contents();
ob_end_clean();
return $formatted;
}
return "";
}
/**
* Compares two arrays to see if their key lists match.
* For an identical match, the ordering and types of the keys
* is significant.
* @param array $first First array.
* @param array $second Array to compare with.
* @param boolean $identical If true then type anomolies count.
* @return boolean True if matching.
* @access private
*/
function _isMatchingKeys($first, $second, $identical) {
$first_keys = array_keys($first);
$second_keys = array_keys($second);
if ($identical) {
return ($first_keys === $second_keys);
}
sort($first_keys);
sort($second_keys);
return ($first_keys == $second_keys);
}
/**
* Creates a human readable description of the
* difference between a resource and another variable.
* @param resource $first First resource.
* @param mixed $second Resource to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeResourceDifference($first, $second, $identical) {
return $this->_describeGenericDifference($first, $second);
}
/**
* Creates a human readable description of the
* difference between two objects.
* @param object $first First object.
* @param mixed $second Object to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
function _describeObjectDifference($first, $second, $identical) {
if (! is_object($second)) {
return $this->_describeGenericDifference($first, $second);
}
return $this->_describeArrayDifference(
get_object_vars($first),
get_object_vars($second),
$identical);
}
/**
* Find the first character position that differs
* in two strings by binary chop.
* @param string $first First string.
* @param string $second String to compare with.
* @return integer Position of first differing
* character.
* @access private
*/
function _stringDiffersAt($first, $second) {
if (! $first || ! $second) {
return 0;
}
if (strlen($first) < strlen($second)) {
list($first, $second) = array($second, $first);
}
$position = 0;
$step = strlen($first);
while ($step > 1) {
$step = (integer)(($step + 1) / 2);
if (strncmp($first, $second, $position + $step) == 0) {
$position += $step;
}
}
return $position;
}
/**
* Sends a formatted dump of a variable to a string.
* @param mixed $variable Variable to display.
* @return string Output from print_r().
* @access public
* @static
*/
function dump($variable) {
ob_start();
print_r($variable);
$formatted = ob_get_contents();
ob_end_clean();
return $formatted;
}
}
?>
+299 -62
View File
@@ -1,70 +1,307 @@
<?php
/**
* base include file for eclipse plugin
* @package SimpleTest
* @version $Id$
*/
include_once "xml.php";
include_once "invoker.php";
include_once "socket.php";
class EclipseReporter extends XmlReporter {
var $_port;
function EclipseReporter($port){
$this->_port = $port;
$this->XmlReporter();
}
function &createInvoker(&$invoker){
$eclinvoker = &new EclipseInvoker($invoker, $this->_port);
return $eclinvoker;
}
function paintMethodStart($method) {
parent::paintGroupStart($this->_group, $this->_size);
parent::paintCaseStart($this->_case);
parent::paintMethodStart($method);
}
function paintMethodEnd($method){
parent::paintMethodEnd($method);
parent::paintCaseEnd($this->_case);
parent::paintGroupEnd($this->_group);
}
function paintCaseStart($case){
$this->_case = $case;
}
function paintCaseEnd($case){
$this->_case = "";
}
function paintGroupStart($group,$size){
$this->_group = $group;
}
function paintGroupEnd($group){
$this->_group = "";
}
* base include file for eclipse plugin
* @package SimpleTest
* @subpackage Eclipse
* @version $Id$
*/
/**#@+
* simpletest include files
*/
include_once 'unit_tester.php';
include_once 'test_case.php';
include_once 'invoker.php';
include_once 'socket.php';
include_once 'mock_objects.php';
/**#@-*/
/**
* base reported class for eclipse plugin
* @package SimpleTest
* @subpackage Eclipse
*/
class EclipseReporter extends SimpleScorer {
/**
* Reporter to be run inside of Eclipse interface.
* @param object $listener Eclipse listener (?).
* @param boolean $cc Whether to include test coverage.
*/
function EclipseReporter(&$listener, $cc=false){
$this->_listener = &$listener;
$this->SimpleScorer();
$this->_case = "";
$this->_group = "";
$this->_method = "";
$this->_cc = $cc;
$this->_error = false;
$this->_fail = false;
}
/**
* Means to display human readable object comparisons.
* @return SimpleDumper Visual comparer.
*/
function getDumper() {
return new SimpleDumper();
}
/**
* Localhost connection from Eclipse.
* @param integer $port Port to connect to Eclipse.
* @param string $host Normally localhost.
* @return SimpleSocket Connection to Eclipse.
*/
function &createListener($port, $host="127.0.0.1"){
$tmplistener = &new SimpleSocket($host, $port, 5);
return $tmplistener;
}
/**
* Wraps the test in an output buffer.
* @param SimpleInvoker $invoker Current test runner.
* @return EclipseInvoker Decorator with output buffering.
* @access public
*/
function &createInvoker(&$invoker){
$eclinvoker = &new EclipseInvoker($invoker, $this->_listener);
return $eclinvoker;
}
/**
* C style escaping.
* @param string $raw String with backslashes, quotes and whitespace.
* @return string Replaced with C backslashed tokens.
*/
function escapeVal($raw){
$needle = array("\\","\"","/","\b","\f","\n","\r","\t");
$replace = array('\\\\','\"','\/','\b','\f','\n','\r','\t');
return str_replace($needle, $replace, $raw);
}
/**
* Stash the first passing item. Clicking the test
* item goes to first pass.
* @param string $message Test message, but we only wnat the first.
* @access public
*/
function paintPass($message){
if (! $this->_pass){
$this->_message = $this->escapeVal($message);
}
$this->_pass = true;
}
/**
* Stash the first failing item. Clicking the test
* item goes to first fail.
* @param string $message Test message, but we only wnat the first.
* @access public
*/
function paintFail($message){
//only get the first failure or error
if (! $this->_fail && ! $this->_error){
$this->_fail = true;
$this->_message = $this->escapeVal($message);
$this->_listener->write('{status:"fail",message:"'.$this->_message.'",group:"'.$this->_group.'",case:"'.$this->_case.'",method:"'.$this->_method.'"}');
}
}
/**
* Stash the first error. Clicking the test
* item goes to first error.
* @param string $message Test message, but we only wnat the first.
* @access public
*/
function paintError($message){
if (! $this->_fail && ! $this->_error){
$this->_error = true;
$this->_message = $this->escapeVal($message);
$this->_listener->write('{status:"error",message:"'.$this->_message.'",group:"'.$this->_group.'",case:"'.$this->_case.'",method:"'.$this->_method.'"}');
}
}
/**
* Stash the first exception. Clicking the test
* item goes to first message.
* @param string $message Test message, but we only wnat the first.
* @access public
*/
function paintException($exception){
if (! $this->_fail && ! $this->_error){
$this->_error = true;
$message = 'Unexpected exception of type[' . get_class($exception) .
'] with message [' . $exception->getMessage() . '] in [' .
$exception->getFile() .' line '. $exception->getLine() . ']';
$this->_message = $this->escapeVal($message);
$this->_listener->write(
'{status:"error",message:"' . $this->_message . '",group:"' .
$this->_group . '",case:"' . $this->_case . '",method:"' . $this->_method
. '"}');
}
}
/**
* We don't display any special header.
* @param string $test_name First test top level
* to start.
* @access public
*/
function paintHeader($test_name) {
}
/**
* We don't display any special footer.
* @param string $test_name The top level test.
* @access public
*/
function paintFooter($test_name) {
}
/**
* Paints nothing at the start of a test method, but stash
* the method name for later.
* @param string $test_name Name of test that is starting.
* @access public
*/
function paintMethodStart($method) {
$this->_pass = false;
$this->_fail = false;
$this->_error = false;
$this->_method = $this->escapeVal($method);
}
/**
* Only send one message if the test passes, after that
* suppress the message.
* @param string $test_name Name of test that is ending.
* @access public
*/
function paintMethodEnd($method){
if ($this->_fail || $this->_error || ! $this->_pass){
} else {
$this->_listener->write(
'{status:"pass",message:"' . $this->_message . '",group:"' .
$this->_group . '",case:"' . $this->_case . '",method:"' .
$this->_method . '"}');
}
}
/**
* Stashes the test case name for the later failure message.
* @param string $test_name Name of test or other label.
* @access public
*/
function paintCaseStart($case){
$this->_case = $this->escapeVal($case);
}
/**
* Drops the name.
* @param string $test_name Name of test or other label.
* @access public
*/
function paintCaseEnd($case){
$this->_case = "";
}
/**
* Stashes the name of the test suite. Starts test coverage
* if enabled.
* @param string $group Name of test or other label.
* @param integer $size Number of test cases starting.
* @access public
*/
function paintGroupStart($group, $size){
$this->_group = $this->escapeVal($group);
if ($this->_cc){
if (extension_loaded('xdebug')){
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
}
}
}
/**
* Paints coverage report if enabled.
* @param string $group Name of test or other label.
* @access public
*/
function paintGroupEnd($group){
$this->_group = "";
$cc = "";
if ($this->_cc){
if (extension_loaded('xdebug')){
$arrfiles = xdebug_get_code_coverage();
xdebug_stop_code_coverage();
$thisdir = dirname(__FILE__);
$thisdirlen = strlen($thisdir);
foreach ($arrfiles as $index=>$file){
if (substr($index, 0, $thisdirlen)===$thisdir){
continue;
}
$lcnt = 0;
$ccnt = 0;
foreach ($file as $line){
if ($line == -2){
continue;
}
$lcnt++;
if ($line==1){
$ccnt++;
}
}
if ($lcnt > 0){
$cc .= round(($ccnt/$lcnt) * 100, 2) . '%';
}else{
$cc .= "0.00%";
}
$cc.= "\t". $index . "\n";
}
}
}
$this->_listener->write('{status:"coverage",message:"' .
EclipseReporter::escapeVal($cc) . '"}');
}
}
/**
* Invoker decorator for Eclipse. Captures output until
* the end of the test.
* @package SimpleTest
* @subpackage Eclipse
*/
class EclipseInvoker extends SimpleInvokerDecorator{
var $_port;
function EclipseInvoker(&$invoker,$port) {
$this->_port = $port;
$this->SimpleInvokerDecorator($invoker);
}
function invoke($method) {
ob_start();
parent::invoke($method);
$output = ob_get_contents();
ob_end_clean();
function EclipseInvoker(&$invoker, &$listener) {
$this->_listener = &$listener;
$this->SimpleInvokerDecorator($invoker);
}
/**
* Starts output buffering.
* @param string $method Test method to call.
* @access public
*/
function before($method){
ob_start();
$this->_invoker->before($method);
}
$sock = new SimpleSocket("127.0.0.1",$this->_port,5);
$sock->write($output);
$sock->close();
echo $sock->getError();
}
/**
* Stops output buffering and send the captured output
* to the listener.
* @param string $method Test method to call.
* @access public
*/
function after($method) {
$this->_invoker->after($method);
$output = ob_get_contents();
ob_end_clean();
if ($output !== ""){
$result = $this->_listener->write('{status:"info",message:"' .
EclipseReporter::escapeVal($output) . '"}');
}
}
}
?>
File diff suppressed because it is too large Load Diff
+275 -233
View File
@@ -1,246 +1,288 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/** @ignore - PHP5 compatibility fix. */
if (! defined('E_STRICT')) {
define('E_STRICT', 2048);
}
/**
* @ignore - PHP5 compatibility fix.
*/
if (! defined('E_STRICT')) {
define('E_STRICT', 2048);
}
/**#@+
* Includes SimpleTest files.
*/
require_once(dirname(__FILE__) . '/invoker.php');
require_once(dirname(__FILE__) . '/test_case.php');
require_once(dirname(__FILE__) . '/expectation.php');
/**#@+
* 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.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleErrorTrappingInvoker extends SimpleInvokerDecorator {
/**
* Extension that traps errors into an error queue.
* @package SimpleTest
* @subpackage UnitTester
* Stores the invoker to wrap.
* @param SimpleInvoker $invoker Test method runner.
*/
class SimpleErrorTrappingInvoker extends SimpleInvokerDecorator {
/**
* Stores the invoker to wrap.
* @param SimpleInvoker $invoker Test method runner.
*/
function SimpleErrorTrappingInvoker(&$invoker) {
$this->SimpleInvokerDecorator($invoker);
}
/**
* Invokes a test method and dispatches any
* untrapped errors. Called back from
* the visiting runner.
* @param string $method Test method to call.
* @access public
*/
function invoke($method) {
$context = &SimpleTest::getContext();
$queue = &$context->get('SimpleErrorQueue');
$queue->setTestCase($this->GetTestCase());
set_error_handler('SimpleTestErrorHandler');
parent::invoke($method);
while (list($severity, $message, $file, $line) = $queue->extract()) {
$severity = SimpleErrorQueue::getSeverityAsString($severity);
$test = &$this->getTestCase();
$test->error($severity, $message, $file, $line);
}
restore_error_handler();
}
function SimpleErrorTrappingInvoker(&$invoker) {
$this->SimpleInvokerDecorator($invoker);
}
/**
* Singleton error queue used to record trapped
* errors.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleErrorQueue {
var $_queue;
var $_expectation_queue;
var $_test;
/**
* Starts with an empty queue.
*/
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 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, $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);
}
}
/**
* Pulls the earliest error from the queue.
* @return False if none, or a list of error
* information. Elements are: severity
* as the PHP error code, the error message,
* the file with the error, the line number
* and a list of PHP super global arrays.
* @access public
*/
function extract() {
if (count($this->_queue)) {
return array_shift($this->_queue);
}
return false;
}
/**
* Discards the contents of the error queue.
* @access public
*/
function clear() {
$this->_queue = array();
$this->_expectation_queue = array();
}
/**
* @deprecated
*/
function assertNoErrors($message) {
return $this->_test->assert(
new TrueExpectation(),
count($this->_queue) == 0,
sprintf($message, 'Should be no errors'));
}
/**
* @deprecated
*/
function assertError($expected, $message) {
if (count($this->_queue) == 0) {
$this->_test->fail(sprintf($message, 'Expected error not found'));
return false;
}
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));
}
/**
* Converts an error code into it's string
* representation.
* @param $severity PHP integer error code.
* @return String version of error code.
* @access public
* @static
*/
function getSeverityAsString($severity) {
static $map = array(
E_STRICT => 'E_STRICT',
E_ERROR => 'E_ERROR',
E_WARNING => 'E_WARNING',
E_PARSE => 'E_PARSE',
E_NOTICE => 'E_NOTICE',
E_CORE_ERROR => 'E_CORE_ERROR',
E_CORE_WARNING => 'E_CORE_WARNING',
E_COMPILE_ERROR => 'E_COMPILE_ERROR',
E_COMPILE_WARNING => 'E_COMPILE_WARNING',
E_USER_ERROR => 'E_USER_ERROR',
E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE');
if (!isset($map[$severity])) {
debug_print_backtrace();
die();
}
return $map[$severity];
}
}
/**
* Error handler that simply stashes any errors into the global
* error queue. Simulates the existing behaviour with respect to
* logging errors, but this feature may be removed in future.
* @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.
* @static
* Invokes a test method and dispatches any
* untrapped errors. Called back from
* the visiting runner.
* @param string $method Test method to call.
* @access public
*/
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");
}
$context = &SimpleTest::getContext();
$queue = &$context->get('SimpleErrorQueue');
$queue->add($severity, $message, $filename, $line);
set_error_handler('SimpleTestErrorHandler');
function invoke($method) {
$queue = &$this->_createErrorQueue();
set_error_handler('SimpleTestErrorHandler');
parent::invoke($method);
restore_error_handler();
$queue->tally();
}
/**
* Wires up the error queue for a single test.
* @return SimpleErrorQueue Queue connected to the test.
* @access private
*/
function &_createErrorQueue() {
$context = &SimpleTest::getContext();
$test = &$this->getTestCase();
$queue = &$context->get('SimpleErrorQueue');
$queue->setTestCase($test);
return $queue;
}
}
/**
* Error queue used to record trapped
* errors.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleErrorQueue {
var $_queue;
var $_expectation_queue;
var $_test;
var $_using_expect_style = false;
/**
* Starts with an empty queue.
*/
function SimpleErrorQueue() {
$this->clear();
}
/**
* Discards the contents of the error queue.
* @access public
*/
function clear() {
$this->_queue = array();
$this->_expectation_queue = array();
}
/**
* Sets the currently running test case.
* @param SimpleTestCase $test Test case to send messages to.
* @access public
*/
function setTestCase(&$test) {
$this->_test = &$test;
}
/**
* 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) {
$this->_using_expect_style = true;
array_push($this->_expectation_queue, array($expected, $message));
}
/**
* Adds an error to the front of the queue.
* @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, $content, $filename, $line) {
$content = str_replace('%', '%%', $content);
if ($this->_using_expect_style) {
$this->_testLatestError($severity, $content, $filename, $line);
} else {
array_push(
$this->_queue,
array($severity, $content, $filename, $line));
}
}
?>
/**
* Any errors still in the queue are sent to the test
* case. Any unfulfilled expectations trigger failures.
* @access public
*/
function tally() {
while (list($severity, $message, $file, $line) = $this->extract()) {
$severity = $this->getSeverityAsString($severity);
$this->_test->error($severity, $message, $file, $line);
}
while (list($expected, $message) = $this->_extractExpectation()) {
$this->_test->assert($expected, false, "%s -> Expected error not caught");
}
}
/**
* 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) {
if ($expectation = $this->_extractExpectation()) {
list($expected, $message) = $expectation;
$this->_test->assert($expected, $content, sprintf(
$message,
"%s -> PHP error [$content] severity [" .
$this->getSeverityAsString($severity) .
"] in [$filename] line [$line]"));
} else {
$this->_test->error($severity, $content, $filename, $line);
}
}
/**
* Pulls the earliest error from the queue.
* @return mixed False if none, or a list of error
* information. Elements are: severity
* as the PHP error code, the error message,
* the file with the error, the line number
* and a list of PHP super global arrays.
* @access public
*/
function extract() {
if (count($this->_queue)) {
return array_shift($this->_queue);
}
return false;
}
/**
* Pulls the earliest expectation from the queue.
* @return SimpleExpectation False if none.
* @access private
*/
function _extractExpectation() {
if (count($this->_expectation_queue)) {
return array_shift($this->_expectation_queue);
}
return false;
}
/**
* @deprecated
*/
function assertNoErrors($message) {
return $this->_test->assert(
new TrueExpectation(),
count($this->_queue) == 0,
sprintf($message, 'Should be no errors'));
}
/**
* @deprecated
*/
function assertError($expected, $message) {
if (count($this->_queue) == 0) {
$this->_test->fail(sprintf($message, 'Expected error not found'));
return false;
}
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]"));
}
/**
* Converts an error code into it's string
* representation.
* @param $severity PHP integer error code.
* @return String version of error code.
* @access public
* @static
*/
function getSeverityAsString($severity) {
static $map = array(
E_STRICT => 'E_STRICT',
E_ERROR => 'E_ERROR',
E_WARNING => 'E_WARNING',
E_PARSE => 'E_PARSE',
E_NOTICE => 'E_NOTICE',
E_CORE_ERROR => 'E_CORE_ERROR',
E_CORE_WARNING => 'E_CORE_WARNING',
E_COMPILE_ERROR => 'E_COMPILE_ERROR',
E_COMPILE_WARNING => 'E_COMPILE_WARNING',
E_USER_ERROR => 'E_USER_ERROR',
E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE');
if (defined('E_RECOVERABLE_ERROR')) {
$map[E_RECOVERABLE_ERROR] = 'E_RECOVERABLE_ERROR';
}
if (defined('E_DEPRECATED')) {
$map[E_DEPRECATED] = 'E_DEPRECATED';
}
return $map[$severity];
}
}
/**
* Error handler that simply stashes any errors into the global
* error queue. Simulates the existing behaviour with respect to
* logging errors, but this feature may be removed in future.
* @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.
* @static
* @access public
*/
function SimpleTestErrorHandler($severity, $message, $filename = null, $line = null, $super_globals = null, $mask = null) {
$severity = $severity & error_reporting();
if ($severity) {
restore_error_handler();
if (ini_get('log_errors')) {
$label = SimpleErrorQueue::getSeverityAsString($severity);
error_log("$label: $message in $filename on line $line");
}
$context = &SimpleTest::getContext();
$queue = &$context->get('SimpleErrorQueue');
$queue->add($severity, $message, $filename, $line);
set_error_handler('SimpleTestErrorHandler');
}
return true;
}
?>
+174 -167
View File
@@ -1,191 +1,198 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**#@+
* Includes SimpleTest files and defined the root constant
* for dependent libraries.
*/
require_once(dirname(__FILE__) . '/invoker.php');
require_once(dirname(__FILE__) . '/expectation.php');
/**#@+
* Include required SimpleTest files
*/
require_once dirname(__FILE__) . '/invoker.php';
require_once dirname(__FILE__) . '/expectation.php';
/**#@-*/
/**
* Extension that traps exceptions and turns them into
* an error message. PHP5 only.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleExceptionTrappingInvoker extends SimpleInvokerDecorator {
/**
* Extension that traps exceptions and turns them into
* an error message. PHP5 only.
* @package SimpleTest
* @subpackage UnitTester
* Stores the invoker to be wrapped.
* @param SimpleInvoker $invoker Test method runner.
*/
class SimpleExceptionTrappingInvoker extends SimpleInvokerDecorator {
function SimpleExceptionTrappingInvoker($invoker) {
$this->SimpleInvokerDecorator($invoker);
}
/**
* Stores the invoker to be wrapped.
* @param SimpleInvoker $invoker Test method runner.
*/
function SimpleExceptionTrappingInvoker($invoker) {
$this->SimpleInvokerDecorator($invoker);
}
/**
* 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.
*/
function invoke($method) {
$trap = SimpleTest::getContext()->get('SimpleExceptionTrap');
/**
* 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.
*/
function invoke($method) {
$trap = SimpleTest::getContext()->get('SimpleExceptionTrap');
$trap->clear();
try {
$has_thrown = false;
parent::invoke($method);
} catch (Exception $exception) {
$has_thrown = true;
if (! $trap->isExpected($this->getTestCase(), $exception)) {
$this->getTestCase()->exception($exception);
}
$trap->clear();
}
if ($message = $trap->getOutstanding()) {
$this->getTestCase()->fail($message);
}
if ($has_thrown) {
try {
parent::invoke($method);
} catch (Exception $exception) {
if (! $trap->isExpected($this->getTestCase(), $exception)) {
$this->getTestCase()->exception($exception);
}
$trap->clear();
}
if ($message = $trap->getOutstanding()) {
$this->getTestCase()->fail($message);
}
parent::getTestCase()->tearDown();
} catch (Exception $e) { }
}
}
}
/**
* 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);
}
/**
* 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
* Carry out the test.
* @param Exception $compare Value to check.
* @return boolean True if matched.
*/
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);
function test($compare) {
if (is_string($this->expected)) {
return ($compare instanceof $this->expected);
}
/**
* 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();
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 . "]";
}
/**
* 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 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();
"] should be type [" . $this->expected . "]";
}
return "Exception [" . $this->describeException($compare) .
"] should match [" .
$this->describeException($this->expected) . "]";
}
/**
* Stores expected exceptions for when they
* get thrown. Saves the irritating try...catch
* block.
* @package SimpleTest
* @subpackage UnitTester
* Summary of an Exception object.
* @param Exception $compare Exception to describe.
* @return string Text description.
*/
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;
}
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;
}
}
?>
File diff suppressed because it is too large Load Diff
@@ -26,7 +26,7 @@
* @param $label Test name to display.
* @public
*/
function TestCase($label) {
function TestCase($label = false) {
$this->SimpleTestCase($label);
}
+42
View File
@@ -0,0 +1,42 @@
<?php
class TestDoxReporter extends SimpleReporter
{
var $_test_case_pattern = '/^TestOf(.*)$/';
function TestDoxReporter($test_case_pattern = '/^TestOf(.*)$/') {
parent::SimpleScorer();
$this->_test_case_pattern = empty($test_case_pattern) ? '/^(.*)$/' : $test_case_pattern;
}
function paintCaseStart($test_name) {
preg_match($this->_test_case_pattern, $test_name, $matches);
if (!empty($matches[1])) {
echo $matches[1] . "\n";
} else {
echo $test_name . "\n";
}
}
function paintCaseEnd() {
echo "\n";
}
function paintMethodStart($test_name) {
if (!preg_match('/^test(.*)$/i', $test_name, $matches)) {
return;
}
$test_name = $matches[1];
$test_name = preg_replace('/([A-Z])([A-Z])/', '$1 $2', $test_name);
echo '- ' . strtolower(preg_replace('/([a-zA-Z])([A-Z0-9])/', '$1 $2', $test_name));
}
function paintMethodEnd() {
echo "\n";
}
function paintFail() {
echo " [FAILED]";
}
}
@@ -0,0 +1,108 @@
<?php
// $Id$
require_once dirname(__FILE__) . '/../../autorun.php';
require_once dirname(__FILE__) . '/../testdox.php';
// uncomment to see test dox in action
//SimpleTest::prefer(new TestDoxReporter());
class TestOfTestDoxReporter extends UnitTestCase
{
function testIsAnInstanceOfSimpleScorerAndReporter() {
$dox = new TestDoxReporter();
$this->assertIsA($dox, 'SimpleScorer');
$this->assertIsA($dox, 'SimpleReporter');
}
function testOutputsNameOfTestCase() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintCaseStart('TestOfTestDoxReporter');
$buffer = ob_get_clean();
$this->assertWantedPattern('/^TestDoxReporter/', $buffer);
}
function testOutputOfTestCaseNameFilteredByConstructParameter() {
$dox = new TestDoxReporter('/^(.*)Test$/');
ob_start();
$dox->paintCaseStart('SomeGreatWidgetTest');
$buffer = ob_get_clean();
$this->assertWantedPattern('/^SomeGreatWidget/', $buffer);
}
function testIfTest_case_patternIsEmptyAssumeEverythingMatches() {
$dox = new TestDoxReporter('');
ob_start();
$dox->paintCaseStart('TestOfTestDoxReporter');
$buffer = ob_get_clean();
$this->assertWantedPattern('/^TestOfTestDoxReporter/', $buffer);
}
function testEmptyLineInsertedWhenCaseEnds() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintCaseEnd('TestOfTestDoxReporter');
$buffer = ob_get_clean();
$this->assertEqual("\n", $buffer);
}
function testPaintsTestMethodInTestDoxFormat() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintMethodStart('testSomeGreatTestCase');
$buffer = ob_get_clean();
$this->assertEqual("- some great test case", $buffer);
unset($buffer);
$random = rand(100, 200);
ob_start();
$dox->paintMethodStart("testRandomNumberIs{$random}");
$buffer = ob_get_clean();
$this->assertEqual("- random number is {$random}", $buffer);
}
function testDoesNotOutputAnythingOnNoneTestMethods() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintMethodStart('nonMatchingMethod');
$buffer = ob_get_clean();
$this->assertEqual('', $buffer);
}
function testPaintMethodAddLineBreak() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintMethodEnd('someMethod');
$buffer = ob_get_clean();
$this->assertEqual("\n", $buffer);
$this->assertNoErrors();
}
function testProperlySpacesSingleLettersInMethodName() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintMethodStart('testAVerySimpleAgainAVerySimpleMethod');
$buffer = ob_get_clean();
$this->assertEqual('- a very simple again a very simple method', $buffer);
}
function testOnFailureThisPrintsFailureNotice() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintFail();
$buffer = ob_get_clean();
$this->assertEqual(' [FAILED]', $buffer);
}
function testWhenMatchingMethodNamesTestPrefixIsCaseInsensitive() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintMethodStart('TESTSupportsAllUppercaseTestPrefixEvenThoughIDoNotKnowWhyYouWouldDoThat');
$buffer = ob_get_clean();
$this->assertEqual(
'- supports all uppercase test prefix even though i do not know why you would do that',
$buffer
);
}
}
+331 -328
View File
@@ -1,352 +1,355 @@
<?php
/**
* Base include file for SimpleTest.
* @package SimpleTest
* @subpackage WebTester
* @version $Id$
*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/tag.php');
require_once(dirname(__FILE__) . '/encoding.php');
require_once(dirname(__FILE__) . '/selector.php');
/**#@-*/
/**
* Base include file for SimpleTest.
* @package SimpleTest
* @subpackage WebTester
* @version $Id$
*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/tag.php');
require_once(dirname(__FILE__) . '/encoding.php');
require_once(dirname(__FILE__) . '/selector.php');
/**#@-*/
/**
* Form tag class to hold widget values.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleForm {
var $_method;
var $_action;
var $_encoding;
var $_default_target;
var $_id;
var $_buttons;
var $_images;
var $_widgets;
var $_radios;
var $_checkboxes;
/**
* Form tag class to hold widget values.
* @package SimpleTest
* @subpackage WebTester
* Starts with no held controls/widgets.
* @param SimpleTag $tag Form tag to read.
* @param SimplePage $page Holding page.
*/
class SimpleForm {
var $_method;
var $_action;
var $_encoding;
var $_default_target;
var $_id;
var $_buttons;
var $_images;
var $_widgets;
var $_radios;
var $_checkboxes;
/**
* Starts with no held controls/widgets.
* @param SimpleTag $tag Form tag to read.
* @param SimpleUrl $url Location of holding page.
*/
function SimpleForm($tag, $url) {
$this->_method = $tag->getAttribute('method');
$this->_action = $this->_createAction($tag->getAttribute('action'), $url);
$this->_encoding = $this->_setEncodingClass($tag);
$this->_default_target = false;
$this->_id = $tag->getAttribute('id');
$this->_buttons = array();
$this->_images = array();
$this->_widgets = array();
$this->_radios = array();
$this->_checkboxes = array();
}
/**
* Creates the request packet to be sent by the form.
* @param SimpleTag $tag Form tag to read.
* @return string Packet class.
* @access private
*/
function _setEncodingClass($tag) {
if (strtolower($tag->getAttribute('method')) == 'post') {
if (strtolower($tag->getAttribute('enctype')) == 'multipart/form-data') {
return 'SimpleMultipartEncoding';
}
return 'SimplePostEncoding';
function SimpleForm($tag, &$page) {
$this->_method = $tag->getAttribute('method');
$this->_action = $this->_createAction($tag->getAttribute('action'), $page);
$this->_encoding = $this->_setEncodingClass($tag);
$this->_default_target = false;
$this->_id = $tag->getAttribute('id');
$this->_buttons = array();
$this->_images = array();
$this->_widgets = array();
$this->_radios = array();
$this->_checkboxes = array();
}
/**
* Creates the request packet to be sent by the form.
* @param SimpleTag $tag Form tag to read.
* @return string Packet class.
* @access private
*/
function _setEncodingClass($tag) {
if (strtolower($tag->getAttribute('method')) == 'post') {
if (strtolower($tag->getAttribute('enctype')) == 'multipart/form-data') {
return 'SimpleMultipartEncoding';
}
return 'SimpleGetEncoding';
return 'SimplePostEncoding';
}
/**
* Sets the frame target within a frameset.
* @param string $frame Name of frame.
* @access public
*/
function setDefaultTarget($frame) {
$this->_default_target = $frame;
return 'SimpleGetEncoding';
}
/**
* Sets the frame target within a frameset.
* @param string $frame Name of frame.
* @access public
*/
function setDefaultTarget($frame) {
$this->_default_target = $frame;
}
/**
* Accessor for method of form submission.
* @return string Either get or post.
* @access public
*/
function getMethod() {
return ($this->_method ? strtolower($this->_method) : 'get');
}
/**
* Combined action attribute with current location
* to get an absolute form target.
* @param string $action Action attribute from form tag.
* @param SimpleUrl $base Page location.
* @return SimpleUrl Absolute form target.
*/
function _createAction($action, &$page) {
if (($action === '') || ($action === false)) {
return $page->expandUrl($page->getUrl());
}
/**
* Accessor for method of form submission.
* @return string Either get or post.
* @access public
*/
function getMethod() {
return ($this->_method ? strtolower($this->_method) : 'get');
return $page->expandUrl(new SimpleUrl($action));;
}
/**
* Absolute URL of the target.
* @return SimpleUrl URL target.
* @access public
*/
function getAction() {
$url = $this->_action;
if ($this->_default_target && ! $url->getTarget()) {
$url->setTarget($this->_default_target);
}
/**
* Combined action attribute with current location
* to get an absolute form target.
* @param string $action Action attribute from form tag.
* @param SimpleUrl $base Page location.
* @return SimpleUrl Absolute form target.
*/
function _createAction($action, $base) {
if (($action === '') || ($action === false)) {
return $base;
return $url;
}
/**
* Creates the encoding for the current values in the
* form.
* @return SimpleFormEncoding Request to submit.
* @access private
*/
function _encode() {
$class = $this->_encoding;
$encoding = new $class();
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
$this->_widgets[$i]->write($encoding);
}
return $encoding;
}
/**
* ID field of form for unique identification.
* @return string Unique tag ID.
* @access public
*/
function getId() {
return $this->_id;
}
/**
* Adds a tag contents to the form.
* @param SimpleWidget $tag Input tag to add.
* @access public
*/
function addWidget(&$tag) {
if (strtolower($tag->getAttribute('type')) == 'submit') {
$this->_buttons[] = &$tag;
} elseif (strtolower($tag->getAttribute('type')) == 'image') {
$this->_images[] = &$tag;
} elseif ($tag->getName()) {
$this->_setWidget($tag);
}
}
/**
* Sets the widget into the form, grouping radio
* buttons if any.
* @param SimpleWidget $tag Incoming form control.
* @access private
*/
function _setWidget(&$tag) {
if (strtolower($tag->getAttribute('type')) == 'radio') {
$this->_addRadioButton($tag);
} elseif (strtolower($tag->getAttribute('type')) == 'checkbox') {
$this->_addCheckbox($tag);
} else {
$this->_widgets[] = &$tag;
}
}
/**
* Adds a radio button, building a group if necessary.
* @param SimpleRadioButtonTag $tag Incoming form control.
* @access private
*/
function _addRadioButton(&$tag) {
if (! isset($this->_radios[$tag->getName()])) {
$this->_widgets[] = &new SimpleRadioGroup();
$this->_radios[$tag->getName()] = count($this->_widgets) - 1;
}
$this->_widgets[$this->_radios[$tag->getName()]]->addWidget($tag);
}
/**
* Adds a checkbox, making it a group on a repeated name.
* @param SimpleCheckboxTag $tag Incoming form control.
* @access private
*/
function _addCheckbox(&$tag) {
if (! isset($this->_checkboxes[$tag->getName()])) {
$this->_widgets[] = &$tag;
$this->_checkboxes[$tag->getName()] = count($this->_widgets) - 1;
} else {
$index = $this->_checkboxes[$tag->getName()];
if (! SimpleTestCompatibility::isA($this->_widgets[$index], 'SimpleCheckboxGroup')) {
$previous = &$this->_widgets[$index];
$this->_widgets[$index] = &new SimpleCheckboxGroup();
$this->_widgets[$index]->addWidget($previous);
}
$url = new SimpleUrl($action);
return $url->makeAbsolute($base);
$this->_widgets[$index]->addWidget($tag);
}
/**
* Absolute URL of the target.
* @return SimpleUrl URL target.
* @access public
*/
function getAction() {
$url = $this->_action;
if ($this->_default_target && ! $url->getTarget()) {
$url->setTarget($this->_default_target);
}
return $url;
}
/**
* Creates the encoding for the current values in the
* form.
* @return SimpleFormEncoding Request to submit.
* @access private
*/
function _encode() {
$class = $this->_encoding;
$encoding = new $class();
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
$this->_widgets[$i]->write($encoding);
}
return $encoding;
}
/**
* ID field of form for unique identification.
* @return string Unique tag ID.
* @access public
*/
function getId() {
return $this->_id;
}
/**
* Adds a tag contents to the form.
* @param SimpleWidget $tag Input tag to add.
* @access public
*/
function addWidget(&$tag) {
if (strtolower($tag->getAttribute('type')) == 'submit') {
$this->_buttons[] = &$tag;
} elseif (strtolower($tag->getAttribute('type')) == 'image') {
$this->_images[] = &$tag;
} elseif ($tag->getName()) {
$this->_setWidget($tag);
}
/**
* Extracts current value from form.
* @param SimpleSelector $selector Criteria to apply.
* @return string/array Value(s) as string or null
* if not set.
* @access public
*/
function getValue($selector) {
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
if ($selector->isMatch($this->_widgets[$i])) {
return $this->_widgets[$i]->getValue();
}
}
/**
* Sets the widget into the form, grouping radio
* buttons if any.
* @param SimpleWidget $tag Incoming form control.
* @access private
*/
function _setWidget(&$tag) {
if (strtolower($tag->getAttribute('type')) == 'radio') {
$this->_addRadioButton($tag);
} elseif (strtolower($tag->getAttribute('type')) == 'checkbox') {
$this->_addCheckbox($tag);
} else {
$this->_widgets[] = &$tag;
foreach ($this->_buttons as $button) {
if ($selector->isMatch($button)) {
return $button->getValue();
}
}
/**
* Adds a radio button, building a group if necessary.
* @param SimpleRadioButtonTag $tag Incoming form control.
* @access private
*/
function _addRadioButton(&$tag) {
if (! isset($this->_radios[$tag->getName()])) {
$this->_widgets[] = &new SimpleRadioGroup();
$this->_radios[$tag->getName()] = count($this->_widgets) - 1;
}
$this->_widgets[$this->_radios[$tag->getName()]]->addWidget($tag);
}
/**
* Adds a checkbox, making it a group on a repeated name.
* @param SimpleCheckboxTag $tag Incoming form control.
* @access private
*/
function _addCheckbox(&$tag) {
if (! isset($this->_checkboxes[$tag->getName()])) {
$this->_widgets[] = &$tag;
$this->_checkboxes[$tag->getName()] = count($this->_widgets) - 1;
} else {
$index = $this->_checkboxes[$tag->getName()];
if (! SimpleTestCompatibility::isA($this->_widgets[$index], 'SimpleCheckboxGroup')) {
$previous = &$this->_widgets[$index];
$this->_widgets[$index] = &new SimpleCheckboxGroup();
$this->_widgets[$index]->addWidget($previous);
}
$this->_widgets[$index]->addWidget($tag);
}
}
/**
* Extracts current value from form.
* @param SimpleSelector $selector Criteria to apply.
* @return string/array Value(s) as string or null
* if not set.
* @access public
*/
function getValue($selector) {
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
if ($selector->isMatch($this->_widgets[$i])) {
return $this->_widgets[$i]->getValue();
}
}
foreach ($this->_buttons as $button) {
if ($selector->isMatch($button)) {
return $button->getValue();
}
}
return null;
}
/**
* Sets a widget value within the form.
* @param SimpleSelector $selector Criteria to apply.
* @param string $value Value to input into the widget.
* @return boolean True if value is legal, false
* otherwise. If the field is not
* present, nothing will be set.
* @access public
*/
function setField($selector, $value) {
$success = false;
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
if ($selector->isMatch($this->_widgets[$i])) {
return null;
}
/**
* Sets a widget value within the form.
* @param SimpleSelector $selector Criteria to apply.
* @param string $value Value to input into the widget.
* @return boolean True if value is legal, false
* otherwise. If the field is not
* present, nothing will be set.
* @access public
*/
function setField($selector, $value, $position=false) {
$success = false;
$_position = 0;
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
if ($selector->isMatch($this->_widgets[$i])) {
$_position++;
if ($position === false or $_position === (int)$position) {
if ($this->_widgets[$i]->setValue($value)) {
$success = true;
}
}
}
return $success;
}
/**
* Used by the page object to set widgets labels to
* external label tags.
* @param SimpleSelector $selector Criteria to apply.
* @access public
*/
function attachLabelBySelector($selector, $label) {
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
if ($selector->isMatch($this->_widgets[$i])) {
if (method_exists($this->_widgets[$i], 'setLabel')) {
$this->_widgets[$i]->setLabel($label);
return;
}
return $success;
}
/**
* Used by the page object to set widgets labels to
* external label tags.
* @param SimpleSelector $selector Criteria to apply.
* @access public
*/
function attachLabelBySelector($selector, $label) {
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
if ($selector->isMatch($this->_widgets[$i])) {
if (method_exists($this->_widgets[$i], 'setLabel')) {
$this->_widgets[$i]->setLabel($label);
return;
}
}
}
/**
* Test to see if a form has a submit button.
* @param SimpleSelector $selector Criteria to apply.
* @return boolean True if present.
* @access public
*/
function hasSubmit($selector) {
foreach ($this->_buttons as $button) {
if ($selector->isMatch($button)) {
return true;
}
}
return false;
}
/**
* Test to see if a form has an image control.
* @param SimpleSelector $selector Criteria to apply.
* @return boolean True if present.
* @access public
*/
function hasImage($selector) {
foreach ($this->_images as $image) {
if ($selector->isMatch($image)) {
return true;
}
}
return false;
}
/**
* Gets the submit values for a selected button.
* @param SimpleSelector $selector Criteria to apply.
* @param hash $additional Additional data for the form.
* @return SimpleEncoding Submitted values or false
* if there is no such button
* in the form.
* @access public
*/
function submitButton($selector, $additional = false) {
$additional = $additional ? $additional : array();
foreach ($this->_buttons as $button) {
if ($selector->isMatch($button)) {
$encoding = $this->_encode();
$button->write($encoding);
if ($additional) {
$encoding->merge($additional);
}
return $encoding;
}
}
return false;
}
/**
* Gets the submit values for an image.
* @param SimpleSelector $selector Criteria to apply.
* @param integer $x X-coordinate of click.
* @param integer $y Y-coordinate of click.
* @param hash $additional Additional data for the form.
* @return SimpleEncoding Submitted values or false
* if there is no such button in the
* form.
* @access public
*/
function submitImage($selector, $x, $y, $additional = false) {
$additional = $additional ? $additional : array();
foreach ($this->_images as $image) {
if ($selector->isMatch($image)) {
$encoding = $this->_encode();
$image->write($encoding, $x, $y);
if ($additional) {
$encoding->merge($additional);
}
return $encoding;
}
}
return false;
}
/**
* Simply submits the form without the submit button
* value. Used when there is only one button or it
* is unimportant.
* @return hash Submitted values.
* @access public
*/
function submit() {
return $this->_encode();
}
}
?>
/**
* Test to see if a form has a submit button.
* @param SimpleSelector $selector Criteria to apply.
* @return boolean True if present.
* @access public
*/
function hasSubmit($selector) {
foreach ($this->_buttons as $button) {
if ($selector->isMatch($button)) {
return true;
}
}
return false;
}
/**
* Test to see if a form has an image control.
* @param SimpleSelector $selector Criteria to apply.
* @return boolean True if present.
* @access public
*/
function hasImage($selector) {
foreach ($this->_images as $image) {
if ($selector->isMatch($image)) {
return true;
}
}
return false;
}
/**
* Gets the submit values for a selected button.
* @param SimpleSelector $selector Criteria to apply.
* @param hash $additional Additional data for the form.
* @return SimpleEncoding Submitted values or false
* if there is no such button
* in the form.
* @access public
*/
function submitButton($selector, $additional = false) {
$additional = $additional ? $additional : array();
foreach ($this->_buttons as $button) {
if ($selector->isMatch($button)) {
$encoding = $this->_encode();
$button->write($encoding);
if ($additional) {
$encoding->merge($additional);
}
return $encoding;
}
}
return false;
}
/**
* Gets the submit values for an image.
* @param SimpleSelector $selector Criteria to apply.
* @param integer $x X-coordinate of click.
* @param integer $y Y-coordinate of click.
* @param hash $additional Additional data for the form.
* @return SimpleEncoding Submitted values or false
* if there is no such button in the
* form.
* @access public
*/
function submitImage($selector, $x, $y, $additional = false) {
$additional = $additional ? $additional : array();
foreach ($this->_images as $image) {
if ($selector->isMatch($image)) {
$encoding = $this->_encode();
$image->write($encoding, $x, $y);
if ($additional) {
$encoding->merge($additional);
}
return $encoding;
}
}
return false;
}
/**
* Simply submits the form without the submit button
* value. Used when there is only one button or it
* is unimportant.
* @return hash Submitted values.
* @access public
*/
function submit() {
return $this->_encode();
}
}
?>
File diff suppressed because it is too large Load Diff
+583 -583
View File
File diff suppressed because it is too large Load Diff
+129 -129
View File
@@ -1,139 +1,139 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**#@+
* Includes SimpleTest files and defined the root constant
* for dependent libraries.
*/
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');
if (! defined('SIMPLE_TEST')) {
define('SIMPLE_TEST', dirname(__FILE__) . '/');
}
/**#@-*/
/**#@+
* Includes SimpleTest files and defined the root constant
* for dependent libraries.
*/
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');
if (! defined('SIMPLE_TEST')) {
define('SIMPLE_TEST', dirname(__FILE__) . '/');
}
/**#@-*/
/**
* This is called by the class runner to run a
* single test method. Will also run the setUp()
* and tearDown() methods.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleInvoker {
var $_test_case;
/**
* This is called by the class runner to run a
* single test method. Will also run the setUp()
* and tearDown() methods.
* @package SimpleTest
* @subpackage UnitTester
* Stashes the test case for later.
* @param SimpleTestCase $test_case Test case to run.
*/
class SimpleInvoker {
var $_test_case;
/**
* Stashes the test case for later.
* @param SimpleTestCase $test_case Test case to run.
*/
function SimpleInvoker(&$test_case) {
$this->_test_case = &$test_case;
}
/**
* Accessor for test case being run.
* @return SimpleTestCase Test case.
* @access public
*/
function &getTestCase() {
return $this->_test_case;
}
/**
* Runs test level set up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function before($method) {
$this->_test_case->before($method);
}
/**
* Invokes a test method and buffered with setUp()
* and tearDown() calls.
* @param string $method Test method to call.
* @access public
*/
function invoke($method) {
$this->_test_case->setUp();
$this->_test_case->$method();
$this->_test_case->tearDown();
}
/**
* Runs test level clean up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function after($method) {
$this->_test_case->after($method);
}
function SimpleInvoker(&$test_case) {
$this->_test_case = &$test_case;
}
/**
* Do nothing decorator. Just passes the invocation
* straight through.
* @package SimpleTest
* @subpackage UnitTester
* Accessor for test case being run.
* @return SimpleTestCase Test case.
* @access public
*/
class SimpleInvokerDecorator {
var $_invoker;
/**
* Stores the invoker to wrap.
* @param SimpleInvoker $invoker Test method runner.
*/
function SimpleInvokerDecorator(&$invoker) {
$this->_invoker = &$invoker;
}
/**
* Accessor for test case being run.
* @return SimpleTestCase Test case.
* @access public
*/
function &getTestCase() {
return $this->_invoker->getTestCase();
}
/**
* Runs test level set up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function before($method) {
$this->_invoker->before($method);
}
/**
* Invokes a test method and buffered with setUp()
* and tearDown() calls.
* @param string $method Test method to call.
* @access public
*/
function invoke($method) {
$this->_invoker->invoke($method);
}
/**
* Runs test level clean up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function after($method) {
$this->_invoker->after($method);
}
function &getTestCase() {
return $this->_test_case;
}
?>
/**
* Runs test level set up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function before($method) {
$this->_test_case->before($method);
}
/**
* Invokes a test method and buffered with setUp()
* and tearDown() calls.
* @param string $method Test method to call.
* @access public
*/
function invoke($method) {
$this->_test_case->setUp();
$this->_test_case->$method();
$this->_test_case->tearDown();
}
/**
* Runs test level clean up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function after($method) {
$this->_test_case->after($method);
}
}
/**
* Do nothing decorator. Just passes the invocation
* straight through.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleInvokerDecorator {
var $_invoker;
/**
* Stores the invoker to wrap.
* @param SimpleInvoker $invoker Test method runner.
*/
function SimpleInvokerDecorator(&$invoker) {
$this->_invoker = &$invoker;
}
/**
* Accessor for test case being run.
* @return SimpleTestCase Test case.
* @access public
*/
function &getTestCase() {
return $this->_invoker->getTestCase();
}
/**
* Runs test level set up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function before($method) {
$this->_invoker->before($method);
}
/**
* Invokes a test method and buffered with setUp()
* and tearDown() calls.
* @param string $method Test method to call.
* @access public
*/
function invoke($method) {
$this->_invoker->invoke($method);
}
/**
* Runs test level clean up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function after($method) {
$this->_invoker->after($method);
}
}
?>
File diff suppressed because it is too large Load Diff
+949 -941
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+130 -109
View File
@@ -1,115 +1,136 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* Version specific reflection API.
* @package SimpleTest
* @subpackage UnitTester
* @ignore duplicate with reflection_php5.php
*/
class SimpleReflection {
var $_interface;
/**
* Version specific reflection API.
* @package SimpleTest
* @subpackage UnitTester
* Stashes the class/interface.
* @param string $interface Class or interface
* to inspect.
*/
class SimpleReflection {
var $_interface;
/**
* Stashes the class/interface.
* @param string $interface Class or interface
* to inspect.
*/
function SimpleReflection($interface) {
$this->_interface = $interface;
}
/**
* Checks that a class has been declared.
* @return boolean True if defined.
* @access public
*/
function classExists() {
return class_exists($this->_interface);
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classExistsSansAutoload() {
return class_exists($this->_interface);
}
/**
* Checks that a class or interface has been
* declared.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExists() {
return class_exists($this->_interface);
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExistsSansAutoload() {
return class_exists($this->_interface);
}
/**
* Gets the list of methods on a class or
* interface.
* @returns array List of method names.
* @access public
*/
function getMethods() {
return get_class_methods($this->_interface);
}
/**
* Gets the list of interfaces from a class. If the
* class name is actually an interface then just that
* interface is returned.
* @returns array List of interfaces.
* @access public
*/
function getInterfaces() {
return array();
}
/**
* Finds the parent class name.
* @returns string Parent class name.
* @access public
*/
function getParent() {
return strtolower(get_parent_class($this->_interface));
}
/**
* Determines if the class is abstract, which for PHP 4
* will never be the case.
* @returns boolean True if abstract.
* @access public
*/
function isAbstract() {
return false;
}
/**
* Gets the source code matching the declaration
* of a method.
* @param string $method Method name.
* @access public
*/
function getSignature($method) {
return "function &$method()";
}
function SimpleReflection($interface) {
$this->_interface = $interface;
}
/**
* Checks that a class has been declared.
* @return boolean True if defined.
* @access public
*/
function classExists() {
return class_exists($this->_interface);
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classExistsSansAutoload() {
return class_exists($this->_interface);
}
/**
* Checks that a class or interface has been
* declared.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExists() {
return class_exists($this->_interface);
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExistsSansAutoload() {
return class_exists($this->_interface);
}
/**
* Gets the list of methods on a class or
* interface.
* @returns array List of method names.
* @access public
*/
function getMethods() {
return get_class_methods($this->_interface);
}
/**
* Gets the list of interfaces from a class. If the
* class name is actually an interface then just that
* interface is returned.
* @returns array List of interfaces.
* @access public
*/
function getInterfaces() {
return array();
}
/**
* Finds the parent class name.
* @returns string Parent class name.
* @access public
*/
function getParent() {
return strtolower(get_parent_class($this->_interface));
}
/**
* Determines if the class is abstract, which for PHP 4
* will never be the case.
* @returns boolean True if abstract.
* @access public
*/
function isAbstract() {
return false;
}
/**
* Determines if the the entity is an interface, which for PHP 4
* will never be the case.
* @returns boolean True if interface.
* @access public
*/
function isInterface() {
return false;
}
/**
* Scans for final methods, but as it's PHP 4 there
* aren't any.
* @returns boolean True if the class has a final method.
* @access public
*/
function hasFinal() {
return false;
}
/**
* Gets the source code matching the declaration
* of a method.
* @param string $method Method name.
* @access public
*/
function getSignature($method) {
return "function &$method()";
}
}
?>
+362 -262
View File
@@ -1,280 +1,380 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* Version specific reflection API.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleReflection {
var $_interface;
/**
* Version specific reflection API.
* @package SimpleTest
* @subpackage UnitTester
* Stashes the class/interface.
* @param string $interface Class or interface
* to inspect.
*/
class SimpleReflection {
var $_interface;
function SimpleReflection($interface) {
$this->_interface = $interface;
}
/**
* Stashes the class/interface.
* @param string $interface Class or interface
* to inspect.
*/
function SimpleReflection($interface) {
$this->_interface = $interface;
}
/**
* Checks that a class has been declared. Versions
* before PHP5.0.2 need a check that it's not really
* an interface.
* @return boolean True if defined.
* @access public
*/
function classExists() {
if (! class_exists($this->_interface)) {
return false;
}
$reflection = new ReflectionClass($this->_interface);
return ! $reflection->isInterface();
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classExistsSansAutoload() {
return class_exists($this->_interface, false);
}
/**
* Checks that a class or interface has been
* declared.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExists() {
return $this->_classOrInterfaceExistsWithAutoload($this->_interface, true);
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExistsSansAutoload() {
return $this->_classOrInterfaceExistsWithAutoload($this->_interface, false);
}
/**
* Needed to select the autoload feature in PHP5
* for classes created dynamically.
* @param string $interface Class or interface name.
* @param boolean $autoload True totriggerautoload.
* @return boolean True if interface defined.
* @access private
*/
function _classOrInterfaceExistsWithAutoload($interface, $autoload) {
if (function_exists('interface_exists')) {
if (interface_exists($this->_interface, $autoload)) {
return true;
}
}
return class_exists($this->_interface, $autoload);
}
/**
* Gets the list of methods on a class or
* interface. Needs to recursively look at all of
* the interfaces included.
* @returns array List of method names.
* @access public
*/
function getMethods() {
return array_unique(get_class_methods($this->_interface));
}
/**
* Gets the list of interfaces from a class. If the
* class name is actually an interface then just that
* interface is returned.
* @returns array List of interfaces.
* @access public
*/
function getInterfaces() {
$reflection = new ReflectionClass($this->_interface);
if ($reflection->isInterface()) {
return array($this->_interface);
}
return $this->_onlyParents($reflection->getInterfaces());
}
/**
* Gets the list of methods for the implemented
* interfaces only.
* @returns array List of enforced method signatures.
* @access public
*/
function getInterfaceMethods() {
$methods = array();
foreach ($this->getInterfaces() as $interface) {
$methods = array_merge($methods, get_class_methods($interface));
}
return array_unique($methods);
}
/**
* Checks to see if the method signature has to be tightly
* specified.
* @param string $method Method name.
* @returns boolean True if enforced.
* @access private
*/
function _isInterfaceMethod($method) {
return in_array($method, $this->getInterfaceMethods());
}
/**
* Finds the parent class name.
* @returns string Parent class name.
* @access public
*/
function getParent() {
$reflection = new ReflectionClass($this->_interface);
$parent = $reflection->getParentClass();
if ($parent) {
return $parent->getName();
}
/**
* Checks that a class has been declared. Versions
* before PHP5.0.2 need a check that it's not really
* an interface.
* @return boolean True if defined.
* @access public
*/
function classExists() {
if (! class_exists($this->_interface)) {
return false;
}
$reflection = new ReflectionClass($this->_interface);
return ! $reflection->isInterface();
}
/**
* Determines if the class is abstract.
* @returns boolean True if abstract.
* @access public
*/
function isAbstract() {
$reflection = new ReflectionClass($this->_interface);
return $reflection->isAbstract();
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classExistsSansAutoload() {
return class_exists($this->_interface, false);
}
/**
* Checks that a class or interface has been
* declared.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExists() {
return $this->_classOrInterfaceExistsWithAutoload($this->_interface, true);
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExistsSansAutoload() {
return $this->_classOrInterfaceExistsWithAutoload($this->_interface, false);
}
/**
* Needed to select the autoload feature in PHP5
* for classes created dynamically.
* @param string $interface Class or interface name.
* @param boolean $autoload True totriggerautoload.
* @return boolean True if interface defined.
* @access private
*/
function _classOrInterfaceExistsWithAutoload($interface, $autoload) {
if (function_exists('interface_exists')) {
if (interface_exists($this->_interface, $autoload)) {
return true;
}
}
return class_exists($this->_interface, $autoload);
}
/**
* Wittles a list of interfaces down to only the top
* level parents.
* @param array $interfaces Reflection API interfaces
* to reduce.
* @returns array List of parent interface names.
* @access private
*/
function _onlyParents($interfaces) {
$parents = array();
foreach ($interfaces as $interface) {
foreach($interfaces as $possible_parent) {
if ($interface->getName() == $possible_parent->getName()) {
continue;
}
if ($interface->isSubClassOf($possible_parent)) {
break;
}
/**
* Gets the list of methods on a class or
* interface.
* @returns array List of method names.
* @access public
*/
function getMethods() {
return array_unique(get_class_methods($this->_interface));
}
/**
* Gets the list of interfaces from a class. If the
* class name is actually an interface then just that
* interface is returned.
* @returns array List of interfaces.
* @access public
*/
function getInterfaces() {
$reflection = new ReflectionClass($this->_interface);
if ($reflection->isInterface()) {
return array($this->_interface);
}
return $this->_onlyParents($reflection->getInterfaces());
}
/**
* Gets the list of methods for the implemented
* interfaces only.
* @returns array List of enforced method signatures.
* @access public
*/
function getInterfaceMethods() {
$methods = array();
foreach ($this->getInterfaces() as $interface) {
$methods = array_merge($methods, get_class_methods($interface));
}
return array_unique($methods);
}
/**
* Checks to see if the method signature has to be tightly
* specified.
* @param string $method Method name.
* @returns boolean True if enforced.
* @access private
*/
function _isInterfaceMethod($method) {
return in_array($method, $this->getInterfaceMethods());
}
/**
* Finds the parent class name.
* @returns string Parent class name.
* @access public
*/
function getParent() {
$reflection = new ReflectionClass($this->_interface);
$parent = $reflection->getParentClass();
if ($parent) {
return $parent->getName();
}
return false;
}
/**
* Trivially determines if the class is abstract.
* @returns boolean True if abstract.
* @access public
*/
function isAbstract() {
$reflection = new ReflectionClass($this->_interface);
return $reflection->isAbstract();
}
/**
* Trivially determines if the class is an interface.
* @returns boolean True if interface.
* @access public
*/
function isInterface() {
$reflection = new ReflectionClass($this->_interface);
return $reflection->isInterface();
}
/**
* Scans for final methods, as they screw up inherited
* mocks by not allowing you to override them.
* @returns boolean True if the class has a final method.
* @access public
*/
function hasFinal() {
$reflection = new ReflectionClass($this->_interface);
foreach ($reflection->getMethods() as $method) {
if ($method->isFinal()) {
return true;
}
}
return false;
}
/**
* Whittles a list of interfaces down to only the
* necessary top level parents.
* @param array $interfaces Reflection API interfaces
* to reduce.
* @returns array List of parent interface names.
* @access private
*/
function _onlyParents($interfaces) {
$parents = array();
$blacklist = array();
foreach ($interfaces as $interface) {
foreach($interfaces as $possible_parent) {
if ($interface->getName() == $possible_parent->getName()) {
continue;
}
if ($interface->isSubClassOf($possible_parent)) {
$blacklist[$possible_parent->getName()] = true;
}
}
if (!isset($blacklist[$interface->getName()])) {
$parents[] = $interface->getName();
}
return $parents;
}
return $parents;
}
/**
* Gets the source code matching the declaration
* of a method.
* @param string $name Method name.
* @return string Method signature up to last
* bracket.
* @access public
*/
function getSignature($name) {
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()";
}
if ($this->_isInterfaceMethod($name)) {
return $this->_getFullSignature($name);
}
return "function $name()";
}
/**
* For a signature specified in an interface, full
* details must be replicated to be a valid implementation.
* @param string $name Method name.
* @return string Method signature up to last
* bracket.
* @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)) .
")";
}
/**
* Gets the source code for each parameter.
* @param ReflectionMethod $method Method object from
* reflection API
* @return array List of strings, each
* a snippet of code.
* @access private
*/
function _getParameterSignatures($method) {
$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' : '');
}
return $signatures;
}
/**
* The SPL library has problems with the
* Reflection library. In particular, you can
* get extra characters in parameter names :(.
* @param string $name Parameter name.
* @return string Cleaner name.
* @access private
*/
function _suppressSpurious($name) {
return str_replace(array('[', ']', ' '), '', $name);
}
/**
* Test of a reflection parameter being optional
* that works with early versions of PHP5.
* @param reflectionParameter $parameter Is this optional.
* @return boolean True if optional.
* @access private
*/
function _isOptional($parameter) {
if (method_exists($parameter, 'isOptional')) {
return $parameter->isOptional();
}
/**
* Checks whether a method is abstract or not.
* @param string $name Method name.
* @return bool true if method is abstract, else false
* @access private
*/
function _isAbstractMethod($name) {
$interface = new ReflectionClass($this->_interface);
if (! $interface->hasMethod($name)) {
return false;
}
return $interface->getMethod($name)->isAbstract();
}
?>
/**
* Checks whether a method is the constructor.
* @param string $name Method name.
* @return bool true if method is the constructor
* @access private
*/
function _isConstructor($name) {
return ($name == '__construct') || ($name == $this->_interface);
}
/**
* Checks whether a method is abstract in all parents or not.
* @param string $name Method name.
* @return bool true if method is abstract in parent, else false
* @access private
*/
function _isAbstractMethodInParents($name) {
$interface = new ReflectionClass($this->_interface);
$parent = $interface->getParentClass();
while($parent) {
if (! $parent->hasMethod($name)) {
return false;
}
if ($parent->getMethod($name)->isAbstract()) {
return true;
}
$parent = $parent->getParentClass();
}
return false;
}
/**
* Checks whether a method is static or not.
* @param string $name Method name
* @return bool true if method is static, else false
* @access private
*/
function _isStaticMethod($name) {
$interface = new ReflectionClass($this->_interface);
if (! $interface->hasMethod($name)) {
return false;
}
return $interface->getMethod($name)->isStatic();
}
/**
* Writes the source code matching the declaration
* of a method.
* @param string $name Method name.
* @return string Method signature up to last
* bracket.
* @access public
*/
function getSignature($name) {
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 ($name == '__toString') {
return "function $name()";
}
if ($this->_isInterfaceMethod($name) ||
$this->_isAbstractMethod($name) ||
$this->_isAbstractMethodInParents($name) ||
$this->_isStaticMethod($name)) {
return $this->_getFullSignature($name);
}
return "function $name()";
}
/**
* For a signature specified in an interface, full
* details must be replicated to be a valid implementation.
* @param string $name Method name.
* @return string Method signature up to last
* bracket.
* @access private
*/
function _getFullSignature($name) {
$interface = new ReflectionClass($this->_interface);
$method = $interface->getMethod($name);
$reference = $method->returnsReference() ? '&' : '';
$static = $method->isStatic() ? 'static ' : '';
return "{$static}function $reference$name(" .
implode(', ', $this->_getParameterSignatures($method)) .
")";
}
/**
* Gets the source code for each parameter.
* @param ReflectionMethod $method Method object from
* reflection API
* @return array List of strings, each
* a snippet of code.
* @access private
*/
function _getParameterSignatures($method) {
$signatures = array();
foreach ($method->getParameters() as $parameter) {
$signature = '';
$type = $parameter->getClass();
if (is_null($type) && version_compare(phpversion(), '5.1.0', '>=') && $parameter->isArray()) {
$signature .= 'array ';
} elseif (!is_null($type)) {
$signature .= $type->getName() . ' ';
}
if ($parameter->isPassedByReference()) {
$signature .= '&';
}
$signature .= '$' . $this->_suppressSpurious($parameter->getName());
if ($this->_isOptional($parameter)) {
$signature .= ' = null';
}
$signatures[] = $signature;
}
return $signatures;
}
/**
* The SPL library has problems with the
* Reflection library. In particular, you can
* get extra characters in parameter names :(.
* @param string $name Parameter name.
* @return string Cleaner name.
* @access private
*/
function _suppressSpurious($name) {
return str_replace(array('[', ']', ' '), '', $name);
}
/**
* Test of a reflection parameter being optional
* that works with early versions of PHP5.
* @param reflectionParameter $parameter Is this optional.
* @return boolean True if optional.
* @access private
*/
function _isOptional($parameter) {
if (method_exists($parameter, 'isOptional')) {
return $parameter->isOptional();
}
return false;
}
}
?>
+98 -98
View File
@@ -1,117 +1,117 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**#@+
* include other SimpleTest class files
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/browser.php');
require_once(dirname(__FILE__) . '/xml.php');
require_once(dirname(__FILE__) . '/test_case.php');
/**#@-*/
/**
* Runs an XML formated test on a remote server.
* @package SimpleTest
* @subpackage UnitTester
*/
class RemoteTestCase {
var $_url;
var $_dry_url;
var $_size;
/**
* Sets the location of the remote test.
* @param string $url Test location.
* @param string $dry_url Location for dry run.
* @access public
*/
require_once(dirname(__FILE__) . '/browser.php');
require_once(dirname(__FILE__) . '/xml.php');
require_once(dirname(__FILE__) . '/test_case.php');
/**#@-*/
function RemoteTestCase($url, $dry_url = false) {
$this->_url = $url;
$this->_dry_url = $dry_url ? $dry_url : $url;
$this->_size = false;
}
/**
* Accessor for the test name for subclasses.
* @return string Name of the test.
* @access public
*/
function getLabel() {
return $this->_url;
}
/**
* Runs an XML formated test on a remote server.
* @package SimpleTest
* @subpackage UnitTester
* Runs the top level test for this class. Currently
* reads the data as a single chunk. I'll fix this
* once I have added iteration to the browser.
* @param SimpleReporter $reporter Target of test results.
* @returns boolean True if no failures.
* @access public
*/
class RemoteTestCase {
var $_url;
var $_dry_url;
var $_size;
/**
* Sets the location of the remote test.
* @param string $url Test location.
* @param string $dry_url Location for dry run.
* @access public
*/
function RemoteTestCase($url, $dry_url = false) {
$this->_url = $url;
$this->_dry_url = $dry_url ? $dry_url : $url;
$this->_size = false;
function run(&$reporter) {
$browser = &$this->_createBrowser();
$xml = $browser->get($this->_url);
if (! $xml) {
trigger_error('Cannot read remote test URL [' . $this->_url . ']');
return false;
}
/**
* Accessor for the test name for subclasses.
* @return string Name of the test.
* @access public
*/
function getLabel() {
return $this->_url;
$parser = &$this->_createParser($reporter);
if (! $parser->parse($xml)) {
trigger_error('Cannot parse incoming XML from [' . $this->_url . ']');
return false;
}
/**
* Runs the top level test for this class. Currently
* reads the data as a single chunk. I'll fix this
* once I have added iteration to the browser.
* @param SimpleReporter $reporter Target of test results.
* @returns boolean True if no failures.
* @access public
*/
function run(&$reporter) {
return true;
}
/**
* Creates a new web browser object for fetching
* the XML report.
* @return SimpleBrowser New browser.
* @access protected
*/
function &_createBrowser() {
$browser = &new SimpleBrowser();
return $browser;
}
/**
* Creates the XML parser.
* @param SimpleReporter $reporter Target of test results.
* @return SimpleTestXmlListener XML reader.
* @access protected
*/
function &_createParser(&$reporter) {
$parser = &new SimpleTestXmlParser($reporter);
return $parser;
}
/**
* Accessor for the number of subtests.
* @return integer Number of test cases.
* @access public
*/
function getSize() {
if ($this->_size === false) {
$browser = &$this->_createBrowser();
$xml = $browser->get($this->_url);
$xml = $browser->get($this->_dry_url);
if (! $xml) {
trigger_error('Cannot read remote test URL [' . $this->_url . ']');
trigger_error('Cannot read remote test URL [' . $this->_dry_url . ']');
return false;
}
$reporter = &new SimpleReporter();
$parser = &$this->_createParser($reporter);
if (! $parser->parse($xml)) {
trigger_error('Cannot parse incoming XML from [' . $this->_url . ']');
trigger_error('Cannot parse incoming XML from [' . $this->_dry_url . ']');
return false;
}
return true;
}
/**
* Creates a new web browser object for fetching
* the XML report.
* @return SimpleBrowser New browser.
* @access protected
*/
function &_createBrowser() {
$browser = &new SimpleBrowser();
return $browser;
}
/**
* Creates the XML parser.
* @param SimpleReporter $reporter Target of test results.
* @return SimpleTestXmlListener XML reader.
* @access protected
*/
function &_createParser(&$reporter) {
$parser = &new SimpleTestXmlParser($reporter);
return $parser;
}
/**
* Accessor for the number of subtests.
* @return integer Number of test cases.
* @access public
*/
function getSize() {
if ($this->_size === false) {
$browser = &$this->_createBrowser();
$xml = $browser->get($this->_dry_url);
if (! $xml) {
trigger_error('Cannot read remote test URL [' . $this->_dry_url . ']');
return false;
}
$reporter = &new SimpleReporter();
$parser = &$this->_createParser($reporter);
if (! $parser->parse($xml)) {
trigger_error('Cannot parse incoming XML from [' . $this->_dry_url . ']');
return false;
}
$this->_size = $reporter->getTestCaseCount();
}
return $this->_size;
$this->_size = $reporter->getTestCaseCount();
}
return $this->_size;
}
}
?>
+414 -393
View File
@@ -1,426 +1,447 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/scorer.php');
/**#@-*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/scorer.php');
/**#@-*/
/**
* Sample minimal test displayer. Generates only
* failure messages and a pass count.
* @package SimpleTest
* @subpackage UnitTester
*/
class HtmlReporter extends SimpleReporter {
var $_character_set;
/**
* Sample minimal test displayer. Generates only
* failure messages and a pass count.
* @package SimpleTest
* @subpackage UnitTester
* Does nothing yet. The first output will
* be sent on the first test start. For use
* by a web browser.
* @access public
*/
class HtmlReporter extends SimpleReporter {
var $_character_set;
function HtmlReporter($character_set = 'ISO-8859-1') {
$this->SimpleReporter();
$this->_character_set = $character_set;
}
/**
* Does nothing yet. The first output will
* be sent on the first test start. For use
* by a web browser.
* @access public
*/
function HtmlReporter($character_set = 'ISO-8859-1') {
$this->SimpleReporter();
$this->_character_set = $character_set;
}
/**
* Paints the top of the web page setting the
* title to the name of the starting test.
* @param string $test_name Name class of test.
* @access public
*/
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";
print "<style type=\"text/css\">\n";
print $this->_getCss() . "\n";
print "</style>\n";
print "</head>\n<body>\n";
print "<h1>$test_name</h1>\n";
flush();
}
/**
* Paints the top of the web page setting the
* title to the name of the starting test.
* @param string $test_name Name class of test.
* @access public
*/
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";
print "<style type=\"text/css\">\n";
print $this->_getCss() . "\n";
print "</style>\n";
print "</head>\n<body>\n";
print "<h1>$test_name</h1>\n";
flush();
}
/**
* Send the headers necessary to ensure the page is
* reloaded on every request. Otherwise you could be
* scratching your head over out of date test data.
* @access public
* @static
*/
function sendNoCacheHeaders() {
if (! headers_sent()) {
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
}
}
/**
* Paints the CSS. Add additional styles here.
* @return string CSS code as text.
* @access protected
*/
function _getCss() {
return ".fail { background-color: inherit; color: red; }" .
".pass { background-color: inherit; color: green; }" .
" pre { background-color: lightgray; color: inherit; }";
}
/**
* Paints the end of the test with a summary of
* the passes and failures.
* @param string $test_name Name class of test.
* @access public
*/
function paintFooter($test_name) {
$colour = ($this->getFailCount() + $this->getExceptionCount() > 0 ? "red" : "green");
print "<div style=\"";
print "padding: 8px; margin-top: 1em; background-color: $colour; color: white;";
print "\">";
print $this->getTestCaseProgress() . "/" . $this->getTestCaseCount();
print " test cases complete:\n";
print "<strong>" . $this->getPassCount() . "</strong> passes, ";
print "<strong>" . $this->getFailCount() . "</strong> fails and ";
print "<strong>" . $this->getExceptionCount() . "</strong> exceptions.";
print "</div>\n";
print "</body>\n</html>\n";
}
/**
* Paints the test failure with a breadcrumbs
* trail of the nesting test suites below the
* top level test.
* @param string $message Failure message displayed in
* the context of the other tests.
* @access public
*/
function paintFail($message) {
parent::paintFail($message);
print "<span class=\"fail\">Fail</span>: ";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print implode(" -&gt; ", $breadcrumb);
print " -&gt; " . $this->_htmlEntities($message) . "<br />\n";
}
/**
* Paints a PHP error.
* @param string $message Message is ignored.
* @access public
*/
function paintError($message) {
parent::paintError($message);
print "<span class=\"fail\">Exception</span>: ";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print implode(" -&gt; ", $breadcrumb);
print " -&gt; <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(" -&gt; ", $breadcrumb);
$message = 'Unexpected exception of type [' . get_class($exception) .
'] with message ['. $exception->getMessage() .
'] in ['. $exception->getFile() .
' line ' . $exception->getLine() . ']';
print " -&gt; <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(" -&gt; ", $breadcrumb);
print " -&gt; " . $this->_htmlEntities($message) . "<br />\n";
}
/**
* Paints formatted text such as dumped variables.
* @param string $message Text to show.
* @access public
*/
function paintFormattedMessage($message) {
print '<pre>' . $this->_htmlEntities($message) . '</pre>';
}
/**
* Character set adjusted entity conversion.
* @param string $message Plain text or Unicode message.
* @return string Browser readable message.
* @access protected
*/
function _htmlEntities($message) {
return htmlentities($message, ENT_COMPAT, $this->_character_set);
/**
* Send the headers necessary to ensure the page is
* reloaded on every request. Otherwise you could be
* scratching your head over out of date test data.
* @access public
* @static
*/
function sendNoCacheHeaders() {
if (! headers_sent()) {
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
}
}
/**
* Sample minimal test displayer. Generates only
* failure messages and a pass count. For command
* line use. I've tried to make it look like JUnit,
* but I wanted to output the errors as they arrived
* which meant dropping the dots.
* @package SimpleTest
* @subpackage UnitTester
* Paints the CSS. Add additional styles here.
* @return string CSS code as text.
* @access protected
*/
class TextReporter extends SimpleReporter {
/**
* Does nothing yet. The first output will
* be sent on the first test start.
* @access public
*/
function TextReporter() {
$this->SimpleReporter();
}
/**
* Paints the title only.
* @param string $test_name Name class of test.
* @access public
*/
function paintHeader($test_name) {
if (! SimpleReporter::inCli()) {
header('Content-type: text/plain');
}
print "$test_name\n";
flush();
}
/**
* Paints the end of the test with a summary of
* the passes and failures.
* @param string $test_name Name class of test.
* @access public
*/
function paintFooter($test_name) {
if ($this->getFailCount() + $this->getExceptionCount() == 0) {
print "OK\n";
} else {
print "FAILURES!!!\n";
}
print "Test cases run: " . $this->getTestCaseProgress() .
"/" . $this->getTestCaseCount() .
", Passes: " . $this->getPassCount() .
", Failures: " . $this->getFailCount() .
", Exceptions: " . $this->getExceptionCount() . "\n";
}
/**
* Paints the test failure as a stack trace.
* @param string $message Failure message displayed in
* the context of the other tests.
* @access public
*/
function paintFail($message) {
parent::paintFail($message);
print $this->getFailCount() . ") $message\n";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
print "\n";
}
/**
* Paints a PHP error or exception.
* @param string $message Message to be shown.
* @access public
* @abstract
*/
function paintError($message) {
parent::paintError($message);
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.
* @access public
*/
function paintFormattedMessage($message) {
print "$message\n";
flush();
}
function _getCss() {
return ".fail { background-color: inherit; color: red; }" .
".pass { background-color: inherit; color: green; }" .
" pre { background-color: lightgray; color: inherit; }";
}
/**
* Runs just a single test group, a single case or
* even a single test within that case.
* @package SimpleTest
* @subpackage UnitTester
* Paints the end of the test with a summary of
* the passes and failures.
* @param string $test_name Name class of test.
* @access public
*/
class SelectiveReporter extends SimpleReporterDecorator {
var $_just_this_case =false;
var $_just_this_test = false;
var $_within_test_case = true;
function paintFooter($test_name) {
$colour = ($this->getFailCount() + $this->getExceptionCount() > 0 ? "red" : "green");
print "<div style=\"";
print "padding: 8px; margin-top: 1em; background-color: $colour; color: white;";
print "\">";
print $this->getTestCaseProgress() . "/" . $this->getTestCaseCount();
print " test cases complete:\n";
print "<strong>" . $this->getPassCount() . "</strong> passes, ";
print "<strong>" . $this->getFailCount() . "</strong> fails and ";
print "<strong>" . $this->getExceptionCount() . "</strong> exceptions.";
print "</div>\n";
print "</body>\n</html>\n";
}
/**
* Selects the test case or group to be run,
* and optionally a specific test.
* @param SimpleScorer $reporter Reporter to receive events.
* @param string $just_this_case Only this case or group will run.
* @param string $just_this_test Only this test method will run.
*/
function SelectiveReporter(&$reporter, $just_this_case = false, $just_this_test = false) {
if (isset($just_this_case) && $just_this_case) {
$this->_just_this_case = strtolower($just_this_case);
$this->_within_test_case = false;
}
if (isset($just_this_test) && $just_this_test) {
$this->_just_this_test = strtolower($just_this_test);
}
$this->SimpleReporterDecorator($reporter);
/**
* Paints the test failure with a breadcrumbs
* trail of the nesting test suites below the
* top level test.
* @param string $message Failure message displayed in
* the context of the other tests.
* @access public
*/
function paintFail($message) {
parent::paintFail($message);
print "<span class=\"fail\">Fail</span>: ";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print implode(" -&gt; ", $breadcrumb);
print " -&gt; " . $this->_htmlEntities($message) . "<br />\n";
}
/**
* Paints a PHP error.
* @param string $message Message is ignored.
* @access public
*/
function paintError($message) {
parent::paintError($message);
print "<span class=\"fail\">Exception</span>: ";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print implode(" -&gt; ", $breadcrumb);
print " -&gt; <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(" -&gt; ", $breadcrumb);
$message = 'Unexpected exception of type [' . get_class($exception) .
'] with message ['. $exception->getMessage() .
'] in ['. $exception->getFile() .
' line ' . $exception->getLine() . ']';
print " -&gt; <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(" -&gt; ", $breadcrumb);
print " -&gt; " . $this->_htmlEntities($message) . "<br />\n";
}
/**
* Paints formatted text such as dumped variables.
* @param string $message Text to show.
* @access public
*/
function paintFormattedMessage($message) {
print '<pre>' . $this->_htmlEntities($message) . '</pre>';
}
/**
* Character set adjusted entity conversion.
* @param string $message Plain text or Unicode message.
* @return string Browser readable message.
* @access protected
*/
function _htmlEntities($message) {
return htmlentities($message, ENT_COMPAT, $this->_character_set);
}
}
/**
* Sample minimal test displayer. Generates only
* failure messages and a pass count. For command
* line use. I've tried to make it look like JUnit,
* but I wanted to output the errors as they arrived
* which meant dropping the dots.
* @package SimpleTest
* @subpackage UnitTester
*/
class TextReporter extends SimpleReporter {
/**
* Does nothing yet. The first output will
* be sent on the first test start.
* @access public
*/
function TextReporter() {
$this->SimpleReporter();
}
/**
* Paints the title only.
* @param string $test_name Name class of test.
* @access public
*/
function paintHeader($test_name) {
if (! SimpleReporter::inCli()) {
header('Content-type: text/plain');
}
print "$test_name\n";
flush();
}
/**
* Compares criteria to actual the case/group name.
* @param string $test_case The incoming test.
* @return boolean True if matched.
* @access protected
*/
function _isCaseMatch($test_case) {
if ($this->_just_this_case) {
return $this->_just_this_case == strtolower($test_case);
}
return false;
/**
* Paints the end of the test with a summary of
* the passes and failures.
* @param string $test_name Name class of test.
* @access public
*/
function paintFooter($test_name) {
if ($this->getFailCount() + $this->getExceptionCount() == 0) {
print "OK\n";
} else {
print "FAILURES!!!\n";
}
print "Test cases run: " . $this->getTestCaseProgress() .
"/" . $this->getTestCaseCount() .
", Passes: " . $this->getPassCount() .
", Failures: " . $this->getFailCount() .
", Exceptions: " . $this->getExceptionCount() . "\n";
}
/**
* Compares criteria to actual the test name.
* @param string $method The incoming test method.
* @return boolean True if matched.
* @access protected
*/
function _isTestMatch($method) {
/**
* Paints the test failure as a stack trace.
* @param string $message Failure message displayed in
* the context of the other tests.
* @access public
*/
function paintFail($message) {
parent::paintFail($message);
print $this->getFailCount() . ") $message\n";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
print "\n";
}
/**
* Paints a PHP error or exception.
* @param string $message Message to be shown.
* @access public
* @abstract
*/
function paintError($message) {
parent::paintError($message);
print "Exception " . $this->getExceptionCount() . "!\n$message\n";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
print "\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";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
print "\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.
* @access public
*/
function paintFormattedMessage($message) {
print "$message\n";
flush();
}
}
/**
* Runs just a single test group, a single case or
* even a single test within that case.
* @package SimpleTest
* @subpackage UnitTester
*/
class SelectiveReporter extends SimpleReporterDecorator {
var $_just_this_case = false;
var $_just_this_test = false;
var $_on;
/**
* Selects the test case or group to be run,
* and optionally a specific test.
* @param SimpleScorer $reporter Reporter to receive events.
* @param string $just_this_case Only this case or group will run.
* @param string $just_this_test Only this test method will run.
*/
function SelectiveReporter(&$reporter, $just_this_case = false, $just_this_test = false) {
if (isset($just_this_case) && $just_this_case) {
$this->_just_this_case = strtolower($just_this_case);
$this->_off();
} else {
$this->_on();
}
if (isset($just_this_test) && $just_this_test) {
$this->_just_this_test = strtolower($just_this_test);
}
$this->SimpleReporterDecorator($reporter);
}
/**
* Compares criteria to actual the case/group name.
* @param string $test_case The incoming test.
* @return boolean True if matched.
* @access protected
*/
function _matchesTestCase($test_case) {
return $this->_just_this_case == strtolower($test_case);
}
/**
* Compares criteria to actual the test name. If no
* name was specified at the beginning, then all tests
* can run.
* @param string $method The incoming test method.
* @return boolean True if matched.
* @access protected
*/
function _shouldRunTest($test_case, $method) {
if ($this->_isOn() || $this->_matchesTestCase($test_case)) {
if ($this->_just_this_test) {
return $this->_just_this_test == strtolower($method);
}
return true;
}
/**
* Veto everything that doesn't match the method wanted.
* @param string $test_case Name of test case.
* @param string $method Name of test method.
* @return boolean True if test should be run.
* @access public
*/
function shouldInvoke($test_case, $method) {
if ($this->_within_test_case && $this->_isTestMatch($method)) {
return $this->_reporter->shouldInvoke($test_case, $method);
}
return false;
}
/**
* Paints the start of a group test.
* @param string $test_case Name of test or other label.
* @param integer $size Number of test cases starting.
* @access public
*/
function paintGroupStart($test_case, $size) {
if ($this->_isCaseMatch($test_case)) {
$this->_within_test_case = true;
}
if ($this->_within_test_case) {
$this->_reporter->paintGroupStart($test_case, $size);
} else {
return true;
}
}
return false;
}
/**
* Switch on testing for the group or subgroup.
* @access private
*/
function _on() {
$this->_on = true;
}
/**
* Switch off testing for the group or subgroup.
* @access private
*/
function _off() {
$this->_on = false;
}
/**
* Is this group actually being tested?
* @return boolean True if the current test group is active.
* @access private
*/
function _isOn() {
return $this->_on;
}
/**
* Paints the end of a group test.
* @param string $test_case Name of test or other label.
* @access public
*/
function paintGroupEnd($test_case) {
if ($this->_within_test_case) {
$this->_reporter->paintGroupEnd($test_case);
}
if ($this->_isCaseMatch($test_case)) {
$this->_within_test_case = false;
}
/**
* Veto everything that doesn't match the method wanted.
* @param string $test_case Name of test case.
* @param string $method Name of test method.
* @return boolean True if test should be run.
* @access public
*/
function shouldInvoke($test_case, $method) {
if ($this->_shouldRunTest($test_case, $method)) {
return $this->_reporter->shouldInvoke($test_case, $method);
}
return false;
}
/**
* Paints the start of a test case.
* @param string $test_case Name of test or other label.
* @access public
*/
function paintCaseStart($test_case) {
if ($this->_isCaseMatch($test_case)) {
$this->_within_test_case = true;
}
if ($this->_within_test_case) {
$this->_reporter->paintCaseStart($test_case);
}
/**
* Paints the start of a group test.
* @param string $test_case Name of test or other label.
* @param integer $size Number of test cases starting.
* @access public
*/
function paintGroupStart($test_case, $size) {
if ($this->_just_this_case && $this->_matchesTestCase($test_case)) {
$this->_on();
}
$this->_reporter->paintGroupStart($test_case, $size);
}
/**
* Paints the end of a test case.
* @param string $test_case Name of test or other label.
* @access public
*/
function paintCaseEnd($test_case) {
if ($this->_within_test_case) {
$this->_reporter->paintCaseEnd($test_case);
}
if ($this->_isCaseMatch($test_case)) {
$this->_within_test_case = false;
}
/**
* Paints the end of a group test.
* @param string $test_case Name of test or other label.
* @access public
*/
function paintGroupEnd($test_case) {
$this->_reporter->paintGroupEnd($test_case);
if ($this->_just_this_case && $this->_matchesTestCase($test_case)) {
$this->_off();
}
}
}
/**
* Suppresses skip messages.
* @package SimpleTest
* @subpackage UnitTester
*/
class NoSkipsReporter extends SimpleReporterDecorator {
/**
* Does nothing.
* @param string $message Text of skip condition.
* @access public
*/
function paintSkip($message) { }
}
?>
File diff suppressed because it is too large Load Diff
+120 -116
View File
@@ -1,133 +1,137 @@
<?php
/**
* Base include file for SimpleTest.
* @package SimpleTest
* @subpackage WebTester
* @version $Id$
*/
/**
* Base include file for SimpleTest.
* @package SimpleTest
* @subpackage WebTester
* @version $Id$
*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/tag.php');
require_once(dirname(__FILE__) . '/encoding.php');
/**#@-*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/tag.php');
require_once(dirname(__FILE__) . '/encoding.php');
/**#@-*/
/**
* Used to extract form elements for testing against.
* Searches by name attribute.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleByName {
var $_name;
/**
* Used to extract form elements for testing against.
* Searches by name attribute.
* @package SimpleTest
* @subpackage WebTester
* Stashes the name for later comparison.
* @param string $name Name attribute to match.
*/
class SimpleByName {
var $_name;
function SimpleByName($name) {
$this->_name = $name;
}
/**
* Stashes the name for later comparison.
* @param string $name Name attribute to match.
*/
function SimpleByName($name) {
$this->_name = $name;
}
/**
* Compares with name attribute of widget.
* @param SimpleWidget $widget Control to compare.
* @access public
*/
function isMatch($widget) {
return ($widget->getName() == $this->_name);
}
function getName() {
return $this->_name;
}
/**
* Used to extract form elements for testing against.
* Searches by visible label or alt text.
* @package SimpleTest
* @subpackage WebTester
* Compares with name attribute of widget.
* @param SimpleWidget $widget Control to compare.
* @access public
*/
class SimpleByLabel {
var $_label;
function isMatch($widget) {
return ($widget->getName() == $this->_name);
}
}
/**
* Stashes the name for later comparison.
* @param string $label Visible text to match.
*/
function SimpleByLabel($label) {
$this->_label = $label;
/**
* Used to extract form elements for testing against.
* Searches by visible label or alt text.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleByLabel {
var $_label;
/**
* Stashes the name for later comparison.
* @param string $label Visible text to match.
*/
function SimpleByLabel($label) {
$this->_label = $label;
}
/**
* Comparison. Compares visible text of widget or
* related label.
* @param SimpleWidget $widget Control to compare.
* @access public
*/
function isMatch($widget) {
if (! method_exists($widget, 'isLabel')) {
return false;
}
return $widget->isLabel($this->_label);
}
}
/**
* Comparison. Compares visible text of widget or
* related label.
* @param SimpleWidget $widget Control to compare.
* @access public
*/
function isMatch($widget) {
if (! method_exists($widget, 'isLabel')) {
return false;
/**
* Used to extract form elements for testing against.
* Searches dy id attribute.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleById {
var $_id;
/**
* Stashes the name for later comparison.
* @param string $id ID atribute to match.
*/
function SimpleById($id) {
$this->_id = $id;
}
/**
* Comparison. Compares id attribute of widget.
* @param SimpleWidget $widget Control to compare.
* @access public
*/
function isMatch($widget) {
return $widget->isId($this->_id);
}
}
/**
* Used to extract form elements for testing against.
* Searches by visible label, name or alt text.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleByLabelOrName {
var $_label;
/**
* Stashes the name/label for later comparison.
* @param string $label Visible text to match.
*/
function SimpleByLabelOrName($label) {
$this->_label = $label;
}
/**
* Comparison. Compares visible text of widget or
* related label or name.
* @param SimpleWidget $widget Control to compare.
* @access public
*/
function isMatch($widget) {
if (method_exists($widget, 'isLabel')) {
if ($widget->isLabel($this->_label)) {
return true;
}
return $widget->isLabel($this->_label);
}
}
/**
* Used to extract form elements for testing against.
* Searches dy id attribute.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleById {
var $_id;
/**
* Stashes the name for later comparison.
* @param string $id ID atribute to match.
*/
function SimpleById($id) {
$this->_id = $id;
}
/**
* Comparison. Compares id attribute of widget.
* @param SimpleWidget $widget Control to compare.
* @access public
*/
function isMatch($widget) {
return $widget->isId($this->_id);
}
}
/**
* Used to extract form elements for testing against.
* Searches by visible label, name or alt text.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleByLabelOrName {
var $_label;
/**
* Stashes the name/label for later comparison.
* @param string $label Visible text to match.
*/
function SimpleByLabelOrName($label) {
$this->_label = $label;
}
/**
* Comparison. Compares visible text of widget or
* related label or name.
* @param SimpleWidget $widget Control to compare.
* @access public
*/
function isMatch($widget) {
if (method_exists($widget, 'isLabel')) {
if ($widget->isLabel($this->_label)) {
return true;
}
}
return ($widget->getName() == $this->_label);
}
return ($widget->getName() == $this->_label);
}
}
?>
+322 -322
View File
@@ -1,333 +1,333 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/test_case.php');
/**#@-*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/test_case.php');
/**#@-*/
/**
* Wrapper for exec() functionality.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleShell {
var $_output;
/**
* Wrapper for exec() functionality.
* @package SimpleTest
* @subpackage UnitTester
* Executes the shell comand and stashes the output.
* @access public
*/
class SimpleShell {
var $_output;
/**
* Executes the shell comand and stashes the output.
* @access public
*/
function SimpleShell() {
$this->_output = false;
}
/**
* Actually runs the command. Does not trap the
* error stream output as this need PHP 4.3+.
* @param string $command The actual command line
* to run.
* @return integer Exit code.
* @access public
*/
function execute($command) {
$this->_output = false;
exec($command, $this->_output, $ret);
return $ret;
}
/**
* Accessor for the last output.
* @return string Output as text.
* @access public
*/
function getOutput() {
return implode("\n", $this->_output);
}
/**
* Accessor for the last output.
* @return array Output as array of lines.
* @access public
*/
function getOutputAsList() {
return $this->_output;
}
function SimpleShell() {
$this->_output = false;
}
/**
* Test case for testing of command line scripts and
* utilities. Usually scripts that are external to the
* PHP code, but support it in some way.
* @package SimpleTest
* @subpackage UnitTester
* Actually runs the command. Does not trap the
* error stream output as this need PHP 4.3+.
* @param string $command The actual command line
* to run.
* @return integer Exit code.
* @access public
*/
class ShellTestCase extends SimpleTestCase {
var $_current_shell;
var $_last_status;
var $_last_command;
/**
* Creates an empty test case. Should be subclassed
* with test methods for a functional test case.
* @param string $label Name of test case. Will use
* the class name if none specified.
* @access public
*/
function ShellTestCase($label = false) {
$this->SimpleTestCase($label);
$this->_current_shell = &$this->_createShell();
$this->_last_status = false;
$this->_last_command = '';
}
/**
* Executes a command and buffers the results.
* @param string $command Command to run.
* @return boolean True if zero exit code.
* @access public
*/
function execute($command) {
$shell = &$this->_getShell();
$this->_last_status = $shell->execute($command);
$this->_last_command = $command;
return ($this->_last_status === 0);
}
/**
* Dumps the output of the last command.
* @access public
*/
function dumpOutput() {
$this->dump($this->getOutput());
}
/**
* Accessor for the last output.
* @return string Output as text.
* @access public
*/
function getOutput() {
$shell = &$this->_getShell();
return $shell->getOutput();
}
/**
* Accessor for the last output.
* @return array Output as array of lines.
* @access public
*/
function getOutputAsList() {
$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
* 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 the last status code from the shell.
* @param integer $status Expected status of last
* command.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertExitCode($status, $message = "%s") {
$message = sprintf($message, "Expected status code of [$status] from [" .
$this->_last_command . "], but got [" .
$this->_last_status . "]");
return $this->assertTrue($status === $this->_last_status, $message);
}
/**
* Attempt to exactly match the combined STDERR and
* STDOUT output.
* @param string $expected Expected output.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertOutput($expected, $message = "%s") {
$shell = &$this->_getShell();
return $this->assert(
new EqualExpectation($expected),
$shell->getOutput(),
$message);
}
/**
* Scans the output for a Perl regex. If found
* anywhere it passes, else it fails.
* @param string $pattern Regex to search for.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertOutputPattern($pattern, $message = "%s") {
$shell = &$this->_getShell();
return $this->assert(
new PatternExpectation($pattern),
$shell->getOutput(),
$message);
}
/**
* If a Perl regex is found anywhere in the current
* output then a failure is generated, else a pass.
* @param string $pattern Regex to search for.
* @param $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertNoOutputPattern($pattern, $message = "%s") {
$shell = &$this->_getShell();
return $this->assert(
new NoPatternExpectation($pattern),
$shell->getOutput(),
$message);
}
/**
* File existence check.
* @param string $path Full filename and path.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertFileExists($path, $message = "%s") {
$message = sprintf($message, "File [$path] should exist");
return $this->assertTrue(file_exists($path), $message);
}
/**
* File non-existence check.
* @param string $path Full filename and path.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertFileNotExists($path, $message = "%s") {
$message = sprintf($message, "File [$path] should not exist");
return $this->assertFalse(file_exists($path), $message);
}
/**
* Scans a file for a Perl regex. If found
* anywhere it passes, else it fails.
* @param string $pattern Regex to search for.
* @param string $path Full filename and path.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertFilePattern($pattern, $path, $message = "%s") {
$shell = &$this->_getShell();
return $this->assert(
new PatternExpectation($pattern),
implode('', file($path)),
$message);
}
/**
* If a Perl regex is found anywhere in the named
* file then a failure is generated, else a pass.
* @param string $pattern Regex to search for.
* @param string $path Full filename and path.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertNoFilePattern($pattern, $path, $message = "%s") {
$shell = &$this->_getShell();
return $this->assert(
new NoPatternExpectation($pattern),
implode('', file($path)),
$message);
}
/**
* Accessor for current shell. Used for testing the
* the tester itself.
* @return Shell Current shell.
* @access protected
*/
function &_getShell() {
return $this->_current_shell;
}
/**
* Factory for the shell to run the command on.
* @return Shell New shell object.
* @access protected
*/
function &_createShell() {
$shell = &new SimpleShell();
return $shell;
}
function execute($command) {
$this->_output = false;
exec($command, $this->_output, $ret);
return $ret;
}
/**
* Accessor for the last output.
* @return string Output as text.
* @access public
*/
function getOutput() {
return implode("\n", $this->_output);
}
/**
* Accessor for the last output.
* @return array Output as array of lines.
* @access public
*/
function getOutputAsList() {
return $this->_output;
}
}
/**
* Test case for testing of command line scripts and
* utilities. Usually scripts that are external to the
* PHP code, but support it in some way.
* @package SimpleTest
* @subpackage UnitTester
*/
class ShellTestCase extends SimpleTestCase {
var $_current_shell;
var $_last_status;
var $_last_command;
/**
* Creates an empty test case. Should be subclassed
* with test methods for a functional test case.
* @param string $label Name of test case. Will use
* the class name if none specified.
* @access public
*/
function ShellTestCase($label = false) {
$this->SimpleTestCase($label);
$this->_current_shell = &$this->_createShell();
$this->_last_status = false;
$this->_last_command = '';
}
/**
* Executes a command and buffers the results.
* @param string $command Command to run.
* @return boolean True if zero exit code.
* @access public
*/
function execute($command) {
$shell = &$this->_getShell();
$this->_last_status = $shell->execute($command);
$this->_last_command = $command;
return ($this->_last_status === 0);
}
/**
* Dumps the output of the last command.
* @access public
*/
function dumpOutput() {
$this->dump($this->getOutput());
}
/**
* Accessor for the last output.
* @return string Output as text.
* @access public
*/
function getOutput() {
$shell = &$this->_getShell();
return $shell->getOutput();
}
/**
* Accessor for the last output.
* @return array Output as array of lines.
* @access public
*/
function getOutputAsList() {
$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
* 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 the last status code from the shell.
* @param integer $status Expected status of last
* command.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertExitCode($status, $message = "%s") {
$message = sprintf($message, "Expected status code of [$status] from [" .
$this->_last_command . "], but got [" .
$this->_last_status . "]");
return $this->assertTrue($status === $this->_last_status, $message);
}
/**
* Attempt to exactly match the combined STDERR and
* STDOUT output.
* @param string $expected Expected output.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertOutput($expected, $message = "%s") {
$shell = &$this->_getShell();
return $this->assert(
new EqualExpectation($expected),
$shell->getOutput(),
$message);
}
/**
* Scans the output for a Perl regex. If found
* anywhere it passes, else it fails.
* @param string $pattern Regex to search for.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertOutputPattern($pattern, $message = "%s") {
$shell = &$this->_getShell();
return $this->assert(
new PatternExpectation($pattern),
$shell->getOutput(),
$message);
}
/**
* If a Perl regex is found anywhere in the current
* output then a failure is generated, else a pass.
* @param string $pattern Regex to search for.
* @param $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertNoOutputPattern($pattern, $message = "%s") {
$shell = &$this->_getShell();
return $this->assert(
new NoPatternExpectation($pattern),
$shell->getOutput(),
$message);
}
/**
* File existence check.
* @param string $path Full filename and path.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertFileExists($path, $message = "%s") {
$message = sprintf($message, "File [$path] should exist");
return $this->assertTrue(file_exists($path), $message);
}
/**
* File non-existence check.
* @param string $path Full filename and path.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertFileNotExists($path, $message = "%s") {
$message = sprintf($message, "File [$path] should not exist");
return $this->assertFalse(file_exists($path), $message);
}
/**
* Scans a file for a Perl regex. If found
* anywhere it passes, else it fails.
* @param string $pattern Regex to search for.
* @param string $path Full filename and path.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertFilePattern($pattern, $path, $message = "%s") {
$shell = &$this->_getShell();
return $this->assert(
new PatternExpectation($pattern),
implode('', file($path)),
$message);
}
/**
* If a Perl regex is found anywhere in the named
* file then a failure is generated, else a pass.
* @param string $pattern Regex to search for.
* @param string $path Full filename and path.
* @param string $message Message to display.
* @return boolean True if pass.
* @access public
*/
function assertNoFilePattern($pattern, $path, $message = "%s") {
$shell = &$this->_getShell();
return $this->assert(
new NoPatternExpectation($pattern),
implode('', file($path)),
$message);
}
/**
* Accessor for current shell. Used for testing the
* the tester itself.
* @return Shell Current shell.
* @access protected
*/
function &_getShell() {
return $this->_current_shell;
}
/**
* Factory for the shell to run the command on.
* @return Shell New shell object.
* @access protected
*/
function &_createShell() {
$shell = &new SimpleShell();
return $shell;
}
}
?>
+452 -407
View File
@@ -1,433 +1,478 @@
<?php
/**
* Global state for SimpleTest and kicker script in future versions.
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* Global state for SimpleTest and kicker script in future versions.
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**#@+
* include SimpleTest files
/**#@+
* include SimpleTest files
*/
if (version_compare(phpversion(), '5') >= 0) {
require_once(dirname(__FILE__) . '/reflection_php5.php');
} else {
require_once(dirname(__FILE__) . '/reflection_php4.php');
}
require_once(dirname(__FILE__) . '/default_reporter.php');
require_once(dirname(__FILE__) . '/compatibility.php');
/**#@-*/
/**
* Registry and test context. Includes a few
* global options that I'm slowly getting rid of.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleTest {
/**
* Reads the SimpleTest version from the release file.
* @return string Version string.
* @static
* @access public
*/
if (version_compare(phpversion(), '5') >= 0) {
require_once(dirname(__FILE__) . '/reflection_php5.php');
} else {
require_once(dirname(__FILE__) . '/reflection_php4.php');
function getVersion() {
$content = file(dirname(__FILE__) . '/VERSION');
return trim($content[0]);
}
/**#@-*/
/**
* Registry and test context. Includes a few
* global options that I'm slowly getting rid of.
* @package SimpleTest
* Sets the name of a test case to ignore, usually
* because the class is an abstract case that should
* not be run. Once PHP4 is dropped this will disappear
* as a public method and "abstract" will rule.
* @param string $class Add a class to ignore.
* @static
* @access public
*/
class SimpleTest {
function ignore($class) {
$registry = &SimpleTest::_getRegistry();
$registry['IgnoreList'][strtolower($class)] = true;
}
/**
* Reads the SimpleTest version from the release file.
* @return string Version string.
* @static
* @access public
*/
function getVersion() {
$content = file(dirname(__FILE__) . '/VERSION');
return trim($content[0]);
/**
* Scans the now complete ignore list, and adds
* all parent classes to the list. If a class
* is not a runnable test case, then it's parents
* wouldn't be either. This is syntactic sugar
* to cut down on ommissions of ignore()'s or
* 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 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
*/
function ignoreParentsIfIgnored($classes) {
$registry = &SimpleTest::_getRegistry();
foreach ($classes as $class) {
if (SimpleTest::isIgnored($class)) {
$reflection = new SimpleReflection($class);
if ($parent = $reflection->getParent()) {
SimpleTest::ignore($parent);
}
}
}
}
/**
* Sets the name of a test case to ignore, usually
* because the class is an abstract case that should
* not be run. Once PHP4 is dropped this will disappear
* as a public method and "abstract" will rule.
* @param string $class Add a class to ignore.
* @static
* @access public
*/
function ignore($class) {
$registry = &SimpleTest::_getRegistry();
$registry['IgnoreList'][strtolower($class)] = true;
/**
* Puts the object to the global pool of 'preferred' objects
* which can be retrieved with SimpleTest :: preferred() method.
* Instances of the same class are overwritten.
* @param object $object Preferred object
* @static
* @access public
* @see preferred()
*/
function prefer(&$object) {
$registry = &SimpleTest::_getRegistry();
$registry['Preferred'][] = &$object;
}
/**
* Retrieves 'preferred' objects from global pool. Class filter
* can be applied in order to retrieve the object of the specific
* class
* @param array|string $classes Allowed classes or interfaces.
* @static
* @access public
* @return array|object|null
* @see prefer()
*/
function &preferred($classes) {
if (! is_array($classes)) {
$classes = array($classes);
}
/**
* Scans the now complete ignore list, and adds
* all parent classes to the list. If a class
* is not a runnable test case, then it's parents
* wouldn't be either. This is syntactic sugar
* to cut down on ommissions of ignore()'s or
* 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 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
*/
function ignoreParentsIfIgnored($classes) {
$registry = &SimpleTest::_getRegistry();
$registry = &SimpleTest::_getRegistry();
for ($i = count($registry['Preferred']) - 1; $i >= 0; $i--) {
foreach ($classes as $class) {
if (SimpleTest::isIgnored($class)) {
$reflection = new SimpleReflection($class);
if ($parent = $reflection->getParent()) {
SimpleTest::ignore($parent);
}
if (SimpleTestCompatibility::isA($registry['Preferred'][$i], $class)) {
return $registry['Preferred'][$i];
}
}
}
/**
* Test to see if a test case is in the ignore
* list. Quite obviously the ignore list should
* be a separate object and will be one day.
* This method is internal to SimpleTest. Don't
* use it.
* @param string $class Class name to test.
* @return boolean True if should not be run.
* @access public
* @static
*/
function isIgnored($class) {
$registry = &SimpleTest::_getRegistry();
return isset($registry['IgnoreList'][strtolower($class)]);
}
/**
* @deprecated
*/
function setMockBaseClass($mock_base) {
$registry = &SimpleTest::_getRegistry();
$registry['MockBaseClass'] = $mock_base;
}
/**
* @deprecated
*/
function getMockBaseClass() {
$registry = &SimpleTest::_getRegistry();
return $registry['MockBaseClass'];
}
/**
* Sets proxy to use on all requests for when
* testing from behind a firewall. Set host
* to false to disable. This will take effect
* if there are no other proxy settings.
* @param string $proxy Proxy host as URL.
* @param string $username Proxy username for authentication.
* @param string $password Proxy password for authentication.
* @access public
*/
function useProxy($proxy, $username = false, $password = false) {
$registry = &SimpleTest::_getRegistry();
$registry['DefaultProxy'] = $proxy;
$registry['DefaultProxyUsername'] = $username;
$registry['DefaultProxyPassword'] = $password;
}
/**
* Accessor for default proxy host.
* @return string Proxy URL.
* @access public
*/
function getDefaultProxy() {
$registry = &SimpleTest::_getRegistry();
return $registry['DefaultProxy'];
}
/**
* Accessor for default proxy username.
* @return string Proxy username for authentication.
* @access public
*/
function getDefaultProxyUsername() {
$registry = &SimpleTest::_getRegistry();
return $registry['DefaultProxyUsername'];
}
/**
* Accessor for default proxy password.
* @return string Proxy password for authentication.
* @access public
*/
function getDefaultProxyPassword() {
$registry = &SimpleTest::_getRegistry();
return $registry['DefaultProxyPassword'];
}
/**
* Accessor for global registry of options.
* @return hash All stored values.
* @access private
* @static
*/
function &_getRegistry() {
static $registry = false;
if (! $registry) {
$registry = SimpleTest::_getDefaults();
}
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.
* @access private
* @static
*/
function _getDefaults() {
return array(
'StubBaseClass' => 'SimpleStub',
'MockBaseClass' => 'SimpleMock',
'IgnoreList' => array(),
'DefaultProxy' => false,
'DefaultProxyUsername' => false,
'DefaultProxyPassword' => false);
}
return null;
}
/**
* 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
* Test to see if a test case is in the ignore
* list. Quite obviously the ignore list should
* be a separate object and will be one day.
* This method is internal to SimpleTest. Don't
* use it.
* @param string $class Class name to test.
* @return boolean True if should not be run.
* @access public
* @static
*/
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();
}
function isIgnored($class) {
$registry = &SimpleTest::_getRegistry();
return isset($registry['IgnoreList'][strtolower($class)]);
}
/**
* @deprecated
*/
class SimpleTestOptions extends SimpleTest {
/**
* @deprecated
*/
function getVersion() {
return Simpletest::getVersion();
}
/**
* @deprecated
*/
function ignore($class) {
return Simpletest::ignore($class);
}
/**
* @deprecated
*/
function isIgnored($class) {
return Simpletest::isIgnored($class);
}
/**
* @deprecated
*/
function setMockBaseClass($mock_base) {
return Simpletest::setMockBaseClass($mock_base);
}
/**
* @deprecated
*/
function getMockBaseClass() {
return Simpletest::getMockBaseClass();
}
/**
* @deprecated
*/
function useProxy($proxy, $username = false, $password = false) {
return Simpletest::useProxy($proxy, $username, $password);
}
/**
* @deprecated
*/
function getDefaultProxy() {
return Simpletest::getDefaultProxy();
}
/**
* @deprecated
*/
function getDefaultProxyUsername() {
return Simpletest::getDefaultProxyUsername();
}
/**
* @deprecated
*/
function getDefaultProxyPassword() {
return Simpletest::getDefaultProxyPassword();
}
function setMockBaseClass($mock_base) {
$registry = &SimpleTest::_getRegistry();
$registry['MockBaseClass'] = $mock_base;
}
/**
* @deprecated
*/
function getMockBaseClass() {
$registry = &SimpleTest::_getRegistry();
return $registry['MockBaseClass'];
}
/**
* Sets proxy to use on all requests for when
* testing from behind a firewall. Set host
* to false to disable. This will take effect
* if there are no other proxy settings.
* @param string $proxy Proxy host as URL.
* @param string $username Proxy username for authentication.
* @param string $password Proxy password for authentication.
* @access public
*/
function useProxy($proxy, $username = false, $password = false) {
$registry = &SimpleTest::_getRegistry();
$registry['DefaultProxy'] = $proxy;
$registry['DefaultProxyUsername'] = $username;
$registry['DefaultProxyPassword'] = $password;
}
/**
* Accessor for default proxy host.
* @return string Proxy URL.
* @access public
*/
function getDefaultProxy() {
$registry = &SimpleTest::_getRegistry();
return $registry['DefaultProxy'];
}
/**
* Accessor for default proxy username.
* @return string Proxy username for authentication.
* @access public
*/
function getDefaultProxyUsername() {
$registry = &SimpleTest::_getRegistry();
return $registry['DefaultProxyUsername'];
}
/**
* Accessor for default proxy password.
* @return string Proxy password for authentication.
* @access public
*/
function getDefaultProxyPassword() {
$registry = &SimpleTest::_getRegistry();
return $registry['DefaultProxyPassword'];
}
/**
* Accessor for global registry of options.
* @return hash All stored values.
* @access private
* @static
*/
function &_getRegistry() {
static $registry = false;
if (! $registry) {
$registry = SimpleTest::_getDefaults();
}
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.
* @access private
* @static
*/
function _getDefaults() {
return array(
'StubBaseClass' => 'SimpleStub',
'MockBaseClass' => 'SimpleMock',
'IgnoreList' => array(),
'DefaultProxy' => false,
'DefaultProxyUsername' => false,
'DefaultProxyPassword' => false,
'Preferred' => array(new HtmlReporter(), new TextReporter(), new XmlReporter()));
}
}
/**
* 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.
* @access public
*/
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.
* @access public
*/
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();
}
}
/**
* @package SimpleTest
* @subpackage UnitTester
* @deprecated
*/
class SimpleTestOptions extends SimpleTest {
/**
* @deprecated
*/
function getVersion() {
return Simpletest::getVersion();
}
/**
* @deprecated
*/
function ignore($class) {
return Simpletest::ignore($class);
}
/**
* @deprecated
*/
function isIgnored($class) {
return Simpletest::isIgnored($class);
}
/**
* @deprecated
*/
function setMockBaseClass($mock_base) {
return Simpletest::setMockBaseClass($mock_base);
}
/**
* @deprecated
*/
function getMockBaseClass() {
return Simpletest::getMockBaseClass();
}
/**
* @deprecated
*/
function useProxy($proxy, $username = false, $password = false) {
return Simpletest::useProxy($proxy, $username, $password);
}
/**
* @deprecated
*/
function getDefaultProxy() {
return Simpletest::getDefaultProxy();
}
/**
* @deprecated
*/
function getDefaultProxyUsername() {
return Simpletest::getDefaultProxyUsername();
}
/**
* @deprecated
*/
function getDefaultProxyPassword() {
return Simpletest::getDefaultProxyPassword();
}
}
?>
+192 -192
View File
@@ -1,216 +1,216 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage MockObjects
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage MockObjects
* @version $Id$
*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/compatibility.php');
/**#@-*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/compatibility.php');
/**#@-*/
/**
* Stashes an error for later. Useful for constructors
* until PHP gets exceptions.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleStickyError {
var $_error = 'Constructor not chained';
/**
* Stashes an error for later. Useful for constructors
* until PHP gets exceptions.
* @package SimpleTest
* @subpackage WebTester
* Sets the error to empty.
* @access public
*/
class SimpleStickyError {
var $_error = 'Constructor not chained';
/**
* Sets the error to empty.
* @access public
*/
function SimpleStickyError() {
$this->_clearError();
}
/**
* Test for an outstanding error.
* @return boolean True if there is an error.
* @access public
*/
function isError() {
return ($this->_error != '');
}
/**
* Accessor for an outstanding error.
* @return string Empty string if no error otherwise
* the error message.
* @access public
*/
function getError() {
return $this->_error;
}
/**
* Sets the internal error.
* @param string Error message to stash.
* @access protected
*/
function _setError($error) {
$this->_error = $error;
}
/**
* Resets the error state to no error.
* @access protected
*/
function _clearError() {
$this->_setError('');
}
function SimpleStickyError() {
$this->_clearError();
}
/**
* Wrapper for TCP/IP socket.
* @package SimpleTest
* @subpackage WebTester
* Test for an outstanding error.
* @return boolean True if there is an error.
* @access public
*/
class SimpleSocket extends SimpleStickyError {
var $_handle;
var $_is_open = false;
var $_sent = '';
var $lock_size;
function isError() {
return ($this->_error != '');
}
/**
* Opens a socket for reading and writing.
* @param string $host Hostname to send request to.
* @param integer $port Port on remote machine to open.
* @param integer $timeout Connection timeout in seconds.
* @param integer $block_size Size of chunk to read.
* @access public
*/
function SimpleSocket($host, $port, $timeout, $block_size = 255) {
$this->SimpleStickyError();
if (! ($this->_handle = $this->_openSocket($host, $port, $error_number, $error, $timeout))) {
$this->_setError("Cannot open [$host:$port] with [$error] within [$timeout] seconds");
return;
}
$this->_is_open = true;
$this->_block_size = $block_size;
SimpleTestCompatibility::setTimeout($this->_handle, $timeout);
/**
* Accessor for an outstanding error.
* @return string Empty string if no error otherwise
* the error message.
* @access public
*/
function getError() {
return $this->_error;
}
/**
* Sets the internal error.
* @param string Error message to stash.
* @access protected
*/
function _setError($error) {
$this->_error = $error;
}
/**
* Resets the error state to no error.
* @access protected
*/
function _clearError() {
$this->_setError('');
}
}
/**
* Wrapper for TCP/IP socket.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleSocket extends SimpleStickyError {
var $_handle;
var $_is_open = false;
var $_sent = '';
var $lock_size;
/**
* Opens a socket for reading and writing.
* @param string $host Hostname to send request to.
* @param integer $port Port on remote machine to open.
* @param integer $timeout Connection timeout in seconds.
* @param integer $block_size Size of chunk to read.
* @access public
*/
function SimpleSocket($host, $port, $timeout, $block_size = 255) {
$this->SimpleStickyError();
if (! ($this->_handle = $this->_openSocket($host, $port, $error_number, $error, $timeout))) {
$this->_setError("Cannot open [$host:$port] with [$error] within [$timeout] seconds");
return;
}
$this->_is_open = true;
$this->_block_size = $block_size;
SimpleTestCompatibility::setTimeout($this->_handle, $timeout);
}
/**
* Writes some data to the socket and saves alocal copy.
* @param string $message String to send to socket.
* @return boolean True if successful.
* @access public
*/
function write($message) {
if ($this->isError() || ! $this->isOpen()) {
return false;
}
$count = fwrite($this->_handle, $message);
if (! $count) {
if ($count === false) {
$this->_setError('Cannot write to socket');
$this->close();
}
return false;
}
fflush($this->_handle);
$this->_sent .= $message;
return true;
/**
* Writes some data to the socket and saves alocal copy.
* @param string $message String to send to socket.
* @return boolean True if successful.
* @access public
*/
function write($message) {
if ($this->isError() || ! $this->isOpen()) {
return false;
}
/**
* Reads data from the socket. The error suppresion
* is a workaround for PHP4 always throwing a warning
* with a secure socket.
* @return integer/boolean Incoming bytes. False
* on error.
* @access public
*/
function read() {
if ($this->isError() || ! $this->isOpen()) {
return false;
}
$raw = @fread($this->_handle, $this->_block_size);
if ($raw === false) {
$this->_setError('Cannot read from socket');
$count = fwrite($this->_handle, $message);
if (! $count) {
if ($count === false) {
$this->_setError('Cannot write to socket');
$this->close();
}
return $raw;
}
/**
* Accessor for socket open state.
* @return boolean True if open.
* @access public
*/
function isOpen() {
return $this->_is_open;
}
/**
* Closes the socket preventing further reads.
* Cannot be reopened once closed.
* @return boolean True if successful.
* @access public
*/
function close() {
$this->_is_open = false;
return fclose($this->_handle);
}
/**
* Accessor for content so far.
* @return string Bytes sent only.
* @access public
*/
function getSent() {
return $this->_sent;
}
/**
* Actually opens the low level socket.
* @param string $host Host to connect to.
* @param integer $port Port on host.
* @param integer $error_number Recipient of error code.
* @param string $error Recipoent of error message.
* @param integer $timeout Maximum time to wait for connection.
* @access protected
*/
function _openSocket($host, $port, &$error_number, &$error, $timeout) {
return @fsockopen($host, $port, $error_number, $error, $timeout);
return false;
}
fflush($this->_handle);
$this->_sent .= $message;
return true;
}
/**
* Wrapper for TCP/IP socket over TLS.
* @package SimpleTest
* @subpackage WebTester
* Reads data from the socket. The error suppresion
* is a workaround for PHP4 always throwing a warning
* with a secure socket.
* @return integer/boolean Incoming bytes. False
* on error.
* @access public
*/
class SimpleSecureSocket extends SimpleSocket {
/**
* Opens a secure socket for reading and writing.
* @param string $host Hostname to send request to.
* @param integer $port Port on remote machine to open.
* @param integer $timeout Connection timeout in seconds.
* @access public
*/
function SimpleSecureSocket($host, $port, $timeout) {
$this->SimpleSocket($host, $port, $timeout);
function read() {
if ($this->isError() || ! $this->isOpen()) {
return false;
}
/**
* Actually opens the low level socket.
* @param string $host Host to connect to.
* @param integer $port Port on host.
* @param integer $error_number Recipient of error code.
* @param string $error Recipient of error message.
* @param integer $timeout Maximum time to wait for connection.
* @access protected
*/
function _openSocket($host, $port, &$error_number, &$error, $timeout) {
return parent::_openSocket("tls://$host", $port, $error_number, $error, $timeout);
$raw = @fread($this->_handle, $this->_block_size);
if ($raw === false) {
$this->_setError('Cannot read from socket');
$this->close();
}
return $raw;
}
/**
* Accessor for socket open state.
* @return boolean True if open.
* @access public
*/
function isOpen() {
return $this->_is_open;
}
/**
* Closes the socket preventing further reads.
* Cannot be reopened once closed.
* @return boolean True if successful.
* @access public
*/
function close() {
$this->_is_open = false;
return fclose($this->_handle);
}
/**
* Accessor for content so far.
* @return string Bytes sent only.
* @access public
*/
function getSent() {
return $this->_sent;
}
/**
* Actually opens the low level socket.
* @param string $host Host to connect to.
* @param integer $port Port on host.
* @param integer $error_number Recipient of error code.
* @param string $error Recipoent of error message.
* @param integer $timeout Maximum time to wait for connection.
* @access protected
*/
function _openSocket($host, $port, &$error_number, &$error, $timeout) {
return @fsockopen($host, $port, $error_number, $error, $timeout);
}
}
/**
* Wrapper for TCP/IP socket over TLS.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleSecureSocket extends SimpleSocket {
/**
* Opens a secure socket for reading and writing.
* @param string $host Hostname to send request to.
* @param integer $port Port on remote machine to open.
* @param integer $timeout Connection timeout in seconds.
* @access public
*/
function SimpleSecureSocket($host, $port, $timeout) {
$this->SimpleSocket($host, $port, $timeout);
}
/**
* Actually opens the low level socket.
* @param string $host Host to connect to.
* @param integer $port Port on host.
* @param integer $error_number Recipient of error code.
* @param string $error Recipient of error message.
* @param integer $timeout Maximum time to wait for connection.
* @access protected
*/
function _openSocket($host, $port, &$error_number, &$error, $timeout) {
return parent::_openSocket("tls://$host", $port, $error_number, $error, $timeout);
}
}
?>
+1359 -1333
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+412 -411
View File
@@ -1,419 +1,420 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id$
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/test_case.php');
require_once(dirname(__FILE__) . '/dumper.php');
/**#@-*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/test_case.php');
require_once(dirname(__FILE__) . '/dumper.php');
/**#@-*/
/**
* Standard unit test class for day to day testing
* of PHP code XP style. Adds some useful standard
* assertions.
* @package SimpleTest
* @subpackage UnitTester
*/
class UnitTestCase extends SimpleTestCase {
/**
* Standard unit test class for day to day testing
* of PHP code XP style. Adds some useful standard
* assertions.
* @package SimpleTest
* @subpackage UnitTester
* Creates an empty test case. Should be subclassed
* with test methods for a functional test case.
* @param string $label Name of test case. Will use
* the class name if none specified.
* @access public
*/
class UnitTestCase extends SimpleTestCase {
/**
* Creates an empty test case. Should be subclassed
* with test methods for a functional test case.
* @param string $label Name of test case. Will use
* the class name if none specified.
* @access public
*/
function UnitTestCase($label = false) {
if (! $label) {
$label = get_class($this);
}
$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.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertNull($value, $message = '%s') {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($value) . '] should be null');
return $this->assertTrue(! isset($value), $message);
}
/**
* Will be true if the value is set.
* @param mixed $value Supposedly set value.
* @param string $message Message to display.
* @return boolean True on pass.
* @access public
*/
function assertNotNull($value, $message = '%s') {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($value) . '] should not be null');
return $this->assertTrue(isset($value), $message);
}
/**
* Type and class test. Will pass if class
* matches the type name or is a subclass or
* if not an object, but the type is correct.
* @param mixed $object Object to test.
* @param string $type Type name as string.
* @param string $message Message to display.
* @return boolean True on pass.
* @access public
*/
function assertIsA($object, $type, $message = '%s') {
return $this->assert(
new IsAExpectation($type),
$object,
$message);
}
/**
* Type and class mismatch test. Will pass if class
* name or underling type does not match the one
* specified.
* @param mixed $object Object to test.
* @param string $type Type name as string.
* @param string $message Message to display.
* @return boolean True on pass.
* @access public
*/
function assertNotA($object, $type, $message = '%s') {
return $this->assert(
new NotAExpectation($type),
$object,
$message);
}
/**
* Will trigger a pass if the two parameters have
* the same value only. Otherwise a fail.
* @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.
* @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);
}
/**
* Will trigger a pass if the if the first parameter
* is near enough to the second by the margin.
* @param mixed $first Value to compare.
* @param mixed $second Value to compare.
* @param mixed $margin Fuzziness of match.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertWithinMargin($first, $second, $margin, $message = '%s') {
return $this->assert(
new WithinMarginExpectation($first, $margin),
$second,
$message);
}
/**
* Will trigger a pass if the two parameters differ
* by more than the margin.
* @param mixed $first Value to compare.
* @param mixed $second Value to compare.
* @param mixed $margin Fuzziness of match.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertOutsideMargin($first, $second, $margin, $message = '%s') {
return $this->assert(
new OutsideMarginExpectation($first, $margin),
$second,
$message);
}
/**
* Will trigger a pass if the two parameters have
* the same value and same type. Otherwise a fail.
* @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 assertIdentical($first, $second, $message = '%s') {
return $this->assert(
new IdenticalExpectation($first),
$second,
$message);
}
/**
* Will trigger a pass if the two parameters have
* the different value or different type.
* @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 assertNotIdentical($first, $second, $message = '%s') {
return $this->assert(
new NotIdenticalExpectation($first),
$second,
$message);
}
/**
* Will trigger a pass if both parameters refer
* to the same object. Fail otherwise.
* @param mixed $first Object reference to check.
* @param mixed $second Hopefully the same object.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertReference(&$first, &$second, $message = '%s') {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($first) .
'] and [' . $dumper->describeValue($second) .
'] should reference the same object');
return $this->assertTrue(
SimpleTestCompatibility::isReference($first, $second),
$message);
}
/**
* Will trigger a pass if both parameters refer
* to different objects. Fail otherwise. The objects
* have to be identical though.
* @param mixed $first Object reference to check.
* @param mixed $second Hopefully not the same object.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
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');
$identical = &new IdenticalExpectation($first);
return $this->assertTrue(
$identical->test($second) &&
! SimpleTestCompatibility::isReference($first, $second),
$message);
}
/**
* @deprecated
*/
function assertCopy(&$first, &$second, $message = "%s") {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
"[" . $dumper->describeValue($first) .
"] and [" . $dumper->describeValue($second) .
"] should not be the same object");
return $this->assertFalse(
SimpleTestCompatibility::isReference($first, $second),
$message);
}
/**
* Will trigger a pass if the Perl regex pattern
* is found in the subject. Fail otherwise.
* @param string $pattern Perl regex to look for including
* the regex delimiters.
* @param string $subject String to search in.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertPattern($pattern, $subject, $message = '%s') {
return $this->assert(
new PatternExpectation($pattern),
$subject,
$message);
}
/**
* @deprecated
*/
function assertWantedPattern($pattern, $subject, $message = '%s') {
return $this->assertPattern($pattern, $subject, $message);
}
/**
* Will trigger a pass if the perl regex pattern
* is not present in subject. Fail if found.
* @param string $pattern Perl regex to look for including
* the regex delimiters.
* @param string $subject String to search in.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertNoPattern($pattern, $subject, $message = '%s') {
return $this->assert(
new NoPatternExpectation($pattern),
$subject,
$message);
}
/**
* @deprecated
*/
function assertNoUnwantedPattern($pattern, $subject, $message = '%s') {
return $this->assertNoPattern($pattern, $subject, $message);
}
/**
* @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 expectError($expected = false, $message = '%s') {
$context = &SimpleTest::getContext();
$queue = &$context->get('SimpleErrorQueue');
$queue->expectError($this->_coerceExpectation($expected), $message);
}
/**
* 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 expectException($expected = false, $message = '%s') {
$context = &SimpleTest::getContext();
$queue = &$context->get('SimpleExceptionTrap');
$queue->expectException($expected, $message . $this->getAssertionLine());
}
/**
* Creates an equality expectation if the
* object/value is not already some type
* of expectation.
* @param mixed $expected Expected value.
* @return SimpleExpectation Expectation object.
* @access private
*/
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') {
return $this->assertError(new PatternExpectation($pattern), $message);
function UnitTestCase($label = false) {
if (! $label) {
$label = get_class($this);
}
$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.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertNull($value, $message = '%s') {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($value) . '] should be null');
return $this->assertTrue(! isset($value), $message);
}
/**
* Will be true if the value is set.
* @param mixed $value Supposedly set value.
* @param string $message Message to display.
* @return boolean True on pass.
* @access public
*/
function assertNotNull($value, $message = '%s') {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($value) . '] should not be null');
return $this->assertTrue(isset($value), $message);
}
/**
* Type and class test. Will pass if class
* matches the type name or is a subclass or
* if not an object, but the type is correct.
* @param mixed $object Object to test.
* @param string $type Type name as string.
* @param string $message Message to display.
* @return boolean True on pass.
* @access public
*/
function assertIsA($object, $type, $message = '%s') {
return $this->assert(
new IsAExpectation($type),
$object,
$message);
}
/**
* Type and class mismatch test. Will pass if class
* name or underling type does not match the one
* specified.
* @param mixed $object Object to test.
* @param string $type Type name as string.
* @param string $message Message to display.
* @return boolean True on pass.
* @access public
*/
function assertNotA($object, $type, $message = '%s') {
return $this->assert(
new NotAExpectation($type),
$object,
$message);
}
/**
* Will trigger a pass if the two parameters have
* the same value only. Otherwise a fail.
* @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.
* @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);
}
/**
* Will trigger a pass if the if the first parameter
* is near enough to the second by the margin.
* @param mixed $first Value to compare.
* @param mixed $second Value to compare.
* @param mixed $margin Fuzziness of match.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertWithinMargin($first, $second, $margin, $message = '%s') {
return $this->assert(
new WithinMarginExpectation($first, $margin),
$second,
$message);
}
/**
* Will trigger a pass if the two parameters differ
* by more than the margin.
* @param mixed $first Value to compare.
* @param mixed $second Value to compare.
* @param mixed $margin Fuzziness of match.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertOutsideMargin($first, $second, $margin, $message = '%s') {
return $this->assert(
new OutsideMarginExpectation($first, $margin),
$second,
$message);
}
/**
* Will trigger a pass if the two parameters have
* the same value and same type. Otherwise a fail.
* @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 assertIdentical($first, $second, $message = '%s') {
return $this->assert(
new IdenticalExpectation($first),
$second,
$message);
}
/**
* Will trigger a pass if the two parameters have
* the different value or different type.
* @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 assertNotIdentical($first, $second, $message = '%s') {
return $this->assert(
new NotIdenticalExpectation($first),
$second,
$message);
}
/**
* Will trigger a pass if both parameters refer
* to the same object. Fail otherwise.
* @param mixed $first Object reference to check.
* @param mixed $second Hopefully the same object.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertReference(&$first, &$second, $message = '%s') {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($first) .
'] and [' . $dumper->describeValue($second) .
'] should reference the same object');
return $this->assertTrue(
SimpleTestCompatibility::isReference($first, $second),
$message);
}
/**
* Will trigger a pass if both parameters refer
* to different objects. Fail otherwise. The objects
* have to be identical though.
* @param mixed $first Object reference to check.
* @param mixed $second Hopefully not the same object.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
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');
$identical = &new IdenticalExpectation($first);
return $this->assertTrue(
$identical->test($second) &&
! SimpleTestCompatibility::isReference($first, $second),
$message);
}
/**
* @deprecated
*/
function assertCopy(&$first, &$second, $message = "%s") {
$dumper = &new SimpleDumper();
$message = sprintf(
$message,
"[" . $dumper->describeValue($first) .
"] and [" . $dumper->describeValue($second) .
"] should not be the same object");
return $this->assertFalse(
SimpleTestCompatibility::isReference($first, $second),
$message);
}
/**
* Will trigger a pass if the Perl regex pattern
* is found in the subject. Fail otherwise.
* @param string $pattern Perl regex to look for including
* the regex delimiters.
* @param string $subject String to search in.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertPattern($pattern, $subject, $message = '%s') {
return $this->assert(
new PatternExpectation($pattern),
$subject,
$message);
}
/**
* @deprecated
*/
function assertWantedPattern($pattern, $subject, $message = '%s') {
return $this->assertPattern($pattern, $subject, $message);
}
/**
* Will trigger a pass if the perl regex pattern
* is not present in subject. Fail if found.
* @param string $pattern Perl regex to look for including
* the regex delimiters.
* @param string $subject String to search in.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertNoPattern($pattern, $subject, $message = '%s') {
return $this->assert(
new NoPatternExpectation($pattern),
$subject,
$message);
}
/**
* @deprecated
*/
function assertNoUnwantedPattern($pattern, $subject, $message = '%s') {
return $this->assertNoPattern($pattern, $subject, $message);
}
/**
* @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 expectError($expected = false, $message = '%s') {
$context = &SimpleTest::getContext();
$queue = &$context->get('SimpleErrorQueue');
$queue->expectError($this->_coerceExpectation($expected), $message);
}
/**
* 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 expectException($expected = false, $message = '%s') {
$context = &SimpleTest::getContext();
$queue = &$context->get('SimpleExceptionTrap');
// :HACK: Directly substituting in seems to cause a segfault with
// Zend Optimizer on some systems
$line = $this->getAssertionLine();
$queue->expectException($expected, $message . $line);
}
/**
* Creates an equality expectation if the
* object/value is not already some type
* of expectation.
* @param mixed $expected Expected value.
* @return SimpleExpectation Expectation object.
* @access private
*/
function _coerceExpectation($expected) {
if ($expected == false) {
return new TrueExpectation();
}
if (SimpleTestCompatibility::isA($expected, 'SimpleExpectation')) {
return $expected;
}
return new EqualExpectation(
is_string($expected) ? str_replace('%', '%%', $expected) : $expected);
}
/**
* @deprecated
*/
function assertErrorPattern($pattern, $message = '%s') {
return $this->assertError(new PatternExpectation($pattern), $message);
}
}
?>
+499 -496
View File
File diff suppressed because it is too large Load Diff
+314 -315
View File
@@ -1,333 +1,332 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id$
*/
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id$
*/
/**#@+
* include other SimpleTest class files
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/cookies.php');
require_once(dirname(__FILE__) . '/http.php');
require_once(dirname(__FILE__) . '/encoding.php');
require_once(dirname(__FILE__) . '/authentication.php');
/**#@-*/
if (! defined('DEFAULT_MAX_REDIRECTS')) {
define('DEFAULT_MAX_REDIRECTS', 3);
}
if (! defined('DEFAULT_CONNECTION_TIMEOUT')) {
define('DEFAULT_CONNECTION_TIMEOUT', 15);
}
/**
* Fetches web pages whilst keeping track of
* cookies and authentication.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleUserAgent {
var $_cookie_jar;
var $_cookies_enabled = true;
var $_authenticator;
var $_max_redirects = DEFAULT_MAX_REDIRECTS;
var $_proxy = false;
var $_proxy_username = false;
var $_proxy_password = false;
var $_connection_timeout = DEFAULT_CONNECTION_TIMEOUT;
var $_additional_headers = array();
/**
* Starts with no cookies, realms or proxies.
* @access public
*/
require_once(dirname(__FILE__) . '/cookies.php');
require_once(dirname(__FILE__) . '/http.php');
require_once(dirname(__FILE__) . '/encoding.php');
require_once(dirname(__FILE__) . '/authentication.php');
/**#@-*/
if (! defined('DEFAULT_MAX_REDIRECTS')) {
define('DEFAULT_MAX_REDIRECTS', 3);
function SimpleUserAgent() {
$this->_cookie_jar = &new SimpleCookieJar();
$this->_authenticator = &new SimpleAuthenticator();
}
if (! defined('DEFAULT_CONNECTION_TIMEOUT')) {
define('DEFAULT_CONNECTION_TIMEOUT', 15);
}
/**
* Fetches web pages whilst keeping track of
* cookies and authentication.
* @package SimpleTest
* @subpackage WebTester
* Removes expired and temporary cookies as if
* the browser was closed and re-opened. Authorisation
* has to be obtained again as well.
* @param string/integer $date Time when session restarted.
* If omitted then all persistent
* cookies are kept.
* @access public
*/
class SimpleUserAgent {
var $_cookie_jar;
var $_cookies_enabled = true;
var $_authenticator;
var $_max_redirects = DEFAULT_MAX_REDIRECTS;
var $_proxy = false;
var $_proxy_username = false;
var $_proxy_password = false;
var $_connection_timeout = DEFAULT_CONNECTION_TIMEOUT;
var $_additional_headers = array();
/**
* Starts with no cookies, realms or proxies.
* @access public
*/
function SimpleUserAgent() {
$this->_cookie_jar = &new SimpleCookieJar();
$this->_authenticator = &new SimpleAuthenticator();
function restart($date = false) {
$this->_cookie_jar->restartSession($date);
$this->_authenticator->restartSession();
}
/**
* Adds a header to every fetch.
* @param string $header Header line to add to every
* request until cleared.
* @access public
*/
function addHeader($header) {
$this->_additional_headers[] = $header;
}
/**
* Ages the cookies by the specified time.
* @param integer $interval Amount in seconds.
* @access public
*/
function ageCookies($interval) {
$this->_cookie_jar->agePrematurely($interval);
}
/**
* Sets an additional cookie. If a cookie has
* the same name and path it is replaced.
* @param string $name Cookie key.
* @param string $value Value of cookie.
* @param string $host Host upon which the cookie is valid.
* @param string $path Cookie path if not host wide.
* @param string $expiry Expiry date.
* @access public
*/
function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
$this->_cookie_jar->setCookie($name, $value, $host, $path, $expiry);
}
/**
* Reads the most specific cookie value from the
* browser cookies.
* @param string $host Host to search.
* @param string $path Applicable path.
* @param string $name Name of cookie to read.
* @return string False if not present, else the
* value as a string.
* @access public
*/
function getCookieValue($host, $path, $name) {
return $this->_cookie_jar->getCookieValue($host, $path, $name);
}
/**
* Reads the current cookies within the base URL.
* @param string $name Key of cookie to find.
* @param SimpleUrl $base Base URL to search from.
* @return string/boolean Null if there is no base URL, false
* if the cookie is not set.
* @access public
*/
function getBaseCookieValue($name, $base) {
if (! $base) {
return null;
}
/**
* Removes expired and temporary cookies as if
* the browser was closed and re-opened. Authorisation
* has to be obtained again as well.
* @param string/integer $date Time when session restarted.
* If omitted then all persistent
* cookies are kept.
* @access public
*/
function restart($date = false) {
$this->_cookie_jar->restartSession($date);
$this->_authenticator->restartSession();
return $this->getCookieValue($base->getHost(), $base->getPath(), $name);
}
/**
* Switches off cookie sending and recieving.
* @access public
*/
function ignoreCookies() {
$this->_cookies_enabled = false;
}
/**
* Switches back on the cookie sending and recieving.
* @access public
*/
function useCookies() {
$this->_cookies_enabled = true;
}
/**
* Sets the socket timeout for opening a connection.
* @param integer $timeout Maximum time in seconds.
* @access public
*/
function setConnectionTimeout($timeout) {
$this->_connection_timeout = $timeout;
}
/**
* Sets the maximum number of redirects before
* a page will be loaded anyway.
* @param integer $max Most hops allowed.
* @access public
*/
function setMaximumRedirects($max) {
$this->_max_redirects = $max;
}
/**
* Sets proxy to use on all requests for when
* testing from behind a firewall. Set URL
* to false to disable.
* @param string $proxy Proxy URL.
* @param string $username Proxy username for authentication.
* @param string $password Proxy password for authentication.
* @access public
*/
function useProxy($proxy, $username, $password) {
if (! $proxy) {
$this->_proxy = false;
return;
}
/**
* Adds a header to every fetch.
* @param string $header Header line to add to every
* request until cleared.
* @access public
*/
function addHeader($header) {
$this->_additional_headers[] = $header;
if ((strncmp($proxy, 'http://', 7) != 0) && (strncmp($proxy, 'https://', 8) != 0)) {
$proxy = 'http://'. $proxy;
}
/**
* Ages the cookies by the specified time.
* @param integer $interval Amount in seconds.
* @access public
*/
function ageCookies($interval) {
$this->_cookie_jar->agePrematurely($interval);
$this->_proxy = &new SimpleUrl($proxy);
$this->_proxy_username = $username;
$this->_proxy_password = $password;
}
/**
* Test to see if the redirect limit is passed.
* @param integer $redirects Count so far.
* @return boolean True if over.
* @access private
*/
function _isTooManyRedirects($redirects) {
return ($redirects > $this->_max_redirects);
}
/**
* Sets the identity for the current realm.
* @param string $host Host to which realm applies.
* @param string $realm Full name of realm.
* @param string $username Username for realm.
* @param string $password Password for realm.
* @access public
*/
function setIdentity($host, $realm, $username, $password) {
$this->_authenticator->setIdentityForRealm($host, $realm, $username, $password);
}
/**
* Fetches a URL as a response object. Will keep trying if redirected.
* It will also collect authentication realm information.
* @param string/SimpleUrl $url Target to fetch.
* @param SimpleEncoding $encoding Additional parameters for request.
* @return SimpleHttpResponse Hopefully the target page.
* @access public
*/
function &fetchResponse($url, $encoding) {
if ($encoding->getMethod() != 'POST') {
$url->addRequestParameters($encoding);
$encoding->clear();
}
/**
* Sets an additional cookie. If a cookie has
* the same name and path it is replaced.
* @param string $name Cookie key.
* @param string $value Value of cookie.
* @param string $host Host upon which the cookie is valid.
* @param string $path Cookie path if not host wide.
* @param string $expiry Expiry date.
* @access public
*/
function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
$this->_cookie_jar->setCookie($name, $value, $host, $path, $expiry);
}
/**
* Reads the most specific cookie value from the
* browser cookies.
* @param string $host Host to search.
* @param string $path Applicable path.
* @param string $name Name of cookie to read.
* @return string False if not present, else the
* value as a string.
* @access public
*/
function getCookieValue($host, $path, $name) {
return $this->_cookie_jar->getCookieValue($host, $path, $name);
}
/**
* Reads the current cookies within the base URL.
* @param string $name Key of cookie to find.
* @param SimpleUrl $base Base URL to search from.
* @return string/boolean Null if there is no base URL, false
* if the cookie is not set.
* @access public
*/
function getBaseCookieValue($name, $base) {
if (! $base) {
return null;
}
return $this->getCookieValue($base->getHost(), $base->getPath(), $name);
}
/**
* Switches off cookie sending and recieving.
* @access public
*/
function ignoreCookies() {
$this->_cookies_enabled = false;
}
/**
* Switches back on the cookie sending and recieving.
* @access public
*/
function useCookies() {
$this->_cookies_enabled = true;
}
/**
* Sets the socket timeout for opening a connection.
* @param integer $timeout Maximum time in seconds.
* @access public
*/
function setConnectionTimeout($timeout) {
$this->_connection_timeout = $timeout;
}
/**
* Sets the maximum number of redirects before
* a page will be loaded anyway.
* @param integer $max Most hops allowed.
* @access public
*/
function setMaximumRedirects($max) {
$this->_max_redirects = $max;
}
/**
* Sets proxy to use on all requests for when
* testing from behind a firewall. Set URL
* to false to disable.
* @param string $proxy Proxy URL.
* @param string $username Proxy username for authentication.
* @param string $password Proxy password for authentication.
* @access public
*/
function useProxy($proxy, $username, $password) {
if (! $proxy) {
$this->_proxy = false;
return;
}
if ((strncmp($proxy, 'http://', 7) != 0) && (strncmp($proxy, 'https://', 8) != 0)) {
$proxy = 'http://'. $proxy;
}
$this->_proxy = &new SimpleUrl($proxy);
$this->_proxy_username = $username;
$this->_proxy_password = $password;
}
/**
* Test to see if the redirect limit is passed.
* @param integer $redirects Count so far.
* @return boolean True if over.
* @access private
*/
function _isTooManyRedirects($redirects) {
return ($redirects > $this->_max_redirects);
}
/**
* Sets the identity for the current realm.
* @param string $host Host to which realm applies.
* @param string $realm Full name of realm.
* @param string $username Username for realm.
* @param string $password Password for realm.
* @access public
*/
function setIdentity($host, $realm, $username, $password) {
$this->_authenticator->setIdentityForRealm($host, $realm, $username, $password);
}
/**
* Fetches a URL as a response object. Will keep trying if redirected.
* It will also collect authentication realm information.
* @param string/SimpleUrl $url Target to fetch.
* @param SimpleEncoding $encoding Additional parameters for request.
* @return SimpleHttpResponse Hopefully the target page.
* @access public
*/
function &fetchResponse($url, $encoding) {
if ($encoding->getMethod() != 'POST') {
$url->addRequestParameters($encoding);
$encoding->clear();
}
$response = &$this->_fetchWhileRedirected($url, $encoding);
if ($headers = $response->getHeaders()) {
if ($headers->isChallenge()) {
$this->_authenticator->addRealm(
$url,
$headers->getAuthentication(),
$headers->getRealm());
}
}
return $response;
}
/**
* Fetches the page until no longer redirected or
* until the redirect limit runs out.
* @param SimpleUrl $url Target to fetch.
* @param SimpelFormEncoding $encoding Additional parameters for request.
* @return SimpleHttpResponse Hopefully the target page.
* @access private
*/
function &_fetchWhileRedirected($url, $encoding) {
$redirects = 0;
do {
$response = &$this->_fetch($url, $encoding);
if ($response->isError()) {
return $response;
}
$headers = $response->getHeaders();
$location = new SimpleUrl($headers->getLocation());
$url = $location->makeAbsolute($url);
if ($this->_cookies_enabled) {
$headers->writeCookiesToJar($this->_cookie_jar, $url);
}
if (! $headers->isRedirect()) {
break;
}
$encoding = new SimpleGetEncoding();
} while (! $this->_isTooManyRedirects(++$redirects));
return $response;
}
/**
* Actually make the web request.
* @param SimpleUrl $url Target to fetch.
* @param SimpleFormEncoding $encoding Additional parameters for request.
* @return SimpleHttpResponse Headers and hopefully content.
* @access protected
*/
function &_fetch($url, $encoding) {
$request = &$this->_createRequest($url, $encoding);
$response = &$request->fetch($this->_connection_timeout);
return $response;
}
/**
* Creates a full page request.
* @param SimpleUrl $url Target to fetch as url object.
* @param SimpleFormEncoding $encoding POST/GET parameters.
* @return SimpleHttpRequest New request.
* @access private
*/
function &_createRequest($url, $encoding) {
$request = &$this->_createHttpRequest($url, $encoding);
$this->_addAdditionalHeaders($request);
if ($this->_cookies_enabled) {
$request->readCookiesFromJar($this->_cookie_jar, $url);
}
$this->_authenticator->addHeaders($request, $url);
return $request;
}
/**
* Builds the appropriate HTTP request object.
* @param SimpleUrl $url Target to fetch as url object.
* @param SimpleFormEncoding $parameters POST/GET parameters.
* @return SimpleHttpRequest New request object.
* @access protected
*/
function &_createHttpRequest($url, $encoding) {
$request = &new SimpleHttpRequest($this->_createRoute($url), $encoding);
return $request;
}
/**
* Sets up either a direct route or via a proxy.
* @param SimpleUrl $url Target to fetch as url object.
* @return SimpleRoute Route to take to fetch URL.
* @access protected
*/
function &_createRoute($url) {
if ($this->_proxy) {
$route = &new SimpleProxyRoute(
$response = &$this->_fetchWhileRedirected($url, $encoding);
if ($headers = $response->getHeaders()) {
if ($headers->isChallenge()) {
$this->_authenticator->addRealm(
$url,
$this->_proxy,
$this->_proxy_username,
$this->_proxy_password);
} else {
$route = &new SimpleRoute($url);
$headers->getAuthentication(),
$headers->getRealm());
}
return $route;
}
/**
* Adds additional manual headers.
* @param SimpleHttpRequest $request Outgoing request.
* @access private
*/
function _addAdditionalHeaders(&$request) {
foreach ($this->_additional_headers as $header) {
$request->addHeaderLine($header);
return $response;
}
/**
* Fetches the page until no longer redirected or
* until the redirect limit runs out.
* @param SimpleUrl $url Target to fetch.
* @param SimpelFormEncoding $encoding Additional parameters for request.
* @return SimpleHttpResponse Hopefully the target page.
* @access private
*/
function &_fetchWhileRedirected($url, $encoding) {
$redirects = 0;
do {
$response = &$this->_fetch($url, $encoding);
if ($response->isError()) {
return $response;
}
$headers = $response->getHeaders();
$location = new SimpleUrl($headers->getLocation());
$url = $location->makeAbsolute($url);
if ($this->_cookies_enabled) {
$headers->writeCookiesToJar($this->_cookie_jar, $url);
}
if (! $headers->isRedirect()) {
break;
}
$encoding = new SimpleGetEncoding();
} while (! $this->_isTooManyRedirects(++$redirects));
return $response;
}
/**
* Actually make the web request.
* @param SimpleUrl $url Target to fetch.
* @param SimpleFormEncoding $encoding Additional parameters for request.
* @return SimpleHttpResponse Headers and hopefully content.
* @access protected
*/
function &_fetch($url, $encoding) {
$request = &$this->_createRequest($url, $encoding);
$response = &$request->fetch($this->_connection_timeout);
return $response;
}
/**
* Creates a full page request.
* @param SimpleUrl $url Target to fetch as url object.
* @param SimpleFormEncoding $encoding POST/GET parameters.
* @return SimpleHttpRequest New request.
* @access private
*/
function &_createRequest($url, $encoding) {
$request = &$this->_createHttpRequest($url, $encoding);
$this->_addAdditionalHeaders($request);
if ($this->_cookies_enabled) {
$request->readCookiesFromJar($this->_cookie_jar, $url);
}
$this->_authenticator->addHeaders($request, $url);
return $request;
}
/**
* Builds the appropriate HTTP request object.
* @param SimpleUrl $url Target to fetch as url object.
* @param SimpleFormEncoding $parameters POST/GET parameters.
* @return SimpleHttpRequest New request object.
* @access protected
*/
function &_createHttpRequest($url, $encoding) {
$request = &new SimpleHttpRequest($this->_createRoute($url), $encoding);
return $request;
}
/**
* Sets up either a direct route or via a proxy.
* @param SimpleUrl $url Target to fetch as url object.
* @return SimpleRoute Route to take to fetch URL.
* @access protected
*/
function &_createRoute($url) {
if ($this->_proxy) {
$route = &new SimpleProxyRoute(
$url,
$this->_proxy,
$this->_proxy_username,
$this->_proxy_password);
} else {
$route = &new SimpleRoute($url);
}
return $route;
}
/**
* Adds additional manual headers.
* @param SimpleHttpRequest $request Outgoing request.
* @access private
*/
function _addAdditionalHeaders(&$request) {
foreach ($this->_additional_headers as $header) {
$request->addHeaderLine($header);
}
}
}
?>
File diff suppressed because it is too large Load Diff
+617 -617
View File
File diff suppressed because it is too large Load Diff