diff --git a/.gitignore b/.gitignore
index 344ed21..846324e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,5 @@
*.DS_Store
settings.json
errors.txt
-*/simpletest/*
tests/test_dbs/*
test_config.json
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..f7735a4
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,13 @@
+language: php
+
+php:
+ - 5.2
+ - 5.3
+ - 5.4
+
+before_script:
+ - sh -c "psql -c 'DROP DATABASE IF EXISTS test;' -U postgres"
+ - sh -c "psql -c 'create database test;' -U postgres"
+ - sh -c "mysql -e 'create database IF NOT EXISTS test;'"
+
+script: php ./tests/index.php
\ No newline at end of file
diff --git a/sys/db/drivers/pgsql.php b/sys/db/drivers/pgsql.php
index 30722b8..78e7b9e 100644
--- a/sys/db/drivers/pgsql.php
+++ b/sys/db/drivers/pgsql.php
@@ -89,8 +89,15 @@ SQL;
$res = $this->query($sql);
$tables = $res->fetchAll(PDO::FETCH_ASSOC);
+
+ $good_tables = array();
+
+ foreach($tables as $t)
+ {
+ $good_tables[] = $t['tablename'];
+ }
- return $tables;
+ return $good_tables;
}
// --------------------------------------------------------------------------
diff --git a/tests/databases/mysql-qb.php b/tests/databases/mysql-qb.php
index 8c444ee..cc23b17 100644
--- a/tests/databases/mysql-qb.php
+++ b/tests/databases/mysql-qb.php
@@ -29,6 +29,19 @@ class MySQLQBTest extends QBTest {
// echo '
MySQL Queries
';
}
+ elseif (($var = getenv('CI')))
+ {
+ $params = array(
+ 'host' => '127.0.0.1',
+ 'port' => '3306',
+ 'database' => 'test',
+ 'user' => 'root',
+ 'pass' => NULL,
+ 'type' => 'mysql'
+ );
+
+ $this->db = new Query_Builder($params);
+ }
}
diff --git a/tests/databases/mysql.php b/tests/databases/mysql.php
index 923258c..3c41f73 100644
--- a/tests/databases/mysql.php
+++ b/tests/databases/mysql.php
@@ -29,6 +29,10 @@ class MySQLTest extends DBTest {
$this->db = new MySQL("host={$params->host};port={$params->port};dbname={$params->database}", $params->user, $params->pass);
}
+ elseif (($var = getenv('CI')))
+ {
+ $this->db = new MySQL('host=127.0.0.1;port=3306;dbname=test', 'root');
+ }
}
function TestExists()
diff --git a/tests/databases/pgsql-qb.php b/tests/databases/pgsql-qb.php
index 7ccd13b..0cdc513 100644
--- a/tests/databases/pgsql-qb.php
+++ b/tests/databases/pgsql-qb.php
@@ -30,6 +30,19 @@ class PgSQLQBTest extends QBTest {
// echo '
Postgres Queries
';
}
+ elseif (($var = getenv('CI')))
+ {
+ $params = array(
+ 'host' => '127.0.0.1',
+ 'port' => '5432',
+ 'database' => 'test',
+ 'user' => 'postgres',
+ 'pass' => '',
+ 'type' => 'pgsql'
+ );
+
+ $this->db = new Query_Builder($params);
+ }
}
function TestExists()
diff --git a/tests/databases/pgsql.php b/tests/databases/pgsql.php
index 8acae01..57891ce 100644
--- a/tests/databases/pgsql.php
+++ b/tests/databases/pgsql.php
@@ -34,6 +34,10 @@ class PgTest extends DBTest {
$this->db = new PgSQL("host={$params->host};port={$params->port};dbname={$params->database}", $params->user, $params->pass);
}
+ elseif (($var = getenv('CI')))
+ {
+ $this->db = new PgSQL('host=127.0.0.1;port=5432;dbname=test', 'postgres');
+ }
}
function TestExists()
@@ -48,9 +52,16 @@ class PgTest extends DBTest {
$this->assertIsA($this->db, 'PgSQL');
}
- /*function TestCreateTable()
+ function TestCreateTable()
{
if (empty($this->db)) return;
+
+ // Drop the table(s) if they exist
+ $sql = 'DROP TABLE IF EXISTS "create_test"';
+ $this->db->query($sql);
+ $sql = 'DROP TABLE IF EXISTS "create_join"';
+ $this->db->query($sql);
+
//Attempt to create the table
$sql = $this->db->sql->create_table('create_test',
@@ -79,12 +90,15 @@ class PgTest extends DBTest {
);
$this->db->query($sql);
- echo $sql.'
';
+ //echo $sql.'
';
+
+ //Reset
+ unset($this->db);
+ $this->setUp();
//Check
$dbs = $this->db->get_tables();
-
$this->assertTrue(in_array('create_test', $dbs));
- }*/
+ }
}
\ No newline at end of file
diff --git a/tests/index.php b/tests/index.php
index 672abae..63c2f09 100644
--- a/tests/index.php
+++ b/tests/index.php
@@ -15,10 +15,11 @@
/**
* Unit test bootstrap - Using php simpletest
*/
-define('BASE_DIR', '../src');
define('TEST_DIR', dirname(__FILE__));
+define('BASE_DIR', str_replace(basename(TEST_DIR), '', TEST_DIR).'/sys/');
define('DS', DIRECTORY_SEPARATOR);
+
// Include simpletest
// it has to be set in your php path, or put in the tests folder
require_once('simpletest/autorun.php');
@@ -34,14 +35,14 @@ function do_include($path)
// Include core tests
require_once("core.php");
-require_once("../sys/db/db_pdo.php");
-require_once("../sys/db/query_builder.php");
+require_once(BASE_DIR.'db/db_pdo.php');
+require_once(BASE_DIR.'db/query_builder.php');
// Include db tests
// Load db classes based on capability
-$src_path = "../sys/db/drivers/";
-$test_path = "./databases/";
+$src_path = BASE_DIR.'db/drivers/';
+$test_path = TEST_DIR.'/databases/';
foreach(pdo_drivers() as $d)
{
diff --git a/tests/simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE b/tests/simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE
new file mode 100644
index 0000000..a65e83e
--- /dev/null
+++ b/tests/simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE
@@ -0,0 +1,399 @@
+Simple Test interface changes
+=============================
+Because the SimpleTest tool set is still evolving it is likely that tests
+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...
+
+assertText() no longer finds a string inside a ', 'js');
+ $this->mapHandler('comment', 'ignore');
+ $this->addEntryPattern('', 'comment');
+ }
+
+ /**
+ * Pattern matches to start and end a tag.
+ * @param string $tag Name of tag to scan for.
+ * @access private
+ */
+ protected function addTag($tag) {
+ $this->addSpecialPattern("$tag>", 'text', 'acceptEndToken');
+ $this->addEntryPattern("<$tag", 'text', 'tag');
+ }
+
+ /**
+ * Pattern matches to parse the inside of a tag
+ * including the attributes and their quoting.
+ * @access private
+ */
+ protected function addInTagTokens() {
+ $this->mapHandler('tag', 'acceptStartToken');
+ $this->addSpecialPattern('\s+', 'tag', 'ignore');
+ $this->addAttributeTokens();
+ $this->addExitPattern('/>', 'tag');
+ $this->addExitPattern('>', 'tag');
+ }
+
+ /**
+ * Matches attributes that are either single quoted,
+ * double quoted or unquoted.
+ * @access private
+ */
+ protected function addAttributeTokens() {
+ $this->mapHandler('dq_attribute', 'acceptAttributeToken');
+ $this->addEntryPattern('=\s*"', 'tag', 'dq_attribute');
+ $this->addPattern("\\\\\"", 'dq_attribute');
+ $this->addExitPattern('"', 'dq_attribute');
+ $this->mapHandler('sq_attribute', 'acceptAttributeToken');
+ $this->addEntryPattern("=\s*'", 'tag', 'sq_attribute');
+ $this->addPattern("\\\\'", 'sq_attribute');
+ $this->addExitPattern("'", 'sq_attribute');
+ $this->mapHandler('uq_attribute', 'acceptAttributeToken');
+ $this->addSpecialPattern('=\s*[^>\s]*', 'tag', 'uq_attribute');
+ }
+}
+
+/**
+ * Converts HTML tokens into selected SAX events.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleHtmlSaxParser {
+ private $lexer;
+ private $listener;
+ private $tag;
+ private $attributes;
+ private $current_attribute;
+
+ /**
+ * Sets the listener.
+ * @param SimplePhpPageBuilder $listener SAX event handler.
+ * @access public
+ */
+ function __construct($listener) {
+ $this->listener = $listener;
+ $this->lexer = $this->createLexer($this);
+ $this->tag = '';
+ $this->attributes = array();
+ $this->current_attribute = '';
+ }
+
+ /**
+ * Runs the content through the lexer which
+ * should call back to the acceptors.
+ * @param string $raw Page text to parse.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function parse($raw) {
+ return $this->lexer->parse($raw);
+ }
+
+ /**
+ * Sets up the matching lexer. Starts in 'text' mode.
+ * @param SimpleSaxParser $parser Event generator, usually $self.
+ * @return SimpleLexer Lexer suitable for this parser.
+ * @access public
+ */
+ static function createLexer(&$parser) {
+ return new SimpleHtmlLexer($parser);
+ }
+
+ /**
+ * Accepts a token from the tag mode. If the
+ * starting element completes then the element
+ * is dispatched and the current attributes
+ * set back to empty. The element or attribute
+ * name is converted to lower case.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function acceptStartToken($token, $event) {
+ if ($event == LEXER_ENTER) {
+ $this->tag = strtolower(substr($token, 1));
+ return true;
+ }
+ if ($event == LEXER_EXIT) {
+ $success = $this->listener->startElement(
+ $this->tag,
+ $this->attributes);
+ $this->tag = '';
+ $this->attributes = array();
+ return $success;
+ }
+ if ($token != '=') {
+ $this->current_attribute = strtolower(html_entity_decode($token, ENT_QUOTES));
+ $this->attributes[$this->current_attribute] = '';
+ }
+ return true;
+ }
+
+ /**
+ * Accepts a token from the end tag mode.
+ * The element name is converted to lower case.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function acceptEndToken($token, $event) {
+ if (! preg_match('/<\/(.*)>/', $token, $matches)) {
+ return false;
+ }
+ return $this->listener->endElement(strtolower($matches[1]));
+ }
+
+ /**
+ * Part of the tag data.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function acceptAttributeToken($token, $event) {
+ if ($this->current_attribute) {
+ if ($event == LEXER_UNMATCHED) {
+ $this->attributes[$this->current_attribute] .=
+ html_entity_decode($token, ENT_QUOTES);
+ }
+ if ($event == LEXER_SPECIAL) {
+ $this->attributes[$this->current_attribute] .=
+ preg_replace('/^=\s*/' , '', html_entity_decode($token, ENT_QUOTES));
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A character entity.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function acceptEntityToken($token, $event) {
+ }
+
+ /**
+ * Character data between tags regarded as
+ * important.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function acceptTextToken($token, $event) {
+ return $this->listener->addContent($token);
+ }
+
+ /**
+ * Incoming data to be ignored.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function ignore($token, $event) {
+ return true;
+ }
+}
+
+/**
+ * SAX event handler. Maintains a list of
+ * open tags and dispatches them as they close.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimplePhpPageBuilder {
+ private $tags;
+ private $page;
+ private $private_content_tag;
+ private $open_forms = array();
+ private $complete_forms = array();
+ private $frameset = false;
+ private $loading_frames = array();
+ private $frameset_nesting_level = 0;
+ private $left_over_labels = array();
+
+ /**
+ * Frees up any references so as to allow the PHP garbage
+ * collection from unset() to work.
+ * @access public
+ */
+ function free() {
+ unset($this->tags);
+ unset($this->page);
+ unset($this->private_content_tags);
+ $this->open_forms = array();
+ $this->complete_forms = array();
+ $this->frameset = false;
+ $this->loading_frames = array();
+ $this->frameset_nesting_level = 0;
+ $this->left_over_labels = array();
+ }
+
+ /**
+ * This builder is always available.
+ * @return boolean Always true.
+ */
+ function can() {
+ return true;
+ }
+
+ /**
+ * Reads the raw content and send events
+ * into the page to be built.
+ * @param $response SimpleHttpResponse Fetched response.
+ * @return SimplePage Newly parsed page.
+ * @access public
+ */
+ function parse($response) {
+ $this->tags = array();
+ $this->page = $this->createPage($response);
+ $parser = $this->createParser($this);
+ $parser->parse($response->getContent());
+ $this->acceptPageEnd();
+ $page = $this->page;
+ $this->free();
+ return $page;
+ }
+
+ /**
+ * Creates an empty page.
+ * @return SimplePage New unparsed page.
+ * @access protected
+ */
+ protected function createPage($response) {
+ return new SimplePage($response);
+ }
+
+ /**
+ * Creates the parser used with the builder.
+ * @param SimplePhpPageBuilder $listener Target of parser.
+ * @return SimpleSaxParser Parser to generate
+ * events for the builder.
+ * @access protected
+ */
+ protected function createParser(&$listener) {
+ return new SimpleHtmlSaxParser($listener);
+ }
+
+ /**
+ * Start of element event. Opens a new tag.
+ * @param string $name Element name.
+ * @param hash $attributes Attributes without content
+ * are marked as true.
+ * @return boolean False on parse error.
+ * @access public
+ */
+ function startElement($name, $attributes) {
+ $factory = new SimpleTagBuilder();
+ $tag = $factory->createTag($name, $attributes);
+ if (! $tag) {
+ return true;
+ }
+ if ($tag->getTagName() == 'label') {
+ $this->acceptLabelStart($tag);
+ $this->openTag($tag);
+ return true;
+ }
+ if ($tag->getTagName() == 'form') {
+ $this->acceptFormStart($tag);
+ return true;
+ }
+ if ($tag->getTagName() == 'frameset') {
+ $this->acceptFramesetStart($tag);
+ return true;
+ }
+ if ($tag->getTagName() == 'frame') {
+ $this->acceptFrame($tag);
+ return true;
+ }
+ if ($tag->isPrivateContent() && ! isset($this->private_content_tag)) {
+ $this->private_content_tag = &$tag;
+ }
+ if ($tag->expectEndTag()) {
+ $this->openTag($tag);
+ return true;
+ }
+ $this->acceptTag($tag);
+ return true;
+ }
+
+ /**
+ * End of element event.
+ * @param string $name Element name.
+ * @return boolean False on parse error.
+ * @access public
+ */
+ function endElement($name) {
+ if ($name == 'label') {
+ $this->acceptLabelEnd();
+ return true;
+ }
+ if ($name == 'form') {
+ $this->acceptFormEnd();
+ return true;
+ }
+ if ($name == 'frameset') {
+ $this->acceptFramesetEnd();
+ return true;
+ }
+ if ($this->hasNamedTagOnOpenTagStack($name)) {
+ $tag = array_pop($this->tags[$name]);
+ if ($tag->isPrivateContent() && $this->private_content_tag->getTagName() == $name) {
+ unset($this->private_content_tag);
+ }
+ $this->addContentTagToOpenTags($tag);
+ $this->acceptTag($tag);
+ return true;
+ }
+ return true;
+ }
+
+ /**
+ * Test to see if there are any open tags awaiting
+ * closure that match the tag name.
+ * @param string $name Element name.
+ * @return boolean True if any are still open.
+ * @access private
+ */
+ protected function hasNamedTagOnOpenTagStack($name) {
+ return isset($this->tags[$name]) && (count($this->tags[$name]) > 0);
+ }
+
+ /**
+ * Unparsed, but relevant data. The data is added
+ * to every open tag.
+ * @param string $text May include unparsed tags.
+ * @return boolean False on parse error.
+ * @access public
+ */
+ function addContent($text) {
+ if (isset($this->private_content_tag)) {
+ $this->private_content_tag->addContent($text);
+ } else {
+ $this->addContentToAllOpenTags($text);
+ }
+ return true;
+ }
+
+ /**
+ * Any content fills all currently open tags unless it
+ * is part of an option tag.
+ * @param string $text May include unparsed tags.
+ * @access private
+ */
+ protected function addContentToAllOpenTags($text) {
+ foreach (array_keys($this->tags) as $name) {
+ for ($i = 0, $count = count($this->tags[$name]); $i < $count; $i++) {
+ $this->tags[$name][$i]->addContent($text);
+ }
+ }
+ }
+
+ /**
+ * Parsed data in tag form. The parsed tag is added
+ * to every open tag. Used for adding options to select
+ * fields only.
+ * @param SimpleTag $tag Option tags only.
+ * @access private
+ */
+ protected function addContentTagToOpenTags(&$tag) {
+ if ($tag->getTagName() != 'option') {
+ return;
+ }
+ foreach (array_keys($this->tags) as $name) {
+ for ($i = 0, $count = count($this->tags[$name]); $i < $count; $i++) {
+ $this->tags[$name][$i]->addTag($tag);
+ }
+ }
+ }
+
+ /**
+ * Opens a tag for receiving content. Multiple tags
+ * will be receiving input at the same time.
+ * @param SimpleTag $tag New content tag.
+ * @access private
+ */
+ protected function openTag($tag) {
+ $name = $tag->getTagName();
+ if (! in_array($name, array_keys($this->tags))) {
+ $this->tags[$name] = array();
+ }
+ $this->tags[$name][] = $tag;
+ }
+
+ /**
+ * Adds a tag to the page.
+ * @param SimpleTag $tag Tag to accept.
+ * @access public
+ */
+ protected function acceptTag($tag) {
+ if ($tag->getTagName() == "a") {
+ $this->page->addLink($tag);
+ } elseif ($tag->getTagName() == "base") {
+ $this->page->setBase($tag->getAttribute('href'));
+ } elseif ($tag->getTagName() == "title") {
+ $this->page->setTitle($tag);
+ } elseif ($this->isFormElement($tag->getTagName())) {
+ for ($i = 0; $i < count($this->open_forms); $i++) {
+ $this->open_forms[$i]->addWidget($tag);
+ }
+ $this->last_widget = $tag;
+ }
+ }
+
+ /**
+ * Opens a label for a described widget.
+ * @param SimpleFormTag $tag Tag to accept.
+ * @access public
+ */
+ protected function acceptLabelStart($tag) {
+ $this->label = $tag;
+ unset($this->last_widget);
+ }
+
+ /**
+ * Closes the most recently opened label.
+ * @access public
+ */
+ protected function acceptLabelEnd() {
+ if (isset($this->label)) {
+ if (isset($this->last_widget)) {
+ $this->last_widget->setLabel($this->label->getText());
+ unset($this->last_widget);
+ } else {
+ $this->left_over_labels[] = SimpleTestCompatibility::copy($this->label);
+ }
+ unset($this->label);
+ }
+ }
+
+ /**
+ * Tests to see if a tag is a possible form
+ * element.
+ * @param string $name HTML element name.
+ * @return boolean True if form element.
+ * @access private
+ */
+ protected function isFormElement($name) {
+ return in_array($name, array('input', 'button', 'textarea', 'select'));
+ }
+
+ /**
+ * Opens a form. New widgets go here.
+ * @param SimpleFormTag $tag Tag to accept.
+ * @access public
+ */
+ protected function acceptFormStart($tag) {
+ $this->open_forms[] = new SimpleForm($tag, $this->page);
+ }
+
+ /**
+ * Closes the most recently opened form.
+ * @access public
+ */
+ protected function acceptFormEnd() {
+ if (count($this->open_forms)) {
+ $this->complete_forms[] = array_pop($this->open_forms);
+ }
+ }
+
+ /**
+ * Opens a frameset. A frameset may contain nested
+ * frameset tags.
+ * @param SimpleFramesetTag $tag Tag to accept.
+ * @access public
+ */
+ protected function acceptFramesetStart($tag) {
+ if (! $this->isLoadingFrames()) {
+ $this->frameset = $tag;
+ }
+ $this->frameset_nesting_level++;
+ }
+
+ /**
+ * Closes the most recently opened frameset.
+ * @access public
+ */
+ protected function acceptFramesetEnd() {
+ if ($this->isLoadingFrames()) {
+ $this->frameset_nesting_level--;
+ }
+ }
+
+ /**
+ * Takes a single frame tag and stashes it in
+ * the current frame set.
+ * @param SimpleFrameTag $tag Tag to accept.
+ * @access public
+ */
+ protected function acceptFrame($tag) {
+ if ($this->isLoadingFrames()) {
+ if ($tag->getAttribute('src')) {
+ $this->loading_frames[] = $tag;
+ }
+ }
+ }
+
+ /**
+ * Test to see if in the middle of reading
+ * a frameset.
+ * @return boolean True if inframeset.
+ * @access private
+ */
+ protected function isLoadingFrames() {
+ return $this->frameset and $this->frameset_nesting_level > 0;
+ }
+
+ /**
+ * Marker for end of complete page. Any work in
+ * progress can now be closed.
+ * @access public
+ */
+ protected function acceptPageEnd() {
+ while (count($this->open_forms)) {
+ $this->complete_forms[] = array_pop($this->open_forms);
+ }
+ foreach ($this->left_over_labels as $label) {
+ for ($i = 0, $count = count($this->complete_forms); $i < $count; $i++) {
+ $this->complete_forms[$i]->attachLabelBySelector(
+ new SimpleById($label->getFor()),
+ $label->getText());
+ }
+ }
+ $this->page->setForms($this->complete_forms);
+ $this->page->setFrames($this->loading_frames);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/recorder.php b/tests/simpletest/recorder.php
new file mode 100644
index 0000000..b3d0d01
--- /dev/null
+++ b/tests/simpletest/recorder.php
@@ -0,0 +1,101 @@
+time, $this->breadcrumb, $this->message) =
+ array(time(), $breadcrumb, $message);
+ }
+}
+
+/**
+ * A single pass captured for later.
+ * @package SimpleTest
+ * @subpackage Extensions
+ */
+class SimpleResultOfPass extends SimpleResult { }
+
+/**
+ * A single failure captured for later.
+ * @package SimpleTest
+ * @subpackage Extensions
+ */
+class SimpleResultOfFail extends SimpleResult { }
+
+/**
+ * A single exception captured for later.
+ * @package SimpleTest
+ * @subpackage Extensions
+ */
+class SimpleResultOfException extends SimpleResult { }
+
+/**
+ * Array-based test recorder. Returns an array
+ * with timestamp, status, test name and message for each pass and failure.
+ * @package SimpleTest
+ * @subpackage Extensions
+ */
+class Recorder extends SimpleReporterDecorator {
+ public $results = array();
+
+ /**
+ * Stashes the pass as a SimpleResultOfPass
+ * for later retrieval.
+ * @param string $message Pass message to be displayed
+ * eventually.
+ */
+ function paintPass($message) {
+ parent::paintPass($message);
+ $this->results[] = new SimpleResultOfPass(parent::getTestList(), $message);
+ }
+
+ /**
+ * Stashes the fail as a SimpleResultOfFail
+ * for later retrieval.
+ * @param string $message Failure message to be displayed
+ * eventually.
+ */
+ function paintFail($message) {
+ parent::paintFail($message);
+ $this->results[] = new SimpleResultOfFail(parent::getTestList(), $message);
+ }
+
+ /**
+ * Stashes the exception as a SimpleResultOfException
+ * for later retrieval.
+ * @param string $message Exception message to be displayed
+ * eventually.
+ */
+ function paintException($message) {
+ parent::paintException($message);
+ $this->results[] = new SimpleResultOfException(parent::getTestList(), $message);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/reflection_php4.php b/tests/simpletest/reflection_php4.php
new file mode 100644
index 0000000..39801ea
--- /dev/null
+++ b/tests/simpletest/reflection_php4.php
@@ -0,0 +1,136 @@
+_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()";
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/reflection_php5.php b/tests/simpletest/reflection_php5.php
new file mode 100644
index 0000000..43d8a7b
--- /dev/null
+++ b/tests/simpletest/reflection_php5.php
@@ -0,0 +1,386 @@
+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
+ */
+ protected 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.
+ * @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
+ */
+ protected 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
+ */
+ protected 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;
+ }
+
+ /**
+ * Checks whether a method is abstract or not.
+ * @param string $name Method name.
+ * @return bool true if method is abstract, else false
+ * @access private
+ */
+ protected 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
+ */
+ protected 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
+ */
+ protected 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
+ */
+ protected 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()";
+ }
+
+ // This wonky try-catch is a work around for a faulty method_exists()
+ // in early versions of PHP 5 which would return false for static
+ // methods. The Reflection classes work fine, but hasMethod()
+ // doesn't exist prior to PHP 5.1.0, so we need to use a more crude
+ // detection method.
+ try {
+ $interface = new ReflectionClass($this->interface);
+ $interface->getMethod($name);
+ } catch (ReflectionException $e) {
+ return "function $name()";
+ }
+ return $this->getFullSignature($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
+ */
+ protected 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
+ */
+ protected 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
+ */
+ protected 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
+ */
+ protected function isOptional($parameter) {
+ if (method_exists($parameter, 'isOptional')) {
+ return $parameter->isOptional();
+ }
+ return false;
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/remote.php b/tests/simpletest/remote.php
new file mode 100644
index 0000000..4bb37b7
--- /dev/null
+++ b/tests/simpletest/remote.php
@@ -0,0 +1,115 @@
+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 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) {
+ $browser = $this->createBrowser();
+ $xml = $browser->get($this->url);
+ if (! $xml) {
+ trigger_error('Cannot read remote test URL [' . $this->url . ']');
+ return false;
+ }
+ $parser = $this->createParser($reporter);
+ if (! $parser->parse($xml)) {
+ trigger_error('Cannot parse incoming XML from [' . $this->url . ']');
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates a new web browser object for fetching
+ * the XML report.
+ * @return SimpleBrowser New browser.
+ * @access protected
+ */
+ protected function createBrowser() {
+ return new SimpleBrowser();
+ }
+
+ /**
+ * Creates the XML parser.
+ * @param SimpleReporter $reporter Target of test results.
+ * @return SimpleTestXmlListener XML reader.
+ * @access protected
+ */
+ protected function createParser($reporter) {
+ return new SimpleTestXmlParser($reporter);
+ }
+
+ /**
+ * 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;
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/reporter.php b/tests/simpletest/reporter.php
new file mode 100644
index 0000000..bd4f3fa
--- /dev/null
+++ b/tests/simpletest/reporter.php
@@ -0,0 +1,445 @@
+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 "";
+ print "\n\n$test_name\n";
+ print "\n";
+ print "\n";
+ print "\n\n";
+ print "$test_name
\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
+ */
+ 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 "";
+ print $this->getTestCaseProgress() . "/" . $this->getTestCaseCount();
+ print " test cases complete:\n";
+ print "" . $this->getPassCount() . " passes, ";
+ print "" . $this->getFailCount() . " fails and ";
+ print "" . $this->getExceptionCount() . " exceptions.";
+ print "
\n";
+ print "\n\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.
+ */
+ function paintFail($message) {
+ parent::paintFail($message);
+ print "Fail: ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ print " -> " . $this->htmlEntities($message) . "
\n";
+ }
+
+ /**
+ * Paints a PHP error.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintError($message) {
+ parent::paintError($message);
+ print "Exception: ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ print " -> " . $this->htmlEntities($message) . "
\n";
+ }
+
+ /**
+ * Paints a PHP exception.
+ * @param Exception $exception Exception to display.
+ * @access public
+ */
+ function paintException($exception) {
+ parent::paintException($exception);
+ print "Exception: ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ $message = 'Unexpected exception of type [' . get_class($exception) .
+ '] with message ['. $exception->getMessage() .
+ '] in ['. $exception->getFile() .
+ ' line ' . $exception->getLine() . ']';
+ print " -> " . $this->htmlEntities($message) . "
\n";
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ parent::paintSkip($message);
+ print "Skipped: ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ print " -> " . $this->htmlEntities($message) . "
\n";
+ }
+
+ /**
+ * Paints formatted text such as dumped privateiables.
+ * @param string $message Text to show.
+ * @access public
+ */
+ function paintFormattedMessage($message) {
+ print '' . $this->htmlEntities($message) . '
';
+ }
+
+ /**
+ * Character set adjusted entity conversion.
+ * @param string $message Plain text or Unicode message.
+ * @return string Browser readable message.
+ * @access protected
+ */
+ 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.
+ */
+ function __construct() {
+ parent::__construct();
+ }
+
+ /**
+ * 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";
+ $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 privateiables.
+ * @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 {
+ private $just_this_case = false;
+ private $just_this_test = false;
+ private $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 __construct($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);
+ }
+ parent::__construct($reporter);
+ }
+
+ /**
+ * Compares criteria to actual the case/group name.
+ * @param string $test_case The incoming test.
+ * @return boolean True if matched.
+ * @access protected
+ */
+ 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
+ */
+ 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);
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Switch on testing for the group or subgroup.
+ * @access private
+ */
+ protected function on() {
+ $this->on = true;
+ }
+
+ /**
+ * Switch off testing for the group or subgroup.
+ * @access private
+ */
+ protected function off() {
+ $this->on = false;
+ }
+
+ /**
+ * Is this group actually being tested?
+ * @return boolean True if the current test group is active.
+ * @access private
+ */
+ protected function isOn() {
+ return $this->on;
+ }
+
+ /**
+ * 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 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 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) { }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/scorer.php b/tests/simpletest/scorer.php
new file mode 100644
index 0000000..27776f4
--- /dev/null
+++ b/tests/simpletest/scorer.php
@@ -0,0 +1,875 @@
+passes = 0;
+ $this->fails = 0;
+ $this->exceptions = 0;
+ $this->is_dry_run = false;
+ }
+
+ /**
+ * Signals that the next evaluation will be a dry
+ * run. That is, the structure events will be
+ * recorded, but no tests will be run.
+ * @param boolean $is_dry Dry run if true.
+ * @access public
+ */
+ function makeDry($is_dry = true) {
+ $this->is_dry_run = $is_dry;
+ }
+
+ /**
+ * The reporter has a veto on what should be run.
+ * @param string $test_case_name name of test case.
+ * @param string $method Name of test method.
+ * @access public
+ */
+ function shouldInvoke($test_case_name, $method) {
+ return ! $this->is_dry_run;
+ }
+
+ /**
+ * Can wrap the invoker in preperation for running
+ * a test.
+ * @param SimpleInvoker $invoker Individual test runner.
+ * @return SimpleInvoker Wrapped test runner.
+ * @access public
+ */
+ function createInvoker($invoker) {
+ return $invoker;
+ }
+
+ /**
+ * Accessor for current status. Will be false
+ * if there have been any failures or exceptions.
+ * Used for command line tools.
+ * @return boolean True if no failures.
+ * @access public
+ */
+ function getStatus() {
+ if ($this->exceptions + $this->fails > 0) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Paints the start of a group test.
+ * @param string $test_name Name of test or other label.
+ * @param integer $size Number of test cases starting.
+ * @access public
+ */
+ function paintGroupStart($test_name, $size) {
+ }
+
+ /**
+ * Paints the end of a group test.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintGroupEnd($test_name) {
+ }
+
+ /**
+ * Paints the start of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseStart($test_name) {
+ }
+
+ /**
+ * Paints the end of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseEnd($test_name) {
+ }
+
+ /**
+ * Paints the start of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodStart($test_name) {
+ }
+
+ /**
+ * Paints the end of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodEnd($test_name) {
+ }
+
+ /**
+ * Increments the pass count.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintPass($message) {
+ $this->passes++;
+ }
+
+ /**
+ * Increments the fail count.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintFail($message) {
+ $this->fails++;
+ }
+
+ /**
+ * Deals with PHP 4 throwing an error.
+ * @param string $message Text of error formatted by
+ * the test case.
+ * @access public
+ */
+ function paintError($message) {
+ $this->exceptions++;
+ }
+
+ /**
+ * Deals with PHP 5 throwing an exception.
+ * @param Exception $exception The actual exception thrown.
+ * @access public
+ */
+ function paintException($exception) {
+ $this->exceptions++;
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ }
+
+ /**
+ * Accessor for the number of passes so far.
+ * @return integer Number of passes.
+ * @access public
+ */
+ function getPassCount() {
+ return $this->passes;
+ }
+
+ /**
+ * Accessor for the number of fails so far.
+ * @return integer Number of fails.
+ * @access public
+ */
+ function getFailCount() {
+ return $this->fails;
+ }
+
+ /**
+ * Accessor for the number of untrapped errors
+ * so far.
+ * @return integer Number of exceptions.
+ * @access public
+ */
+ function getExceptionCount() {
+ return $this->exceptions;
+ }
+
+ /**
+ * Paints a simple supplementary message.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintMessage($message) {
+ }
+
+ /**
+ * Paints a formatted ASCII message such as a
+ * privateiable dump.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintFormattedMessage($message) {
+ }
+
+ /**
+ * By default just ignores user generated events.
+ * @param string $type Event type as text.
+ * @param mixed $payload Message or object.
+ * @access public
+ */
+ function paintSignal($type, $payload) {
+ }
+}
+
+/**
+ * Recipient of generated test messages that can display
+ * page footers and headers. Also keeps track of the
+ * test nesting. This is the main base class on which
+ * to build the finished test (page based) displays.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class SimpleReporter extends SimpleScorer {
+ private $test_stack;
+ private $size;
+ private $progress;
+
+ /**
+ * Starts the display with no results in.
+ * @access public
+ */
+ function __construct() {
+ parent::__construct();
+ $this->test_stack = array();
+ $this->size = null;
+ $this->progress = 0;
+ }
+
+ /**
+ * Gets the formatter for small generic data items.
+ * @return SimpleDumper Formatter.
+ * @access public
+ */
+ function getDumper() {
+ return new SimpleDumper();
+ }
+
+ /**
+ * Paints the start of a group test. Will also paint
+ * the page header and footer if this is the
+ * first test. Will stash the size if the first
+ * start.
+ * @param string $test_name Name of test that is starting.
+ * @param integer $size Number of test cases starting.
+ * @access public
+ */
+ function paintGroupStart($test_name, $size) {
+ if (! isset($this->size)) {
+ $this->size = $size;
+ }
+ if (count($this->test_stack) == 0) {
+ $this->paintHeader($test_name);
+ }
+ $this->test_stack[] = $test_name;
+ }
+
+ /**
+ * Paints the end of a group test. Will paint the page
+ * footer if the stack of tests has unwound.
+ * @param string $test_name Name of test that is ending.
+ * @param integer $progress Number of test cases ending.
+ * @access public
+ */
+ function paintGroupEnd($test_name) {
+ array_pop($this->test_stack);
+ if (count($this->test_stack) == 0) {
+ $this->paintFooter($test_name);
+ }
+ }
+
+ /**
+ * Paints the start of a test case. Will also paint
+ * the page header and footer if this is the
+ * first test. Will stash the size if the first
+ * start.
+ * @param string $test_name Name of test that is starting.
+ * @access public
+ */
+ function paintCaseStart($test_name) {
+ if (! isset($this->size)) {
+ $this->size = 1;
+ }
+ if (count($this->test_stack) == 0) {
+ $this->paintHeader($test_name);
+ }
+ $this->test_stack[] = $test_name;
+ }
+
+ /**
+ * Paints the end of a test case. Will paint the page
+ * footer if the stack of tests has unwound.
+ * @param string $test_name Name of test that is ending.
+ * @access public
+ */
+ function paintCaseEnd($test_name) {
+ $this->progress++;
+ array_pop($this->test_stack);
+ if (count($this->test_stack) == 0) {
+ $this->paintFooter($test_name);
+ }
+ }
+
+ /**
+ * Paints the start of a test method.
+ * @param string $test_name Name of test that is starting.
+ * @access public
+ */
+ function paintMethodStart($test_name) {
+ $this->test_stack[] = $test_name;
+ }
+
+ /**
+ * Paints the end of a test method. Will paint the page
+ * footer if the stack of tests has unwound.
+ * @param string $test_name Name of test that is ending.
+ * @access public
+ */
+ function paintMethodEnd($test_name) {
+ array_pop($this->test_stack);
+ }
+
+ /**
+ * Paints the test document header.
+ * @param string $test_name First test top level
+ * to start.
+ * @access public
+ * @abstract
+ */
+ function paintHeader($test_name) {
+ }
+
+ /**
+ * Paints the test document footer.
+ * @param string $test_name The top level test.
+ * @access public
+ * @abstract
+ */
+ function paintFooter($test_name) {
+ }
+
+ /**
+ * Accessor for internal test stack. For
+ * subclasses that need to see the whole test
+ * history for display purposes.
+ * @return array List of methods in nesting order.
+ * @access public
+ */
+ function getTestList() {
+ return $this->test_stack;
+ }
+
+ /**
+ * Accessor for total test size in number
+ * of test cases. Null until the first
+ * test is started.
+ * @return integer Total number of cases at start.
+ * @access public
+ */
+ function getTestCaseCount() {
+ return $this->size;
+ }
+
+ /**
+ * Accessor for the number of test cases
+ * completed so far.
+ * @return integer Number of ended cases.
+ * @access public
+ */
+ function getTestCaseProgress() {
+ return $this->progress;
+ }
+
+ /**
+ * Static check for running in the comand line.
+ * @return boolean True if CLI.
+ * @access public
+ */
+ static function inCli() {
+ return php_sapi_name() == 'cli';
+ }
+}
+
+/**
+ * For modifying the behaviour of the visual reporters.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class SimpleReporterDecorator {
+ protected $reporter;
+
+ /**
+ * Mediates between the reporter and the test case.
+ * @param SimpleScorer $reporter Reporter to receive events.
+ */
+ function __construct($reporter) {
+ $this->reporter = $reporter;
+ }
+
+ /**
+ * Signals that the next evaluation will be a dry
+ * run. That is, the structure events will be
+ * recorded, but no tests will be run.
+ * @param boolean $is_dry Dry run if true.
+ * @access public
+ */
+ function makeDry($is_dry = true) {
+ $this->reporter->makeDry($is_dry);
+ }
+
+ /**
+ * Accessor for current status. Will be false
+ * if there have been any failures or exceptions.
+ * Used for command line tools.
+ * @return boolean True if no failures.
+ * @access public
+ */
+ function getStatus() {
+ return $this->reporter->getStatus();
+ }
+
+ /**
+ * The nesting of the test cases so far. Not
+ * all reporters have this facility.
+ * @return array Test list if accessible.
+ * @access public
+ */
+ function getTestList() {
+ if (method_exists($this->reporter, 'getTestList')) {
+ return $this->reporter->getTestList();
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * The reporter has a veto on what should be run.
+ * @param string $test_case_name 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_name, $method) {
+ return $this->reporter->shouldInvoke($test_case_name, $method);
+ }
+
+ /**
+ * Can wrap the invoker in preparation for running
+ * a test.
+ * @param SimpleInvoker $invoker Individual test runner.
+ * @return SimpleInvoker Wrapped test runner.
+ * @access public
+ */
+ function createInvoker($invoker) {
+ return $this->reporter->createInvoker($invoker);
+ }
+
+ /**
+ * Gets the formatter for privateiables and other small
+ * generic data items.
+ * @return SimpleDumper Formatter.
+ * @access public
+ */
+ function getDumper() {
+ return $this->reporter->getDumper();
+ }
+
+ /**
+ * Paints the start of a group test.
+ * @param string $test_name Name of test or other label.
+ * @param integer $size Number of test cases starting.
+ * @access public
+ */
+ function paintGroupStart($test_name, $size) {
+ $this->reporter->paintGroupStart($test_name, $size);
+ }
+
+ /**
+ * Paints the end of a group test.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintGroupEnd($test_name) {
+ $this->reporter->paintGroupEnd($test_name);
+ }
+
+ /**
+ * Paints the start of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseStart($test_name) {
+ $this->reporter->paintCaseStart($test_name);
+ }
+
+ /**
+ * Paints the end of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseEnd($test_name) {
+ $this->reporter->paintCaseEnd($test_name);
+ }
+
+ /**
+ * Paints the start of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodStart($test_name) {
+ $this->reporter->paintMethodStart($test_name);
+ }
+
+ /**
+ * Paints the end of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodEnd($test_name) {
+ $this->reporter->paintMethodEnd($test_name);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintPass($message) {
+ $this->reporter->paintPass($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintFail($message) {
+ $this->reporter->paintFail($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text of error formatted by
+ * the test case.
+ * @access public
+ */
+ function paintError($message) {
+ $this->reporter->paintError($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param Exception $exception Exception to show.
+ * @access public
+ */
+ function paintException($exception) {
+ $this->reporter->paintException($exception);
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ $this->reporter->paintSkip($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintMessage($message) {
+ $this->reporter->paintMessage($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintFormattedMessage($message) {
+ $this->reporter->paintFormattedMessage($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $type Event type as text.
+ * @param mixed $payload Message or object.
+ * @return boolean Should return false if this
+ * type of signal should fail the
+ * test suite.
+ * @access public
+ */
+ function paintSignal($type, $payload) {
+ $this->reporter->paintSignal($type, $payload);
+ }
+}
+
+/**
+ * For sending messages to multiple reporters at
+ * the same time.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class MultipleReporter {
+ private $reporters = array();
+
+ /**
+ * Adds a reporter to the subscriber list.
+ * @param SimpleScorer $reporter Reporter to receive events.
+ * @access public
+ */
+ function attachReporter($reporter) {
+ $this->reporters[] = $reporter;
+ }
+
+ /**
+ * Signals that the next evaluation will be a dry
+ * run. That is, the structure events will be
+ * recorded, but no tests will be run.
+ * @param boolean $is_dry Dry run if true.
+ * @access public
+ */
+ function makeDry($is_dry = true) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->makeDry($is_dry);
+ }
+ }
+
+ /**
+ * Accessor for current status. Will be false
+ * if there have been any failures or exceptions.
+ * If any reporter reports a failure, the whole
+ * suite fails.
+ * @return boolean True if no failures.
+ * @access public
+ */
+ function getStatus() {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ if (! $this->reporters[$i]->getStatus()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The reporter has a veto on what should be run.
+ * It requires all reporters to want to run the method.
+ * @param string $test_case_name name of test case.
+ * @param string $method Name of test method.
+ * @access public
+ */
+ function shouldInvoke($test_case_name, $method) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ if (! $this->reporters[$i]->shouldInvoke($test_case_name, $method)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Every reporter gets a chance to wrap the invoker.
+ * @param SimpleInvoker $invoker Individual test runner.
+ * @return SimpleInvoker Wrapped test runner.
+ * @access public
+ */
+ function createInvoker($invoker) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $invoker = $this->reporters[$i]->createInvoker($invoker);
+ }
+ return $invoker;
+ }
+
+ /**
+ * Gets the formatter for privateiables and other small
+ * generic data items.
+ * @return SimpleDumper Formatter.
+ * @access public
+ */
+ function getDumper() {
+ return new SimpleDumper();
+ }
+
+ /**
+ * Paints the start of a group test.
+ * @param string $test_name Name of test or other label.
+ * @param integer $size Number of test cases starting.
+ * @access public
+ */
+ function paintGroupStart($test_name, $size) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintGroupStart($test_name, $size);
+ }
+ }
+
+ /**
+ * Paints the end of a group test.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintGroupEnd($test_name) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintGroupEnd($test_name);
+ }
+ }
+
+ /**
+ * Paints the start of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseStart($test_name) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintCaseStart($test_name);
+ }
+ }
+
+ /**
+ * Paints the end of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseEnd($test_name) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintCaseEnd($test_name);
+ }
+ }
+
+ /**
+ * Paints the start of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodStart($test_name) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintMethodStart($test_name);
+ }
+ }
+
+ /**
+ * Paints the end of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodEnd($test_name) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintMethodEnd($test_name);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintPass($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintPass($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintFail($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintFail($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text of error formatted by
+ * the test case.
+ * @access public
+ */
+ function paintError($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintError($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param Exception $exception Exception to display.
+ * @access public
+ */
+ function paintException($exception) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintException($exception);
+ }
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintSkip($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintMessage($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintMessage($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintFormattedMessage($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintFormattedMessage($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $type Event type as text.
+ * @param mixed $payload Message or object.
+ * @return boolean Should return false if this
+ * type of signal should fail the
+ * test suite.
+ * @access public
+ */
+ function paintSignal($type, $payload) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintSignal($type, $payload);
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/selector.php b/tests/simpletest/selector.php
new file mode 100644
index 0000000..ba2fed3
--- /dev/null
+++ b/tests/simpletest/selector.php
@@ -0,0 +1,141 @@
+name = $name;
+ }
+
+ /**
+ * Accessor for name.
+ * @returns string $name Name to match.
+ */
+ function getName() {
+ return $this->name;
+ }
+
+ /**
+ * Compares with name attribute of widget.
+ * @param SimpleWidget $widget Control to compare.
+ * @access public
+ */
+ function isMatch($widget) {
+ return ($widget->getName() == $this->name);
+ }
+}
+
+/**
+ * Used to extract form elements for testing against.
+ * Searches by visible label or alt text.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleByLabel {
+ private $label;
+
+ /**
+ * Stashes the name for later comparison.
+ * @param string $label Visible text to match.
+ */
+ function __construct($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);
+ }
+}
+
+/**
+ * Used to extract form elements for testing against.
+ * Searches dy id attribute.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleById {
+ private $id;
+
+ /**
+ * Stashes the name for later comparison.
+ * @param string $id ID atribute to match.
+ */
+ function __construct($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 {
+ private $label;
+
+ /**
+ * Stashes the name/label for later comparison.
+ * @param string $label Visible text to match.
+ */
+ function __construct($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);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/shell_tester.php b/tests/simpletest/shell_tester.php
new file mode 100644
index 0000000..9a3bd38
--- /dev/null
+++ b/tests/simpletest/shell_tester.php
@@ -0,0 +1,330 @@
+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;
+ }
+}
+
+/**
+ * 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 {
+ private $current_shell;
+ private $last_status;
+ private $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 __construct($label = false) {
+ parent::__construct($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") {
+ 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") {
+ 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
+ */
+ protected function getShell() {
+ return $this->current_shell;
+ }
+
+ /**
+ * Factory for the shell to run the command on.
+ * @return Shell New shell object.
+ * @access protected
+ */
+ protected function createShell() {
+ return new SimpleShell();
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/simpletest.php b/tests/simpletest/simpletest.php
new file mode 100644
index 0000000..425c869
--- /dev/null
+++ b/tests/simpletest/simpletest.php
@@ -0,0 +1,391 @@
+getParent()) {
+ SimpleTest::ignore($parent);
+ }
+ }
+ }
+ }
+
+ /**
+ * 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
+ * @see preferred()
+ */
+ static 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.
+ * @return array|object|null
+ * @see prefer()
+ */
+ static function preferred($classes) {
+ if (! is_array($classes)) {
+ $classes = array($classes);
+ }
+ $registry = &SimpleTest::getRegistry();
+ for ($i = count($registry['Preferred']) - 1; $i >= 0; $i--) {
+ foreach ($classes as $class) {
+ if (SimpleTestCompatibility::isA($registry['Preferred'][$i], $class)) {
+ return $registry['Preferred'][$i];
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 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.
+ */
+ static function isIgnored($class) {
+ $registry = &SimpleTest::getRegistry();
+ return isset($registry['IgnoreList'][strtolower($class)]);
+ }
+
+ /**
+ * 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.
+ */
+ static 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.
+ */
+ static function getDefaultProxy() {
+ $registry = &SimpleTest::getRegistry();
+ return $registry['DefaultProxy'];
+ }
+
+ /**
+ * Accessor for default proxy username.
+ * @return string Proxy username for authentication.
+ */
+ static function getDefaultProxyUsername() {
+ $registry = &SimpleTest::getRegistry();
+ return $registry['DefaultProxyUsername'];
+ }
+
+ /**
+ * Accessor for default proxy password.
+ * @return string Proxy password for authentication.
+ */
+ static function getDefaultProxyPassword() {
+ $registry = &SimpleTest::getRegistry();
+ return $registry['DefaultProxyPassword'];
+ }
+
+ /**
+ * Accessor for default HTML parsers.
+ * @return array List of parsers to try in
+ * order until one responds true
+ * to can().
+ */
+ static function getParsers() {
+ $registry = &SimpleTest::getRegistry();
+ return $registry['Parsers'];
+ }
+
+ /**
+ * Set the list of HTML parsers to attempt to use by default.
+ * @param array $parsers List of parsers to try in
+ * order until one responds true
+ * to can().
+ */
+ static function setParsers($parsers) {
+ $registry = &SimpleTest::getRegistry();
+ $registry['Parsers'] = $parsers;
+ }
+
+ /**
+ * Accessor for global registry of options.
+ * @return hash All stored values.
+ */
+ protected 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.
+ */
+ static function getContext() {
+ static $context = false;
+ if (! $context) {
+ $context = new SimpleTestContext();
+ }
+ return $context;
+ }
+
+ /**
+ * Constant default values.
+ * @return hash All registry defaults.
+ */
+ protected static function getDefaults() {
+ return array(
+ 'Parsers' => false,
+ 'MockBaseClass' => 'SimpleMock',
+ 'IgnoreList' => array(),
+ 'DefaultProxy' => false,
+ 'DefaultProxyUsername' => false,
+ 'DefaultProxyPassword' => false,
+ 'Preferred' => array(new HtmlReporter(), new TextReporter(), new XmlReporter()));
+ }
+
+ /**
+ * @deprecated
+ */
+ static function setMockBaseClass($mock_base) {
+ $registry = &SimpleTest::getRegistry();
+ $registry['MockBaseClass'] = $mock_base;
+ }
+
+ /**
+ * @deprecated
+ */
+ static function getMockBaseClass() {
+ $registry = &SimpleTest::getRegistry();
+ return $registry['MockBaseClass'];
+ }
+}
+
+/**
+ * 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 {
+ private $test;
+ private $reporter;
+ private $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.
+ */
+ function setTest($test) {
+ $this->clear();
+ $this->test = $test;
+ }
+
+ /**
+ * Accessor for currently running test case.
+ * @return SimpleTestCase Current test.
+ */
+ 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.
+ */
+ function setReporter($reporter) {
+ $this->clear();
+ $this->reporter = $reporter;
+ }
+
+ /**
+ * Accessor for current reporter.
+ * @return SimpleReporter Current reporter.
+ */
+ function getReporter() {
+ return $this->reporter;
+ }
+
+ /**
+ * Accessor for the Singleton resource.
+ * @return object Global resource.
+ */
+ 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 {
+ private $prefixes;
+
+ /**
+ * Stashes the list of target prefixes.
+ * @param array $prefixes List of method prefixes
+ * to search for.
+ */
+ function __construct($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.
+ */
+ 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.
+ */
+ protected 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.
+ */
+ protected 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.
+ */
+ protected function captureTrace() {
+ if (function_exists('debug_backtrace')) {
+ return array_reverse(debug_backtrace());
+ }
+ return array();
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/socket.php b/tests/simpletest/socket.php
new file mode 100644
index 0000000..06e8ca6
--- /dev/null
+++ b/tests/simpletest/socket.php
@@ -0,0 +1,312 @@
+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('');
+ }
+}
+
+/**
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleFileSocket extends SimpleStickyError {
+ private $handle;
+ private $is_open = false;
+ private $sent = '';
+ private $block_size;
+
+ /**
+ * Opens a socket for reading and writing.
+ * @param SimpleUrl $file Target URI to fetch.
+ * @param integer $block_size Size of chunk to read.
+ * @access public
+ */
+ function __construct($file, $block_size = 1024) {
+ parent::__construct();
+ if (! ($this->handle = $this->openFile($file, $error))) {
+ $file_string = $file->asString();
+ $this->setError("Cannot open [$file_string] with [$error]");
+ return;
+ }
+ $this->is_open = true;
+ $this->block_size = $block_size;
+ }
+
+ /**
+ * 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) {
+ return true;
+ }
+
+ /**
+ * 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() {
+ $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() {
+ if (!$this->is_open) return false;
+ $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 SimpleUrl $file SimpleUrl file target.
+ * @param string $error Recipient of error message.
+ * @param integer $timeout Maximum time to wait for connection.
+ * @access protected
+ */
+ protected function openFile($file, &$error) {
+ return @fopen($file->asString(), 'r');
+ }
+}
+
+/**
+ * Wrapper for TCP/IP socket.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleSocket extends SimpleStickyError {
+ private $handle;
+ private $is_open = false;
+ private $sent = '';
+ private $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 __construct($host, $port, $timeout, $block_size = 255) {
+ parent::__construct();
+ 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;
+ }
+
+ /**
+ * 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');
+ $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
+ */
+ 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 __construct($host, $port, $timeout) {
+ parent::__construct($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);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/tag.php b/tests/simpletest/tag.php
new file mode 100644
index 0000000..afe649e
--- /dev/null
+++ b/tests/simpletest/tag.php
@@ -0,0 +1,1527 @@
+ 'SimpleAnchorTag',
+ 'title' => 'SimpleTitleTag',
+ 'base' => 'SimpleBaseTag',
+ 'button' => 'SimpleButtonTag',
+ 'textarea' => 'SimpleTextAreaTag',
+ 'option' => 'SimpleOptionTag',
+ 'label' => 'SimpleLabelTag',
+ 'form' => 'SimpleFormTag',
+ 'frame' => 'SimpleFrameTag');
+ $attributes = $this->keysToLowerCase($attributes);
+ if (array_key_exists($name, $map)) {
+ $tag_class = $map[$name];
+ return new $tag_class($attributes);
+ } elseif ($name == 'select') {
+ return $this->createSelectionTag($attributes);
+ } elseif ($name == 'input') {
+ return $this->createInputTag($attributes);
+ }
+ return new SimpleTag($name, $attributes);
+ }
+
+ /**
+ * Factory for selection fields.
+ * @param hash $attributes Element attributes.
+ * @return SimpleTag Tag object.
+ * @access protected
+ */
+ protected function createSelectionTag($attributes) {
+ if (isset($attributes['multiple'])) {
+ return new MultipleSelectionTag($attributes);
+ }
+ return new SimpleSelectionTag($attributes);
+ }
+
+ /**
+ * Factory for input tags.
+ * @param hash $attributes Element attributes.
+ * @return SimpleTag Tag object.
+ * @access protected
+ */
+ protected function createInputTag($attributes) {
+ if (! isset($attributes['type'])) {
+ return new SimpleTextTag($attributes);
+ }
+ $type = strtolower(trim($attributes['type']));
+ $map = array(
+ 'submit' => 'SimpleSubmitTag',
+ 'image' => 'SimpleImageSubmitTag',
+ 'checkbox' => 'SimpleCheckboxTag',
+ 'radio' => 'SimpleRadioButtonTag',
+ 'text' => 'SimpleTextTag',
+ 'hidden' => 'SimpleTextTag',
+ 'password' => 'SimpleTextTag',
+ 'file' => 'SimpleUploadTag');
+ if (array_key_exists($type, $map)) {
+ $tag_class = $map[$type];
+ return new $tag_class($attributes);
+ }
+ return false;
+ }
+
+ /**
+ * Make the keys lower case for case insensitive look-ups.
+ * @param hash $map Hash to convert.
+ * @return hash Unchanged values, but keys lower case.
+ * @access private
+ */
+ protected function keysToLowerCase($map) {
+ $lower = array();
+ foreach ($map as $key => $value) {
+ $lower[strtolower($key)] = $value;
+ }
+ return $lower;
+ }
+}
+
+/**
+ * HTML or XML tag.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleTag {
+ private $name;
+ private $attributes;
+ private $content;
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param string $name Tag name.
+ * @param hash $attributes Attribute names and
+ * string values. Note that
+ * the keys must have been
+ * converted to lower case.
+ */
+ function __construct($name, $attributes) {
+ $this->name = strtolower(trim($name));
+ $this->attributes = $attributes;
+ $this->content = '';
+ }
+
+ /**
+ * Check to see if the tag can have both start and
+ * end tags with content in between.
+ * @return boolean True if content allowed.
+ * @access public
+ */
+ function expectEndTag() {
+ return true;
+ }
+
+ /**
+ * The current tag should not swallow all content for
+ * itself as it's searchable page content. Private
+ * content tags are usually widgets that contain default
+ * values.
+ * @return boolean False as content is available
+ * to other tags by default.
+ * @access public
+ */
+ function isPrivateContent() {
+ return false;
+ }
+
+ /**
+ * Appends string content to the current content.
+ * @param string $content Additional text.
+ * @access public
+ */
+ function addContent($content) {
+ $this->content .= (string)$content;
+ return $this;
+ }
+
+ /**
+ * Adds an enclosed tag to the content.
+ * @param SimpleTag $tag New tag.
+ * @access public
+ */
+ function addTag($tag) {
+ }
+
+ /**
+ * Adds multiple enclosed tags to the content.
+ * @param array List of SimpleTag objects to be added.
+ */
+ function addTags($tags) {
+ foreach ($tags as $tag) {
+ $this->addTag($tag);
+ }
+ }
+
+ /**
+ * Accessor for tag name.
+ * @return string Name of tag.
+ * @access public
+ */
+ function getTagName() {
+ return $this->name;
+ }
+
+ /**
+ * List of legal child elements.
+ * @return array List of element names.
+ * @access public
+ */
+ function getChildElements() {
+ return array();
+ }
+
+ /**
+ * Accessor for an attribute.
+ * @param string $label Attribute name.
+ * @return string Attribute value.
+ * @access public
+ */
+ function getAttribute($label) {
+ $label = strtolower($label);
+ if (! isset($this->attributes[$label])) {
+ return false;
+ }
+ return (string)$this->attributes[$label];
+ }
+
+ /**
+ * Sets an attribute.
+ * @param string $label Attribute name.
+ * @return string $value New attribute value.
+ * @access protected
+ */
+ protected function setAttribute($label, $value) {
+ $this->attributes[strtolower($label)] = $value;
+ }
+
+ /**
+ * Accessor for the whole content so far.
+ * @return string Content as big raw string.
+ * @access public
+ */
+ function getContent() {
+ return $this->content;
+ }
+
+ /**
+ * Accessor for content reduced to visible text. Acts
+ * like a text mode browser, normalising space and
+ * reducing images to their alt text.
+ * @return string Content as plain text.
+ * @access public
+ */
+ function getText() {
+ return SimplePage::normalise($this->content);
+ }
+
+ /**
+ * Test to see if id attribute matches.
+ * @param string $id ID to test against.
+ * @return boolean True on match.
+ * @access public
+ */
+ function isId($id) {
+ return ($this->getAttribute('id') == $id);
+ }
+}
+
+/**
+ * Base url.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleBaseTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('base', $attributes);
+ }
+
+ /**
+ * Base tag is not a block tag.
+ * @return boolean false
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+}
+
+/**
+ * Page title.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleTitleTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('title', $attributes);
+ }
+}
+
+/**
+ * Link.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleAnchorTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('a', $attributes);
+ }
+
+ /**
+ * Accessor for URL as string.
+ * @return string Coerced as string.
+ * @access public
+ */
+ function getHref() {
+ $url = $this->getAttribute('href');
+ if (is_bool($url)) {
+ $url = '';
+ }
+ return $url;
+ }
+}
+
+/**
+ * Form element.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleWidget extends SimpleTag {
+ private $value;
+ private $label;
+ private $is_set;
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param string $name Tag name.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($name, $attributes) {
+ parent::__construct($name, $attributes);
+ $this->value = false;
+ $this->label = false;
+ $this->is_set = false;
+ }
+
+ /**
+ * Accessor for name submitted as the key in
+ * GET/POST privateiables hash.
+ * @return string Parsed value.
+ * @access public
+ */
+ function getName() {
+ return $this->getAttribute('name');
+ }
+
+ /**
+ * Accessor for default value parsed with the tag.
+ * @return string Parsed value.
+ * @access public
+ */
+ function getDefault() {
+ return $this->getAttribute('value');
+ }
+
+ /**
+ * Accessor for currently set value or default if
+ * none.
+ * @return string Value set by form or default
+ * if none.
+ * @access public
+ */
+ function getValue() {
+ if (! $this->is_set) {
+ return $this->getDefault();
+ }
+ return $this->value;
+ }
+
+ /**
+ * Sets the current form element value.
+ * @param string $value New value.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ $this->value = $value;
+ $this->is_set = true;
+ return true;
+ }
+
+ /**
+ * Resets the form element value back to the
+ * default.
+ * @access public
+ */
+ function resetValue() {
+ $this->is_set = false;
+ }
+
+ /**
+ * Allows setting of a label externally, say by a
+ * label tag.
+ * @param string $label Label to attach.
+ * @access public
+ */
+ function setLabel($label) {
+ $this->label = trim($label);
+ return $this;
+ }
+
+ /**
+ * Reads external or internal label.
+ * @param string $label Label to test.
+ * @return boolean True is match.
+ * @access public
+ */
+ function isLabel($label) {
+ return $this->label == trim($label);
+ }
+
+ /**
+ * Dispatches the value into the form encoded packet.
+ * @param SimpleEncoding $encoding Form packet.
+ * @access public
+ */
+ function write($encoding) {
+ if ($this->getName()) {
+ $encoding->add($this->getName(), $this->getValue());
+ }
+ }
+}
+
+/**
+ * Text, password and hidden field.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleTextTag extends SimpleWidget {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ if ($this->getAttribute('value') === false) {
+ $this->setAttribute('value', '');
+ }
+ }
+
+ /**
+ * Tag contains no content.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * Sets the current form element value. Cannot
+ * change the value of a hidden field.
+ * @param string $value New value.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ if ($this->getAttribute('type') == 'hidden') {
+ return false;
+ }
+ return parent::setValue($value);
+ }
+}
+
+/**
+ * Submit button as input tag.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleSubmitTag extends SimpleWidget {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ if ($this->getAttribute('value') === false) {
+ $this->setAttribute('value', 'Submit');
+ }
+ }
+
+ /**
+ * Tag contains no end element.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * Disables the setting of the button value.
+ * @param string $value Ignored.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ return false;
+ }
+
+ /**
+ * Value of browser visible text.
+ * @return string Visible label.
+ * @access public
+ */
+ function getLabel() {
+ return $this->getValue();
+ }
+
+ /**
+ * Test for a label match when searching.
+ * @param string $label Label to test.
+ * @return boolean True on match.
+ * @access public
+ */
+ function isLabel($label) {
+ return trim($label) == trim($this->getLabel());
+ }
+}
+
+/**
+ * Image button as input tag.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleImageSubmitTag extends SimpleWidget {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ }
+
+ /**
+ * Tag contains no end element.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * Disables the setting of the button value.
+ * @param string $value Ignored.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ return false;
+ }
+
+ /**
+ * Value of browser visible text.
+ * @return string Visible label.
+ * @access public
+ */
+ function getLabel() {
+ if ($this->getAttribute('title')) {
+ return $this->getAttribute('title');
+ }
+ return $this->getAttribute('alt');
+ }
+
+ /**
+ * Test for a label match when searching.
+ * @param string $label Label to test.
+ * @return boolean True on match.
+ * @access public
+ */
+ function isLabel($label) {
+ return trim($label) == trim($this->getLabel());
+ }
+
+ /**
+ * Dispatches the value into the form encoded packet.
+ * @param SimpleEncoding $encoding Form packet.
+ * @param integer $x X coordinate of click.
+ * @param integer $y Y coordinate of click.
+ * @access public
+ */
+ function write($encoding, $x = 1, $y = 1) {
+ if ($this->getName()) {
+ $encoding->add($this->getName() . '.x', $x);
+ $encoding->add($this->getName() . '.y', $y);
+ } else {
+ $encoding->add('x', $x);
+ $encoding->add('y', $y);
+ }
+ }
+}
+
+/**
+ * Submit button as button tag.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleButtonTag extends SimpleWidget {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * Defaults are very browser dependent.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('button', $attributes);
+ }
+
+ /**
+ * Check to see if the tag can have both start and
+ * end tags with content in between.
+ * @return boolean True if content allowed.
+ * @access public
+ */
+ function expectEndTag() {
+ return true;
+ }
+
+ /**
+ * Disables the setting of the button value.
+ * @param string $value Ignored.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ return false;
+ }
+
+ /**
+ * Value of browser visible text.
+ * @return string Visible label.
+ * @access public
+ */
+ function getLabel() {
+ return $this->getContent();
+ }
+
+ /**
+ * Test for a label match when searching.
+ * @param string $label Label to test.
+ * @return boolean True on match.
+ * @access public
+ */
+ function isLabel($label) {
+ return trim($label) == trim($this->getLabel());
+ }
+}
+
+/**
+ * Content tag for text area.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleTextAreaTag extends SimpleWidget {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('textarea', $attributes);
+ }
+
+ /**
+ * Accessor for starting value.
+ * @return string Parsed value.
+ * @access public
+ */
+ function getDefault() {
+ return $this->wrap(html_entity_decode($this->getContent(), ENT_QUOTES));
+ }
+
+ /**
+ * Applies word wrapping if needed.
+ * @param string $value New value.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ return parent::setValue($this->wrap($value));
+ }
+
+ /**
+ * Test to see if text should be wrapped.
+ * @return boolean True if wrapping on.
+ * @access private
+ */
+ function wrapIsEnabled() {
+ if ($this->getAttribute('cols')) {
+ $wrap = $this->getAttribute('wrap');
+ if (($wrap == 'physical') || ($wrap == 'hard')) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Performs the formatting that is peculiar to
+ * this tag. There is strange behaviour in this
+ * one, including stripping a leading new line.
+ * Go figure. I am using Firefox as a guide.
+ * @param string $text Text to wrap.
+ * @return string Text wrapped with carriage
+ * returns and line feeds
+ * @access private
+ */
+ protected function wrap($text) {
+ $text = str_replace("\r\r\n", "\r\n", str_replace("\n", "\r\n", $text));
+ $text = str_replace("\r\n\n", "\r\n", str_replace("\r", "\r\n", $text));
+ if (strncmp($text, "\r\n", strlen("\r\n")) == 0) {
+ $text = substr($text, strlen("\r\n"));
+ }
+ if ($this->wrapIsEnabled()) {
+ return wordwrap(
+ $text,
+ (integer)$this->getAttribute('cols'),
+ "\r\n");
+ }
+ return $text;
+ }
+
+ /**
+ * The content of textarea is not part of the page.
+ * @return boolean True.
+ * @access public
+ */
+ function isPrivateContent() {
+ return true;
+ }
+}
+
+/**
+ * File upload widget.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleUploadTag extends SimpleWidget {
+
+ /**
+ * Starts with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ }
+
+ /**
+ * Tag contains no content.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * Dispatches the value into the form encoded packet.
+ * @param SimpleEncoding $encoding Form packet.
+ * @access public
+ */
+ function write($encoding) {
+ if (! file_exists($this->getValue())) {
+ return;
+ }
+ $encoding->attach(
+ $this->getName(),
+ implode('', file($this->getValue())),
+ basename($this->getValue()));
+ }
+}
+
+/**
+ * Drop down widget.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleSelectionTag extends SimpleWidget {
+ private $options;
+ private $choice;
+
+ /**
+ * Starts with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('select', $attributes);
+ $this->options = array();
+ $this->choice = false;
+ }
+
+ /**
+ * Adds an option tag to a selection field.
+ * @param SimpleOptionTag $tag New option.
+ * @access public
+ */
+ function addTag($tag) {
+ if ($tag->getTagName() == 'option') {
+ $this->options[] = $tag;
+ }
+ }
+
+ /**
+ * Text within the selection element is ignored.
+ * @param string $content Ignored.
+ * @access public
+ */
+ function addContent($content) {
+ return $this;
+ }
+
+ /**
+ * Scans options for defaults. If none, then
+ * the first option is selected.
+ * @return string Selected field.
+ * @access public
+ */
+ function getDefault() {
+ for ($i = 0, $count = count($this->options); $i < $count; $i++) {
+ if ($this->options[$i]->getAttribute('selected') !== false) {
+ return $this->options[$i]->getDefault();
+ }
+ }
+ if ($count > 0) {
+ return $this->options[0]->getDefault();
+ }
+ return '';
+ }
+
+ /**
+ * Can only set allowed values.
+ * @param string $value New choice.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ for ($i = 0, $count = count($this->options); $i < $count; $i++) {
+ if ($this->options[$i]->isValue($value)) {
+ $this->choice = $i;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Accessor for current selection value.
+ * @return string Value attribute or
+ * content of opton.
+ * @access public
+ */
+ function getValue() {
+ if ($this->choice === false) {
+ return $this->getDefault();
+ }
+ return $this->options[$this->choice]->getValue();
+ }
+}
+
+/**
+ * Drop down widget.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class MultipleSelectionTag extends SimpleWidget {
+ private $options;
+ private $values;
+
+ /**
+ * Starts with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('select', $attributes);
+ $this->options = array();
+ $this->values = false;
+ }
+
+ /**
+ * Adds an option tag to a selection field.
+ * @param SimpleOptionTag $tag New option.
+ * @access public
+ */
+ function addTag($tag) {
+ if ($tag->getTagName() == 'option') {
+ $this->options[] = &$tag;
+ }
+ }
+
+ /**
+ * Text within the selection element is ignored.
+ * @param string $content Ignored.
+ * @access public
+ */
+ function addContent($content) {
+ return $this;
+ }
+
+ /**
+ * Scans options for defaults to populate the
+ * value array().
+ * @return array Selected fields.
+ * @access public
+ */
+ function getDefault() {
+ $default = array();
+ for ($i = 0, $count = count($this->options); $i < $count; $i++) {
+ if ($this->options[$i]->getAttribute('selected') !== false) {
+ $default[] = $this->options[$i]->getDefault();
+ }
+ }
+ return $default;
+ }
+
+ /**
+ * Can only set allowed values. Any illegal value
+ * will result in a failure, but all correct values
+ * will be set.
+ * @param array $desired New choices.
+ * @return boolean True if all allowed.
+ * @access public
+ */
+ function setValue($desired) {
+ $achieved = array();
+ foreach ($desired as $value) {
+ $success = false;
+ for ($i = 0, $count = count($this->options); $i < $count; $i++) {
+ if ($this->options[$i]->isValue($value)) {
+ $achieved[] = $this->options[$i]->getValue();
+ $success = true;
+ break;
+ }
+ }
+ if (! $success) {
+ return false;
+ }
+ }
+ $this->values = $achieved;
+ return true;
+ }
+
+ /**
+ * Accessor for current selection value.
+ * @return array List of currently set options.
+ * @access public
+ */
+ function getValue() {
+ if ($this->values === false) {
+ return $this->getDefault();
+ }
+ return $this->values;
+ }
+}
+
+/**
+ * Option for selection field.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleOptionTag extends SimpleWidget {
+
+ /**
+ * Stashes the attributes.
+ */
+ function __construct($attributes) {
+ parent::__construct('option', $attributes);
+ }
+
+ /**
+ * Does nothing.
+ * @param string $value Ignored.
+ * @return boolean Not allowed.
+ * @access public
+ */
+ function setValue($value) {
+ return false;
+ }
+
+ /**
+ * Test to see if a value matches the option.
+ * @param string $compare Value to compare with.
+ * @return boolean True if possible match.
+ * @access public
+ */
+ function isValue($compare) {
+ $compare = trim($compare);
+ if (trim($this->getValue()) == $compare) {
+ return true;
+ }
+ return trim(strip_tags($this->getContent())) == $compare;
+ }
+
+ /**
+ * Accessor for starting value. Will be set to
+ * the option label if no value exists.
+ * @return string Parsed value.
+ * @access public
+ */
+ function getDefault() {
+ if ($this->getAttribute('value') === false) {
+ return strip_tags($this->getContent());
+ }
+ return $this->getAttribute('value');
+ }
+
+ /**
+ * The content of options is not part of the page.
+ * @return boolean True.
+ * @access public
+ */
+ function isPrivateContent() {
+ return true;
+ }
+}
+
+/**
+ * Radio button.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleRadioButtonTag extends SimpleWidget {
+
+ /**
+ * Stashes the attributes.
+ * @param array $attributes Hash of attributes.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ if ($this->getAttribute('value') === false) {
+ $this->setAttribute('value', 'on');
+ }
+ }
+
+ /**
+ * Tag contains no content.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * The only allowed value sn the one in the
+ * "value" attribute.
+ * @param string $value New value.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ if ($value === false) {
+ return parent::setValue($value);
+ }
+ if ($value != $this->getAttribute('value')) {
+ return false;
+ }
+ return parent::setValue($value);
+ }
+
+ /**
+ * Accessor for starting value.
+ * @return string Parsed value.
+ * @access public
+ */
+ function getDefault() {
+ if ($this->getAttribute('checked') !== false) {
+ return $this->getAttribute('value');
+ }
+ return false;
+ }
+}
+
+/**
+ * Checkbox widget.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleCheckboxTag extends SimpleWidget {
+
+ /**
+ * Starts with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ if ($this->getAttribute('value') === false) {
+ $this->setAttribute('value', 'on');
+ }
+ }
+
+ /**
+ * Tag contains no content.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * The only allowed value in the one in the
+ * "value" attribute. The default for this
+ * attribute is "on". If this widget is set to
+ * true, then the usual value will be taken.
+ * @param string $value New value.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ if ($value === false) {
+ return parent::setValue($value);
+ }
+ if ($value === true) {
+ return parent::setValue($this->getAttribute('value'));
+ }
+ if ($value != $this->getAttribute('value')) {
+ return false;
+ }
+ return parent::setValue($value);
+ }
+
+ /**
+ * Accessor for starting value. The default
+ * value is "on".
+ * @return string Parsed value.
+ * @access public
+ */
+ function getDefault() {
+ if ($this->getAttribute('checked') !== false) {
+ return $this->getAttribute('value');
+ }
+ return false;
+ }
+}
+
+/**
+ * A group of multiple widgets with some shared behaviour.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleTagGroup {
+ private $widgets = array();
+
+ /**
+ * Adds a tag to the group.
+ * @param SimpleWidget $widget
+ * @access public
+ */
+ function addWidget($widget) {
+ $this->widgets[] = $widget;
+ }
+
+ /**
+ * Accessor to widget set.
+ * @return array All widgets.
+ * @access protected
+ */
+ protected function &getWidgets() {
+ return $this->widgets;
+ }
+
+ /**
+ * Accessor for an attribute.
+ * @param string $label Attribute name.
+ * @return boolean Always false.
+ * @access public
+ */
+ function getAttribute($label) {
+ return false;
+ }
+
+ /**
+ * Fetches the name for the widget from the first
+ * member.
+ * @return string Name of widget.
+ * @access public
+ */
+ function getName() {
+ if (count($this->widgets) > 0) {
+ return $this->widgets[0]->getName();
+ }
+ }
+
+ /**
+ * Scans the widgets for one with the appropriate
+ * ID field.
+ * @param string $id ID value to try.
+ * @return boolean True if matched.
+ * @access public
+ */
+ function isId($id) {
+ for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
+ if ($this->widgets[$i]->isId($id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Scans the widgets for one with the appropriate
+ * attached label.
+ * @param string $label Attached label to try.
+ * @return boolean True if matched.
+ * @access public
+ */
+ function isLabel($label) {
+ for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
+ if ($this->widgets[$i]->isLabel($label)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Dispatches the value into the form encoded packet.
+ * @param SimpleEncoding $encoding Form packet.
+ * @access public
+ */
+ function write($encoding) {
+ $encoding->add($this->getName(), $this->getValue());
+ }
+}
+
+/**
+ * A group of tags with the same name within a form.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleCheckboxGroup extends SimpleTagGroup {
+
+ /**
+ * Accessor for current selected widget or false
+ * if none.
+ * @return string/array Widget values or false if none.
+ * @access public
+ */
+ function getValue() {
+ $values = array();
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if ($widgets[$i]->getValue() !== false) {
+ $values[] = $widgets[$i]->getValue();
+ }
+ }
+ return $this->coerceValues($values);
+ }
+
+ /**
+ * Accessor for starting value that is active.
+ * @return string/array Widget values or false if none.
+ * @access public
+ */
+ function getDefault() {
+ $values = array();
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if ($widgets[$i]->getDefault() !== false) {
+ $values[] = $widgets[$i]->getDefault();
+ }
+ }
+ return $this->coerceValues($values);
+ }
+
+ /**
+ * Accessor for current set values.
+ * @param string/array/boolean $values Either a single string, a
+ * hash or false for nothing set.
+ * @return boolean True if all values can be set.
+ * @access public
+ */
+ function setValue($values) {
+ $values = $this->makeArray($values);
+ if (! $this->valuesArePossible($values)) {
+ return false;
+ }
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ $possible = $widgets[$i]->getAttribute('value');
+ if (in_array($widgets[$i]->getAttribute('value'), $values)) {
+ $widgets[$i]->setValue($possible);
+ } else {
+ $widgets[$i]->setValue(false);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tests to see if a possible value set is legal.
+ * @param string/array/boolean $values Either a single string, a
+ * hash or false for nothing set.
+ * @return boolean False if trying to set a
+ * missing value.
+ * @access private
+ */
+ protected function valuesArePossible($values) {
+ $matches = array();
+ $widgets = &$this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ $possible = $widgets[$i]->getAttribute('value');
+ if (in_array($possible, $values)) {
+ $matches[] = $possible;
+ }
+ }
+ return ($values == $matches);
+ }
+
+ /**
+ * Converts the output to an appropriate format. This means
+ * that no values is false, a single value is just that
+ * value and only two or more are contained in an array.
+ * @param array $values List of values of widgets.
+ * @return string/array/boolean Expected format for a tag.
+ * @access private
+ */
+ protected function coerceValues($values) {
+ if (count($values) == 0) {
+ return false;
+ } elseif (count($values) == 1) {
+ return $values[0];
+ } else {
+ return $values;
+ }
+ }
+
+ /**
+ * Converts false or string into array. The opposite of
+ * the coercian method.
+ * @param string/array/boolean $value A single item is converted
+ * to a one item list. False
+ * gives an empty list.
+ * @return array List of values, possibly empty.
+ * @access private
+ */
+ protected function makeArray($value) {
+ if ($value === false) {
+ return array();
+ }
+ if (is_string($value)) {
+ return array($value);
+ }
+ return $value;
+ }
+}
+
+/**
+ * A group of tags with the same name within a form.
+ * Used for radio buttons.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleRadioGroup extends SimpleTagGroup {
+
+ /**
+ * Each tag is tried in turn until one is
+ * successfully set. The others will be
+ * unchecked if successful.
+ * @param string $value New value.
+ * @return boolean True if any allowed.
+ * @access public
+ */
+ function setValue($value) {
+ if (! $this->valueIsPossible($value)) {
+ return false;
+ }
+ $index = false;
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if (! $widgets[$i]->setValue($value)) {
+ $widgets[$i]->setValue(false);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tests to see if a value is allowed.
+ * @param string Attempted value.
+ * @return boolean True if a valid value.
+ * @access private
+ */
+ protected function valueIsPossible($value) {
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if ($widgets[$i]->getAttribute('value') == $value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Accessor for current selected widget or false
+ * if none.
+ * @return string/boolean Value attribute or
+ * content of opton.
+ * @access public
+ */
+ function getValue() {
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if ($widgets[$i]->getValue() !== false) {
+ return $widgets[$i]->getValue();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Accessor for starting value that is active.
+ * @return string/boolean Value of first checked
+ * widget or false if none.
+ * @access public
+ */
+ function getDefault() {
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if ($widgets[$i]->getDefault() !== false) {
+ return $widgets[$i]->getDefault();
+ }
+ }
+ return false;
+ }
+}
+
+/**
+ * Tag to keep track of labels.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleLabelTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('label', $attributes);
+ }
+
+ /**
+ * Access for the ID to attach the label to.
+ * @return string For attribute.
+ * @access public
+ */
+ function getFor() {
+ return $this->getAttribute('for');
+ }
+}
+
+/**
+ * Tag to aid parsing the form.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleFormTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('form', $attributes);
+ }
+}
+
+/**
+ * Tag to aid parsing the frames in a page.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleFrameTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('frame', $attributes);
+ }
+
+ /**
+ * Tag contains no content.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/acceptance_test.php b/tests/simpletest/test/acceptance_test.php
new file mode 100644
index 0000000..e96fe73
--- /dev/null
+++ b/tests/simpletest/test/acceptance_test.php
@@ -0,0 +1,1729 @@
+addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $this->assertTrue($browser->get($this->samples() . 'network_confirm.php'));
+ $this->assertPattern('/target for the SimpleTest/', $browser->getContent());
+ $this->assertPattern('/Request method.*?GET<\/dd>/', $browser->getContent());
+ $this->assertEqual($browser->getTitle(), 'Simple test target file');
+ $this->assertEqual($browser->getResponseCode(), 200);
+ $this->assertEqual($browser->getMimeType(), 'text/html');
+ }
+
+ function testPost() {
+ $browser = new SimpleBrowser();
+ $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $this->assertTrue($browser->post($this->samples() . 'network_confirm.php'));
+ $this->assertPattern('/target for the SimpleTest/', $browser->getContent());
+ $this->assertPattern('/Request method.*?POST<\/dd>/', $browser->getContent());
+ }
+
+ function testAbsoluteLinkFollowing() {
+ $browser = new SimpleBrowser();
+ $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $browser->get($this->samples() . 'link_confirm.php');
+ $this->assertTrue($browser->clickLink('Absolute'));
+ $this->assertPattern('/target for the SimpleTest/', $browser->getContent());
+ }
+
+ function testRelativeEncodedLinkFollowing() {
+ $browser = new SimpleBrowser();
+ $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $browser->get($this->samples() . 'link_confirm.php');
+ // Warning: the below data is ISO 8859-1 encoded
+ $this->assertTrue($browser->clickLink("m\xE4rc\xEAl kiek'eboe"));
+ $this->assertPattern('/target for the SimpleTest/', $browser->getContent());
+ }
+
+ function testRelativeLinkFollowing() {
+ $browser = new SimpleBrowser();
+ $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $browser->get($this->samples() . 'link_confirm.php');
+ $this->assertTrue($browser->clickLink('Relative'));
+ $this->assertPattern('/target for the SimpleTest/', $browser->getContent());
+ }
+
+ function testUnifiedClickLinkClicking() {
+ $browser = new SimpleBrowser();
+ $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $browser->get($this->samples() . 'link_confirm.php');
+ $this->assertTrue($browser->click('Relative'));
+ $this->assertPattern('/target for the SimpleTest/', $browser->getContent());
+ }
+
+ function testIdLinkFollowing() {
+ $browser = new SimpleBrowser();
+ $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $browser->get($this->samples() . 'link_confirm.php');
+ $this->assertTrue($browser->clickLinkById(1));
+ $this->assertPattern('/target for the SimpleTest/', $browser->getContent());
+ }
+
+ function testCookieReading() {
+ $browser = new SimpleBrowser();
+ $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $browser->get($this->samples() . 'set_cookies.php');
+ $this->assertEqual($browser->getCurrentCookieValue('session_cookie'), 'A');
+ $this->assertEqual($browser->getCurrentCookieValue('short_cookie'), 'B');
+ $this->assertEqual($browser->getCurrentCookieValue('day_cookie'), 'C');
+ }
+
+ function testSimpleSubmit() {
+ $browser = new SimpleBrowser();
+ $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $browser->get($this->samples() . 'form.html');
+ $this->assertTrue($browser->clickSubmit('Go!'));
+ $this->assertPattern('/Request method.*?POST<\/dd>/', $browser->getContent());
+ $this->assertPattern('/go=\[Go!\]/', $browser->getContent());
+ }
+
+ function testUnifiedClickCanSubmit() {
+ $browser = new SimpleBrowser();
+ $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $browser->get($this->samples() . 'form.html');
+ $this->assertTrue($browser->click('Go!'));
+ $this->assertPattern('/go=\[Go!\]/', $browser->getContent());
+ }
+}
+
+class TestOfLocalFileBrowser extends UnitTestCase {
+ function samples() {
+ return 'file://'.dirname(__FILE__).'/site/';
+ }
+
+ function testGet() {
+ $browser = new SimpleBrowser();
+ $browser->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ $this->assertTrue($browser->get($this->samples() . 'file.html'));
+ $this->assertPattern('/Link to SimpleTest/', $browser->getContent());
+ $this->assertEqual($browser->getTitle(), 'Link to SimpleTest');
+ $this->assertFalse($browser->getResponseCode());
+ $this->assertEqual($browser->getMimeType(), '');
+ }
+}
+
+class TestOfRequestMethods extends UnitTestCase {
+ function samples() {
+ return SimpleTestAcceptanceTest::samples();
+ }
+
+ function testHeadRequest() {
+ $browser = new SimpleBrowser();
+ $this->assertTrue($browser->head($this->samples() . 'request_methods.php'));
+ $this->assertEqual($browser->getResponseCode(), 202);
+ }
+
+ function testGetRequest() {
+ $browser = new SimpleBrowser();
+ $this->assertTrue($browser->get($this->samples() . 'request_methods.php'));
+ $this->assertEqual($browser->getResponseCode(), 405);
+ }
+
+ function testPostWithPlainEncoding() {
+ $browser = new SimpleBrowser();
+ $this->assertTrue($browser->post($this->samples() . 'request_methods.php', 'A content message'));
+ $this->assertEqual($browser->getResponseCode(), 406);
+ $this->assertPattern('/Please ensure content type is an XML format/', $browser->getContent());
+ }
+
+ function testPostWithXmlEncoding() {
+ $browser = new SimpleBrowser();
+ $this->assertTrue($browser->post($this->samples() . 'request_methods.php', 'c', 'text/xml'));
+ $this->assertEqual($browser->getResponseCode(), 201);
+ $this->assertPattern('/c/', $browser->getContent());
+ }
+
+ function testPutWithPlainEncoding() {
+ $browser = new SimpleBrowser();
+ $this->assertTrue($browser->put($this->samples() . 'request_methods.php', 'A content message'));
+ $this->assertEqual($browser->getResponseCode(), 406);
+ $this->assertPattern('/Please ensure content type is an XML format/', $browser->getContent());
+ }
+
+ function testPutWithXmlEncoding() {
+ $browser = new SimpleBrowser();
+ $this->assertTrue($browser->put($this->samples() . 'request_methods.php', 'c', 'application/xml'));
+ $this->assertEqual($browser->getResponseCode(), 201);
+ $this->assertPattern('/c/', $browser->getContent());
+ }
+
+ function testDeleteRequest() {
+ $browser = new SimpleBrowser();
+ $browser->delete($this->samples() . 'request_methods.php');
+ $this->assertEqual($browser->getResponseCode(), 202);
+ $this->assertPattern('/Your delete request was accepted/', $browser->getContent());
+ }
+
+}
+
+class TestRadioFields extends SimpleTestAcceptanceTest {
+ function testSetFieldAsInteger() {
+ $this->get($this->samples() . 'form_with_radio_buttons.html');
+ $this->assertTrue($this->setField('tested_field', 2));
+ $this->clickSubmitByName('send');
+ $this->assertEqual($this->getUrl(), $this->samples() . 'form_with_radio_buttons.html?tested_field=2&send=click+me');
+ }
+
+ function testSetFieldAsString() {
+ $this->get($this->samples() . 'form_with_radio_buttons.html');
+ $this->assertTrue($this->setField('tested_field', '2'));
+ $this->clickSubmitByName('send');
+ $this->assertEqual($this->getUrl(), $this->samples() . 'form_with_radio_buttons.html?tested_field=2&send=click+me');
+ }
+}
+
+class TestOfLiveFetching extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testFormWithArrayBasedInputs() {
+ $this->get($this->samples() . 'form_with_array_based_inputs.php');
+ $this->setField('value[]', '3', '1');
+ $this->setField('value[]', '4', '2');
+ $this->clickSubmit('Go');
+ $this->assertPattern('/QUERY_STRING : value%5B%5D=3&value%5B%5D=4&submit=Go/');
+ }
+
+ function testFormWithQuotedValues() {
+ $this->get($this->samples() . 'form_with_quoted_values.php');
+ $this->assertField('a', 'default');
+ $this->assertFieldById('text_field', 'default');
+ $this->clickSubmit('Go');
+ $this->assertPattern('/a=default&submit=Go/');
+ }
+
+ function testGet() {
+ $this->assertTrue($this->get($this->samples() . 'network_confirm.php'));
+ $this->assertEqual($this->getUrl(), $this->samples() . 'network_confirm.php');
+ $this->assertText('target for the SimpleTest');
+ $this->assertPattern('/Request method.*?GET<\/dd>/');
+ $this->assertTitle('Simple test target file');
+ $this->assertTitle(new PatternExpectation('/target file/'));
+ $this->assertResponse(200);
+ $this->assertMime('text/html');
+ $this->assertHeader('connection', 'close');
+ $this->assertHeader('connection', new PatternExpectation('/los/'));
+ }
+
+ function testSlowGet() {
+ $this->assertTrue($this->get($this->samples() . 'slow_page.php'));
+ }
+
+ function testTimedOutGet() {
+ $this->setConnectionTimeout(1);
+ $this->ignoreErrors();
+ $this->assertFalse($this->get($this->samples() . 'slow_page.php'));
+ }
+
+ function testPost() {
+ $this->assertTrue($this->post($this->samples() . 'network_confirm.php'));
+ $this->assertText('target for the SimpleTest');
+ $this->assertPattern('/Request method.*?POST<\/dd>/');
+ }
+
+ function testGetWithData() {
+ $this->get($this->samples() . 'network_confirm.php', array("a" => "aaa"));
+ $this->assertPattern('/Request method.*?GET<\/dd>/');
+ $this->assertText('a=[aaa]');
+ }
+
+ function testPostWithData() {
+ $this->post($this->samples() . 'network_confirm.php', array("a" => "aaa"));
+ $this->assertPattern('/Request method.*?POST<\/dd>/');
+ $this->assertText('a=[aaa]');
+ }
+
+ function testPostWithRecursiveData() {
+ $this->post($this->samples() . 'network_confirm.php', array("a" => "aaa"));
+ $this->assertPattern('/Request method.*?POST<\/dd>/');
+ $this->assertText('a=[aaa]');
+
+ $this->post($this->samples() . 'network_confirm.php', array("a[aa]" => "aaa"));
+ $this->assertPattern('/Request method.*?POST<\/dd>/');
+ $this->assertText('a=[aa=[aaa]]');
+
+ $this->post($this->samples() . 'network_confirm.php', array("a[aa][aaa]" => "aaaa"));
+ $this->assertPattern('/Request method.*?POST<\/dd>/');
+ $this->assertText('a=[aa=[aaa=[aaaa]]]');
+
+ $this->post($this->samples() . 'network_confirm.php', array("a" => array("aa" => "aaa")));
+ $this->assertPattern('/Request method.*?POST<\/dd>/');
+ $this->assertText('a=[aa=[aaa]]');
+
+ $this->post($this->samples() . 'network_confirm.php', array("a" => array("aa" => array("aaa" => "aaaa"))));
+ $this->assertPattern('/Request method.*?POST<\/dd>/');
+ $this->assertText('a=[aa=[aaa=[aaaa]]]');
+ }
+
+ function testRelativeGet() {
+ $this->get($this->samples() . 'link_confirm.php');
+ $this->assertTrue($this->get('network_confirm.php'));
+ $this->assertText('target for the SimpleTest');
+ }
+
+ function testRelativePost() {
+ $this->post($this->samples() . 'link_confirm.php', array('a' => '123'));
+ $this->assertTrue($this->post('network_confirm.php'));
+ $this->assertText('target for the SimpleTest');
+ }
+}
+
+class TestOfLinkFollowing extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testLinkAssertions() {
+ $this->get($this->samples() . 'link_confirm.php');
+ $this->assertLink('Absolute', $this->samples() . 'network_confirm.php');
+ $this->assertLink('Absolute', new PatternExpectation('/confirm/'));
+ $this->assertClickable('Absolute');
+ }
+
+ function testAbsoluteLinkFollowing() {
+ $this->get($this->samples() . 'link_confirm.php');
+ $this->assertTrue($this->clickLink('Absolute'));
+ $this->assertText('target for the SimpleTest');
+ }
+
+ function testRelativeLinkFollowing() {
+ $this->get($this->samples() . 'link_confirm.php');
+ $this->assertTrue($this->clickLink('Relative'));
+ $this->assertText('target for the SimpleTest');
+ }
+
+ function testLinkIdFollowing() {
+ $this->get($this->samples() . 'link_confirm.php');
+ $this->assertLinkById(1);
+ $this->assertTrue($this->clickLinkById(1));
+ $this->assertText('target for the SimpleTest');
+ }
+
+ function testAbsoluteUrlBehavesAbsolutely() {
+ $this->get($this->samples() . 'link_confirm.php');
+ $this->get('http://www.lastcraft.com');
+ $this->assertText('No guarantee of quality is given or even intended');
+ }
+
+ function testRelativeUrlRespectsBaseTag() {
+ $this->get($this->samples() . 'base_tag/base_link.html');
+ $this->click('Back to test pages');
+ $this->assertTitle('Simple test target file');
+ }
+}
+
+class TestOfLivePageLinkingWithMinimalLinks extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testClickToExplicitelyNamedSelfReturns() {
+ $this->get($this->samples() . 'front_controller_style/a_page.php');
+ $this->assertEqual($this->getUrl(), $this->samples() . 'front_controller_style/a_page.php');
+ $this->assertTitle('Simple test page with links');
+ $this->assertLink('Self');
+ $this->clickLink('Self');
+ $this->assertTitle('Simple test page with links');
+ }
+
+ function testClickToMissingPageReturnsToSamePage() {
+ $this->get($this->samples() . 'front_controller_style/a_page.php');
+ $this->clickLink('No page');
+ $this->assertTitle('Simple test page with links');
+ $this->assertText('[action=no_page]');
+ }
+
+ function testClickToBareActionReturnsToSamePage() {
+ $this->get($this->samples() . 'front_controller_style/a_page.php');
+ $this->clickLink('Bare action');
+ $this->assertTitle('Simple test page with links');
+ $this->assertText('[action=]');
+ }
+
+ function testClickToSingleQuestionMarkReturnsToSamePage() {
+ $this->get($this->samples() . 'front_controller_style/a_page.php');
+ $this->clickLink('Empty query');
+ $this->assertTitle('Simple test page with links');
+ }
+
+ function testClickToEmptyStringReturnsToSamePage() {
+ $this->get($this->samples() . 'front_controller_style/a_page.php');
+ $this->clickLink('Empty link');
+ $this->assertTitle('Simple test page with links');
+ }
+
+ function testClickToSingleDotGoesToCurrentDirectory() {
+ $this->get($this->samples() . 'front_controller_style/a_page.php');
+ $this->clickLink('Current directory');
+ $this->assertTitle(
+ 'Simple test front controller',
+ '%s -> index.php needs to be set as a default web server home page');
+ }
+
+ function testClickBackADirectoryLevel() {
+ $this->get($this->samples() . 'front_controller_style/');
+ $this->clickLink('Down one');
+ $this->assertPattern('|Index of .*?/test|i');
+ }
+}
+
+class TestOfLiveFrontControllerEmulation extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testJumpToNamedPage() {
+ $this->get($this->samples() . 'front_controller_style/');
+ $this->assertText('Simple test front controller');
+ $this->clickLink('Index');
+ $this->assertResponse(200);
+ $this->assertText('[action=index]');
+ }
+
+ function testJumpToUnnamedPage() {
+ $this->get($this->samples() . 'front_controller_style/');
+ $this->clickLink('No page');
+ $this->assertResponse(200);
+ $this->assertText('Simple test front controller');
+ $this->assertText('[action=no_page]');
+ }
+
+ function testJumpToUnnamedPageWithBareParameter() {
+ $this->get($this->samples() . 'front_controller_style/');
+ $this->clickLink('Bare action');
+ $this->assertResponse(200);
+ $this->assertText('Simple test front controller');
+ $this->assertText('[action=]');
+ }
+
+ function testJumpToUnnamedPageWithEmptyQuery() {
+ $this->get($this->samples() . 'front_controller_style/');
+ $this->clickLink('Empty query');
+ $this->assertResponse(200);
+ $this->assertPattern('/Simple test front controller/');
+ $this->assertPattern('/raw get data.*?\[\].*?get data/si');
+ }
+
+ function testJumpToUnnamedPageWithEmptyLink() {
+ $this->get($this->samples() . 'front_controller_style/');
+ $this->clickLink('Empty link');
+ $this->assertResponse(200);
+ $this->assertPattern('/Simple test front controller/');
+ $this->assertPattern('/raw get data.*?\[\].*?get data/si');
+ }
+
+ function testJumpBackADirectoryLevel() {
+ $this->get($this->samples() . 'front_controller_style/');
+ $this->clickLink('Down one');
+ $this->assertPattern('|Index of .*?/test|');
+ }
+
+ function testSubmitToNamedPage() {
+ $this->get($this->samples() . 'front_controller_style/');
+ $this->assertText('Simple test front controller');
+ $this->clickSubmit('Index');
+ $this->assertResponse(200);
+ $this->assertText('[action=Index]');
+ }
+
+ function testSubmitToSameDirectory() {
+ $this->get($this->samples() . 'front_controller_style/index.php');
+ $this->clickSubmit('Same directory');
+ $this->assertResponse(200);
+ $this->assertText('[action=Same+directory]');
+ }
+
+ function testSubmitToEmptyAction() {
+ $this->get($this->samples() . 'front_controller_style/index.php');
+ $this->clickSubmit('Empty action');
+ $this->assertResponse(200);
+ $this->assertText('[action=Empty+action]');
+ }
+
+ function testSubmitToNoAction() {
+ $this->get($this->samples() . 'front_controller_style/index.php');
+ $this->clickSubmit('No action');
+ $this->assertResponse(200);
+ $this->assertText('[action=No+action]');
+ }
+
+ function testSubmitBackADirectoryLevel() {
+ $this->get($this->samples() . 'front_controller_style/');
+ $this->clickSubmit('Down one');
+ $this->assertPattern('|Index of .*?/test|');
+ }
+
+ function testSubmitToNamedPageWithMixedPostAndGet() {
+ $this->get($this->samples() . 'front_controller_style/?a=A');
+ $this->assertText('Simple test front controller');
+ $this->clickSubmit('Index post');
+ $this->assertText('action=[Index post]');
+ $this->assertNoText('[a=A]');
+ }
+
+ function testSubmitToSameDirectoryMixedPostAndGet() {
+ $this->get($this->samples() . 'front_controller_style/index.php?a=A');
+ $this->clickSubmit('Same directory post');
+ $this->assertText('action=[Same directory post]');
+ $this->assertNoText('[a=A]');
+ }
+
+ function testSubmitToEmptyActionMixedPostAndGet() {
+ $this->get($this->samples() . 'front_controller_style/index.php?a=A');
+ $this->clickSubmit('Empty action post');
+ $this->assertText('action=[Empty action post]');
+ $this->assertText('[a=A]');
+ }
+
+ function testSubmitToNoActionMixedPostAndGet() {
+ $this->get($this->samples() . 'front_controller_style/index.php?a=A');
+ $this->clickSubmit('No action post');
+ $this->assertText('action=[No action post]');
+ $this->assertText('[a=A]');
+ }
+}
+
+class TestOfLiveHeaders extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testConfirmingHeaderExistence() {
+ $this->get('http://www.lastcraft.com/');
+ $this->assertHeader('content-type');
+ $this->assertHeader('content-type', 'text/html');
+ $this->assertHeader('content-type', new PatternExpectation('/HTML/i'));
+ $this->assertNoHeader('WWW-Authenticate');
+ }
+}
+
+class TestOfLiveRedirects extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testNoRedirects() {
+ $this->setMaximumRedirects(0);
+ $this->get($this->samples() . 'redirect.php');
+ $this->assertTitle('Redirection test');
+ }
+
+ function testRedirects() {
+ $this->setMaximumRedirects(1);
+ $this->get($this->samples() . 'redirect.php');
+ $this->assertTitle('Simple test target file');
+ }
+
+ function testRedirectLosesGetData() {
+ $this->get($this->samples() . 'redirect.php', array('a' => 'aaa'));
+ $this->assertNoText('a=[aaa]');
+ }
+
+ function testRedirectKeepsExtraRequestDataOfItsOwn() {
+ $this->get($this->samples() . 'redirect.php');
+ $this->assertText('r=[rrr]');
+ }
+
+ function testRedirectLosesPostData() {
+ $this->post($this->samples() . 'redirect.php', array('a' => 'aaa'));
+ $this->assertTitle('Simple test target file');
+ $this->assertNoText('a=[aaa]');
+ }
+
+ function testRedirectWithBaseUrlChange() {
+ $this->get($this->samples() . 'base_change_redirect.php');
+ $this->assertTitle('Simple test target file in folder');
+ $this->get($this->samples() . 'path/base_change_redirect.php');
+ $this->assertTitle('Simple test target file');
+ }
+
+ function testRedirectWithDoubleBaseUrlChange() {
+ $this->get($this->samples() . 'double_base_change_redirect.php');
+ $this->assertTitle('Simple test target file');
+ }
+}
+
+class TestOfLiveCookies extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function here() {
+ return new SimpleUrl($this->samples());
+ }
+
+ function thisHost() {
+ $here = $this->here();
+ return $here->getHost();
+ }
+
+ function thisPath() {
+ $here = $this->here();
+ return $here->getPath();
+ }
+
+ function testCookieSettingAndAssertions() {
+ $this->setCookie('a', 'Test cookie a');
+ $this->setCookie('b', 'Test cookie b', $this->thisHost());
+ $this->setCookie('c', 'Test cookie c', $this->thisHost(), $this->thisPath());
+ $this->get($this->samples() . 'network_confirm.php');
+ $this->assertText('Test cookie a');
+ $this->assertText('Test cookie b');
+ $this->assertText('Test cookie c');
+ $this->assertCookie('a');
+ $this->assertCookie('b', 'Test cookie b');
+ $this->assertTrue($this->getCookie('c') == 'Test cookie c');
+ }
+
+ function testNoCookieSetWhenCookiesDisabled() {
+ $this->setCookie('a', 'Test cookie a');
+ $this->ignoreCookies();
+ $this->get($this->samples() . 'network_confirm.php');
+ $this->assertNoText('Test cookie a');
+ }
+
+ function testCookieReading() {
+ $this->get($this->samples() . 'set_cookies.php');
+ $this->assertCookie('session_cookie', 'A');
+ $this->assertCookie('short_cookie', 'B');
+ $this->assertCookie('day_cookie', 'C');
+ }
+
+ function testNoCookie() {
+ $this->assertNoCookie('aRandomCookie');
+ }
+
+ function testNoCookieReadingWhenCookiesDisabled() {
+ $this->ignoreCookies();
+ $this->get($this->samples() . 'set_cookies.php');
+ $this->assertNoCookie('session_cookie');
+ $this->assertNoCookie('short_cookie');
+ $this->assertNoCookie('day_cookie');
+ }
+
+ function testCookiePatternAssertions() {
+ $this->get($this->samples() . 'set_cookies.php');
+ $this->assertCookie('session_cookie', new PatternExpectation('/a/i'));
+ }
+
+ function testTemporaryCookieExpiry() {
+ $this->get($this->samples() . 'set_cookies.php');
+ $this->restart();
+ $this->assertNoCookie('session_cookie');
+ $this->assertCookie('day_cookie', 'C');
+ }
+
+ function testTimedCookieExpiryWith100SecondMargin() {
+ $this->get($this->samples() . 'set_cookies.php');
+ $this->ageCookies(3600);
+ $this->restart(time() + 100);
+ $this->assertNoCookie('session_cookie');
+ $this->assertNoCookie('hour_cookie');
+ $this->assertCookie('day_cookie', 'C');
+ }
+
+ function testNoClockOverDriftBy100Seconds() {
+ $this->get($this->samples() . 'set_cookies.php');
+ $this->restart(time() + 200);
+ $this->assertNoCookie(
+ 'short_cookie',
+ '%s -> Please check your computer clock setting if you are not using NTP');
+ }
+
+ function testNoClockUnderDriftBy100Seconds() {
+ $this->get($this->samples() . 'set_cookies.php');
+ $this->restart(time() + 0);
+ $this->assertCookie(
+ 'short_cookie',
+ 'B',
+ '%s -> Please check your computer clock setting if you are not using NTP');
+ }
+
+ function testCookiePath() {
+ $this->get($this->samples() . 'set_cookies.php');
+ $this->assertNoCookie('path_cookie', 'D');
+ $this->get('./path/show_cookies.php');
+ $this->assertPattern('/path_cookie/');
+ $this->assertCookie('path_cookie', 'D');
+ }
+}
+
+class LiveTestOfForms extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testSimpleSubmit() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertPattern('/Request method.*?POST<\/dd>/');
+ $this->assertText('go=[Go!]');
+ }
+
+ function testDefaultFormValues() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertFieldByName('a', '');
+ $this->assertFieldByName('b', 'Default text');
+ $this->assertFieldByName('c', '');
+ $this->assertFieldByName('d', 'd1');
+ $this->assertFieldByName('e', false);
+ $this->assertFieldByName('f', 'on');
+ $this->assertFieldByName('g', 'g3');
+ $this->assertFieldByName('h', 2);
+ $this->assertFieldByName('go', 'Go!');
+ $this->assertClickable('Go!');
+ $this->assertSubmit('Go!');
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('go=[Go!]');
+ $this->assertText('a=[]');
+ $this->assertText('b=[Default text]');
+ $this->assertText('c=[]');
+ $this->assertText('d=[d1]');
+ $this->assertNoText('e=[');
+ $this->assertText('f=[on]');
+ $this->assertText('g=[g3]');
+ }
+
+ function testFormSubmissionByButtonLabel() {
+ $this->get($this->samples() . 'form.html');
+ $this->setFieldByName('a', 'aaa');
+ $this->setFieldByName('b', 'bbb');
+ $this->setFieldByName('c', 'ccc');
+ $this->setFieldByName('d', 'D2');
+ $this->setFieldByName('e', 'on');
+ $this->setFieldByName('f', false);
+ $this->setFieldByName('g', 'g2');
+ $this->setFieldByName('h', 1);
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('a=[aaa]');
+ $this->assertText('b=[bbb]');
+ $this->assertText('c=[ccc]');
+ $this->assertText('d=[d2]');
+ $this->assertText('e=[on]');
+ $this->assertNoText('f=[');
+ $this->assertText('g=[g2]');
+ }
+
+ function testAdditionalFormValues() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertTrue($this->clickSubmit('Go!', array('add' => 'A')));
+ $this->assertText('go=[Go!]');
+ $this->assertText('add=[A]');
+ }
+
+ function testFormSubmissionByName() {
+ $this->get($this->samples() . 'form.html');
+ $this->setFieldByName('a', 'A');
+ $this->assertTrue($this->clickSubmitByName('go'));
+ $this->assertText('a=[A]');
+ }
+
+ function testFormSubmissionByNameAndAdditionalParameters() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertTrue($this->clickSubmitByName('go', array('add' => 'A')));
+ $this->assertText('go=[Go!]');
+ $this->assertText('add=[A]');
+ }
+
+ function testFormSubmissionBySubmitButtonLabeledSubmit() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertTrue($this->clickSubmitByName('test'));
+ $this->assertText('test=[Submit]');
+ }
+
+ function testFormSubmissionWithIds() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertFieldById(1, '');
+ $this->assertFieldById(2, 'Default text');
+ $this->assertFieldById(3, '');
+ $this->assertFieldById(4, 'd1');
+ $this->assertFieldById(5, false);
+ $this->assertFieldById(6, 'on');
+ $this->assertFieldById(8, 'g3');
+ $this->assertFieldById(11, 2);
+ $this->setFieldById(1, 'aaa');
+ $this->setFieldById(2, 'bbb');
+ $this->setFieldById(3, 'ccc');
+ $this->setFieldById(4, 'D2');
+ $this->setFieldById(5, 'on');
+ $this->setFieldById(6, false);
+ $this->setFieldById(8, 'g2');
+ $this->setFieldById(11, 'H1');
+ $this->assertTrue($this->clickSubmitById(99));
+ $this->assertText('a=[aaa]');
+ $this->assertText('b=[bbb]');
+ $this->assertText('c=[ccc]');
+ $this->assertText('d=[d2]');
+ $this->assertText('e=[on]');
+ $this->assertNoText('f=[');
+ $this->assertText('g=[g2]');
+ $this->assertText('h=[1]');
+ $this->assertText('go=[Go!]');
+ }
+
+ function testFormSubmissionWithIdsAndAdditionnalData() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertTrue($this->clickSubmitById(99, array('additionnal' => "data")));
+ $this->assertText('additionnal=[data]');
+ }
+
+ function testFormSubmissionWithLabels() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertField('Text A', '');
+ $this->assertField('Text B', 'Default text');
+ $this->assertField('Text area C', '');
+ $this->assertField('Selection D', 'd1');
+ $this->assertField('Checkbox E', false);
+ $this->assertField('Checkbox F', 'on');
+ $this->assertField('3', 'g3');
+ $this->assertField('Selection H', 2);
+ $this->setField('Text A', 'aaa');
+ $this->setField('Text B', 'bbb');
+ $this->setField('Text area C', 'ccc');
+ $this->setField('Selection D', 'D2');
+ $this->setField('Checkbox E', 'on');
+ $this->setField('Checkbox F', false);
+ $this->setField('2', 'g2');
+ $this->setField('Selection H', 'H1');
+ $this->clickSubmit('Go!');
+ $this->assertText('a=[aaa]');
+ $this->assertText('b=[bbb]');
+ $this->assertText('c=[ccc]');
+ $this->assertText('d=[d2]');
+ $this->assertText('e=[on]');
+ $this->assertNoText('f=[');
+ $this->assertText('g=[g2]');
+ $this->assertText('h=[1]');
+ $this->assertText('go=[Go!]');
+ }
+
+ function testSettingCheckboxWithBooleanTrueSetsUnderlyingValue() {
+ $this->get($this->samples() . 'form.html');
+ $this->setField('Checkbox E', true);
+ $this->assertField('Checkbox E', 'on');
+ $this->clickSubmit('Go!');
+ $this->assertText('e=[on]');
+ }
+
+ function testFormSubmissionWithMixedPostAndGet() {
+ $this->get($this->samples() . 'form_with_mixed_post_and_get.html');
+ $this->setField('Text A', 'Hello');
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('a=[Hello]');
+ $this->assertText('x=[X]');
+ $this->assertText('y=[Y]');
+ }
+
+ function testFormSubmissionWithMixedPostAndEncodedGet() {
+ $this->get($this->samples() . 'form_with_mixed_post_and_get.html');
+ $this->setField('Text B', 'Hello');
+ $this->assertTrue($this->clickSubmit('Go encoded!'));
+ $this->assertText('b=[Hello]');
+ $this->assertText('x=[X]');
+ $this->assertText('y=[Y]');
+ }
+
+ function testFormSubmissionWithoutAction() {
+ $this->get($this->samples() . 'form_without_action.php?test=test');
+ $this->assertText('_GET : [test]');
+ $this->assertTrue($this->clickSubmit('Submit Post With Empty Action'));
+ $this->assertText('_GET : [test]');
+ $this->assertText('_POST : [test]');
+ }
+
+ function testImageSubmissionByLabel() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertImage('Image go!');
+ $this->assertTrue($this->clickImage('Image go!', 10, 12));
+ $this->assertText('go_x=[10]');
+ $this->assertText('go_y=[12]');
+ }
+
+ function testImageSubmissionByLabelWithAdditionalParameters() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertTrue($this->clickImage('Image go!', 10, 12, array('add' => 'A')));
+ $this->assertText('add=[A]');
+ }
+
+ function testImageSubmissionByName() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertTrue($this->clickImageByName('go', 10, 12));
+ $this->assertText('go_x=[10]');
+ $this->assertText('go_y=[12]');
+ }
+
+ function testImageSubmissionById() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertTrue($this->clickImageById(97, 10, 12));
+ $this->assertText('go_x=[10]');
+ $this->assertText('go_y=[12]');
+ }
+
+ function testButtonSubmissionByLabel() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertTrue($this->clickSubmit('Button go!', 10, 12));
+ $this->assertPattern('/go=\[ButtonGo\]/s');
+ }
+
+ function testNamelessSubmitSendsNoValue() {
+ $this->get($this->samples() . 'form_with_unnamed_submit.html');
+ $this->click('Go!');
+ $this->assertNoText('Go!');
+ $this->assertNoText('submit');
+ }
+
+ function testNamelessImageSendsXAndYValues() {
+ $this->get($this->samples() . 'form_with_unnamed_submit.html');
+ $this->clickImage('Image go!', 4, 5);
+ $this->assertNoText('ImageGo');
+ $this->assertText('x=[4]');
+ $this->assertText('y=[5]');
+ }
+
+ function testNamelessButtonSendsNoValue() {
+ $this->get($this->samples() . 'form_with_unnamed_submit.html');
+ $this->click('Button Go!');
+ $this->assertNoText('ButtonGo');
+ }
+
+ function testSelfSubmit() {
+ $this->get($this->samples() . 'self_form.php');
+ $this->assertNoText('[Submitted]');
+ $this->assertNoText('[Wrong form]');
+ $this->assertTrue($this->clickSubmit());
+ $this->assertText('[Submitted]');
+ $this->assertNoText('[Wrong form]');
+ $this->assertTitle('Test of form self submission');
+ }
+
+ function testSelfSubmitWithParameters() {
+ $this->get($this->samples() . 'self_form.php');
+ $this->setFieldByName('visible', 'Resent');
+ $this->assertTrue($this->clickSubmit());
+ $this->assertText('[Resent]');
+ }
+
+ function testSettingOfBlankOption() {
+ $this->get($this->samples() . 'form.html');
+ $this->assertTrue($this->setFieldByName('d', ''));
+ $this->clickSubmit('Go!');
+ $this->assertText('d=[]');
+ }
+
+ function testAssertingFieldValueWithPattern() {
+ $this->get($this->samples() . 'form.html');
+ $this->setField('c', 'A very long string');
+ $this->assertField('c', new PatternExpectation('/very long/'));
+ }
+
+ function testSendingMultipartFormDataEncodedForm() {
+ $this->get($this->samples() . 'form_data_encoded_form.html');
+ $this->assertField('Text A', '');
+ $this->assertField('Text B', 'Default text');
+ $this->assertField('Text area C', '');
+ $this->assertField('Selection D', 'd1');
+ $this->assertField('Checkbox E', false);
+ $this->assertField('Checkbox F', 'on');
+ $this->assertField('3', 'g3');
+ $this->assertField('Selection H', 2);
+ $this->setField('Text A', 'aaa');
+ $this->setField('Text B', 'bbb');
+ $this->setField('Text area C', 'ccc');
+ $this->setField('Selection D', 'D2');
+ $this->setField('Checkbox E', 'on');
+ $this->setField('Checkbox F', false);
+ $this->setField('2', 'g2');
+ $this->setField('Selection H', 'H1');
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('a=[aaa]');
+ $this->assertText('b=[bbb]');
+ $this->assertText('c=[ccc]');
+ $this->assertText('d=[d2]');
+ $this->assertText('e=[on]');
+ $this->assertNoText('f=[');
+ $this->assertText('g=[g2]');
+ $this->assertText('h=[1]');
+ $this->assertText('go=[Go!]');
+ }
+
+ function testSettingVariousBlanksInFields() {
+ $this->get($this->samples() . 'form_with_false_defaults.html');
+ $this->assertField('Text A', '');
+ $this->setField('Text A', '0');
+ $this->assertField('Text A', '0');
+ $this->assertField('Text area B', '');
+ $this->setField('Text area B', '0');
+ $this->assertField('Text area B', '0');
+ $this->assertField('Selection D', '');
+ $this->setField('Selection D', 'D2');
+ $this->assertField('Selection D', 'D2');
+ $this->setField('Selection D', 'D3');
+ $this->assertField('Selection D', '0');
+ $this->setField('Selection D', 'D4');
+ $this->assertField('Selection D', '?');
+ $this->assertField('Checkbox E', '');
+ $this->assertField('Checkbox F', 'on');
+ $this->assertField('Checkbox G', '0');
+ $this->assertField('Checkbox H', '?');
+ $this->assertFieldByName('i', 'on');
+ $this->setFieldByName('i', '');
+ $this->assertFieldByName('i', '');
+ $this->setFieldByName('i', '0');
+ $this->assertFieldByName('i', '0');
+ $this->setFieldByName('i', '?');
+ $this->assertFieldByName('i', '?');
+ }
+
+ function testDefaultValueOfTextareaHasNewlinesAndWhitespacePreserved() {
+ $this->get($this->samples() . 'form_with_false_defaults.html');
+ $this->assertField('Text area C', ' ');
+ }
+
+ function chars($t) {
+ for ($i = 0; $i < strlen($t); $i++) {
+ print "[$t[$i]]";
+ }
+ }
+
+ function testSubmissionOfBlankFields() {
+ $this->get($this->samples() . 'form_with_false_defaults.html');
+ $this->setField('Text A', '');
+ $this->setField('Text area B', '');
+ $this->setFieldByName('i', '');
+ $this->click('Go!');
+ $this->assertText('a=[]');
+ $this->assertText('b=[]');
+ $this->assertText('d=[]');
+ $this->assertText('e=[]');
+ $this->assertText('i=[]');
+ }
+
+ function testDefaultValueOfTextareaHasNewlinesAndWhitespacePreservedOnSubmission() {
+ $this->get($this->samples() . 'form_with_false_defaults.html');
+ $this->click('Go!');
+ $this->assertPattern('/c=\[ \]/');
+ }
+
+ function testSubmissionOfEmptyValues() {
+ $this->get($this->samples() . 'form_with_false_defaults.html');
+ $this->setField('Selection D', 'D2');
+ $this->click('Go!');
+ $this->assertText('a=[]');
+ $this->assertText('b=[]');
+ $this->assertText('d=[D2]');
+ $this->assertText('f=[on]');
+ $this->assertText('i=[on]');
+ }
+
+ function testSubmissionOfZeroes() {
+ $this->get($this->samples() . 'form_with_false_defaults.html');
+ $this->setField('Text A', '0');
+ $this->setField('Text area B', '0');
+ $this->setField('Selection D', 'D3');
+ $this->setFieldByName('i', '0');
+ $this->click('Go!');
+ $this->assertText('a=[0]');
+ $this->assertText('b=[0]');
+ $this->assertText('d=[0]');
+ $this->assertText('g=[0]');
+ $this->assertText('i=[0]');
+ }
+
+ function testSubmissionOfQuestionMarks() {
+ $this->get($this->samples() . 'form_with_false_defaults.html');
+ $this->setField('Text A', '?');
+ $this->setField('Text area B', '?');
+ $this->setField('Selection D', 'D4');
+ $this->setFieldByName('i', '?');
+ $this->click('Go!');
+ $this->assertText('a=[?]');
+ $this->assertText('b=[?]');
+ $this->assertText('d=[?]');
+ $this->assertText('h=[?]');
+ $this->assertText('i=[?]');
+ }
+
+ function testSubmissionOfHtmlEncodedValues() {
+ $this->get($this->samples() . 'form_with_tricky_defaults.html');
+ $this->assertField('Text A', '&\'"<>');
+ $this->assertField('Text B', '"');
+ $this->assertField('Text area C', '&\'"<>');
+ $this->assertField('Selection D', "'");
+ $this->assertField('Checkbox E', '&\'"<>');
+ $this->assertField('Checkbox F', false);
+ $this->assertFieldByname('i', "'");
+ $this->click('Go!');
+ $this->assertText('a=[&\'"<>, "]');
+ $this->assertText('c=[&\'"<>]');
+ $this->assertText("d=[']");
+ $this->assertText('e=[&\'"<>]');
+ $this->assertText("i=[']");
+ }
+
+ function testFormActionRespectsBaseTag() {
+ $this->get($this->samples() . 'base_tag/form.html');
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('go=[Go!]');
+ $this->assertText('a=[]');
+ }
+}
+
+class TestOfLiveMultiValueWidgets extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testDefaultFormValueSubmission() {
+ $this->get($this->samples() . 'multiple_widget_form.html');
+ $this->assertFieldByName('a', array('a2', 'a3'));
+ $this->assertFieldByName('b', array('b2', 'b3'));
+ $this->assertFieldByName('c[]', array('c2', 'c3'));
+ $this->assertFieldByName('d', array('2', '3'));
+ $this->assertFieldByName('e', array('2', '3'));
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('a=[a2, a3]');
+ $this->assertText('b=[b2, b3]');
+ $this->assertText('c=[c2, c3]');
+ $this->assertText('d=[2, 3]');
+ $this->assertText('e=[2, 3]');
+ }
+
+ function testSubmittingMultipleValues() {
+ $this->get($this->samples() . 'multiple_widget_form.html');
+ $this->setFieldByName('a', array('a1', 'a4'));
+ $this->assertFieldByName('a', array('a1', 'a4'));
+ $this->assertFieldByName('a', array('a4', 'a1'));
+ $this->setFieldByName('b', array('b1', 'b4'));
+ $this->assertFieldByName('b', array('b1', 'b4'));
+ $this->setFieldByName('c[]', array('c1', 'c4'));
+ $this->assertField('c[]', array('c1', 'c4'));
+ $this->setFieldByName('d', array('1', '4'));
+ $this->assertField('d', array('1', '4'));
+ $this->setFieldByName('e', array('e1', 'e4'));
+ $this->assertField('e', array('1', '4'));
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('a=[a1, a4]');
+ $this->assertText('b=[b1, b4]');
+ $this->assertText('c=[c1, c4]');
+ $this->assertText('d=[1, 4]');
+ $this->assertText('e=[1, 4]');
+ }
+
+ function testSettingByOptionValue() {
+ $this->get($this->samples() . 'multiple_widget_form.html');
+ $this->setFieldByName('d', array('1', '4'));
+ $this->assertField('d', array('1', '4'));
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('d=[1, 4]');
+ }
+
+ function testSubmittingMultipleValuesByLabel() {
+ $this->get($this->samples() . 'multiple_widget_form.html');
+ $this->setField('Multiple selection A', array('a1', 'a4'));
+ $this->assertField('Multiple selection A', array('a1', 'a4'));
+ $this->assertField('Multiple selection A', array('a4', 'a1'));
+ $this->setField('multiple selection C', array('c1', 'c4'));
+ $this->assertField('multiple selection C', array('c1', 'c4'));
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('a=[a1, a4]');
+ $this->assertText('c=[c1, c4]');
+ }
+
+ function testSavantStyleHiddenFieldDefaults() {
+ $this->get($this->samples() . 'savant_style_form.html');
+ $this->assertFieldByName('a', array('a0'));
+ $this->assertFieldByName('b', array('b0'));
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('a=[a0]');
+ $this->assertText('b=[b0]');
+ }
+
+ function testSavantStyleHiddenDefaultsAreOverridden() {
+ $this->get($this->samples() . 'savant_style_form.html');
+ $this->assertTrue($this->setFieldByName('a', array('a1')));
+ $this->assertTrue($this->setFieldByName('b', 'b1'));
+ $this->assertTrue($this->clickSubmit('Go!'));
+ $this->assertText('a=[a1]');
+ $this->assertText('b=[b1]');
+ }
+
+ function testSavantStyleFormSettingById() {
+ $this->get($this->samples() . 'savant_style_form.html');
+ $this->assertFieldById(1, array('a0'));
+ $this->assertFieldById(4, array('b0'));
+ $this->assertTrue($this->setFieldById(2, 'a1'));
+ $this->assertTrue($this->setFieldById(5, 'b1'));
+ $this->assertTrue($this->clickSubmitById(99));
+ $this->assertText('a=[a1]');
+ $this->assertText('b=[b1]');
+ }
+}
+
+class TestOfFileUploads extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testSingleFileUpload() {
+ $this->get($this->samples() . 'upload_form.html');
+ $this->assertTrue($this->setField('Content:',
+ dirname(__FILE__) . '/support/upload_sample.txt'));
+ $this->assertField('Content:', dirname(__FILE__) . '/support/upload_sample.txt');
+ $this->click('Go!');
+ $this->assertText('Sample for testing file upload');
+ }
+
+ function testMultipleFileUpload() {
+ $this->get($this->samples() . 'upload_form.html');
+ $this->assertTrue($this->setField('Content:',
+ dirname(__FILE__) . '/support/upload_sample.txt'));
+ $this->assertTrue($this->setField('Supplemental:',
+ dirname(__FILE__) . '/support/supplementary_upload_sample.txt'));
+ $this->assertField('Supplemental:',
+ dirname(__FILE__) . '/support/supplementary_upload_sample.txt');
+ $this->click('Go!');
+ $this->assertText('Sample for testing file upload');
+ $this->assertText('Some more text content');
+ }
+
+ function testBinaryFileUpload() {
+ $this->get($this->samples() . 'upload_form.html');
+ $this->assertTrue($this->setField('Content:',
+ dirname(__FILE__) . '/support/latin1_sample'));
+ $this->click('Go!');
+ $this->assertText(
+ implode('', file(dirname(__FILE__) . '/support/latin1_sample')));
+ }
+}
+
+class TestOfLiveHistoryNavigation extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testRetry() {
+ $this->get($this->samples() . 'cookie_based_counter.php');
+ $this->assertPattern('/count: 1/i');
+ $this->retry();
+ $this->assertPattern('/count: 2/i');
+ $this->retry();
+ $this->assertPattern('/count: 3/i');
+ }
+
+ function testOfBackButton() {
+ $this->get($this->samples() . '1.html');
+ $this->clickLink('2');
+ $this->assertTitle('2');
+ $this->assertTrue($this->back());
+ $this->assertTitle('1');
+ $this->assertTrue($this->forward());
+ $this->assertTitle('2');
+ $this->assertFalse($this->forward());
+ }
+
+ function testGetRetryResubmitsData() {
+ $this->assertTrue($this->get(
+ $this->samples() . 'network_confirm.php?a=aaa'));
+ $this->assertPattern('/Request method.*?GET<\/dd>/');
+ $this->assertText('a=[aaa]');
+ $this->retry();
+ $this->assertPattern('/Request method.*?GET<\/dd>/');
+ $this->assertText('a=[aaa]');
+ }
+
+ function testGetRetryResubmitsExtraData() {
+ $this->assertTrue($this->get(
+ $this->samples() . 'network_confirm.php',
+ array('a' => 'aaa')));
+ $this->assertPattern('/Request method.*?GET<\/dd>/');
+ $this->assertText('a=[aaa]');
+ $this->retry();
+ $this->assertPattern('/Request method.*?GET<\/dd>/');
+ $this->assertText('a=[aaa]');
+ }
+
+ function testPostRetryResubmitsData() {
+ $this->assertTrue($this->post(
+ $this->samples() . 'network_confirm.php',
+ array('a' => 'aaa')));
+ $this->assertPattern('/Request method.*?POST<\/dd>/');
+ $this->assertText('a=[aaa]');
+ $this->retry();
+ $this->assertPattern('/Request method.*?POST<\/dd>/');
+ $this->assertText('a=[aaa]');
+ }
+
+ function testGetRetryResubmitsRepeatedData() {
+ $this->assertTrue($this->get(
+ $this->samples() . 'network_confirm.php?a=1&a=2'));
+ $this->assertPattern('/Request method.*?GET<\/dd>/');
+ $this->assertText('a=[1, 2]');
+ $this->retry();
+ $this->assertPattern('/Request method.*?GET<\/dd>/');
+ $this->assertText('a=[1, 2]');
+ }
+}
+
+class TestOfLiveAuthentication extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testChallengeFromProtectedPage() {
+ $this->get($this->samples() . 'protected/');
+ $this->assertResponse(401);
+ $this->assertAuthentication('Basic');
+ $this->assertRealm('SimpleTest basic authentication');
+ $this->assertRealm(new PatternExpectation('/simpletest/i'));
+ $this->authenticate('test', 'secret');
+ $this->assertResponse(200);
+ $this->retry();
+ $this->assertResponse(200);
+ }
+
+ function testTrailingSlashImpliedWithinRealm() {
+ $this->get($this->samples() . 'protected/');
+ $this->authenticate('test', 'secret');
+ $this->assertResponse(200);
+ $this->get($this->samples() . 'protected');
+ $this->assertResponse(200);
+ }
+
+ function testTrailingSlashImpliedSettingRealm() {
+ $this->get($this->samples() . 'protected');
+ $this->authenticate('test', 'secret');
+ $this->assertResponse(200);
+ $this->get($this->samples() . 'protected/');
+ $this->assertResponse(200);
+ }
+
+ function testEncodedAuthenticationFetchesPage() {
+ $this->get('http://test:secret@www.lastcraft.com/test/protected/');
+ $this->assertResponse(200);
+ }
+
+ function testEncodedAuthenticationFetchesPageAfterTrailingSlashRedirect() {
+ $this->get('http://test:secret@www.lastcraft.com/test/protected');
+ $this->assertResponse(200);
+ }
+
+ function testRealmExtendsToWholeDirectory() {
+ $this->get($this->samples() . 'protected/1.html');
+ $this->authenticate('test', 'secret');
+ $this->clickLink('2');
+ $this->assertResponse(200);
+ $this->clickLink('3');
+ $this->assertResponse(200);
+ }
+
+ function testRedirectKeepsAuthentication() {
+ $this->get($this->samples() . 'protected/local_redirect.php');
+ $this->authenticate('test', 'secret');
+ $this->assertTitle('Simple test target file');
+ }
+
+ function testRedirectKeepsEncodedAuthentication() {
+ $this->get('http://test:secret@www.lastcraft.com/test/protected/local_redirect.php');
+ $this->assertResponse(200);
+ $this->assertTitle('Simple test target file');
+ }
+
+ function testSessionRestartLosesAuthentication() {
+ $this->get($this->samples() . 'protected/');
+ $this->authenticate('test', 'secret');
+ $this->assertResponse(200);
+ $this->restart();
+ $this->get($this->samples() . 'protected/');
+ $this->assertResponse(401);
+ }
+}
+
+class TestOfLoadingFrames extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testNoFramesContentWhenFramesDisabled() {
+ $this->ignoreFrames();
+ $this->get($this->samples() . 'one_page_frameset.html');
+ $this->assertTitle('Frameset for testing of SimpleTest');
+ $this->assertText('This content is for no frames only');
+ }
+
+ function testPatternMatchCanReadTheOnlyFrame() {
+ $this->get($this->samples() . 'one_page_frameset.html');
+ $this->assertText('A target for the SimpleTest test suite');
+ $this->assertNoText('This content is for no frames only');
+ }
+
+ function testMessyFramesetResponsesByName() {
+ $this->assertTrue($this->get(
+ $this->samples() . 'messy_frameset.html'));
+ $this->assertTitle('Frameset for testing of SimpleTest');
+
+ $this->assertTrue($this->setFrameFocus('Front controller'));
+ $this->assertResponse(200);
+ $this->assertText('Simple test front controller');
+
+ $this->assertTrue($this->setFrameFocus('One'));
+ $this->assertResponse(200);
+ $this->assertLink('2');
+
+ $this->assertTrue($this->setFrameFocus('Frame links'));
+ $this->assertResponse(200);
+ $this->assertLink('Set one to 2');
+
+ $this->assertTrue($this->setFrameFocus('Counter'));
+ $this->assertResponse(200);
+ $this->assertText('Count: 1');
+
+ $this->assertTrue($this->setFrameFocus('Redirected'));
+ $this->assertResponse(200);
+ $this->assertText('r=rrr');
+
+ $this->assertTrue($this->setFrameFocus('Protected'));
+ $this->assertResponse(401);
+
+ $this->assertTrue($this->setFrameFocus('Protected redirect'));
+ $this->assertResponse(401);
+
+ $this->assertTrue($this->setFrameFocusByIndex(1));
+ $this->assertResponse(200);
+ $this->assertText('Simple test front controller');
+
+ $this->assertTrue($this->setFrameFocusByIndex(2));
+ $this->assertResponse(200);
+ $this->assertLink('2');
+
+ $this->assertTrue($this->setFrameFocusByIndex(3));
+ $this->assertResponse(200);
+ $this->assertLink('Set one to 2');
+
+ $this->assertTrue($this->setFrameFocusByIndex(4));
+ $this->assertResponse(200);
+ $this->assertText('Count: 1');
+
+ $this->assertTrue($this->setFrameFocusByIndex(5));
+ $this->assertResponse(200);
+ $this->assertText('r=rrr');
+
+ $this->assertTrue($this->setFrameFocusByIndex(6));
+ $this->assertResponse(401);
+
+ $this->assertTrue($this->setFrameFocusByIndex(7));
+ }
+
+ function testReloadingFramesetPage() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->assertText('Count: 1');
+ $this->retry();
+ $this->assertText('Count: 2');
+ $this->retry();
+ $this->assertText('Count: 3');
+ }
+
+ function testReloadingSingleFrameWithCookieCounter() {
+ $this->get($this->samples() . 'counting_frameset.html');
+ $this->setFrameFocus('a');
+ $this->assertText('Count: 1');
+ $this->setFrameFocus('b');
+ $this->assertText('Count: 2');
+
+ $this->setFrameFocus('a');
+ $this->retry();
+ $this->assertText('Count: 3');
+ $this->retry();
+ $this->assertText('Count: 4');
+ $this->setFrameFocus('b');
+ $this->assertText('Count: 2');
+ }
+
+ function testReloadingFrameWhenUnfocusedReloadsWholeFrameset() {
+ $this->get($this->samples() . 'counting_frameset.html');
+ $this->setFrameFocus('a');
+ $this->assertText('Count: 1');
+ $this->setFrameFocus('b');
+ $this->assertText('Count: 2');
+
+ $this->clearFrameFocus('a');
+ $this->retry();
+
+ $this->assertTitle('Frameset for testing of SimpleTest');
+ $this->setFrameFocus('a');
+ $this->assertText('Count: 3');
+ $this->setFrameFocus('b');
+ $this->assertText('Count: 4');
+ }
+
+ function testClickingNormalLinkReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickLink('2');
+ $this->assertLink('3');
+ $this->assertText('Simple test front controller');
+ }
+
+ function testJumpToNamedPageReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->assertPattern('/Simple test front controller/');
+ $this->clickLink('Index');
+ $this->assertResponse(200);
+ $this->assertText('[action=index]');
+ $this->assertText('Count: 1');
+ }
+
+ function testJumpToUnnamedPageReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickLink('No page');
+ $this->assertResponse(200);
+ $this->assertText('Simple test front controller');
+ $this->assertText('[action=no_page]');
+ $this->assertText('Count: 1');
+ }
+
+ function testJumpToUnnamedPageWithBareParameterReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickLink('Bare action');
+ $this->assertResponse(200);
+ $this->assertText('Simple test front controller');
+ $this->assertText('[action=]');
+ $this->assertText('Count: 1');
+ }
+
+ function testJumpToUnnamedPageWithEmptyQueryReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickLink('Empty query');
+ $this->assertResponse(200);
+ $this->assertPattern('/Simple test front controller/');
+ $this->assertPattern('/raw get data.*?\[\].*?get data/si');
+ $this->assertPattern('/Count: 1/');
+ }
+
+ function testJumpToUnnamedPageWithEmptyLinkReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickLink('Empty link');
+ $this->assertResponse(200);
+ $this->assertPattern('/Simple test front controller/');
+ $this->assertPattern('/raw get data.*?\[\].*?get data/si');
+ $this->assertPattern('/Count: 1/');
+ }
+
+ function testJumpBackADirectoryLevelReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickLink('Down one');
+ $this->assertPattern('/index of .*\/test/i');
+ $this->assertPattern('/Count: 1/');
+ }
+
+ function testSubmitToNamedPageReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->assertPattern('/Simple test front controller/');
+ $this->clickSubmit('Index');
+ $this->assertResponse(200);
+ $this->assertText('[action=Index]');
+ $this->assertText('Count: 1');
+ }
+
+ function testSubmitToSameDirectoryReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickSubmit('Same directory');
+ $this->assertResponse(200);
+ $this->assertText('[action=Same+directory]');
+ $this->assertText('Count: 1');
+ }
+
+ function testSubmitToEmptyActionReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickSubmit('Empty action');
+ $this->assertResponse(200);
+ $this->assertText('[action=Empty+action]');
+ $this->assertText('Count: 1');
+ }
+
+ function testSubmitToNoActionReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickSubmit('No action');
+ $this->assertResponse(200);
+ $this->assertText('[action=No+action]');
+ $this->assertText('Count: 1');
+ }
+
+ function testSubmitBackADirectoryLevelReplacesJustThatFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickSubmit('Down one');
+ $this->assertPattern('/index of .*\/test/i');
+ $this->assertPattern('/Count: 1/');
+ }
+
+ function testTopLinkExitsFrameset() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->clickLink('Exit the frameset');
+ $this->assertTitle('Simple test target file');
+ }
+
+ function testLinkInOnePageCanLoadAnother() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->assertNoLink('3');
+ $this->clickLink('Set one to 2');
+ $this->assertLink('3');
+ $this->assertNoLink('2');
+ $this->assertTitle('Frameset for testing of SimpleTest');
+ }
+
+ function testFrameWithRelativeLinksRespectsBaseTagForThatPage() {
+ $this->get($this->samples() . 'base_tag/frameset.html');
+ $this->click('Back to test pages');
+ $this->assertTitle('Frameset for testing of SimpleTest');
+ $this->assertText('A target for the SimpleTest test suite');
+ }
+
+ function testRelativeLinkInFrameIsNotAffectedByFramesetBaseTag() {
+ $this->get($this->samples() . 'base_tag/frameset_with_base_tag.html');
+ $this->assertText('This is page 1');
+ $this->click('To page 2');
+ $this->assertTitle('Frameset for testing of SimpleTest');
+ $this->assertText('This is page 2');
+ }
+}
+
+class TestOfFrameAuthentication extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testUnauthenticatedFrameSendsChallenge() {
+ $this->get($this->samples() . 'protected/');
+ $this->setFrameFocus('Protected');
+ $this->assertAuthentication('Basic');
+ $this->assertRealm('SimpleTest basic authentication');
+ $this->assertResponse(401);
+ }
+
+ function testCanReadFrameFromAlreadyAuthenticatedRealm() {
+ $this->get($this->samples() . 'protected/');
+ $this->authenticate('test', 'secret');
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->setFrameFocus('Protected');
+ $this->assertResponse(200);
+ $this->assertText('A target for the SimpleTest test suite');
+ }
+
+ function testCanAuthenticateFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->setFrameFocus('Protected');
+ $this->authenticate('test', 'secret');
+ $this->assertResponse(200);
+ $this->assertText('A target for the SimpleTest test suite');
+ $this->clearFrameFocus();
+ $this->assertText('Count: 1');
+ }
+
+ function testCanAuthenticateRedirectedFrame() {
+ $this->get($this->samples() . 'messy_frameset.html');
+ $this->setFrameFocus('Protected redirect');
+ $this->assertResponse(401);
+ $this->authenticate('test', 'secret');
+ $this->assertResponse(200);
+ $this->assertText('A target for the SimpleTest test suite');
+ $this->clearFrameFocus();
+ $this->assertText('Count: 1');
+ }
+}
+
+class TestOfNestedFrames extends SimpleTestAcceptanceTest {
+ function setUp() {
+ $this->addHeader('User-Agent: SimpleTest ' . SimpleTest::getVersion());
+ }
+
+ function testCanNavigateToSpecificContent() {
+ $this->get($this->samples() . 'nested_frameset.html');
+ $this->assertTitle('Nested frameset for testing of SimpleTest');
+
+ $this->assertPattern('/This is frame A/');
+ $this->assertPattern('/This is frame B/');
+ $this->assertPattern('/Simple test front controller/');
+ $this->assertLink('2');
+ $this->assertLink('Set one to 2');
+ $this->assertPattern('/Count: 1/');
+ $this->assertPattern('/r=rrr/');
+
+ $this->setFrameFocus('pair');
+ $this->assertPattern('/This is frame A/');
+ $this->assertPattern('/This is frame B/');
+ $this->assertNoPattern('/Simple test front controller/');
+ $this->assertNoLink('2');
+
+ $this->setFrameFocus('aaa');
+ $this->assertPattern('/This is frame A/');
+ $this->assertNoPattern('/This is frame B/');
+
+ $this->clearFrameFocus();
+ $this->assertResponse(200);
+ $this->setFrameFocus('messy');
+ $this->assertResponse(200);
+ $this->setFrameFocus('Front controller');
+ $this->assertResponse(200);
+ $this->assertPattern('/Simple test front controller/');
+ $this->assertNoLink('2');
+ }
+
+ function testReloadingFramesetPage() {
+ $this->get($this->samples() . 'nested_frameset.html');
+ $this->assertPattern('/Count: 1/');
+ $this->retry();
+ $this->assertPattern('/Count: 2/');
+ $this->retry();
+ $this->assertPattern('/Count: 3/');
+ }
+
+ function testRetryingNestedPageOnlyRetriesThatSet() {
+ $this->get($this->samples() . 'nested_frameset.html');
+ $this->assertPattern('/Count: 1/');
+ $this->setFrameFocus('messy');
+ $this->retry();
+ $this->assertPattern('/Count: 2/');
+ $this->setFrameFocus('Counter');
+ $this->retry();
+ $this->assertPattern('/Count: 3/');
+
+ $this->clearFrameFocus();
+ $this->setFrameFocus('messy');
+ $this->setFrameFocus('Front controller');
+ $this->retry();
+
+ $this->clearFrameFocus();
+ $this->assertPattern('/Count: 3/');
+ }
+
+ function testAuthenticatingNestedPage() {
+ $this->get($this->samples() . 'nested_frameset.html');
+ $this->setFrameFocus('messy');
+ $this->setFrameFocus('Protected');
+ $this->assertAuthentication('Basic');
+ $this->assertRealm('SimpleTest basic authentication');
+ $this->assertResponse(401);
+
+ $this->authenticate('test', 'secret');
+ $this->assertResponse(200);
+ $this->assertPattern('/A target for the SimpleTest test suite/');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/adapter_test.php b/tests/simpletest/test/adapter_test.php
new file mode 100644
index 0000000..c1a06a2
--- /dev/null
+++ b/tests/simpletest/test/adapter_test.php
@@ -0,0 +1,50 @@
+assertTrue(true, "PEAR true");
+ $this->assertFalse(false, "PEAR false");
+ }
+
+ function testName() {
+ $this->assertTrue($this->getName() == get_class($this));
+ }
+
+ function testPass() {
+ $this->pass("PEAR pass");
+ }
+
+ function testNulls() {
+ $value = null;
+ $this->assertNull($value, "PEAR null");
+ $value = 0;
+ $this->assertNotNull($value, "PEAR not null");
+ }
+
+ function testType() {
+ $this->assertType("Hello", "string", "PEAR type");
+ }
+
+ function testEquals() {
+ $this->assertEquals(12, 12, "PEAR identity");
+ $this->setLooselyTyped(true);
+ $this->assertEquals("12", 12, "PEAR equality");
+ }
+
+ function testSame() {
+ $same = new SameTestClass();
+ $this->assertSame($same, $same, "PEAR same");
+ }
+
+ function testRegExp() {
+ $this->assertRegExp('/hello/', "A big hello from me", "PEAR regex");
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/all_tests.php b/tests/simpletest/test/all_tests.php
new file mode 100644
index 0000000..99ce945
--- /dev/null
+++ b/tests/simpletest/test/all_tests.php
@@ -0,0 +1,13 @@
+TestSuite('All tests for SimpleTest ' . SimpleTest::getVersion());
+ $this->addFile(dirname(__FILE__) . '/unit_tests.php');
+ $this->addFile(dirname(__FILE__) . '/shell_test.php');
+ $this->addFile(dirname(__FILE__) . '/live_test.php');
+ $this->addFile(dirname(__FILE__) . '/acceptance_test.php');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/arguments_test.php b/tests/simpletest/test/arguments_test.php
new file mode 100644
index 0000000..0cca4e9
--- /dev/null
+++ b/tests/simpletest/test/arguments_test.php
@@ -0,0 +1,82 @@
+assertIdentical($arguments->a, false);
+ $this->assertIdentical($arguments->all(), array());
+ }
+
+ function testSingleArgumentNameRecordedAsTrue() {
+ $arguments = new SimpleArguments(array('me', '-a'));
+ $this->assertIdentical($arguments->a, true);
+ }
+
+ function testSingleArgumentCanBeGivenAValue() {
+ $arguments = new SimpleArguments(array('me', '-a=AAA'));
+ $this->assertIdentical($arguments->a, 'AAA');
+ }
+
+ function testSingleArgumentCanBeGivenSpaceSeparatedValue() {
+ $arguments = new SimpleArguments(array('me', '-a', 'AAA'));
+ $this->assertIdentical($arguments->a, 'AAA');
+ }
+
+ function testWillBuildArrayFromRepeatedValue() {
+ $arguments = new SimpleArguments(array('me', '-a', 'A', '-a', 'AA'));
+ $this->assertIdentical($arguments->a, array('A', 'AA'));
+ }
+
+ function testWillBuildArrayFromMultiplyRepeatedValues() {
+ $arguments = new SimpleArguments(array('me', '-a', 'A', '-a', 'AA', '-a', 'AAA'));
+ $this->assertIdentical($arguments->a, array('A', 'AA', 'AAA'));
+ }
+
+ function testCanParseLongFormArguments() {
+ $arguments = new SimpleArguments(array('me', '--aa=AA', '--bb', 'BB'));
+ $this->assertIdentical($arguments->aa, 'AA');
+ $this->assertIdentical($arguments->bb, 'BB');
+ }
+
+ function testGetsFullSetOfResultsAsHash() {
+ $arguments = new SimpleArguments(array('me', '-a', '-b=1', '-b', '2', '--aa=AA', '--bb', 'BB', '-c'));
+ $this->assertEqual($arguments->all(),
+ array('a' => true, 'b' => array('1', '2'), 'aa' => 'AA', 'bb' => 'BB', 'c' => true));
+ }
+}
+
+class TestOfHelpOutput extends UnitTestCase {
+ function testDisplaysGeneralHelpBanner() {
+ $help = new SimpleHelp('Cool program');
+ $this->assertEqual($help->render(), "Cool program\n");
+ }
+
+ function testDisplaysOnlySingleLineEndings() {
+ $help = new SimpleHelp("Cool program\n");
+ $this->assertEqual($help->render(), "Cool program\n");
+ }
+
+ function testDisplaysHelpOnShortFlag() {
+ $help = new SimpleHelp('Cool program');
+ $help->explainFlag('a', 'Enables A');
+ $this->assertEqual($help->render(), "Cool program\n-a Enables A\n");
+ }
+
+ function testHasAtleastFourSpacesAfterLongestFlag() {
+ $help = new SimpleHelp('Cool program');
+ $help->explainFlag('a', 'Enables A');
+ $help->explainFlag('long', 'Enables Long');
+ $this->assertEqual($help->render(),
+ "Cool program\n-a Enables A\n--long Enables Long\n");
+ }
+
+ function testCanDisplaysMultipleFlagsForEachOption() {
+ $help = new SimpleHelp('Cool program');
+ $help->explainFlag(array('a', 'aa'), 'Enables A');
+ $this->assertEqual($help->render(), "Cool program\n-a Enables A\n --aa\n");
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/authentication_test.php b/tests/simpletest/test/authentication_test.php
new file mode 100644
index 0000000..081cccd
--- /dev/null
+++ b/tests/simpletest/test/authentication_test.php
@@ -0,0 +1,145 @@
+assertTrue($realm->isWithin(
+ new SimpleUrl('http://www.here.com/path/hello.html')));
+ }
+
+ function testInsideWithLongerUrl() {
+ $realm = new SimpleRealm(
+ 'Basic',
+ new SimpleUrl('http://www.here.com/path/'));
+ $this->assertTrue($realm->isWithin(
+ new SimpleUrl('http://www.here.com/path/hello.html')));
+ }
+
+ function testBelowRootIsOutside() {
+ $realm = new SimpleRealm(
+ 'Basic',
+ new SimpleUrl('http://www.here.com/path/'));
+ $this->assertTrue($realm->isWithin(
+ new SimpleUrl('http://www.here.com/path/more/hello.html')));
+ }
+
+ function testOldNetscapeDefinitionIsOutside() {
+ $realm = new SimpleRealm(
+ 'Basic',
+ new SimpleUrl('http://www.here.com/path/'));
+ $this->assertFalse($realm->isWithin(
+ new SimpleUrl('http://www.here.com/pathmore/hello.html')));
+ }
+
+ function testInsideWithMissingTrailingSlash() {
+ $realm = new SimpleRealm(
+ 'Basic',
+ new SimpleUrl('http://www.here.com/path/'));
+ $this->assertTrue($realm->isWithin(
+ new SimpleUrl('http://www.here.com/path')));
+ }
+
+ function testDifferentPageNameStillInside() {
+ $realm = new SimpleRealm(
+ 'Basic',
+ new SimpleUrl('http://www.here.com/path/hello.html'));
+ $this->assertTrue($realm->isWithin(
+ new SimpleUrl('http://www.here.com/path/goodbye.html')));
+ }
+
+ function testNewUrlInSameDirectoryDoesNotChangeRealm() {
+ $realm = new SimpleRealm(
+ 'Basic',
+ new SimpleUrl('http://www.here.com/path/hello.html'));
+ $realm->stretch(new SimpleUrl('http://www.here.com/path/goodbye.html'));
+ $this->assertTrue($realm->isWithin(
+ new SimpleUrl('http://www.here.com/path/index.html')));
+ $this->assertFalse($realm->isWithin(
+ new SimpleUrl('http://www.here.com/index.html')));
+ }
+
+ function testNewUrlMakesRealmTheCommonPath() {
+ $realm = new SimpleRealm(
+ 'Basic',
+ new SimpleUrl('http://www.here.com/path/here/hello.html'));
+ $realm->stretch(new SimpleUrl('http://www.here.com/path/there/goodbye.html'));
+ $this->assertTrue($realm->isWithin(
+ new SimpleUrl('http://www.here.com/path/here/index.html')));
+ $this->assertTrue($realm->isWithin(
+ new SimpleUrl('http://www.here.com/path/there/index.html')));
+ $this->assertTrue($realm->isWithin(
+ new SimpleUrl('http://www.here.com/path/index.html')));
+ $this->assertFalse($realm->isWithin(
+ new SimpleUrl('http://www.here.com/index.html')));
+ $this->assertFalse($realm->isWithin(
+ new SimpleUrl('http://www.here.com/paths/index.html')));
+ $this->assertFalse($realm->isWithin(
+ new SimpleUrl('http://www.here.com/pathindex.html')));
+ }
+}
+
+class TestOfAuthenticator extends UnitTestCase {
+
+ function testNoRealms() {
+ $request = new MockSimpleHttpRequest();
+ $request->expectNever('addHeaderLine');
+ $authenticator = new SimpleAuthenticator();
+ $authenticator->addHeaders($request, new SimpleUrl('http://here.com/'));
+ }
+
+ function &createSingleRealm() {
+ $authenticator = new SimpleAuthenticator();
+ $authenticator->addRealm(
+ new SimpleUrl('http://www.here.com/path/hello.html'),
+ 'Basic',
+ 'Sanctuary');
+ $authenticator->setIdentityForRealm('www.here.com', 'Sanctuary', 'test', 'secret');
+ return $authenticator;
+ }
+
+ function testOutsideRealm() {
+ $request = new MockSimpleHttpRequest();
+ $request->expectNever('addHeaderLine');
+ $authenticator = &$this->createSingleRealm();
+ $authenticator->addHeaders(
+ $request,
+ new SimpleUrl('http://www.here.com/hello.html'));
+ }
+
+ function testWithinRealm() {
+ $request = new MockSimpleHttpRequest();
+ $request->expectOnce('addHeaderLine');
+ $authenticator = &$this->createSingleRealm();
+ $authenticator->addHeaders(
+ $request,
+ new SimpleUrl('http://www.here.com/path/more/hello.html'));
+ }
+
+ function testRestartingClearsRealm() {
+ $request = new MockSimpleHttpRequest();
+ $request->expectNever('addHeaderLine');
+ $authenticator = &$this->createSingleRealm();
+ $authenticator->restartSession();
+ $authenticator->addHeaders(
+ $request,
+ new SimpleUrl('http://www.here.com/hello.html'));
+ }
+
+ function testDifferentHostIsOutsideRealm() {
+ $request = new MockSimpleHttpRequest();
+ $request->expectNever('addHeaderLine');
+ $authenticator = &$this->createSingleRealm();
+ $authenticator->addHeaders(
+ $request,
+ new SimpleUrl('http://here.com/path/hello.html'));
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/autorun_test.php b/tests/simpletest/test/autorun_test.php
new file mode 100644
index 0000000..d85ea19
--- /dev/null
+++ b/tests/simpletest/test/autorun_test.php
@@ -0,0 +1,23 @@
+addFile(dirname(__FILE__) . '/support/test1.php');
+ $this->assertEqual($tests->getSize(), 1);
+ }
+
+ function testExitStatusOneIfTestsFail() {
+ exec('php ' . dirname(__FILE__) . '/support/failing_test.php', $output, $exit_status);
+ $this->assertEqual($exit_status, 1);
+ }
+
+ function testExitStatusZeroIfTestsPass() {
+ exec('php ' . dirname(__FILE__) . '/support/passing_test.php', $output, $exit_status);
+ $this->assertEqual($exit_status, 0);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/bad_test_suite.php b/tests/simpletest/test/bad_test_suite.php
new file mode 100644
index 0000000..b426013
--- /dev/null
+++ b/tests/simpletest/test/bad_test_suite.php
@@ -0,0 +1,10 @@
+TestSuite('Two bad test cases');
+ $this->addFile(dirname(__FILE__) . '/support/empty_test_file.php');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/browser_test.php b/tests/simpletest/test/browser_test.php
new file mode 100644
index 0000000..3a52aaa
--- /dev/null
+++ b/tests/simpletest/test/browser_test.php
@@ -0,0 +1,802 @@
+assertIdentical($history->getUrl(), false);
+ $this->assertIdentical($history->getParameters(), false);
+ }
+
+ function testCannotMoveInEmptyHistory() {
+ $history = new SimpleBrowserHistory();
+ $this->assertFalse($history->back());
+ $this->assertFalse($history->forward());
+ }
+
+ function testCurrentTargetAccessors() {
+ $history = new SimpleBrowserHistory();
+ $history->recordEntry(
+ new SimpleUrl('http://www.here.com/'),
+ new SimpleGetEncoding());
+ $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.here.com/'));
+ $this->assertIdentical($history->getParameters(), new SimpleGetEncoding());
+ }
+
+ function testSecondEntryAccessors() {
+ $history = new SimpleBrowserHistory();
+ $history->recordEntry(
+ new SimpleUrl('http://www.first.com/'),
+ new SimpleGetEncoding());
+ $history->recordEntry(
+ new SimpleUrl('http://www.second.com/'),
+ new SimplePostEncoding(array('a' => 1)));
+ $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.second.com/'));
+ $this->assertIdentical(
+ $history->getParameters(),
+ new SimplePostEncoding(array('a' => 1)));
+ }
+
+ function testGoingBackwards() {
+ $history = new SimpleBrowserHistory();
+ $history->recordEntry(
+ new SimpleUrl('http://www.first.com/'),
+ new SimpleGetEncoding());
+ $history->recordEntry(
+ new SimpleUrl('http://www.second.com/'),
+ new SimplePostEncoding(array('a' => 1)));
+ $this->assertTrue($history->back());
+ $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/'));
+ $this->assertIdentical($history->getParameters(), new SimpleGetEncoding());
+ }
+
+ function testGoingBackwardsOffBeginning() {
+ $history = new SimpleBrowserHistory();
+ $history->recordEntry(
+ new SimpleUrl('http://www.first.com/'),
+ new SimpleGetEncoding());
+ $this->assertFalse($history->back());
+ $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/'));
+ $this->assertIdentical($history->getParameters(), new SimpleGetEncoding());
+ }
+
+ function testGoingForwardsOffEnd() {
+ $history = new SimpleBrowserHistory();
+ $history->recordEntry(
+ new SimpleUrl('http://www.first.com/'),
+ new SimpleGetEncoding());
+ $this->assertFalse($history->forward());
+ $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/'));
+ $this->assertIdentical($history->getParameters(), new SimpleGetEncoding());
+ }
+
+ function testGoingBackwardsAndForwards() {
+ $history = new SimpleBrowserHistory();
+ $history->recordEntry(
+ new SimpleUrl('http://www.first.com/'),
+ new SimpleGetEncoding());
+ $history->recordEntry(
+ new SimpleUrl('http://www.second.com/'),
+ new SimplePostEncoding(array('a' => 1)));
+ $this->assertTrue($history->back());
+ $this->assertTrue($history->forward());
+ $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.second.com/'));
+ $this->assertIdentical(
+ $history->getParameters(),
+ new SimplePostEncoding(array('a' => 1)));
+ }
+
+ function testNewEntryReplacesNextOne() {
+ $history = new SimpleBrowserHistory();
+ $history->recordEntry(
+ new SimpleUrl('http://www.first.com/'),
+ new SimpleGetEncoding());
+ $history->recordEntry(
+ new SimpleUrl('http://www.second.com/'),
+ new SimplePostEncoding(array('a' => 1)));
+ $history->back();
+ $history->recordEntry(
+ new SimpleUrl('http://www.third.com/'),
+ new SimpleGetEncoding());
+ $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.third.com/'));
+ $this->assertIdentical($history->getParameters(), new SimpleGetEncoding());
+ }
+
+ function testNewEntryDropsFutureEntries() {
+ $history = new SimpleBrowserHistory();
+ $history->recordEntry(
+ new SimpleUrl('http://www.first.com/'),
+ new SimpleGetEncoding());
+ $history->recordEntry(
+ new SimpleUrl('http://www.second.com/'),
+ new SimpleGetEncoding());
+ $history->recordEntry(
+ new SimpleUrl('http://www.third.com/'),
+ new SimpleGetEncoding());
+ $history->back();
+ $history->back();
+ $history->recordEntry(
+ new SimpleUrl('http://www.fourth.com/'),
+ new SimpleGetEncoding());
+ $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.fourth.com/'));
+ $this->assertFalse($history->forward());
+ $history->back();
+ $this->assertIdentical($history->getUrl(), new SimpleUrl('http://www.first.com/'));
+ $this->assertFalse($history->back());
+ }
+}
+
+class TestOfParsedPageAccess extends UnitTestCase {
+
+ function loadPage(&$page) {
+ $response = new MockSimpleHttpResponse($this);
+ $agent = new MockSimpleUserAgent($this);
+ $agent->returns('fetchResponse', $response);
+
+ $browser = new MockParseSimpleBrowser($this);
+ $browser->returns('createUserAgent', $agent);
+ $browser->returns('parse', $page);
+ $browser->__construct();
+
+ $browser->get('http://this.com/page.html');
+ return $browser;
+ }
+
+ function testAccessorsWhenNoPage() {
+ $agent = new MockSimpleUserAgent($this);
+ $browser = new MockParseSimpleBrowser($this);
+ $browser->returns('createUserAgent', $agent);
+ $browser->__construct();
+ $this->assertEqual($browser->getContent(), '');
+ }
+
+ function testParse() {
+ $page = new MockSimplePage();
+ $page->setReturnValue('getRequest', "GET here.html\r\n\r\n");
+ $page->setReturnValue('getRaw', 'Raw HTML');
+ $page->setReturnValue('getTitle', 'Here');
+ $page->setReturnValue('getFrameFocus', 'Frame');
+ $page->setReturnValue('getMimeType', 'text/html');
+ $page->setReturnValue('getResponseCode', 200);
+ $page->setReturnValue('getAuthentication', 'Basic');
+ $page->setReturnValue('getRealm', 'Somewhere');
+ $page->setReturnValue('getTransportError', 'Ouch!');
+
+ $browser = $this->loadPage($page);
+ $this->assertEqual($browser->getRequest(), "GET here.html\r\n\r\n");
+ $this->assertEqual($browser->getContent(), 'Raw HTML');
+ $this->assertEqual($browser->getTitle(), 'Here');
+ $this->assertEqual($browser->getFrameFocus(), 'Frame');
+ $this->assertIdentical($browser->getResponseCode(), 200);
+ $this->assertEqual($browser->getMimeType(), 'text/html');
+ $this->assertEqual($browser->getAuthentication(), 'Basic');
+ $this->assertEqual($browser->getRealm(), 'Somewhere');
+ $this->assertEqual($browser->getTransportError(), 'Ouch!');
+ }
+
+ function testLinkAffirmationWhenPresent() {
+ $page = new MockSimplePage();
+ $page->setReturnValue('getUrlsByLabel', array('http://www.nowhere.com'));
+ $page->expectOnce('getUrlsByLabel', array('a link label'));
+ $browser = $this->loadPage($page);
+ $this->assertIdentical($browser->getLink('a link label'), 'http://www.nowhere.com');
+ }
+
+ function testLinkAffirmationByIdWhenPresent() {
+ $page = new MockSimplePage();
+ $page->setReturnValue('getUrlById', 'a_page.com', array(99));
+ $page->setReturnValue('getUrlById', false, array('*'));
+ $browser = $this->loadPage($page);
+ $this->assertIdentical($browser->getLinkById(99), 'a_page.com');
+ $this->assertFalse($browser->getLinkById(98));
+ }
+
+ function testSettingFieldIsPassedToPage() {
+ $page = new MockSimplePage();
+ $page->expectOnce('setField', array(new SimpleByLabelOrName('key'), 'Value', false));
+ $page->setReturnValue('getField', 'Value');
+ $browser = $this->loadPage($page);
+ $this->assertEqual($browser->getField('key'), 'Value');
+ $browser->setField('key', 'Value');
+ }
+}
+
+class TestOfBrowserNavigation extends UnitTestCase {
+ function createBrowser($agent, $page) {
+ $browser = new MockParseSimpleBrowser();
+ $browser->returns('createUserAgent', $agent);
+ $browser->returns('parse', $page);
+ $browser->__construct();
+ return $browser;
+ }
+
+ function testBrowserRequestMethods() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+ $agent->expectAt(
+ 0,
+ 'fetchResponse',
+ array(new SimpleUrl('http://this.com/get.req'), new SimpleGetEncoding()));
+ $agent->expectAt(
+ 1,
+ 'fetchResponse',
+ array(new SimpleUrl('http://this.com/post.req'), new SimplePostEncoding()));
+ $agent->expectAt(
+ 2,
+ 'fetchResponse',
+ array(new SimpleUrl('http://this.com/put.req'), new SimplePutEncoding()));
+ $agent->expectAt(
+ 3,
+ 'fetchResponse',
+ array(new SimpleUrl('http://this.com/delete.req'), new SimpleDeleteEncoding()));
+ $agent->expectAt(
+ 4,
+ 'fetchResponse',
+ array(new SimpleUrl('http://this.com/head.req'), new SimpleHeadEncoding()));
+ $agent->expectCallCount('fetchResponse', 5);
+
+ $page = new MockSimplePage();
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/get.req');
+ $browser->post('http://this.com/post.req');
+ $browser->put('http://this.com/put.req');
+ $browser->delete('http://this.com/delete.req');
+ $browser->head('http://this.com/head.req');
+ }
+
+ function testClickLinkRequestsPage() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+ $agent->expectAt(
+ 0,
+ 'fetchResponse',
+ array(new SimpleUrl('http://this.com/page.html'), new SimpleGetEncoding()));
+ $agent->expectAt(
+ 1,
+ 'fetchResponse',
+ array(new SimpleUrl('http://this.com/new.html'), new SimpleGetEncoding()));
+ $agent->expectCallCount('fetchResponse', 2);
+
+ $page = new MockSimplePage();
+ $page->setReturnValue('getUrlsByLabel', array(new SimpleUrl('http://this.com/new.html')));
+ $page->expectOnce('getUrlsByLabel', array('New'));
+ $page->setReturnValue('getRaw', 'A page');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickLink('New'));
+ }
+
+ function testClickLinkWithUnknownFrameStillRequestsWholePage() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+ $agent->expectAt(
+ 0,
+ 'fetchResponse',
+ array(new SimpleUrl('http://this.com/page.html'), new SimpleGetEncoding()));
+ $target = new SimpleUrl('http://this.com/new.html');
+ $target->setTarget('missing');
+ $agent->expectAt(
+ 1,
+ 'fetchResponse',
+ array($target, new SimpleGetEncoding()));
+ $agent->expectCallCount('fetchResponse', 2);
+
+ $parsed_url = new SimpleUrl('http://this.com/new.html');
+ $parsed_url->setTarget('missing');
+
+ $page = new MockSimplePage();
+ $page->setReturnValue('getUrlsByLabel', array($parsed_url));
+ $page->setReturnValue('hasFrames', false);
+ $page->expectOnce('getUrlsByLabel', array('New'));
+ $page->setReturnValue('getRaw', 'A page');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickLink('New'));
+ }
+
+ function testClickingMissingLinkFails() {
+ $agent = new MockSimpleUserAgent($this);
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+
+ $page = new MockSimplePage();
+ $page->setReturnValue('getUrlsByLabel', array());
+ $page->setReturnValue('getRaw', 'stuff');
+
+ $browser = $this->createBrowser($agent, $page);
+ $this->assertTrue($browser->get('http://this.com/page.html'));
+ $this->assertFalse($browser->clickLink('New'));
+ }
+
+ function testClickIndexedLink() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+ $agent->expectAt(
+ 1,
+ 'fetchResponse',
+ array(new SimpleUrl('1.html'), new SimpleGetEncoding()));
+ $agent->expectCallCount('fetchResponse', 2);
+
+ $page = new MockSimplePage();
+ $page->setReturnValue(
+ 'getUrlsByLabel',
+ array(new SimpleUrl('0.html'), new SimpleUrl('1.html')));
+ $page->setReturnValue('getRaw', 'A page');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickLink('New', 1));
+ }
+
+ function testClinkLinkById() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+ $agent->expectAt(1, 'fetchResponse', array(
+ new SimpleUrl('http://this.com/link.html'),
+ new SimpleGetEncoding()));
+ $agent->expectCallCount('fetchResponse', 2);
+
+ $page = new MockSimplePage();
+ $page->setReturnValue('getUrlById', new SimpleUrl('http://this.com/link.html'));
+ $page->expectOnce('getUrlById', array(2));
+ $page->setReturnValue('getRaw', 'A page');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickLinkById(2));
+ }
+
+ function testClickingMissingLinkIdFails() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+
+ $page = new MockSimplePage();
+ $page->setReturnValue('getUrlById', false);
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertFalse($browser->clickLink(0));
+ }
+
+ function testSubmitFormByLabel() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+ $agent->expectAt(1, 'fetchResponse', array(
+ new SimpleUrl('http://this.com/handler.html'),
+ new SimplePostEncoding(array('a' => 'A'))));
+ $agent->expectCallCount('fetchResponse', 2);
+
+ $form = new MockSimpleForm();
+ $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html'));
+ $form->setReturnValue('getMethod', 'post');
+ $form->setReturnValue('submitButton', new SimplePostEncoding(array('a' => 'A')));
+ $form->expectOnce('submitButton', array(new SimpleByLabel('Go'), false));
+
+ $page = new MockSimplePage();
+ $page->returns('getFormBySubmit', $form);
+ $page->expectOnce('getFormBySubmit', array(new SimpleByLabel('Go')));
+ $page->setReturnValue('getRaw', 'stuff');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickSubmit('Go'));
+ }
+
+ function testDefaultSubmitFormByLabel() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+ $agent->expectAt(1, 'fetchResponse', array(
+ new SimpleUrl('http://this.com/page.html'),
+ new SimpleGetEncoding(array('a' => 'A'))));
+ $agent->expectCallCount('fetchResponse', 2);
+
+ $form = new MockSimpleForm();
+ $form->setReturnValue('getAction', new SimpleUrl('http://this.com/page.html'));
+ $form->setReturnValue('getMethod', 'get');
+ $form->setReturnValue('submitButton', new SimpleGetEncoding(array('a' => 'A')));
+
+ $page = new MockSimplePage();
+ $page->returns('getFormBySubmit', $form);
+ $page->expectOnce('getFormBySubmit', array(new SimpleByLabel('Submit')));
+ $page->setReturnValue('getRaw', 'stuff');
+ $page->setReturnValue('getUrl', new SimpleUrl('http://this.com/page.html'));
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickSubmit());
+ }
+
+ function testSubmitFormByName() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+
+ $form = new MockSimpleForm();
+ $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html'));
+ $form->setReturnValue('getMethod', 'post');
+ $form->setReturnValue('submitButton', new SimplePostEncoding(array('a' => 'A')));
+
+ $page = new MockSimplePage();
+ $page->returns('getFormBySubmit', $form);
+ $page->expectOnce('getFormBySubmit', array(new SimpleByName('me')));
+ $page->setReturnValue('getRaw', 'stuff');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickSubmitByName('me'));
+ }
+
+ function testSubmitFormById() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+
+ $form = new MockSimpleForm();
+ $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html'));
+ $form->setReturnValue('getMethod', 'post');
+ $form->setReturnValue('submitButton', new SimplePostEncoding(array('a' => 'A')));
+ $form->expectOnce('submitButton', array(new SimpleById(99), false));
+
+ $page = new MockSimplePage();
+ $page->returns('getFormBySubmit', $form);
+ $page->expectOnce('getFormBySubmit', array(new SimpleById(99)));
+ $page->setReturnValue('getRaw', 'stuff');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickSubmitById(99));
+ }
+
+ function testSubmitFormByImageLabel() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+
+ $form = new MockSimpleForm();
+ $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html'));
+ $form->setReturnValue('getMethod', 'post');
+ $form->setReturnValue('submitImage', new SimplePostEncoding(array('a' => 'A')));
+ $form->expectOnce('submitImage', array(new SimpleByLabel('Go!'), 10, 11, false));
+
+ $page = new MockSimplePage();
+ $page->returns('getFormByImage', $form);
+ $page->expectOnce('getFormByImage', array(new SimpleByLabel('Go!')));
+ $page->setReturnValue('getRaw', 'stuff');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickImage('Go!', 10, 11));
+ }
+
+ function testSubmitFormByImageName() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+
+ $form = new MockSimpleForm();
+ $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html'));
+ $form->setReturnValue('getMethod', 'post');
+ $form->setReturnValue('submitImage', new SimplePostEncoding(array('a' => 'A')));
+ $form->expectOnce('submitImage', array(new SimpleByName('a'), 10, 11, false));
+
+ $page = new MockSimplePage();
+ $page->returns('getFormByImage', $form);
+ $page->expectOnce('getFormByImage', array(new SimpleByName('a')));
+ $page->setReturnValue('getRaw', 'stuff');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickImageByName('a', 10, 11));
+ }
+
+ function testSubmitFormByImageId() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+
+ $form = new MockSimpleForm();
+ $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html'));
+ $form->setReturnValue('getMethod', 'post');
+ $form->setReturnValue('submitImage', new SimplePostEncoding(array('a' => 'A')));
+ $form->expectOnce('submitImage', array(new SimpleById(99), 10, 11, false));
+
+ $page = new MockSimplePage();
+ $page->returns('getFormByImage', $form);
+ $page->expectOnce('getFormByImage', array(new SimpleById(99)));
+ $page->setReturnValue('getRaw', 'stuff');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->clickImageById(99, 10, 11));
+ }
+
+ function testSubmitFormByFormId() {
+ $agent = new MockSimpleUserAgent();
+ $agent->returns('fetchResponse', new MockSimpleHttpResponse());
+ $agent->expectAt(1, 'fetchResponse', array(
+ new SimpleUrl('http://this.com/handler.html'),
+ new SimplePostEncoding(array('a' => 'A'))));
+ $agent->expectCallCount('fetchResponse', 2);
+
+ $form = new MockSimpleForm();
+ $form->setReturnValue('getAction', new SimpleUrl('http://this.com/handler.html'));
+ $form->setReturnValue('getMethod', 'post');
+ $form->setReturnValue('submit', new SimplePostEncoding(array('a' => 'A')));
+
+ $page = new MockSimplePage();
+ $page->returns('getFormById', $form);
+ $page->expectOnce('getFormById', array(33));
+ $page->setReturnValue('getRaw', 'stuff');
+
+ $browser = $this->createBrowser($agent, $page);
+ $browser->get('http://this.com/page.html');
+ $this->assertTrue($browser->submitFormById(33));
+ }
+}
+
+class TestOfBrowserFrames extends UnitTestCase {
+
+ function createBrowser($agent) {
+ $browser = new MockUserAgentSimpleBrowser();
+ $browser->returns('createUserAgent', $agent);
+ $browser->__construct();
+ return $browser;
+ }
+
+ function createUserAgent($pages) {
+ $agent = new MockSimpleUserAgent();
+ foreach ($pages as $url => $raw) {
+ $url = new SimpleUrl($url);
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('getUrl', $url);
+ $response->setReturnValue('getContent', $raw);
+ $agent->returns('fetchResponse', $response, array($url, '*'));
+ }
+ return $agent;
+ }
+
+ function testSimplePageHasNoFrames() {
+ $browser = $this->createBrowser($this->createUserAgent(
+ array('http://site.with.no.frames/' => 'A non-framed page')));
+ $this->assertEqual(
+ $browser->get('http://site.with.no.frames/'),
+ 'A non-framed page');
+ $this->assertIdentical($browser->getFrames(), 'http://site.with.no.frames/');
+ }
+
+ function testFramesetWithSingleFrame() {
+ $frameset = '';
+ $browser = $this->createBrowser($this->createUserAgent(array(
+ 'http://site.with.one.frame/' => $frameset,
+ 'http://site.with.one.frame/frame.html' => 'A frame')));
+ $this->assertEqual($browser->get('http://site.with.one.frame/'), 'A frame');
+ $this->assertIdentical(
+ $browser->getFrames(),
+ array('a' => 'http://site.with.one.frame/frame.html'));
+ }
+
+ function testTitleTakenFromFramesetPage() {
+ $frameset = 'Frameset title' .
+ '';
+ $browser = $this->createBrowser($this->createUserAgent(array(
+ 'http://site.with.one.frame/' => $frameset,
+ 'http://site.with.one.frame/frame.html' => 'Page title')));
+ $browser->get('http://site.with.one.frame/');
+ $this->assertEqual($browser->getTitle(), 'Frameset title');
+ }
+
+ function testFramesetWithSingleUnnamedFrame() {
+ $frameset = '';
+ $browser = $this->createBrowser($this->createUserAgent(array(
+ 'http://site.with.one.frame/' => $frameset,
+ 'http://site.with.one.frame/frame.html' => 'One frame')));
+ $this->assertEqual(
+ $browser->get('http://site.with.one.frame/'),
+ 'One frame');
+ $this->assertIdentical(
+ $browser->getFrames(),
+ array(1 => 'http://site.with.one.frame/frame.html'));
+ }
+
+ function testFramesetWithMultipleFrames() {
+ $frameset = '';
+ $browser = $this->createBrowser($this->createUserAgent(array(
+ 'http://site.with.frames/' => $frameset,
+ 'http://site.with.frames/frame_a.html' => 'A frame',
+ 'http://site.with.frames/frame_b.html' => 'B frame',
+ 'http://site.with.frames/frame_c.html' => 'C frame')));
+ $this->assertEqual(
+ $browser->get('http://site.with.frames/'),
+ 'A frameB frameC frame');
+ $this->assertIdentical($browser->getFrames(), array(
+ 'a' => 'http://site.with.frames/frame_a.html',
+ 'b' => 'http://site.with.frames/frame_b.html',
+ 'c' => 'http://site.with.frames/frame_c.html'));
+ }
+
+ function testFrameFocusByName() {
+ $frameset = '';
+ $browser = $this->createBrowser($this->createUserAgent(array(
+ 'http://site.with.frames/' => $frameset,
+ 'http://site.with.frames/frame_a.html' => 'A frame',
+ 'http://site.with.frames/frame_b.html' => 'B frame',
+ 'http://site.with.frames/frame_c.html' => 'C frame')));
+ $browser->get('http://site.with.frames/');
+ $browser->setFrameFocus('a');
+ $this->assertEqual($browser->getContent(), 'A frame');
+ $browser->setFrameFocus('b');
+ $this->assertEqual($browser->getContent(), 'B frame');
+ $browser->setFrameFocus('c');
+ $this->assertEqual($browser->getContent(), 'C frame');
+ }
+
+ function testFramesetWithSomeNamedFrames() {
+ $frameset = '';
+ $browser = $this->createBrowser($this->createUserAgent(array(
+ 'http://site.with.frames/' => $frameset,
+ 'http://site.with.frames/frame_a.html' => 'A frame',
+ 'http://site.with.frames/frame_b.html' => 'B frame',
+ 'http://site.with.frames/frame_c.html' => 'C frame',
+ 'http://site.with.frames/frame_d.html' => 'D frame')));
+ $this->assertEqual(
+ $browser->get('http://site.with.frames/'),
+ 'A frameB frameC frameD frame');
+ $this->assertIdentical($browser->getFrames(), array(
+ 'a' => 'http://site.with.frames/frame_a.html',
+ 2 => 'http://site.with.frames/frame_b.html',
+ 'c' => 'http://site.with.frames/frame_c.html',
+ 4 => 'http://site.with.frames/frame_d.html'));
+ }
+
+ function testFrameFocusWithMixedNamesAndIndexes() {
+ $frameset = '';
+ $browser = $this->createBrowser($this->createUserAgent(array(
+ 'http://site.with.frames/' => $frameset,
+ 'http://site.with.frames/frame_a.html' => 'A frame',
+ 'http://site.with.frames/frame_b.html' => 'B frame',
+ 'http://site.with.frames/frame_c.html' => 'C frame',
+ 'http://site.with.frames/frame_d.html' => 'D frame')));
+ $browser->get('http://site.with.frames/');
+ $browser->setFrameFocus('a');
+ $this->assertEqual($browser->getContent(), 'A frame');
+ $browser->setFrameFocus(2);
+ $this->assertEqual($browser->getContent(), 'B frame');
+ $browser->setFrameFocus('c');
+ $this->assertEqual($browser->getContent(), 'C frame');
+ $browser->setFrameFocus(4);
+ $this->assertEqual($browser->getContent(), 'D frame');
+ $browser->clearFrameFocus();
+ $this->assertEqual($browser->getContent(), 'A frameB frameC frameD frame');
+ }
+
+ function testNestedFrameset() {
+ $inner = '';
+ $outer = '';
+ $browser = $this->createBrowser($this->createUserAgent(array(
+ 'http://site.with.nested.frame/' => $outer,
+ 'http://site.with.nested.frame/inner.html' => $inner,
+ 'http://site.with.nested.frame/page.html' => 'The page')));
+ $this->assertEqual(
+ $browser->get('http://site.with.nested.frame/'),
+ 'The page');
+ $this->assertIdentical($browser->getFrames(), array(
+ 'inner' => array(
+ 'page' => 'http://site.with.nested.frame/page.html')));
+ }
+
+ function testCanNavigateToNestedFrame() {
+ $inner = '';
+ $outer = '';
+ $browser = $this->createBrowser($this->createUserAgent(array(
+ 'http://site.with.nested.frames/' => $outer,
+ 'http://site.with.nested.frames/inner.html' => $inner,
+ 'http://site.with.nested.frames/one.html' => 'Page one',
+ 'http://site.with.nested.frames/two.html' => 'Page two',
+ 'http://site.with.nested.frames/three.html' => 'Page three')));
+
+ $browser->get('http://site.with.nested.frames/');
+ $this->assertEqual($browser->getContent(), 'Page onePage twoPage three');
+
+ $this->assertTrue($browser->setFrameFocus('inner'));
+ $this->assertEqual($browser->getFrameFocus(), array('inner'));
+ $this->assertTrue($browser->setFrameFocus('one'));
+ $this->assertEqual($browser->getFrameFocus(), array('inner', 'one'));
+ $this->assertEqual($browser->getContent(), 'Page one');
+
+ $this->assertTrue($browser->setFrameFocus('two'));
+ $this->assertEqual($browser->getFrameFocus(), array('inner', 'two'));
+ $this->assertEqual($browser->getContent(), 'Page two');
+
+ $browser->clearFrameFocus();
+ $this->assertTrue($browser->setFrameFocus('three'));
+ $this->assertEqual($browser->getFrameFocus(), array('three'));
+ $this->assertEqual($browser->getContent(), 'Page three');
+
+ $this->assertTrue($browser->setFrameFocus('inner'));
+ $this->assertEqual($browser->getContent(), 'Page onePage two');
+ }
+
+ function testCanNavigateToNestedFrameByIndex() {
+ $inner = '';
+ $outer = '';
+ $browser = $this->createBrowser($this->createUserAgent(array(
+ 'http://site.with.nested.frames/' => $outer,
+ 'http://site.with.nested.frames/inner.html' => $inner,
+ 'http://site.with.nested.frames/one.html' => 'Page one',
+ 'http://site.with.nested.frames/two.html' => 'Page two',
+ 'http://site.with.nested.frames/three.html' => 'Page three')));
+
+ $browser->get('http://site.with.nested.frames/');
+ $this->assertEqual($browser->getContent(), 'Page onePage twoPage three');
+
+ $this->assertTrue($browser->setFrameFocusByIndex(1));
+ $this->assertEqual($browser->getFrameFocus(), array(1));
+ $this->assertTrue($browser->setFrameFocusByIndex(1));
+ $this->assertEqual($browser->getFrameFocus(), array(1, 1));
+ $this->assertEqual($browser->getContent(), 'Page one');
+
+ $this->assertTrue($browser->setFrameFocusByIndex(2));
+ $this->assertEqual($browser->getFrameFocus(), array(1, 2));
+ $this->assertEqual($browser->getContent(), 'Page two');
+
+ $browser->clearFrameFocus();
+ $this->assertTrue($browser->setFrameFocusByIndex(2));
+ $this->assertEqual($browser->getFrameFocus(), array(2));
+ $this->assertEqual($browser->getContent(), 'Page three');
+
+ $this->assertTrue($browser->setFrameFocusByIndex(1));
+ $this->assertEqual($browser->getContent(), 'Page onePage two');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/collector_test.php b/tests/simpletest/test/collector_test.php
new file mode 100644
index 0000000..efdbf37
--- /dev/null
+++ b/tests/simpletest/test/collector_test.php
@@ -0,0 +1,50 @@
+expectMinimumCallCount('addFile', 2);
+ $suite->expect(
+ 'addFile',
+ array(new PatternExpectation('/collectable\\.(1|2)$/')));
+ $collector = new SimpleCollector();
+ $collector->collect($suite, dirname(__FILE__) . '/support/collector/');
+ }
+}
+
+class TestOfPatternCollector extends UnitTestCase {
+
+ function testAddingEverythingToGroup() {
+ $suite = new MockTestSuite();
+ $suite->expectCallCount('addFile', 2);
+ $suite->expect(
+ 'addFile',
+ array(new PatternExpectation('/collectable\\.(1|2)$/')));
+ $collector = new SimplePatternCollector('/.*/');
+ $collector->collect($suite, dirname(__FILE__) . '/support/collector/');
+ }
+
+ function testOnlyMatchedFilesAreAddedToGroup() {
+ $suite = new MockTestSuite();
+ $suite->expectOnce('addFile', array(new PathEqualExpectation(
+ dirname(__FILE__) . '/support/collector/collectable.1')));
+ $collector = new SimplePatternCollector('/1$/');
+ $collector->collect($suite, dirname(__FILE__) . '/support/collector/');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/command_line_test.php b/tests/simpletest/test/command_line_test.php
new file mode 100644
index 0000000..5baabff
--- /dev/null
+++ b/tests/simpletest/test/command_line_test.php
@@ -0,0 +1,40 @@
+assertIdentical($parser->getTest(), '');
+ $this->assertIdentical($parser->getTestCase(), '');
+ }
+
+ function testNotXmlByDefault() {
+ $parser = new SimpleCommandLineParser(array());
+ $this->assertFalse($parser->isXml());
+ }
+
+ function testCanDetectRequestForXml() {
+ $parser = new SimpleCommandLineParser(array('--xml'));
+ $this->assertTrue($parser->isXml());
+ }
+
+ function testCanReadAssignmentSyntax() {
+ $parser = new SimpleCommandLineParser(array('--test=myTest'));
+ $this->assertEqual($parser->getTest(), 'myTest');
+ }
+
+ function testCanReadFollowOnSyntax() {
+ $parser = new SimpleCommandLineParser(array('--test', 'myTest'));
+ $this->assertEqual($parser->getTest(), 'myTest');
+ }
+
+ function testCanReadShortForms() {
+ $parser = new SimpleCommandLineParser(array('-t', 'myTest', '-c', 'MyClass', '-x'));
+ $this->assertEqual($parser->getTest(), 'myTest');
+ $this->assertEqual($parser->getTestCase(), 'MyClass');
+ $this->assertTrue($parser->isXml());
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/compatibility_test.php b/tests/simpletest/test/compatibility_test.php
new file mode 100644
index 0000000..b8635e5
--- /dev/null
+++ b/tests/simpletest/test/compatibility_test.php
@@ -0,0 +1,87 @@
+assertTrue(SimpleTestCompatibility::isA(
+ new ComparisonClass(),
+ 'ComparisonClass'));
+ $this->assertFalse(SimpleTestCompatibility::isA(
+ new ComparisonClass(),
+ 'ComparisonSubclass'));
+ $this->assertTrue(SimpleTestCompatibility::isA(
+ new ComparisonSubclass(),
+ 'ComparisonClass'));
+ }
+
+ function testIdentityOfNumericStrings() {
+ $numericString1 = "123";
+ $numericString2 = "00123";
+ $this->assertNotIdentical($numericString1, $numericString2);
+ }
+
+ function testIdentityOfObjects() {
+ $object1 = new ComparisonClass();
+ $object2 = new ComparisonClass();
+ $this->assertIdentical($object1, $object2);
+ }
+
+ function testReferences () {
+ $thing = "Hello";
+ $thing_reference = &$thing;
+ $thing_copy = $thing;
+ $this->assertTrue(SimpleTestCompatibility::isReference(
+ $thing,
+ $thing));
+ $this->assertTrue(SimpleTestCompatibility::isReference(
+ $thing,
+ $thing_reference));
+ $this->assertFalse(SimpleTestCompatibility::isReference(
+ $thing,
+ $thing_copy));
+ }
+
+ function testObjectReferences () {
+ $object = new ComparisonClass();
+ $object_reference = $object;
+ $object_copy = new ComparisonClass();
+ $object_assignment = $object;
+ $this->assertTrue(SimpleTestCompatibility::isReference(
+ $object,
+ $object));
+ $this->assertTrue(SimpleTestCompatibility::isReference(
+ $object,
+ $object_reference));
+ $this->assertFalse(SimpleTestCompatibility::isReference(
+ $object,
+ $object_copy));
+ if (version_compare(phpversion(), '5', '>=')) {
+ $this->assertTrue(SimpleTestCompatibility::isReference(
+ $object,
+ $object_assignment));
+ } else {
+ $this->assertFalse(SimpleTestCompatibility::isReference(
+ $object,
+ $object_assignment));
+ }
+ }
+
+ function testInteraceComparison() {
+ $object = new ComparisonClassWithInterface();
+ $this->assertFalse(SimpleTestCompatibility::isA(
+ new ComparisonClass(),
+ 'ComparisonInterface'));
+ $this->assertTrue(SimpleTestCompatibility::isA(
+ new ComparisonClassWithInterface(),
+ 'ComparisonInterface'));
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/cookies_test.php b/tests/simpletest/test/cookies_test.php
new file mode 100644
index 0000000..0b49e43
--- /dev/null
+++ b/tests/simpletest/test/cookies_test.php
@@ -0,0 +1,227 @@
+assertFalse($cookie->getValue());
+ $this->assertEqual($cookie->getPath(), "/");
+ $this->assertIdentical($cookie->getHost(), false);
+ $this->assertFalse($cookie->getExpiry());
+ $this->assertFalse($cookie->isSecure());
+ }
+
+ function testCookieAccessors() {
+ $cookie = new SimpleCookie(
+ "name",
+ "value",
+ "/path",
+ "Mon, 18 Nov 2002 15:50:29 GMT",
+ true);
+ $this->assertEqual($cookie->getName(), "name");
+ $this->assertEqual($cookie->getValue(), "value");
+ $this->assertEqual($cookie->getPath(), "/path/");
+ $this->assertEqual($cookie->getExpiry(), "Mon, 18 Nov 2002 15:50:29 GMT");
+ $this->assertTrue($cookie->isSecure());
+ }
+
+ function testFullHostname() {
+ $cookie = new SimpleCookie("name");
+ $this->assertTrue($cookie->setHost("host.name.here"));
+ $this->assertEqual($cookie->getHost(), "host.name.here");
+ $this->assertTrue($cookie->setHost("host.com"));
+ $this->assertEqual($cookie->getHost(), "host.com");
+ }
+
+ function testHostTruncation() {
+ $cookie = new SimpleCookie("name");
+ $cookie->setHost("this.host.name.here");
+ $this->assertEqual($cookie->getHost(), "host.name.here");
+ $cookie->setHost("this.host.com");
+ $this->assertEqual($cookie->getHost(), "host.com");
+ $this->assertTrue($cookie->setHost("dashes.in-host.com"));
+ $this->assertEqual($cookie->getHost(), "in-host.com");
+ }
+
+ function testBadHosts() {
+ $cookie = new SimpleCookie("name");
+ $this->assertFalse($cookie->setHost("gibberish"));
+ $this->assertFalse($cookie->setHost("host.here"));
+ $this->assertFalse($cookie->setHost("host..com"));
+ $this->assertFalse($cookie->setHost("..."));
+ $this->assertFalse($cookie->setHost("host.com."));
+ }
+
+ function testHostValidity() {
+ $cookie = new SimpleCookie("name");
+ $cookie->setHost("this.host.name.here");
+ $this->assertTrue($cookie->isValidHost("host.name.here"));
+ $this->assertTrue($cookie->isValidHost("that.host.name.here"));
+ $this->assertFalse($cookie->isValidHost("bad.host"));
+ $this->assertFalse($cookie->isValidHost("nearly.name.here"));
+ }
+
+ function testPathValidity() {
+ $cookie = new SimpleCookie("name", "value", "/path");
+ $this->assertFalse($cookie->isValidPath("/"));
+ $this->assertTrue($cookie->isValidPath("/path/"));
+ $this->assertTrue($cookie->isValidPath("/path/more"));
+ }
+
+ function testSessionExpiring() {
+ $cookie = new SimpleCookie("name", "value", "/path");
+ $this->assertTrue($cookie->isExpired(0));
+ }
+
+ function testTimestampExpiry() {
+ $cookie = new SimpleCookie("name", "value", "/path", 456);
+ $this->assertFalse($cookie->isExpired(0));
+ $this->assertTrue($cookie->isExpired(457));
+ $this->assertFalse($cookie->isExpired(455));
+ }
+
+ function testDateExpiry() {
+ $cookie = new SimpleCookie(
+ "name",
+ "value",
+ "/path",
+ "Mon, 18 Nov 2002 15:50:29 GMT");
+ $this->assertTrue($cookie->isExpired("Mon, 18 Nov 2002 15:50:30 GMT"));
+ $this->assertFalse($cookie->isExpired("Mon, 18 Nov 2002 15:50:28 GMT"));
+ }
+
+ function testAging() {
+ $cookie = new SimpleCookie("name", "value", "/path", 200);
+ $cookie->agePrematurely(199);
+ $this->assertFalse($cookie->isExpired(0));
+ $cookie->agePrematurely(2);
+ $this->assertTrue($cookie->isExpired(0));
+ }
+}
+
+class TestOfCookieJar extends UnitTestCase {
+
+ function testAddCookie() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie("a", "A");
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=A'));
+ }
+
+ function testHostFilter() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'A', 'my-host.com');
+ $jar->setCookie('b', 'B', 'another-host.com');
+ $jar->setCookie('c', 'C');
+ $this->assertEqual(
+ $jar->selectAsPairs(new SimpleUrl('my-host.com')),
+ array('a=A', 'c=C'));
+ $this->assertEqual(
+ $jar->selectAsPairs(new SimpleUrl('another-host.com')),
+ array('b=B', 'c=C'));
+ $this->assertEqual(
+ $jar->selectAsPairs(new SimpleUrl('www.another-host.com')),
+ array('b=B', 'c=C'));
+ $this->assertEqual(
+ $jar->selectAsPairs(new SimpleUrl('new-host.org')),
+ array('c=C'));
+ $this->assertEqual(
+ $jar->selectAsPairs(new SimpleUrl('/')),
+ array('a=A', 'b=B', 'c=C'));
+ }
+
+ function testPathFilter() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'A', false, '/path/');
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array());
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/elsewhere')), array());
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/')), array('a=A'));
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path')), array('a=A'));
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/pa')), array());
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/here')), array('a=A'));
+ }
+
+ function testPathFilterDeeply() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'A', false, '/path/more_path/');
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/')), array());
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path')), array());
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/pa')), array());
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/more_path/')), array('a=A'));
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/more_path/and_more')), array('a=A'));
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/path/not_here/')), array());
+ }
+
+ function testMultipleCookieWithDifferentPathsButSameName() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'abc', false, '/');
+ $jar->setCookie('a', '123', false, '/path/here/');
+ $this->assertEqual(
+ $jar->selectAsPairs(new SimpleUrl('/')),
+ array('a=abc'));
+ $this->assertEqual(
+ $jar->selectAsPairs(new SimpleUrl('my-host.com/')),
+ array('a=abc'));
+ $this->assertEqual(
+ $jar->selectAsPairs(new SimpleUrl('my-host.com/path/')),
+ array('a=abc'));
+ $this->assertEqual(
+ $jar->selectAsPairs(new SimpleUrl('my-host.com/path/here')),
+ array('a=abc', 'a=123'));
+ $this->assertEqual(
+ $jar->selectAsPairs(new SimpleUrl('my-host.com/path/here/there')),
+ array('a=abc', 'a=123'));
+ }
+
+ function testOverwrite() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'abc', false, '/');
+ $jar->setCookie('a', 'cde', false, '/');
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=cde'));
+ }
+
+ function testClearSessionCookies() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'A', false, '/');
+ $jar->restartSession();
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array());
+ }
+
+ function testExpiryFilterByDate() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'A', false, '/', 'Wed, 25-Dec-02 04:24:20 GMT');
+ $jar->restartSession("Wed, 25-Dec-02 04:24:19 GMT");
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=A'));
+ $jar->restartSession("Wed, 25-Dec-02 04:24:21 GMT");
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array());
+ }
+
+ function testExpiryFilterByAgeing() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'A', false, '/', 'Wed, 25-Dec-02 04:24:20 GMT');
+ $jar->restartSession("Wed, 25-Dec-02 04:24:19 GMT");
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=A'));
+ $jar->agePrematurely(2);
+ $jar->restartSession("Wed, 25-Dec-02 04:24:19 GMT");
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array());
+ }
+
+ function testCookieClearing() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'abc', false, '/');
+ $jar->setCookie('a', '', false, '/');
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a='));
+ }
+
+ function testCookieClearByLoweringDate() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'abc', false, '/', 'Wed, 25-Dec-02 04:24:21 GMT');
+ $jar->setCookie('a', 'def', false, '/', 'Wed, 25-Dec-02 04:24:19 GMT');
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array('a=def'));
+ $jar->restartSession('Wed, 25-Dec-02 04:24:20 GMT');
+ $this->assertEqual($jar->selectAsPairs(new SimpleUrl('/')), array());
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/detached_test.php b/tests/simpletest/test/detached_test.php
new file mode 100644
index 0000000..f651d97
--- /dev/null
+++ b/tests/simpletest/test/detached_test.php
@@ -0,0 +1,15 @@
+add(new DetachedTestCase($command));
+if (SimpleReporter::inCli()) {
+ exit ($test->run(new TextReporter()) ? 0 : 1);
+}
+$test->run(new HtmlReporter());
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/dumper_test.php b/tests/simpletest/test/dumper_test.php
new file mode 100644
index 0000000..789047d
--- /dev/null
+++ b/tests/simpletest/test/dumper_test.php
@@ -0,0 +1,88 @@
+assertEqual(
+ $dumper->clipString("Hello", 6),
+ "Hello",
+ "Hello, 6->%s");
+ $this->assertEqual(
+ $dumper->clipString("Hello", 5),
+ "Hello",
+ "Hello, 5->%s");
+ $this->assertEqual(
+ $dumper->clipString("Hello world", 3),
+ "Hel...",
+ "Hello world, 3->%s");
+ $this->assertEqual(
+ $dumper->clipString("Hello world", 6, 3),
+ "Hello ...",
+ "Hello world, 6, 3->%s");
+ $this->assertEqual(
+ $dumper->clipString("Hello world", 3, 6),
+ "...o w...",
+ "Hello world, 3, 6->%s");
+ $this->assertEqual(
+ $dumper->clipString("Hello world", 4, 11),
+ "...orld",
+ "Hello world, 4, 11->%s");
+ $this->assertEqual(
+ $dumper->clipString("Hello world", 4, 12),
+ "...orld",
+ "Hello world, 4, 12->%s");
+ }
+
+ function testDescribeNull() {
+ $dumper = new SimpleDumper();
+ $this->assertPattern('/null/i', $dumper->describeValue(null));
+ }
+
+ function testDescribeBoolean() {
+ $dumper = new SimpleDumper();
+ $this->assertPattern('/boolean/i', $dumper->describeValue(true));
+ $this->assertPattern('/true/i', $dumper->describeValue(true));
+ $this->assertPattern('/false/i', $dumper->describeValue(false));
+ }
+
+ function testDescribeString() {
+ $dumper = new SimpleDumper();
+ $this->assertPattern('/string/i', $dumper->describeValue('Hello'));
+ $this->assertPattern('/Hello/', $dumper->describeValue('Hello'));
+ }
+
+ function testDescribeInteger() {
+ $dumper = new SimpleDumper();
+ $this->assertPattern('/integer/i', $dumper->describeValue(35));
+ $this->assertPattern('/35/', $dumper->describeValue(35));
+ }
+
+ function testDescribeFloat() {
+ $dumper = new SimpleDumper();
+ $this->assertPattern('/float/i', $dumper->describeValue(0.99));
+ $this->assertPattern('/0\.99/', $dumper->describeValue(0.99));
+ }
+
+ function testDescribeArray() {
+ $dumper = new SimpleDumper();
+ $this->assertPattern('/array/i', $dumper->describeValue(array(1, 4)));
+ $this->assertPattern('/2/i', $dumper->describeValue(array(1, 4)));
+ }
+
+ function testDescribeObject() {
+ $dumper = new SimpleDumper();
+ $this->assertPattern(
+ '/object/i',
+ $dumper->describeValue(new DumperDummy()));
+ $this->assertPattern(
+ '/DumperDummy/i',
+ $dumper->describeValue(new DumperDummy()));
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/eclipse_test.php b/tests/simpletest/test/eclipse_test.php
new file mode 100644
index 0000000..c90cbc9
--- /dev/null
+++ b/tests/simpletest/test/eclipse_test.php
@@ -0,0 +1,32 @@
+expectOnce('write',array($expected));
+ $listener->setReturnValue('write',-1);
+
+ $pathparts = pathinfo($fullpath);
+ $filename = $pathparts['basename'];
+ $test= &new TestSuite($filename);
+ $test->addTestFile($fullpath);
+ $test->run(new EclipseReporter($listener));
+ $this->assertEqual($expected,$listener->output);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/encoding_test.php b/tests/simpletest/test/encoding_test.php
new file mode 100644
index 0000000..a09236e
--- /dev/null
+++ b/tests/simpletest/test/encoding_test.php
@@ -0,0 +1,240 @@
+assertEqual($pair->asRequest(), 'a=A');
+ }
+
+ function testMimeEncodedAsHeadersAndContent() {
+ $pair = new SimpleEncodedPair('a', 'A');
+ $this->assertEqual(
+ $pair->asMime(),
+ "Content-Disposition: form-data; name=\"a\"\r\n\r\nA");
+ }
+
+ function testAttachmentEncodedAsHeadersWithDispositionAndContent() {
+ $part = new SimpleAttachment('a', 'A', 'aaa.txt');
+ $this->assertEqual(
+ $part->asMime(),
+ "Content-Disposition: form-data; name=\"a\"; filename=\"aaa.txt\"\r\n" .
+ "Content-Type: text/plain\r\n\r\nA");
+ }
+}
+
+class TestOfEncoding extends UnitTestCase {
+ private $content_so_far;
+
+ function write($content) {
+ $this->content_so_far .= $content;
+ }
+
+ function clear() {
+ $this->content_so_far = '';
+ }
+
+ function assertWritten($encoding, $content, $message = '%s') {
+ $this->clear();
+ $encoding->writeTo($this);
+ $this->assertIdentical($this->content_so_far, $content, $message);
+ }
+
+ function testGetEmpty() {
+ $encoding = new SimpleGetEncoding();
+ $this->assertIdentical($encoding->getValue('a'), false);
+ $this->assertIdentical($encoding->asUrlRequest(), '');
+ }
+
+ function testPostEmpty() {
+ $encoding = new SimplePostEncoding();
+ $this->assertIdentical($encoding->getValue('a'), false);
+ $this->assertWritten($encoding, '');
+ }
+
+ function testPrefilled() {
+ $encoding = new SimplePostEncoding(array('a' => 'aaa'));
+ $this->assertIdentical($encoding->getValue('a'), 'aaa');
+ $this->assertWritten($encoding, 'a=aaa');
+ }
+
+ function testPrefilledWithTwoLevels() {
+ $query = array('a' => array('aa' => 'aaa'));
+ $encoding = new SimplePostEncoding($query);
+ $this->assertTrue($encoding->hasMoreThanOneLevel($query));
+ $this->assertEqual($encoding->rewriteArrayWithMultipleLevels($query), array('a[aa]' => 'aaa'));
+ $this->assertIdentical($encoding->getValue('a[aa]'), 'aaa');
+ $this->assertWritten($encoding, 'a%5Baa%5D=aaa');
+ }
+
+ function testPrefilledWithThreeLevels() {
+ $query = array('a' => array('aa' => array('aaa' => 'aaaa')));
+ $encoding = new SimplePostEncoding($query);
+ $this->assertTrue($encoding->hasMoreThanOneLevel($query));
+ $this->assertEqual($encoding->rewriteArrayWithMultipleLevels($query), array('a[aa][aaa]' => 'aaaa'));
+ $this->assertIdentical($encoding->getValue('a[aa][aaa]'), 'aaaa');
+ $this->assertWritten($encoding, 'a%5Baa%5D%5Baaa%5D=aaaa');
+ }
+
+ function testPrefilledWithObject() {
+ $encoding = new SimplePostEncoding(new SimpleEncoding(array('a' => 'aaa')));
+ $this->assertIdentical($encoding->getValue('a'), 'aaa');
+ $this->assertWritten($encoding, 'a=aaa');
+ }
+
+ function testMultiplePrefilled() {
+ $query = array('a' => array('a1', 'a2'));
+ $encoding = new SimplePostEncoding($query);
+ $this->assertTrue($encoding->hasMoreThanOneLevel($query));
+ $this->assertEqual($encoding->rewriteArrayWithMultipleLevels($query), array('a[0]' => 'a1', 'a[1]' => 'a2'));
+ $this->assertIdentical($encoding->getValue('a[0]'), 'a1');
+ $this->assertIdentical($encoding->getValue('a[1]'), 'a2');
+ $this->assertWritten($encoding, 'a%5B0%5D=a1&a%5B1%5D=a2');
+ }
+
+ function testSingleParameter() {
+ $encoding = new SimplePostEncoding();
+ $encoding->add('a', 'Hello');
+ $this->assertEqual($encoding->getValue('a'), 'Hello');
+ $this->assertWritten($encoding, 'a=Hello');
+ }
+
+ function testFalseParameter() {
+ $encoding = new SimplePostEncoding();
+ $encoding->add('a', false);
+ $this->assertEqual($encoding->getValue('a'), false);
+ $this->assertWritten($encoding, '');
+ }
+
+ function testUrlEncoding() {
+ $encoding = new SimplePostEncoding();
+ $encoding->add('a', 'Hello there!');
+ $this->assertWritten($encoding, 'a=Hello+there%21');
+ }
+
+ function testUrlEncodingOfKey() {
+ $encoding = new SimplePostEncoding();
+ $encoding->add('a!', 'Hello');
+ $this->assertWritten($encoding, 'a%21=Hello');
+ }
+
+ function testMultipleParameter() {
+ $encoding = new SimplePostEncoding();
+ $encoding->add('a', 'Hello');
+ $encoding->add('b', 'Goodbye');
+ $this->assertWritten($encoding, 'a=Hello&b=Goodbye');
+ }
+
+ function testEmptyParameters() {
+ $encoding = new SimplePostEncoding();
+ $encoding->add('a', '');
+ $encoding->add('b', '');
+ $this->assertWritten($encoding, 'a=&b=');
+ }
+
+ function testRepeatedParameter() {
+ $encoding = new SimplePostEncoding();
+ $encoding->add('a', 'Hello');
+ $encoding->add('a', 'Goodbye');
+ $this->assertIdentical($encoding->getValue('a'), array('Hello', 'Goodbye'));
+ $this->assertWritten($encoding, 'a=Hello&a=Goodbye');
+ }
+
+ function testAddingLists() {
+ $encoding = new SimplePostEncoding();
+ $encoding->add('a', array('Hello', 'Goodbye'));
+ $this->assertIdentical($encoding->getValue('a'), array('Hello', 'Goodbye'));
+ $this->assertWritten($encoding, 'a=Hello&a=Goodbye');
+ }
+
+ function testMergeInHash() {
+ $encoding = new SimpleGetEncoding(array('a' => 'A1', 'b' => 'B'));
+ $encoding->merge(array('a' => 'A2'));
+ $this->assertIdentical($encoding->getValue('a'), array('A1', 'A2'));
+ $this->assertIdentical($encoding->getValue('b'), 'B');
+ }
+
+ function testMergeInObject() {
+ $encoding = new SimpleGetEncoding(array('a' => 'A1', 'b' => 'B'));
+ $encoding->merge(new SimpleEncoding(array('a' => 'A2')));
+ $this->assertIdentical($encoding->getValue('a'), array('A1', 'A2'));
+ $this->assertIdentical($encoding->getValue('b'), 'B');
+ }
+
+ function testPrefilledMultipart() {
+ $encoding = new SimpleMultipartEncoding(array('a' => 'aaa'), 'boundary');
+ $this->assertIdentical($encoding->getValue('a'), 'aaa');
+ $this->assertwritten($encoding,
+ "--boundary\r\n" .
+ "Content-Disposition: form-data; name=\"a\"\r\n" .
+ "\r\n" .
+ "aaa\r\n" .
+ "--boundary--\r\n");
+ }
+
+ function testAttachment() {
+ $encoding = new SimpleMultipartEncoding(array(), 'boundary');
+ $encoding->attach('a', 'aaa', 'aaa.txt');
+ $this->assertIdentical($encoding->getValue('a'), 'aaa.txt');
+ $this->assertwritten($encoding,
+ "--boundary\r\n" .
+ "Content-Disposition: form-data; name=\"a\"; filename=\"aaa.txt\"\r\n" .
+ "Content-Type: text/plain\r\n" .
+ "\r\n" .
+ "aaa\r\n" .
+ "--boundary--\r\n");
+ }
+
+ function testEntityEncodingDefaultContentType() {
+ $encoding = new SimpleEntityEncoding();
+ $this->assertIdentical($encoding->getContentType(), 'application/x-www-form-urlencoded');
+ $this->assertWritten($encoding, '');
+ }
+
+ function testEntityEncodingTextBody() {
+ $encoding = new SimpleEntityEncoding('plain text');
+ $this->assertIdentical($encoding->getContentType(), 'text/plain');
+ $this->assertWritten($encoding, 'plain text');
+ }
+
+ function testEntityEncodingXmlBody() {
+ $encoding = new SimpleEntityEncoding('xmltext
', 'text/xml');
+ $this->assertIdentical($encoding->getContentType(), 'text/xml');
+ $this->assertWritten($encoding, 'xmltext
');
+ }
+}
+
+class TestOfEncodingHeaders extends UnitTestCase {
+
+ function testEmptyEncodingWritesZeroContentLength() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("Content-Length: 0\r\n"));
+ $socket->expectAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n"));
+ $encoding = new SimpleEntityEncoding();
+ $encoding->writeHeadersTo($socket);
+ }
+
+ function testTextEncodingWritesDefaultContentType() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("Content-Length: 18\r\n"));
+ $socket->expectAt(1, 'write', array("Content-Type: text/plain\r\n"));
+ $encoding = new SimpleEntityEncoding('one two three four');
+ $encoding->writeHeadersTo($socket);
+ }
+
+ function testEmptyMultipartEncodingWritesEndBoundaryContentLength() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("Content-Length: 14\r\n"));
+ $socket->expectAt(1, 'write', array("Content-Type: multipart/form-data; boundary=boundary\r\n"));
+ $encoding = new SimpleMultipartEncoding(array(), 'boundary');
+ $encoding->writeHeadersTo($socket);
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/errors_test.php b/tests/simpletest/test/errors_test.php
new file mode 100644
index 0000000..ebb9e05
--- /dev/null
+++ b/tests/simpletest/test/errors_test.php
@@ -0,0 +1,229 @@
+get('SimpleErrorQueue');
+ $queue->clear();
+ }
+
+ function tearDown() {
+ $context = SimpleTest::getContext();
+ $queue = $context->get('SimpleErrorQueue');
+ $queue->clear();
+ }
+
+ function testExpectationMatchCancelsIncomingError() {
+ $test = new MockSimpleTestCase();
+ $test->expectOnce('assert', array(
+ new IdenticalExpectation(new AnythingExpectation()),
+ 'B',
+ 'a message'));
+ $test->setReturnValue('assert', true);
+ $test->expectNever('error');
+ $queue = new SimpleErrorQueue();
+ $queue->setTestCase($test);
+ $queue->expectError(new AnythingExpectation(), 'a message');
+ $queue->add(1024, 'B', 'b.php', 100);
+ }
+}
+
+class TestOfErrorTrap extends UnitTestCase {
+ private $old;
+
+ function setUp() {
+ $this->old = error_reporting(E_ALL);
+ set_error_handler('SimpleTestErrorHandler');
+ }
+
+ function tearDown() {
+ restore_error_handler();
+ error_reporting($this->old);
+ }
+
+ function testQueueStartsEmpty() {
+ $context = SimpleTest::getContext();
+ $queue = $context->get('SimpleErrorQueue');
+ $this->assertFalse($queue->extract());
+ }
+
+ function testErrorsAreSwallowedByMatchingExpectation() {
+ $this->expectError('Ouch!');
+ trigger_error('Ouch!');
+ }
+
+ function testErrorsAreSwallowedInOrder() {
+ $this->expectError('a');
+ $this->expectError('b');
+ trigger_error('a');
+ trigger_error('b');
+ }
+
+ function testAnyErrorCanBeSwallowed() {
+ $this->expectError();
+ trigger_error('Ouch!');
+ }
+
+ function testErrorCanBeSwallowedByPatternMatching() {
+ $this->expectError(new PatternExpectation('/ouch/i'));
+ trigger_error('Ouch!');
+ }
+
+ function testErrorWithPercentsPassesWithNoSprintfError() {
+ $this->expectError("%");
+ trigger_error('%');
+ }
+}
+
+class TestOfErrors extends UnitTestCase {
+ private $old;
+
+ function setUp() {
+ $this->old = error_reporting(E_ALL);
+ }
+
+ function tearDown() {
+ error_reporting($this->old);
+ }
+
+ function testDefaultWhenAllReported() {
+ error_reporting(E_ALL);
+ $this->expectError('Ouch!');
+ trigger_error('Ouch!');
+ }
+
+ function testNoticeWhenReported() {
+ error_reporting(E_ALL);
+ $this->expectError('Ouch!');
+ trigger_error('Ouch!', E_USER_NOTICE);
+ }
+
+ function testWarningWhenReported() {
+ error_reporting(E_ALL);
+ $this->expectError('Ouch!');
+ trigger_error('Ouch!', E_USER_WARNING);
+ }
+
+ function testErrorWhenReported() {
+ error_reporting(E_ALL);
+ $this->expectError('Ouch!');
+ trigger_error('Ouch!', E_USER_ERROR);
+ }
+
+ function testNoNoticeWhenNotReported() {
+ error_reporting(0);
+ trigger_error('Ouch!', E_USER_NOTICE);
+ }
+
+ function testNoWarningWhenNotReported() {
+ error_reporting(0);
+ trigger_error('Ouch!', E_USER_WARNING);
+ }
+
+ function testNoticeSuppressedWhenReported() {
+ error_reporting(E_ALL);
+ @trigger_error('Ouch!', E_USER_NOTICE);
+ }
+
+ function testWarningSuppressedWhenReported() {
+ error_reporting(E_ALL);
+ @trigger_error('Ouch!', E_USER_WARNING);
+ }
+
+ function testErrorWithPercentsReportedWithNoSprintfError() {
+ $this->expectError('%');
+ trigger_error('%');
+ }
+}
+
+class TestOfPHP52RecoverableErrors extends UnitTestCase {
+ function skip() {
+ $this->skipIf(
+ version_compare(phpversion(), '5.2', '<'),
+ 'E_RECOVERABLE_ERROR not tested for PHP below 5.2');
+ }
+
+ function testError() {
+ eval('
+ class RecoverableErrorTestingStub {
+ function ouch(RecoverableErrorTestingStub $obj) {
+ }
+ }
+ ');
+
+ $stub = new RecoverableErrorTestingStub();
+ $this->expectError(new PatternExpectation('/must be an instance of RecoverableErrorTestingStub/i'));
+ $stub->ouch(new stdClass());
+ }
+}
+
+class TestOfErrorsExcludingPHP52AndAbove extends UnitTestCase {
+ function skip() {
+ $this->skipIf(
+ version_compare(phpversion(), '5.2', '>='),
+ 'E_USER_ERROR not tested for PHP 5.2 and above');
+ }
+
+ function testNoErrorWhenNotReported() {
+ error_reporting(0);
+ trigger_error('Ouch!', E_USER_ERROR);
+ }
+
+ function testErrorSuppressedWhenReported() {
+ error_reporting(E_ALL);
+ @trigger_error('Ouch!', E_USER_ERROR);
+ }
+}
+
+SimpleTest::ignore('TestOfNotEnoughErrors');
+/**
+ * This test is ignored as it is used by {@link TestRunnerForLeftOverAndNotEnoughErrors}
+ * to verify that it fails as expected.
+ *
+ * @ignore
+ */
+class TestOfNotEnoughErrors extends UnitTestCase {
+ function testExpectTwoErrorsThrowOne() {
+ $this->expectError('Error 1');
+ trigger_error('Error 1');
+ $this->expectError('Error 2');
+ }
+}
+
+SimpleTest::ignore('TestOfLeftOverErrors');
+/**
+ * This test is ignored as it is used by {@link TestRunnerForLeftOverAndNotEnoughErrors}
+ * to verify that it fails as expected.
+ *
+ * @ignore
+ */
+class TestOfLeftOverErrors extends UnitTestCase {
+ function testExpectOneErrorGetTwo() {
+ $this->expectError('Error 1');
+ trigger_error('Error 1');
+ trigger_error('Error 2');
+ }
+}
+
+class TestRunnerForLeftOverAndNotEnoughErrors extends UnitTestCase {
+ function testRunLeftOverErrorsTestCase() {
+ $test = new TestOfLeftOverErrors();
+ $this->assertFalse($test->run(new SimpleReporter()));
+ }
+
+ function testRunNotEnoughErrors() {
+ $test = new TestOfNotEnoughErrors();
+ $this->assertFalse($test->run(new SimpleReporter()));
+ }
+}
+
+// TODO: Add stacked error handler test
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/exceptions_test.php b/tests/simpletest/test/exceptions_test.php
new file mode 100644
index 0000000..1011543
--- /dev/null
+++ b/tests/simpletest/test/exceptions_test.php
@@ -0,0 +1,183 @@
+assertTrue($expectation->test(new MyTestException()));
+ $this->assertTrue($expectation->test(new HigherTestException()));
+ $this->assertFalse($expectation->test(new OtherTestException()));
+ }
+
+ function testMatchesClassAndMessageWhenExceptionExpected() {
+ $expectation = new ExceptionExpectation(new MyTestException('Hello'));
+ $this->assertTrue($expectation->test(new MyTestException('Hello')));
+ $this->assertFalse($expectation->test(new HigherTestException('Hello')));
+ $this->assertFalse($expectation->test(new OtherTestException('Hello')));
+ $this->assertFalse($expectation->test(new MyTestException('Goodbye')));
+ $this->assertFalse($expectation->test(new MyTestException()));
+ }
+
+ function testMessagelessExceptionMatchesOnlyOnClass() {
+ $expectation = new ExceptionExpectation(new MyTestException());
+ $this->assertTrue($expectation->test(new MyTestException()));
+ $this->assertFalse($expectation->test(new HigherTestException()));
+ }
+}
+
+class TestOfExceptionTrap extends UnitTestCase {
+
+ function testNoExceptionsInQueueMeansNoTestMessages() {
+ $test = new MockSimpleTestCase();
+ $test->expectNever('assert');
+ $queue = new SimpleExceptionTrap();
+ $this->assertFalse($queue->isExpected($test, new Exception()));
+ }
+
+ function testMatchingExceptionGivesTrue() {
+ $expectation = new MockSimpleExpectation();
+ $expectation->setReturnValue('test', true);
+ $test = new MockSimpleTestCase();
+ $test->setReturnValue('assert', true);
+ $queue = new SimpleExceptionTrap();
+ $queue->expectException($expectation, 'message');
+ $this->assertTrue($queue->isExpected($test, new Exception()));
+ }
+
+ function testMatchingExceptionTriggersAssertion() {
+ $test = new MockSimpleTestCase();
+ $test->expectOnce('assert', array(
+ '*',
+ new ExceptionExpectation(new Exception()),
+ 'message'));
+ $queue = new SimpleExceptionTrap();
+ $queue->expectException(new ExceptionExpectation(new Exception()), 'message');
+ $queue->isExpected($test, new Exception());
+ }
+}
+
+class TestOfCatchingExceptions extends UnitTestCase {
+
+ function testCanCatchAnyExpectedException() {
+ $this->expectException();
+ throw new Exception();
+ }
+
+ function testCanMatchExceptionByClass() {
+ $this->expectException('MyTestException');
+ throw new HigherTestException();
+ }
+
+ function testCanMatchExceptionExactly() {
+ $this->expectException(new Exception('Ouch'));
+ throw new Exception('Ouch');
+ }
+
+ function testLastListedExceptionIsTheOneThatCounts() {
+ $this->expectException('OtherTestException');
+ $this->expectException('MyTestException');
+ throw new HigherTestException();
+ }
+}
+
+class TestOfIgnoringExceptions extends UnitTestCase {
+
+ function testCanIgnoreAnyException() {
+ $this->ignoreException();
+ throw new Exception();
+ }
+
+ function testCanIgnoreSpecificException() {
+ $this->ignoreException('MyTestException');
+ throw new MyTestException();
+ }
+
+ function testCanIgnoreExceptionExactly() {
+ $this->ignoreException(new Exception('Ouch'));
+ throw new Exception('Ouch');
+ }
+
+ function testIgnoredExceptionsDoNotMaskExpectedExceptions() {
+ $this->ignoreException('Exception');
+ $this->expectException('MyTestException');
+ throw new MyTestException();
+ }
+
+ function testCanIgnoreMultipleExceptions() {
+ $this->ignoreException('MyTestException');
+ $this->ignoreException('OtherTestException');
+ throw new OtherTestException();
+ }
+}
+
+class TestOfCallingTearDownAfterExceptions extends UnitTestCase {
+ private $debri = 0;
+
+ function tearDown() {
+ $this->debri--;
+ }
+
+ function testLeaveSomeDebri() {
+ $this->debri++;
+ $this->expectException();
+ throw new Exception(__FUNCTION__);
+ }
+
+ function testDebriWasRemovedOnce() {
+ $this->assertEqual($this->debri, 0);
+ }
+}
+
+class TestOfExceptionThrownInSetUpDoesNotRunTestBody extends UnitTestCase {
+
+ function setUp() {
+ $this->expectException();
+ throw new Exception();
+ }
+
+ function testShouldNotBeRun() {
+ $this->fail('This test body should not be run');
+ }
+
+ function testShouldNotBeRunEither() {
+ $this->fail('This test body should not be run either');
+ }
+}
+
+class TestOfExpectExceptionWithSetUp extends UnitTestCase {
+
+ function setUp() {
+ $this->expectException();
+ }
+
+ function testThisExceptionShouldBeCaught() {
+ throw new Exception();
+ }
+
+ function testJustThrowingMyTestException() {
+ throw new MyTestException();
+ }
+}
+
+class TestOfThrowingExceptionsInTearDown extends UnitTestCase {
+
+ function tearDown() {
+ throw new Exception();
+ }
+
+ function testDoesntFatal() {
+ $this->expectException();
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/expectation_test.php b/tests/simpletest/test/expectation_test.php
new file mode 100644
index 0000000..31fbe65
--- /dev/null
+++ b/tests/simpletest/test/expectation_test.php
@@ -0,0 +1,317 @@
+assertTrue($is_true->test(true));
+ $this->assertFalse($is_true->test(false));
+ }
+
+ function testStringMatch() {
+ $hello = new EqualExpectation("Hello");
+ $this->assertTrue($hello->test("Hello"));
+ $this->assertFalse($hello->test("Goodbye"));
+ }
+
+ function testInteger() {
+ $fifteen = new EqualExpectation(15);
+ $this->assertTrue($fifteen->test(15));
+ $this->assertFalse($fifteen->test(14));
+ }
+
+ function testFloat() {
+ $pi = new EqualExpectation(3.14);
+ $this->assertTrue($pi->test(3.14));
+ $this->assertFalse($pi->test(3.15));
+ }
+
+ function testArray() {
+ $colours = new EqualExpectation(array("r", "g", "b"));
+ $this->assertTrue($colours->test(array("r", "g", "b")));
+ $this->assertFalse($colours->test(array("g", "b", "r")));
+ }
+
+ function testHash() {
+ $is_blue = new EqualExpectation(array("r" => 0, "g" => 0, "b" => 255));
+ $this->assertTrue($is_blue->test(array("r" => 0, "g" => 0, "b" => 255)));
+ $this->assertFalse($is_blue->test(array("r" => 0, "g" => 255, "b" => 0)));
+ }
+
+ function testHashWithOutOfOrderKeysShouldStillMatch() {
+ $any_order = new EqualExpectation(array('a' => 1, 'b' => 2));
+ $this->assertTrue($any_order->test(array('b' => 2, 'a' => 1)));
+ }
+}
+
+class TestOfWithin extends UnitTestCase {
+
+ function testWithinFloatingPointMargin() {
+ $within = new WithinMarginExpectation(1.0, 0.2);
+ $this->assertFalse($within->test(0.7));
+ $this->assertTrue($within->test(0.8));
+ $this->assertTrue($within->test(0.9));
+ $this->assertTrue($within->test(1.1));
+ $this->assertTrue($within->test(1.2));
+ $this->assertFalse($within->test(1.3));
+ }
+
+ function testOutsideFloatingPointMargin() {
+ $within = new OutsideMarginExpectation(1.0, 0.2);
+ $this->assertTrue($within->test(0.7));
+ $this->assertFalse($within->test(0.8));
+ $this->assertFalse($within->test(1.2));
+ $this->assertTrue($within->test(1.3));
+ }
+}
+
+class TestOfInequality extends UnitTestCase {
+
+ function testStringMismatch() {
+ $not_hello = new NotEqualExpectation("Hello");
+ $this->assertTrue($not_hello->test("Goodbye"));
+ $this->assertFalse($not_hello->test("Hello"));
+ }
+}
+
+class RecursiveNasty {
+ private $me;
+
+ function RecursiveNasty() {
+ $this->me = $this;
+ }
+}
+
+class OpaqueContainer {
+ private $stuff;
+ private $value;
+
+ public function __construct($value) {
+ $this->value = $value;
+ }
+}
+
+class DerivedOpaqueContainer extends OpaqueContainer {
+ // Deliberately have a variable whose name with the same suffix as a later
+ // variable
+ private $new_value = 1;
+
+ // Deliberately obscures the variable of the same name in the base
+ // class.
+ private $value;
+
+ public function __construct($value, $base_value) {
+ parent::__construct($base_value);
+ $this->value = $value;
+ }
+}
+
+class TestOfIdentity extends UnitTestCase {
+
+ function testType() {
+ $string = new IdenticalExpectation("37");
+ $this->assertTrue($string->test("37"));
+ $this->assertFalse($string->test(37));
+ $this->assertFalse($string->test("38"));
+ }
+
+ function _testNastyPhp5Bug() {
+ $this->assertFalse(new RecursiveNasty() != new RecursiveNasty());
+ }
+
+ function _testReallyHorribleRecursiveStructure() {
+ $hopeful = new IdenticalExpectation(new RecursiveNasty());
+ $this->assertTrue($hopeful->test(new RecursiveNasty()));
+ }
+
+ function testCanComparePrivateMembers() {
+ $expectFive = new IdenticalExpectation(new OpaqueContainer(5));
+ $this->assertTrue($expectFive->test(new OpaqueContainer(5)));
+ $this->assertFalse($expectFive->test(new OpaqueContainer(6)));
+ }
+
+ function testCanComparePrivateMembersOfObjectsInArrays() {
+ $expectFive = new IdenticalExpectation(array(new OpaqueContainer(5)));
+ $this->assertTrue($expectFive->test(array(new OpaqueContainer(5))));
+ $this->assertFalse($expectFive->test(array(new OpaqueContainer(6))));
+ }
+
+ function testCanComparePrivateMembersOfObjectsWherePrivateMemberOfBaseClassIsObscured() {
+ $expectFive = new IdenticalExpectation(array(new DerivedOpaqueContainer(1,2)));
+ $this->assertTrue($expectFive->test(array(new DerivedOpaqueContainer(1,2))));
+ $this->assertFalse($expectFive->test(array(new DerivedOpaqueContainer(0,2))));
+ $this->assertFalse($expectFive->test(array(new DerivedOpaqueContainer(0,9))));
+ $this->assertFalse($expectFive->test(array(new DerivedOpaqueContainer(1,0))));
+ }
+}
+
+class TransparentContainer {
+ public $value;
+
+ public function __construct($value) {
+ $this->value = $value;
+ }
+}
+
+class TestOfMemberComparison extends UnitTestCase {
+
+ function testMemberExpectationCanMatchPublicMember() {
+ $expect_five = new MemberExpectation('value', 5);
+ $this->assertTrue($expect_five->test(new TransparentContainer(5)));
+ $this->assertFalse($expect_five->test(new TransparentContainer(8)));
+ }
+
+ function testMemberExpectationCanMatchPrivateMember() {
+ $expect_five = new MemberExpectation('value', 5);
+ $this->assertTrue($expect_five->test(new OpaqueContainer(5)));
+ $this->assertFalse($expect_five->test(new OpaqueContainer(8)));
+ }
+
+ function testMemberExpectationCanMatchPrivateMemberObscuredByDerivedClass() {
+ $expect_five = new MemberExpectation('value', 5);
+ $this->assertTrue($expect_five->test(new DerivedOpaqueContainer(5,8)));
+ $this->assertTrue($expect_five->test(new DerivedOpaqueContainer(5,5)));
+ $this->assertFalse($expect_five->test(new DerivedOpaqueContainer(8,8)));
+ $this->assertFalse($expect_five->test(new DerivedOpaqueContainer(8,5)));
+ }
+
+}
+
+class DummyReferencedObject{}
+
+class TestOfReference extends UnitTestCase {
+
+ function testReference() {
+ $foo = "foo";
+ $ref = &$foo;
+ $not_ref = $foo;
+ $bar = "bar";
+
+ $expect = new ReferenceExpectation($foo);
+ $this->assertTrue($expect->test($ref));
+ $this->assertFalse($expect->test($not_ref));
+ $this->assertFalse($expect->test($bar));
+ }
+}
+
+class TestOfNonIdentity extends UnitTestCase {
+
+ function testType() {
+ $string = new NotIdenticalExpectation("37");
+ $this->assertTrue($string->test("38"));
+ $this->assertTrue($string->test(37));
+ $this->assertFalse($string->test("37"));
+ }
+}
+
+class TestOfPatterns extends UnitTestCase {
+
+ function testWanted() {
+ $pattern = new PatternExpectation('/hello/i');
+ $this->assertTrue($pattern->test("Hello world"));
+ $this->assertFalse($pattern->test("Goodbye world"));
+ }
+
+ function testUnwanted() {
+ $pattern = new NoPatternExpectation('/hello/i');
+ $this->assertFalse($pattern->test("Hello world"));
+ $this->assertTrue($pattern->test("Goodbye world"));
+ }
+}
+
+class ExpectedMethodTarget {
+ function hasThisMethod() {}
+}
+
+class TestOfMethodExistence extends UnitTestCase {
+
+ function testHasMethod() {
+ $instance = new ExpectedMethodTarget();
+ $expectation = new MethodExistsExpectation('hasThisMethod');
+ $this->assertTrue($expectation->test($instance));
+ $expectation = new MethodExistsExpectation('doesNotHaveThisMethod');
+ $this->assertFalse($expectation->test($instance));
+ }
+}
+
+class TestOfIsA extends UnitTestCase {
+
+ function testString() {
+ $expectation = new IsAExpectation('string');
+ $this->assertTrue($expectation->test('Hello'));
+ $this->assertFalse($expectation->test(5));
+ }
+
+ function testBoolean() {
+ $expectation = new IsAExpectation('boolean');
+ $this->assertTrue($expectation->test(true));
+ $this->assertFalse($expectation->test(1));
+ }
+
+ function testBool() {
+ $expectation = new IsAExpectation('bool');
+ $this->assertTrue($expectation->test(true));
+ $this->assertFalse($expectation->test(1));
+ }
+
+ function testDouble() {
+ $expectation = new IsAExpectation('double');
+ $this->assertTrue($expectation->test(5.0));
+ $this->assertFalse($expectation->test(5));
+ }
+
+ function testFloat() {
+ $expectation = new IsAExpectation('float');
+ $this->assertTrue($expectation->test(5.0));
+ $this->assertFalse($expectation->test(5));
+ }
+
+ function testReal() {
+ $expectation = new IsAExpectation('real');
+ $this->assertTrue($expectation->test(5.0));
+ $this->assertFalse($expectation->test(5));
+ }
+
+ function testInteger() {
+ $expectation = new IsAExpectation('integer');
+ $this->assertTrue($expectation->test(5));
+ $this->assertFalse($expectation->test(5.0));
+ }
+
+ function testInt() {
+ $expectation = new IsAExpectation('int');
+ $this->assertTrue($expectation->test(5));
+ $this->assertFalse($expectation->test(5.0));
+ }
+
+ function testScalar() {
+ $expectation = new IsAExpectation('scalar');
+ $this->assertTrue($expectation->test(5));
+ $this->assertFalse($expectation->test(array(5)));
+ }
+
+ function testNumeric() {
+ $expectation = new IsAExpectation('numeric');
+ $this->assertTrue($expectation->test(5));
+ $this->assertFalse($expectation->test('string'));
+ }
+
+ function testNull() {
+ $expectation = new IsAExpectation('null');
+ $this->assertTrue($expectation->test(null));
+ $this->assertFalse($expectation->test('string'));
+ }
+}
+
+class TestOfNotA extends UnitTestCase {
+
+ function testString() {
+ $expectation = new NotAExpectation('string');
+ $this->assertFalse($expectation->test('Hello'));
+ $this->assertTrue($expectation->test(5));
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/form_test.php b/tests/simpletest/test/form_test.php
new file mode 100644
index 0000000..70a18f2
--- /dev/null
+++ b/tests/simpletest/test/form_test.php
@@ -0,0 +1,344 @@
+returns('getUrl', new SimpleUrl($url));
+ $page->returns('expandUrl', new SimpleUrl($url));
+ return $page;
+ }
+
+ function testFormAttributes() {
+ $tag = new SimpleFormTag(array('method' => 'GET', 'action' => 'here.php', 'id' => '33'));
+ $form = new SimpleForm($tag, $this->page('http://host/a/index.html'));
+ $this->assertEqual($form->getMethod(), 'get');
+ $this->assertIdentical($form->getId(), '33');
+ $this->assertNull($form->getValue(new SimpleByName('a')));
+ }
+
+ function testAction() {
+ $page = new MockSimplePage();
+ $page->expectOnce('expandUrl', array(new SimpleUrl('here.php')));
+ $page->setReturnValue('expandUrl', new SimpleUrl('http://host/here.php'));
+ $tag = new SimpleFormTag(array('method' => 'GET', 'action' => 'here.php'));
+ $form = new SimpleForm($tag, $page);
+ $this->assertEqual($form->getAction(), new SimpleUrl('http://host/here.php'));
+ }
+
+ function testEmptyAction() {
+ $tag = new SimpleFormTag(array('method' => 'GET', 'action' => '', 'id' => '33'));
+ $form = new SimpleForm($tag, $this->page('http://host/a/index.html'));
+ $this->assertEqual(
+ $form->getAction(),
+ new SimpleUrl('http://host/a/index.html'));
+ }
+
+ function testMissingAction() {
+ $tag = new SimpleFormTag(array('method' => 'GET'));
+ $form = new SimpleForm($tag, $this->page('http://host/a/index.html'));
+ $this->assertEqual(
+ $form->getAction(),
+ new SimpleUrl('http://host/a/index.html'));
+ }
+
+ function testRootAction() {
+ $page = new MockSimplePage();
+ $page->expectOnce('expandUrl', array(new SimpleUrl('/')));
+ $page->setReturnValue('expandUrl', new SimpleUrl('http://host/'));
+ $tag = new SimpleFormTag(array('method' => 'GET', 'action' => '/'));
+ $form = new SimpleForm($tag, $page);
+ $this->assertEqual(
+ $form->getAction(),
+ new SimpleUrl('http://host/'));
+ }
+
+ function testDefaultFrameTargetOnForm() {
+ $page = new MockSimplePage();
+ $page->expectOnce('expandUrl', array(new SimpleUrl('here.php')));
+ $page->setReturnValue('expandUrl', new SimpleUrl('http://host/here.php'));
+ $tag = new SimpleFormTag(array('method' => 'GET', 'action' => 'here.php'));
+ $form = new SimpleForm($tag, $page);
+ $form->setDefaultTarget('frame');
+ $expected = new SimpleUrl('http://host/here.php');
+ $expected->setTarget('frame');
+ $this->assertEqual($form->getAction(), $expected);
+ }
+
+ function testTextWidget() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleTextTag(
+ array('name' => 'me', 'type' => 'text', 'value' => 'Myself')));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), 'Myself');
+ $this->assertTrue($form->setField(new SimpleByName('me'), 'Not me'));
+ $this->assertFalse($form->setField(new SimpleByName('not_present'), 'Not me'));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), 'Not me');
+ $this->assertNull($form->getValue(new SimpleByName('not_present')));
+ }
+
+ function testTextWidgetById() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleTextTag(
+ array('name' => 'me', 'type' => 'text', 'value' => 'Myself', 'id' => 50)));
+ $this->assertIdentical($form->getValue(new SimpleById(50)), 'Myself');
+ $this->assertTrue($form->setField(new SimpleById(50), 'Not me'));
+ $this->assertIdentical($form->getValue(new SimpleById(50)), 'Not me');
+ }
+
+ function testTextWidgetByLabel() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $widget = new SimpleTextTag(array('name' => 'me', 'type' => 'text', 'value' => 'a'));
+ $form->addWidget($widget);
+ $widget->setLabel('thing');
+ $this->assertIdentical($form->getValue(new SimpleByLabel('thing')), 'a');
+ $this->assertTrue($form->setField(new SimpleByLabel('thing'), 'b'));
+ $this->assertIdentical($form->getValue(new SimpleByLabel('thing')), 'b');
+ }
+
+ function testSubmitEmpty() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $this->assertIdentical($form->submit(), new SimpleGetEncoding());
+ }
+
+ function testSubmitButton() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('http://host'));
+ $form->addWidget(new SimpleSubmitTag(
+ array('type' => 'submit', 'name' => 'go', 'value' => 'Go!', 'id' => '9')));
+ $this->assertTrue($form->hasSubmit(new SimpleByName('go')));
+ $this->assertEqual($form->getValue(new SimpleByName('go')), 'Go!');
+ $this->assertEqual($form->getValue(new SimpleById(9)), 'Go!');
+ $this->assertEqual(
+ $form->submitButton(new SimpleByName('go')),
+ new SimpleGetEncoding(array('go' => 'Go!')));
+ $this->assertEqual(
+ $form->submitButton(new SimpleByLabel('Go!')),
+ new SimpleGetEncoding(array('go' => 'Go!')));
+ $this->assertEqual(
+ $form->submitButton(new SimpleById(9)),
+ new SimpleGetEncoding(array('go' => 'Go!')));
+ }
+
+ function testSubmitWithAdditionalParameters() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('http://host'));
+ $form->addWidget(new SimpleSubmitTag(
+ array('type' => 'submit', 'name' => 'go', 'value' => 'Go!')));
+ $this->assertEqual(
+ $form->submitButton(new SimpleByLabel('Go!'), array('a' => 'A')),
+ new SimpleGetEncoding(array('go' => 'Go!', 'a' => 'A')));
+ }
+
+ function testSubmitButtonWithLabelOfSubmit() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('http://host'));
+ $form->addWidget(new SimpleSubmitTag(
+ array('type' => 'submit', 'name' => 'test', 'value' => 'Submit')));
+ $this->assertEqual(
+ $form->submitButton(new SimpleByName('test')),
+ new SimpleGetEncoding(array('test' => 'Submit')));
+ $this->assertEqual(
+ $form->submitButton(new SimpleByLabel('Submit')),
+ new SimpleGetEncoding(array('test' => 'Submit')));
+ }
+
+ function testSubmitButtonWithWhitespacePaddedLabelOfSubmit() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('http://host'));
+ $form->addWidget(new SimpleSubmitTag(
+ array('type' => 'submit', 'name' => 'test', 'value' => ' Submit ')));
+ $this->assertEqual(
+ $form->submitButton(new SimpleByLabel('Submit')),
+ new SimpleGetEncoding(array('test' => ' Submit ')));
+ }
+
+ function testImageSubmitButton() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleImageSubmitTag(array(
+ 'type' => 'image',
+ 'src' => 'source.jpg',
+ 'name' => 'go',
+ 'alt' => 'Go!',
+ 'id' => '9')));
+ $this->assertTrue($form->hasImage(new SimpleByLabel('Go!')));
+ $this->assertEqual(
+ $form->submitImage(new SimpleByLabel('Go!'), 100, 101),
+ new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101)));
+ $this->assertTrue($form->hasImage(new SimpleByName('go')));
+ $this->assertEqual(
+ $form->submitImage(new SimpleByName('go'), 100, 101),
+ new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101)));
+ $this->assertTrue($form->hasImage(new SimpleById(9)));
+ $this->assertEqual(
+ $form->submitImage(new SimpleById(9), 100, 101),
+ new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101)));
+ }
+
+ function testImageSubmitButtonWithAdditionalData() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleImageSubmitTag(array(
+ 'type' => 'image',
+ 'src' => 'source.jpg',
+ 'name' => 'go',
+ 'alt' => 'Go!')));
+ $this->assertEqual(
+ $form->submitImage(new SimpleByLabel('Go!'), 100, 101, array('a' => 'A')),
+ new SimpleGetEncoding(array('go.x' => 100, 'go.y' => 101, 'a' => 'A')));
+ }
+
+ function testButtonTag() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('http://host'));
+ $widget = new SimpleButtonTag(
+ array('type' => 'submit', 'name' => 'go', 'value' => 'Go', 'id' => '9'));
+ $widget->addContent('Go!');
+ $form->addWidget($widget);
+ $this->assertTrue($form->hasSubmit(new SimpleByName('go')));
+ $this->assertTrue($form->hasSubmit(new SimpleByLabel('Go!')));
+ $this->assertEqual(
+ $form->submitButton(new SimpleByName('go')),
+ new SimpleGetEncoding(array('go' => 'Go')));
+ $this->assertEqual(
+ $form->submitButton(new SimpleByLabel('Go!')),
+ new SimpleGetEncoding(array('go' => 'Go')));
+ $this->assertEqual(
+ $form->submitButton(new SimpleById(9)),
+ new SimpleGetEncoding(array('go' => 'Go')));
+ }
+
+ function testMultipleFieldsWithSameNameSubmitted() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $input = new SimpleTextTag(array('name' => 'elements[]', 'value' => '1'));
+ $form->addWidget($input);
+ $input = new SimpleTextTag(array('name' => 'elements[]', 'value' => '2'));
+ $form->addWidget($input);
+ $form->setField(new SimpleByLabelOrName('elements[]'), '3', 1);
+ $form->setField(new SimpleByLabelOrName('elements[]'), '4', 2);
+ $submit = $form->submit();
+ $requests = $submit->getAll();
+ $this->assertEqual(count($requests), 2);
+ $this->assertIdentical($requests[0], new SimpleEncodedPair('elements[]', '3'));
+ $this->assertIdentical($requests[1], new SimpleEncodedPair('elements[]', '4'));
+ }
+
+ function testSingleSelectFieldSubmitted() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $select = new SimpleSelectionTag(array('name' => 'a'));
+ $select->addTag(new SimpleOptionTag(
+ array('value' => 'aaa', 'selected' => '')));
+ $form->addWidget($select);
+ $this->assertIdentical(
+ $form->submit(),
+ new SimpleGetEncoding(array('a' => 'aaa')));
+ }
+
+ function testSingleSelectFieldSubmittedWithPost() {
+ $form = new SimpleForm(new SimpleFormTag(array('method' => 'post')), $this->page('htp://host'));
+ $select = new SimpleSelectionTag(array('name' => 'a'));
+ $select->addTag(new SimpleOptionTag(
+ array('value' => 'aaa', 'selected' => '')));
+ $form->addWidget($select);
+ $this->assertIdentical(
+ $form->submit(),
+ new SimplePostEncoding(array('a' => 'aaa')));
+ }
+
+ function testUnchecked() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleCheckboxTag(
+ array('name' => 'me', 'type' => 'checkbox')));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), false);
+ $this->assertTrue($form->setField(new SimpleByName('me'), 'on'));
+ $this->assertEqual($form->getValue(new SimpleByName('me')), 'on');
+ $this->assertFalse($form->setField(new SimpleByName('me'), 'other'));
+ $this->assertEqual($form->getValue(new SimpleByName('me')), 'on');
+ }
+
+ function testChecked() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleCheckboxTag(
+ array('name' => 'me', 'value' => 'a', 'type' => 'checkbox', 'checked' => '')));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a');
+ $this->assertTrue($form->setField(new SimpleByName('me'), 'a'));
+ $this->assertEqual($form->getValue(new SimpleByName('me')), 'a');
+ $this->assertTrue($form->setField(new SimpleByName('me'), false));
+ $this->assertEqual($form->getValue(new SimpleByName('me')), false);
+ }
+
+ function testSingleUncheckedRadioButton() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleRadioButtonTag(
+ array('name' => 'me', 'value' => 'a', 'type' => 'radio')));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), false);
+ $this->assertTrue($form->setField(new SimpleByName('me'), 'a'));
+ $this->assertEqual($form->getValue(new SimpleByName('me')), 'a');
+ }
+
+ function testSingleCheckedRadioButton() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleRadioButtonTag(
+ array('name' => 'me', 'value' => 'a', 'type' => 'radio', 'checked' => '')));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a');
+ $this->assertFalse($form->setField(new SimpleByName('me'), 'other'));
+ }
+
+ function testUncheckedRadioButtons() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleRadioButtonTag(
+ array('name' => 'me', 'value' => 'a', 'type' => 'radio')));
+ $form->addWidget(new SimpleRadioButtonTag(
+ array('name' => 'me', 'value' => 'b', 'type' => 'radio')));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), false);
+ $this->assertTrue($form->setField(new SimpleByName('me'), 'a'));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a');
+ $this->assertTrue($form->setField(new SimpleByName('me'), 'b'));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), 'b');
+ $this->assertFalse($form->setField(new SimpleByName('me'), 'c'));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), 'b');
+ }
+
+ function testCheckedRadioButtons() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleRadioButtonTag(
+ array('name' => 'me', 'value' => 'a', 'type' => 'radio')));
+ $form->addWidget(new SimpleRadioButtonTag(
+ array('name' => 'me', 'value' => 'b', 'type' => 'radio', 'checked' => '')));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), 'b');
+ $this->assertTrue($form->setField(new SimpleByName('me'), 'a'));
+ $this->assertIdentical($form->getValue(new SimpleByName('me')), 'a');
+ }
+
+ function testMultipleFieldsWithSameKey() {
+ $form = new SimpleForm(new SimpleFormTag(array()), $this->page('htp://host'));
+ $form->addWidget(new SimpleCheckboxTag(
+ array('name' => 'a', 'type' => 'checkbox', 'value' => 'me')));
+ $form->addWidget(new SimpleCheckboxTag(
+ array('name' => 'a', 'type' => 'checkbox', 'value' => 'you')));
+ $this->assertIdentical($form->getValue(new SimpleByName('a')), false);
+ $this->assertTrue($form->setField(new SimpleByName('a'), 'me'));
+ $this->assertIdentical($form->getValue(new SimpleByName('a')), 'me');
+ }
+
+ function testRemoveGetParamsFromAction() {
+ Mock::generatePartial('SimplePage', 'MockPartialSimplePage', array('getUrl'));
+ $page = new MockPartialSimplePage();
+ $page->returns('getUrl', new SimpleUrl('htp://host/'));
+
+ # Keep GET params in "action", if the form has no widgets
+ $form = new SimpleForm(new SimpleFormTag(array('action'=>'?test=1')), $page);
+ $this->assertEqual($form->getAction()->asString(), 'htp://host/');
+
+ $form = new SimpleForm(new SimpleFormTag(array('action'=>'?test=1')), $page);
+ $form->addWidget(new SimpleTextTag(array('name' => 'me', 'type' => 'text', 'value' => 'a')));
+ $this->assertEqual($form->getAction()->asString(), 'htp://host/');
+
+ $form = new SimpleForm(new SimpleFormTag(array('action'=>'')), $page);
+ $this->assertEqual($form->getAction()->asString(), 'htp://host/');
+
+ $form = new SimpleForm(new SimpleFormTag(array('action'=>'?test=1', 'method'=>'post')), $page);
+ $this->assertEqual($form->getAction()->asString(), 'htp://host/?test=1');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/frames_test.php b/tests/simpletest/test/frames_test.php
new file mode 100644
index 0000000..2930970
--- /dev/null
+++ b/tests/simpletest/test/frames_test.php
@@ -0,0 +1,549 @@
+setReturnValue('getTitle', 'This page');
+ $frameset = new SimpleFrameset($page);
+ $this->assertEqual($frameset->getTitle(), 'This page');
+ }
+
+ function TestHeadersReadFromFramesetByDefault() {
+ $page = new MockSimplePage();
+ $page->setReturnValue('getHeaders', 'Header: content');
+ $page->setReturnValue('getMimeType', 'text/xml');
+ $page->setReturnValue('getResponseCode', 401);
+ $page->setReturnValue('getTransportError', 'Could not parse headers');
+ $page->setReturnValue('getAuthentication', 'Basic');
+ $page->setReturnValue('getRealm', 'Safe place');
+
+ $frameset = new SimpleFrameset($page);
+
+ $this->assertIdentical($frameset->getHeaders(), 'Header: content');
+ $this->assertIdentical($frameset->getMimeType(), 'text/xml');
+ $this->assertIdentical($frameset->getResponseCode(), 401);
+ $this->assertIdentical($frameset->getTransportError(), 'Could not parse headers');
+ $this->assertIdentical($frameset->getAuthentication(), 'Basic');
+ $this->assertIdentical($frameset->getRealm(), 'Safe place');
+ }
+
+ function testEmptyFramesetHasNoContent() {
+ $page = new MockSimplePage();
+ $page->setReturnValue('getRaw', 'This content');
+ $frameset = new SimpleFrameset($page);
+ $this->assertEqual($frameset->getRaw(), '');
+ }
+
+ function testRawContentIsFromOnlyFrame() {
+ $page = new MockSimplePage();
+ $page->expectNever('getRaw');
+
+ $frame = new MockSimplePage();
+ $frame->setReturnValue('getRaw', 'Stuff');
+
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame);
+ $this->assertEqual($frameset->getRaw(), 'Stuff');
+ }
+
+ function testRawContentIsFromAllFrames() {
+ $page = new MockSimplePage();
+ $page->expectNever('getRaw');
+
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue('getRaw', 'Stuff1');
+
+ $frame2 = new MockSimplePage();
+ $frame2->setReturnValue('getRaw', 'Stuff2');
+
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame1);
+ $frameset->addFrame($frame2);
+ $this->assertEqual($frameset->getRaw(), 'Stuff1Stuff2');
+ }
+
+ function testTextContentIsFromOnlyFrame() {
+ $page = new MockSimplePage();
+ $page->expectNever('getText');
+
+ $frame = new MockSimplePage();
+ $frame->setReturnValue('getText', 'Stuff');
+
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame);
+ $this->assertEqual($frameset->getText(), 'Stuff');
+ }
+
+ function testTextContentIsFromAllFrames() {
+ $page = new MockSimplePage();
+ $page->expectNever('getText');
+
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue('getText', 'Stuff1');
+
+ $frame2 = new MockSimplePage();
+ $frame2->setReturnValue('getText', 'Stuff2');
+
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame1);
+ $frameset->addFrame($frame2);
+ $this->assertEqual($frameset->getText(), 'Stuff1 Stuff2');
+ }
+
+ function testFieldFoundIsFirstInFramelist() {
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue('getField', null);
+ $frame1->expectOnce('getField', array(new SimpleByName('a')));
+
+ $frame2 = new MockSimplePage();
+ $frame2->setReturnValue('getField', 'A');
+ $frame2->expectOnce('getField', array(new SimpleByName('a')));
+
+ $frame3 = new MockSimplePage();
+ $frame3->expectNever('getField');
+
+ $page = new MockSimplePage();
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame1);
+ $frameset->addFrame($frame2);
+ $frameset->addFrame($frame3);
+ $this->assertIdentical($frameset->getField(new SimpleByName('a')), 'A');
+ }
+
+ function testFrameReplacementByIndex() {
+ $page = new MockSimplePage();
+ $page->expectNever('getRaw');
+
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue('getRaw', 'Stuff1');
+
+ $frame2 = new MockSimplePage();
+ $frame2->setReturnValue('getRaw', 'Stuff2');
+
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame1);
+ $frameset->setFrame(array(1), $frame2);
+ $this->assertEqual($frameset->getRaw(), 'Stuff2');
+ }
+
+ function testFrameReplacementByName() {
+ $page = new MockSimplePage();
+ $page->expectNever('getRaw');
+
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue('getRaw', 'Stuff1');
+
+ $frame2 = new MockSimplePage();
+ $frame2->setReturnValue('getRaw', 'Stuff2');
+
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame1, 'a');
+ $frameset->setFrame(array('a'), $frame2);
+ $this->assertEqual($frameset->getRaw(), 'Stuff2');
+ }
+}
+
+class TestOfFrameNavigation extends UnitTestCase {
+
+ function testStartsWithoutFrameFocus() {
+ $page = new MockSimplePage();
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame(new MockSimplePage());
+ $this->assertFalse($frameset->getFrameFocus());
+ }
+
+ function testCanFocusOnSingleFrame() {
+ $page = new MockSimplePage();
+ $page->expectNever('getRaw');
+
+ $frame = new MockSimplePage();
+ $frame->setReturnValue('getFrameFocus', array());
+ $frame->setReturnValue('getRaw', 'Stuff');
+
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame);
+
+ $this->assertFalse($frameset->setFrameFocusByIndex(0));
+ $this->assertTrue($frameset->setFrameFocusByIndex(1));
+ $this->assertEqual($frameset->getRaw(), 'Stuff');
+ $this->assertFalse($frameset->setFrameFocusByIndex(2));
+ $this->assertIdentical($frameset->getFrameFocus(), array(1));
+ }
+
+ function testContentComesFromFrameInFocus() {
+ $page = new MockSimplePage();
+
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue('getRaw', 'Stuff1');
+ $frame1->setReturnValue('getFrameFocus', array());
+
+ $frame2 = new MockSimplePage();
+ $frame2->setReturnValue('getRaw', 'Stuff2');
+ $frame2->setReturnValue('getFrameFocus', array());
+
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame1);
+ $frameset->addFrame($frame2);
+
+ $this->assertTrue($frameset->setFrameFocusByIndex(1));
+ $this->assertEqual($frameset->getFrameFocus(), array(1));
+ $this->assertEqual($frameset->getRaw(), 'Stuff1');
+
+ $this->assertTrue($frameset->setFrameFocusByIndex(2));
+ $this->assertEqual($frameset->getFrameFocus(), array(2));
+ $this->assertEqual($frameset->getRaw(), 'Stuff2');
+
+ $this->assertFalse($frameset->setFrameFocusByIndex(3));
+ $this->assertEqual($frameset->getFrameFocus(), array(2));
+
+ $frameset->clearFrameFocus();
+ $this->assertEqual($frameset->getRaw(), 'Stuff1Stuff2');
+ }
+
+ function testCanFocusByName() {
+ $page = new MockSimplePage();
+
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue('getRaw', 'Stuff1');
+ $frame1->setReturnValue('getFrameFocus', array());
+
+ $frame2 = new MockSimplePage();
+ $frame2->setReturnValue('getRaw', 'Stuff2');
+ $frame2->setReturnValue('getFrameFocus', array());
+
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame1, 'A');
+ $frameset->addFrame($frame2, 'B');
+
+ $this->assertTrue($frameset->setFrameFocus('A'));
+ $this->assertEqual($frameset->getFrameFocus(), array('A'));
+ $this->assertEqual($frameset->getRaw(), 'Stuff1');
+
+ $this->assertTrue($frameset->setFrameFocusByIndex(2));
+ $this->assertEqual($frameset->getFrameFocus(), array('B'));
+ $this->assertEqual($frameset->getRaw(), 'Stuff2');
+
+ $this->assertFalse($frameset->setFrameFocus('z'));
+
+ $frameset->clearFrameFocus();
+ $this->assertEqual($frameset->getRaw(), 'Stuff1Stuff2');
+ }
+}
+
+class TestOfFramesetPageInterface extends UnitTestCase {
+ private $page_interface;
+ private $frameset_interface;
+
+ function __construct() {
+ parent::__construct();
+ $this->page_interface = $this->getPageMethods();
+ $this->frameset_interface = $this->getFramesetMethods();
+ }
+
+ function assertListInAnyOrder($list, $expected) {
+ sort($list);
+ sort($expected);
+ $this->assertEqual($list, $expected);
+ }
+
+ private function getPageMethods() {
+ $methods = array();
+ foreach (get_class_methods('SimplePage') as $method) {
+ if (strtolower($method) == strtolower('SimplePage')) {
+ continue;
+ }
+ if (strtolower($method) == strtolower('getFrameset')) {
+ continue;
+ }
+ if (strncmp($method, '_', 1) == 0) {
+ continue;
+ }
+ if (in_array($method, array('setTitle', 'setBase', 'setForms', 'normalise', 'setFrames', 'addLink'))) {
+ continue;
+ }
+ $methods[] = $method;
+ }
+ return $methods;
+ }
+
+ private function getFramesetMethods() {
+ $methods = array();
+ foreach (get_class_methods('SimpleFrameset') as $method) {
+ if (strtolower($method) == strtolower('SimpleFrameset')) {
+ continue;
+ }
+ if (strncmp($method, '_', 1) == 0) {
+ continue;
+ }
+ if (strncmp($method, 'add', 3) == 0) {
+ continue;
+ }
+ $methods[] = $method;
+ }
+ return $methods;
+ }
+
+ function testFramsetHasPageInterface() {
+ $difference = array();
+ foreach ($this->page_interface as $method) {
+ if (! in_array($method, $this->frameset_interface)) {
+ $this->fail("No [$method] in Frameset class");
+ return;
+ }
+ }
+ $this->pass('Frameset covers Page interface');
+ }
+
+ function testHeadersReadFromFrameIfInFocus() {
+ $frame = new MockSimplePage();
+ $frame->setReturnValue('getUrl', new SimpleUrl('http://localhost/stuff'));
+
+ $frame->setReturnValue('getRequest', 'POST stuff');
+ $frame->setReturnValue('getMethod', 'POST');
+ $frame->setReturnValue('getRequestData', array('a' => 'A'));
+ $frame->setReturnValue('getHeaders', 'Header: content');
+ $frame->setReturnValue('getMimeType', 'text/xml');
+ $frame->setReturnValue('getResponseCode', 401);
+ $frame->setReturnValue('getTransportError', 'Could not parse headers');
+ $frame->setReturnValue('getAuthentication', 'Basic');
+ $frame->setReturnValue('getRealm', 'Safe place');
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame($frame);
+ $frameset->setFrameFocusByIndex(1);
+
+ $url = new SimpleUrl('http://localhost/stuff');
+ $url->setTarget(1);
+ $this->assertIdentical($frameset->getUrl(), $url);
+
+ $this->assertIdentical($frameset->getRequest(), 'POST stuff');
+ $this->assertIdentical($frameset->getMethod(), 'POST');
+ $this->assertIdentical($frameset->getRequestData(), array('a' => 'A'));
+ $this->assertIdentical($frameset->getHeaders(), 'Header: content');
+ $this->assertIdentical($frameset->getMimeType(), 'text/xml');
+ $this->assertIdentical($frameset->getResponseCode(), 401);
+ $this->assertIdentical($frameset->getTransportError(), 'Could not parse headers');
+ $this->assertIdentical($frameset->getAuthentication(), 'Basic');
+ $this->assertIdentical($frameset->getRealm(), 'Safe place');
+ }
+
+ function testUrlsComeFromBothFrames() {
+ $page = new MockSimplePage();
+ $page->expectNever('getUrls');
+
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue(
+ 'getUrls',
+ array('http://www.lastcraft.com/', 'http://myserver/'));
+
+ $frame2 = new MockSimplePage();
+ $frame2->setReturnValue(
+ 'getUrls',
+ array('http://www.lastcraft.com/', 'http://test/'));
+
+ $frameset = new SimpleFrameset($page);
+ $frameset->addFrame($frame1);
+ $frameset->addFrame($frame2);
+ $this->assertListInAnyOrder(
+ $frameset->getUrls(),
+ array('http://www.lastcraft.com/', 'http://myserver/', 'http://test/'));
+ }
+
+ function testLabelledUrlsComeFromBothFrames() {
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue(
+ 'getUrlsByLabel',
+ array(new SimpleUrl('goodbye.php')),
+ array('a'));
+
+ $frame2 = new MockSimplePage();
+ $frame2->setReturnValue(
+ 'getUrlsByLabel',
+ array(new SimpleUrl('hello.php')),
+ array('a'));
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame($frame1);
+ $frameset->addFrame($frame2, 'Two');
+
+ $expected1 = new SimpleUrl('goodbye.php');
+ $expected1->setTarget(1);
+ $expected2 = new SimpleUrl('hello.php');
+ $expected2->setTarget('Two');
+ $this->assertEqual(
+ $frameset->getUrlsByLabel('a'),
+ array($expected1, $expected2));
+ }
+
+ function testUrlByIdComesFromFirstFrameToRespond() {
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue('getUrlById', new SimpleUrl('four.php'), array(4));
+ $frame1->setReturnValue('getUrlById', false, array(5));
+
+ $frame2 = new MockSimplePage();
+ $frame2->setReturnValue('getUrlById', false, array(4));
+ $frame2->setReturnValue('getUrlById', new SimpleUrl('five.php'), array(5));
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame($frame1);
+ $frameset->addFrame($frame2);
+
+ $four = new SimpleUrl('four.php');
+ $four->setTarget(1);
+ $this->assertEqual($frameset->getUrlById(4), $four);
+ $five = new SimpleUrl('five.php');
+ $five->setTarget(2);
+ $this->assertEqual($frameset->getUrlById(5), $five);
+ }
+
+ function testReadUrlsFromFrameInFocus() {
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue('getUrls', array('a'));
+ $frame1->setReturnValue('getUrlsByLabel', array(new SimpleUrl('l')));
+ $frame1->setReturnValue('getUrlById', new SimpleUrl('i'));
+
+ $frame2 = new MockSimplePage();
+ $frame2->expectNever('getUrls');
+ $frame2->expectNever('getUrlsByLabel');
+ $frame2->expectNever('getUrlById');
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame($frame1, 'A');
+ $frameset->addFrame($frame2, 'B');
+ $frameset->setFrameFocus('A');
+
+ $this->assertIdentical($frameset->getUrls(), array('a'));
+ $expected = new SimpleUrl('l');
+ $expected->setTarget('A');
+ $this->assertIdentical($frameset->getUrlsByLabel('label'), array($expected));
+ $expected = new SimpleUrl('i');
+ $expected->setTarget('A');
+ $this->assertIdentical($frameset->getUrlById(99), $expected);
+ }
+
+ function testReadFrameTaggedUrlsFromFrameInFocus() {
+ $frame = new MockSimplePage();
+
+ $by_label = new SimpleUrl('l');
+ $by_label->setTarget('L');
+ $frame->setReturnValue('getUrlsByLabel', array($by_label));
+
+ $by_id = new SimpleUrl('i');
+ $by_id->setTarget('I');
+ $frame->setReturnValue('getUrlById', $by_id);
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame($frame, 'A');
+ $frameset->setFrameFocus('A');
+
+ $this->assertIdentical($frameset->getUrlsByLabel('label'), array($by_label));
+ $this->assertIdentical($frameset->getUrlById(99), $by_id);
+ }
+
+ function testFindingFormsById() {
+ $frame = new MockSimplePage();
+ $form = new MockSimpleForm();
+ $frame->returns('getFormById', $form, array('a'));
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame(new MockSimplePage(), 'A');
+ $frameset->addFrame($frame, 'B');
+ $this->assertSame($frameset->getFormById('a'), $form);
+
+ $frameset->setFrameFocus('A');
+ $this->assertNull($frameset->getFormById('a'));
+
+ $frameset->setFrameFocus('B');
+ $this->assertSame($frameset->getFormById('a'), $form);
+ }
+
+ function testFindingFormsBySubmit() {
+ $frame = new MockSimplePage();
+ $form = new MockSimpleForm();
+ $frame->returns(
+ 'getFormBySubmit',
+ $form,
+ array(new SimpleByLabel('a')));
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame(new MockSimplePage(), 'A');
+ $frameset->addFrame($frame, 'B');
+ $this->assertSame($frameset->getFormBySubmit(new SimpleByLabel('a')), $form);
+
+ $frameset->setFrameFocus('A');
+ $this->assertNull($frameset->getFormBySubmit(new SimpleByLabel('a')));
+
+ $frameset->setFrameFocus('B');
+ $this->assertSame($frameset->getFormBySubmit(new SimpleByLabel('a')), $form);
+ }
+
+ function testFindingFormsByImage() {
+ $frame = new MockSimplePage();
+ $form = new MockSimpleForm();
+ $frame->returns(
+ 'getFormByImage',
+ $form,
+ array(new SimpleByLabel('a')));
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame(new MockSimplePage(), 'A');
+ $frameset->addFrame($frame, 'B');
+ $this->assertSame($frameset->getFormByImage(new SimpleByLabel('a')), $form);
+
+ $frameset->setFrameFocus('A');
+ $this->assertNull($frameset->getFormByImage(new SimpleByLabel('a')));
+
+ $frameset->setFrameFocus('B');
+ $this->assertSame($frameset->getFormByImage(new SimpleByLabel('a')), $form);
+ }
+
+ function testSettingAllFrameFieldsWhenNoFrameFocus() {
+ $frame1 = new MockSimplePage();
+ $frame1->expectOnce('setField', array(new SimpleById(22), 'A'));
+
+ $frame2 = new MockSimplePage();
+ $frame2->expectOnce('setField', array(new SimpleById(22), 'A'));
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame($frame1, 'A');
+ $frameset->addFrame($frame2, 'B');
+ $frameset->setField(new SimpleById(22), 'A');
+ }
+
+ function testOnlySettingFieldFromFocusedFrame() {
+ $frame1 = new MockSimplePage();
+ $frame1->expectOnce('setField', array(new SimpleByLabelOrName('a'), 'A'));
+
+ $frame2 = new MockSimplePage();
+ $frame2->expectNever('setField');
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame($frame1, 'A');
+ $frameset->addFrame($frame2, 'B');
+ $frameset->setFrameFocus('A');
+ $frameset->setField(new SimpleByLabelOrName('a'), 'A');
+ }
+
+ function testOnlyGettingFieldFromFocusedFrame() {
+ $frame1 = new MockSimplePage();
+ $frame1->setReturnValue('getField', 'f', array(new SimpleByName('a')));
+
+ $frame2 = new MockSimplePage();
+ $frame2->expectNever('getField');
+
+ $frameset = new SimpleFrameset(new MockSimplePage());
+ $frameset->addFrame($frame1, 'A');
+ $frameset->addFrame($frame2, 'B');
+ $frameset->setFrameFocus('A');
+ $this->assertIdentical($frameset->getField(new SimpleByName('a')), 'f');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/http_test.php b/tests/simpletest/test/http_test.php
new file mode 100644
index 0000000..bd3fdd0
--- /dev/null
+++ b/tests/simpletest/test/http_test.php
@@ -0,0 +1,492 @@
+expectAt(0, 'write', array("GET /here.html HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n"));
+ $socket->expectAt(2, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 3);
+ $route = new PartialSimpleRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(new SimpleUrl('http://a.valid.host/here.html'));
+ $this->assertSame($route->createConnection('GET', 15), $socket);
+ }
+
+ function testDefaultPostRequest() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("POST /here.html HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n"));
+ $socket->expectAt(2, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 3);
+ $route = new PartialSimpleRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(new SimpleUrl('http://a.valid.host/here.html'));
+
+ $route->createConnection('POST', 15);
+ }
+
+ function testDefaultDeleteRequest() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("DELETE /here.html HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n"));
+ $socket->expectAt(2, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 3);
+ $route = new PartialSimpleRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(new SimpleUrl('http://a.valid.host/here.html'));
+ $this->assertSame($route->createConnection('DELETE', 15), $socket);
+ }
+
+ function testDefaultHeadRequest() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("HEAD /here.html HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n"));
+ $socket->expectAt(2, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 3);
+ $route = new PartialSimpleRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(new SimpleUrl('http://a.valid.host/here.html'));
+ $this->assertSame($route->createConnection('HEAD', 15), $socket);
+ }
+
+ function testGetWithPort() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("GET /here.html HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: a.valid.host:81\r\n"));
+ $socket->expectAt(2, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 3);
+
+ $route = new PartialSimpleRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(new SimpleUrl('http://a.valid.host:81/here.html'));
+
+ $route->createConnection('GET', 15);
+ }
+
+ function testGetWithParameters() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("GET /here.html?a=1&b=2 HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: a.valid.host\r\n"));
+ $socket->expectAt(2, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 3);
+
+ $route = new PartialSimpleRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(new SimpleUrl('http://a.valid.host/here.html?a=1&b=2'));
+
+ $route->createConnection('GET', 15);
+ }
+}
+
+class TestOfProxyRoute extends UnitTestCase {
+
+ function testDefaultGet() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("GET http://a.valid.host/here.html HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n"));
+ $socket->expectAt(2, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 3);
+
+ $route = new PartialSimpleProxyRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(
+ new SimpleUrl('http://a.valid.host/here.html'),
+ new SimpleUrl('http://my-proxy'));
+ $route->createConnection('GET', 15);
+ }
+
+ function testDefaultPost() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("POST http://a.valid.host/here.html HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n"));
+ $socket->expectAt(2, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 3);
+
+ $route = new PartialSimpleProxyRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(
+ new SimpleUrl('http://a.valid.host/here.html'),
+ new SimpleUrl('http://my-proxy'));
+ $route->createConnection('POST', 15);
+ }
+
+ function testGetWithPort() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("GET http://a.valid.host:81/here.html HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: my-proxy:8081\r\n"));
+ $socket->expectAt(2, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 3);
+
+ $route = new PartialSimpleProxyRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(
+ new SimpleUrl('http://a.valid.host:81/here.html'),
+ new SimpleUrl('http://my-proxy:8081'));
+ $route->createConnection('GET', 15);
+ }
+
+ function testGetWithParameters() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("GET http://a.valid.host/here.html?a=1&b=2 HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n"));
+ $socket->expectAt(2, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 3);
+
+ $route = new PartialSimpleProxyRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(
+ new SimpleUrl('http://a.valid.host/here.html?a=1&b=2'),
+ new SimpleUrl('http://my-proxy'));
+ $route->createConnection('GET', 15);
+ }
+
+ function testGetWithAuthentication() {
+ $encoded = base64_encode('Me:Secret');
+
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("GET http://a.valid.host/here.html HTTP/1.0\r\n"));
+ $socket->expectAt(1, 'write', array("Host: my-proxy:8080\r\n"));
+ $socket->expectAt(2, 'write', array("Proxy-Authorization: Basic $encoded\r\n"));
+ $socket->expectAt(3, 'write', array("Connection: close\r\n"));
+ $socket->expectCallCount('write', 4);
+
+ $route = new PartialSimpleProxyRoute();
+ $route->setReturnReference('createSocket', $socket);
+ $route->__construct(
+ new SimpleUrl('http://a.valid.host/here.html'),
+ new SimpleUrl('http://my-proxy'),
+ 'Me',
+ 'Secret');
+ $route->createConnection('GET', 15);
+ }
+}
+
+class TestOfHttpRequest extends UnitTestCase {
+
+ function testReadingBadConnection() {
+ $socket = new MockSimpleSocket();
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+ $request = new SimpleHttpRequest($route, new SimpleGetEncoding());
+ $reponse = $request->fetch(15);
+ $this->assertTrue($reponse->isError());
+ }
+
+ function testReadingGoodConnection() {
+ $socket = new MockSimpleSocket();
+ $socket->expectOnce('write', array("\r\n"));
+
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+ $route->expect('createConnection', array('GET', 15));
+
+ $request = new SimpleHttpRequest($route, new SimpleGetEncoding());
+ $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
+ }
+
+ function testWritingAdditionalHeaders() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("My: stuff\r\n"));
+ $socket->expectAt(1, 'write', array("\r\n"));
+ $socket->expectCallCount('write', 2);
+
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+
+ $request = new SimpleHttpRequest($route, new SimpleGetEncoding());
+ $request->addHeaderLine('My: stuff');
+ $request->fetch(15);
+ }
+
+ function testCookieWriting() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("Cookie: a=A\r\n"));
+ $socket->expectAt(1, 'write', array("\r\n"));
+ $socket->expectCallCount('write', 2);
+
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'A');
+
+ $request = new SimpleHttpRequest($route, new SimpleGetEncoding());
+ $request->readCookiesFromJar($jar, new SimpleUrl('/'));
+ $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
+ }
+
+ function testMultipleCookieWriting() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("Cookie: a=A;b=B\r\n"));
+
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'A');
+ $jar->setCookie('b', 'B');
+
+ $request = new SimpleHttpRequest($route, new SimpleGetEncoding());
+ $request->readCookiesFromJar($jar, new SimpleUrl('/'));
+ $request->fetch(15);
+ }
+
+ function testReadingDeleteConnection() {
+ $socket = new MockSimpleSocket();
+
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+ $route->expect('createConnection', array('DELETE', 15));
+
+ $request = new SimpleHttpRequest($route, new SimpleDeleteEncoding());
+ $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
+ }
+}
+
+class TestOfHttpPostRequest extends UnitTestCase {
+
+ function testReadingBadConnectionCausesErrorBecauseOfDeadSocket() {
+ $socket = new MockSimpleSocket();
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+ $request = new SimpleHttpRequest($route, new SimplePostEncoding());
+ $reponse = $request->fetch(15);
+ $this->assertTrue($reponse->isError());
+ }
+
+ function testReadingGoodConnection() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("Content-Length: 0\r\n"));
+ $socket->expectAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n"));
+ $socket->expectAt(2, 'write', array("\r\n"));
+ $socket->expectAt(3, 'write', array(""));
+
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+ $route->expect('createConnection', array('POST', 15));
+
+ $request = new SimpleHttpRequest($route, new SimplePostEncoding());
+ $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
+ }
+
+ function testContentHeadersCalculatedWithUrlEncodedParams() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("Content-Length: 3\r\n"));
+ $socket->expectAt(1, 'write', array("Content-Type: application/x-www-form-urlencoded\r\n"));
+ $socket->expectAt(2, 'write', array("\r\n"));
+ $socket->expectAt(3, 'write', array("a=A"));
+
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+ $route->expect('createConnection', array('POST', 15));
+
+ $request = new SimpleHttpRequest(
+ $route,
+ new SimplePostEncoding(array('a' => 'A')));
+ $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
+ }
+
+ function testContentHeadersCalculatedWithRawEntityBody() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("Content-Length: 8\r\n"));
+ $socket->expectAt(1, 'write', array("Content-Type: text/plain\r\n"));
+ $socket->expectAt(2, 'write', array("\r\n"));
+ $socket->expectAt(3, 'write', array("raw body"));
+
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+ $route->expect('createConnection', array('POST', 15));
+
+ $request = new SimpleHttpRequest(
+ $route,
+ new SimplePostEncoding('raw body'));
+ $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
+ }
+
+ function testContentHeadersCalculatedWithXmlEntityBody() {
+ $socket = new MockSimpleSocket();
+ $socket->expectAt(0, 'write', array("Content-Length: 27\r\n"));
+ $socket->expectAt(1, 'write', array("Content-Type: text/xml\r\n"));
+ $socket->expectAt(2, 'write', array("\r\n"));
+ $socket->expectAt(3, 'write', array("onetwo"));
+
+ $route = new MockSimpleRoute();
+ $route->setReturnReference('createConnection', $socket);
+ $route->expect('createConnection', array('POST', 15));
+
+ $request = new SimpleHttpRequest(
+ $route,
+ new SimplePostEncoding('onetwo', 'text/xml'));
+ $this->assertIsA($request->fetch(15), 'SimpleHttpResponse');
+ }
+}
+
+class TestOfHttpHeaders extends UnitTestCase {
+
+ function testParseBasicHeaders() {
+ $headers = new SimpleHttpHeaders(
+ "HTTP/1.1 200 OK\r\n" .
+ "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n" .
+ "Content-Type: text/plain\r\n" .
+ "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\n" .
+ "Connection: close");
+ $this->assertIdentical($headers->getHttpVersion(), "1.1");
+ $this->assertIdentical($headers->getResponseCode(), 200);
+ $this->assertEqual($headers->getMimeType(), "text/plain");
+ }
+
+ function testNonStandardResponseHeader() {
+ $headers = new SimpleHttpHeaders(
+ "HTTP/1.1 302 (HTTP-Version SP Status-Code CRLF)\r\n" .
+ "Connection: close");
+ $this->assertIdentical($headers->getResponseCode(), 302);
+ }
+
+ function testCanParseMultipleCookies() {
+ $jar = new MockSimpleCookieJar();
+ $jar->expectAt(0, 'setCookie', array('a', 'aaa', 'host', '/here/', 'Wed, 25 Dec 2002 04:24:20 GMT'));
+ $jar->expectAt(1, 'setCookie', array('b', 'bbb', 'host', '/', false));
+
+ $headers = new SimpleHttpHeaders(
+ "HTTP/1.1 200 OK\r\n" .
+ "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n" .
+ "Content-Type: text/plain\r\n" .
+ "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\n" .
+ "Set-Cookie: a=aaa; expires=Wed, 25-Dec-02 04:24:20 GMT; path=/here/\r\n" .
+ "Set-Cookie: b=bbb\r\n" .
+ "Connection: close");
+ $headers->writeCookiesToJar($jar, new SimpleUrl('http://host'));
+ }
+
+ function testCanRecogniseRedirect() {
+ $headers = new SimpleHttpHeaders("HTTP/1.1 301 OK\r\n" .
+ "Content-Type: text/plain\r\n" .
+ "Content-Length: 0\r\n" .
+ "Location: http://www.somewhere-else.com/\r\n" .
+ "Connection: close");
+ $this->assertIdentical($headers->getResponseCode(), 301);
+ $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com/");
+ $this->assertTrue($headers->isRedirect());
+ }
+
+ function testCanParseChallenge() {
+ $headers = new SimpleHttpHeaders("HTTP/1.1 401 Authorization required\r\n" .
+ "Content-Type: text/plain\r\n" .
+ "Connection: close\r\n" .
+ "WWW-Authenticate: Basic realm=\"Somewhere\"");
+ $this->assertEqual($headers->getAuthentication(), 'Basic');
+ $this->assertEqual($headers->getRealm(), 'Somewhere');
+ $this->assertTrue($headers->isChallenge());
+ }
+}
+
+class TestOfHttpResponse extends UnitTestCase {
+
+ function testBadRequest() {
+ $socket = new MockSimpleSocket();
+ $socket->setReturnValue('getSent', '');
+
+ $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
+ $this->assertTrue($response->isError());
+ $this->assertPattern('/Nothing fetched/', $response->getError());
+ $this->assertIdentical($response->getContent(), false);
+ $this->assertIdentical($response->getSent(), '');
+ }
+
+ function testBadSocketDuringResponse() {
+ $socket = new MockSimpleSocket();
+ $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\n");
+ $socket->setReturnValueAt(1, "read", "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n");
+ $socket->setReturnValue("read", "");
+ $socket->setReturnValue('getSent', 'HTTP/1.1 ...');
+
+ $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
+ $this->assertTrue($response->isError());
+ $this->assertEqual($response->getContent(), '');
+ $this->assertEqual($response->getSent(), 'HTTP/1.1 ...');
+ }
+
+ function testIncompleteHeader() {
+ $socket = new MockSimpleSocket();
+ $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\n");
+ $socket->setReturnValueAt(1, "read", "Date: Mon, 18 Nov 2002 15:50:29 GMT\r\n");
+ $socket->setReturnValueAt(2, "read", "Content-Type: text/plain\r\n");
+ $socket->setReturnValue("read", "");
+
+ $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
+ $this->assertTrue($response->isError());
+ $this->assertEqual($response->getContent(), "");
+ }
+
+ function testParseOfResponseHeadersWhenChunked() {
+ $socket = new MockSimpleSocket();
+ $socket->setReturnValueAt(0, "read", "HTTP/1.1 200 OK\r\nDate: Mon, 18 Nov 2002 15:50:29 GMT\r\n");
+ $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n");
+ $socket->setReturnValueAt(2, "read", "Server: Apache/1.3.24 (Win32) PHP/4.2.3\r\nConne");
+ $socket->setReturnValueAt(3, "read", "ction: close\r\n\r\nthis is a test file\n");
+ $socket->setReturnValueAt(4, "read", "with two lines in it\n");
+ $socket->setReturnValue("read", "");
+
+ $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
+ $this->assertFalse($response->isError());
+ $this->assertEqual(
+ $response->getContent(),
+ "this is a test file\nwith two lines in it\n");
+ $headers = $response->getHeaders();
+ $this->assertIdentical($headers->getHttpVersion(), "1.1");
+ $this->assertIdentical($headers->getResponseCode(), 200);
+ $this->assertEqual($headers->getMimeType(), "text/plain");
+ $this->assertFalse($headers->isRedirect());
+ $this->assertFalse($headers->getLocation());
+ }
+
+ function testRedirect() {
+ $socket = new MockSimpleSocket();
+ $socket->setReturnValueAt(0, "read", "HTTP/1.1 301 OK\r\n");
+ $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n");
+ $socket->setReturnValueAt(2, "read", "Location: http://www.somewhere-else.com/\r\n");
+ $socket->setReturnValueAt(3, "read", "Connection: close\r\n");
+ $socket->setReturnValueAt(4, "read", "\r\n");
+ $socket->setReturnValue("read", "");
+
+ $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
+ $headers = $response->getHeaders();
+ $this->assertTrue($headers->isRedirect());
+ $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com/");
+ }
+
+ function testRedirectWithPort() {
+ $socket = new MockSimpleSocket();
+ $socket->setReturnValueAt(0, "read", "HTTP/1.1 301 OK\r\n");
+ $socket->setReturnValueAt(1, "read", "Content-Type: text/plain\r\n");
+ $socket->setReturnValueAt(2, "read", "Location: http://www.somewhere-else.com:80/\r\n");
+ $socket->setReturnValueAt(3, "read", "Connection: close\r\n");
+ $socket->setReturnValueAt(4, "read", "\r\n");
+ $socket->setReturnValue("read", "");
+
+ $response = new SimpleHttpResponse($socket, new SimpleUrl('here'), new SimpleGetEncoding());
+ $headers = $response->getHeaders();
+ $this->assertTrue($headers->isRedirect());
+ $this->assertEqual($headers->getLocation(), "http://www.somewhere-else.com:80/");
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/interfaces_test.php b/tests/simpletest/test/interfaces_test.php
new file mode 100644
index 0000000..ab30fe4
--- /dev/null
+++ b/tests/simpletest/test/interfaces_test.php
@@ -0,0 +1,137 @@
+=')) {
+ include(dirname(__FILE__) . '/interfaces_test_php5_1.php');
+}
+
+interface DummyInterface {
+ function aMethod();
+ function anotherMethod($a);
+ function &referenceMethod(&$a);
+}
+
+Mock::generate('DummyInterface');
+Mock::generatePartial('DummyInterface', 'PartialDummyInterface', array());
+
+class TestOfMockInterfaces extends UnitTestCase {
+
+ function testCanMockAnInterface() {
+ $mock = new MockDummyInterface();
+ $this->assertIsA($mock, 'SimpleMock');
+ $this->assertIsA($mock, 'MockDummyInterface');
+ $this->assertTrue(method_exists($mock, 'aMethod'));
+ $this->assertTrue(method_exists($mock, 'anotherMethod'));
+ $this->assertNull($mock->aMethod());
+ }
+
+ function testMockedInterfaceExpectsParameters() {
+ $mock = new MockDummyInterface();
+ $this->expectError();
+ $mock->anotherMethod();
+ }
+
+ function testCannotPartiallyMockAnInterface() {
+ $this->assertFalse(class_exists('PartialDummyInterface'));
+ }
+}
+
+class TestOfSpl extends UnitTestCase {
+
+ function skip() {
+ $this->skipUnless(function_exists('spl_classes'), 'No SPL module loaded');
+ }
+
+ function testCanMockAllSplClasses() {
+ if (! function_exists('spl_classes')) {
+ return;
+ }
+ foreach(spl_classes() as $class) {
+ if ($class == 'SplHeap' or $class = 'SplFileObject') {
+ continue;
+ }
+ if (version_compare(PHP_VERSION, '5.1', '<') &&
+ $class == 'CachingIterator' ||
+ $class == 'CachingRecursiveIterator' ||
+ $class == 'FilterIterator' ||
+ $class == 'LimitIterator' ||
+ $class == 'ParentIterator') {
+ // These iterators require an iterator be passed to them during
+ // construction in PHP 5.0; there is no way for SimpleTest
+ // to supply such an iterator, however, so support for it is
+ // disabled.
+ continue;
+ }
+ $mock_class = "Mock$class";
+ Mock::generate($class);
+ $this->assertIsA(new $mock_class(), $mock_class);
+ }
+ }
+
+ function testExtensionOfCommonSplClasses() {
+ Mock::generate('IteratorImplementation');
+ $this->assertIsA(
+ new IteratorImplementation(),
+ 'IteratorImplementation');
+ Mock::generate('IteratorAggregateImplementation');
+ $this->assertIsA(
+ new IteratorAggregateImplementation(),
+ 'IteratorAggregateImplementation');
+ }
+}
+
+class WithHint {
+ function hinted(DummyInterface $object) { }
+}
+
+class ImplementsDummy implements DummyInterface {
+ function aMethod() { }
+ function anotherMethod($a) { }
+ function &referenceMethod(&$a) { }
+ function extraMethod($a = false) { }
+}
+Mock::generate('ImplementsDummy');
+
+class TestOfImplementations extends UnitTestCase {
+
+ function testMockedInterfaceCanPassThroughTypeHint() {
+ $mock = new MockDummyInterface();
+ $hinter = new WithHint();
+ $hinter->hinted($mock);
+ }
+
+ function testImplementedInterfacesAreCarried() {
+ $mock = new MockImplementsDummy();
+ $hinter = new WithHint();
+ $hinter->hinted($mock);
+ }
+
+ function testNoSpuriousWarningsWhenSkippingDefaultedParameter() {
+ $mock = new MockImplementsDummy();
+ $mock->extraMethod();
+ }
+}
+
+interface SampleInterfaceWithConstruct {
+ function __construct($something);
+}
+
+class TestOfInterfaceMocksWithConstruct extends UnitTestCase {
+ function TODO_testBasicConstructOfAnInterface() { // Fails in PHP 5.3dev
+ Mock::generate('SampleInterfaceWithConstruct');
+ }
+}
+
+interface SampleInterfaceWithClone {
+ function __clone();
+}
+
+class TestOfSampleInterfaceWithClone extends UnitTestCase {
+ function testCanMockWithoutErrors() {
+ Mock::generate('SampleInterfaceWithClone');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/interfaces_test_php5_1.php b/tests/simpletest/test/interfaces_test_php5_1.php
new file mode 100644
index 0000000..3d154f9
--- /dev/null
+++ b/tests/simpletest/test/interfaces_test_php5_1.php
@@ -0,0 +1,14 @@
+assertIsA($mock, 'SampleInterfaceWithHintInSignature');
+ }
+}
+
diff --git a/tests/simpletest/test/live_test.php b/tests/simpletest/test/live_test.php
new file mode 100644
index 0000000..3fbb544
--- /dev/null
+++ b/tests/simpletest/test/live_test.php
@@ -0,0 +1,47 @@
+assertTrue($socket->isError());
+ $this->assertPattern(
+ '/Cannot open \\[bad_url:111\\] with \\[/',
+ $socket->getError());
+ $this->assertFalse($socket->isOpen());
+ $this->assertFalse($socket->write('A message'));
+ }
+
+ function testSocketClosure() {
+ $socket = new SimpleSocket('www.lastcraft.com', 80, 15, 8);
+ $this->assertTrue($socket->isOpen());
+ $this->assertTrue($socket->write("GET /test/network_confirm.php HTTP/1.0\r\n"));
+ $socket->write("Host: www.lastcraft.com\r\n");
+ $socket->write("Connection: close\r\n\r\n");
+ $this->assertEqual($socket->read(), "HTTP/1.1");
+ $socket->close();
+ $this->assertIdentical($socket->read(), false);
+ }
+
+ function testRecordOfSentCharacters() {
+ $socket = new SimpleSocket('www.lastcraft.com', 80, 15);
+ $this->assertTrue($socket->write("GET /test/network_confirm.php HTTP/1.0\r\n"));
+ $socket->write("Host: www.lastcraft.com\r\n");
+ $socket->write("Connection: close\r\n\r\n");
+ $socket->close();
+ $this->assertEqual($socket->getSent(),
+ "GET /test/network_confirm.php HTTP/1.0\r\n" .
+ "Host: www.lastcraft.com\r\n" .
+ "Connection: close\r\n\r\n");
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/mock_objects_test.php b/tests/simpletest/test/mock_objects_test.php
new file mode 100644
index 0000000..7f31789
--- /dev/null
+++ b/tests/simpletest/test/mock_objects_test.php
@@ -0,0 +1,985 @@
+assertTrue($expectation->test(33));
+ $this->assertTrue($expectation->test(false));
+ $this->assertTrue($expectation->test(null));
+ }
+}
+
+class TestOfParametersExpectation extends UnitTestCase {
+
+ function testEmptyMatch() {
+ $expectation = new ParametersExpectation(array());
+ $this->assertTrue($expectation->test(array()));
+ $this->assertFalse($expectation->test(array(33)));
+ }
+
+ function testSingleMatch() {
+ $expectation = new ParametersExpectation(array(0));
+ $this->assertFalse($expectation->test(array(1)));
+ $this->assertTrue($expectation->test(array(0)));
+ }
+
+ function testAnyMatch() {
+ $expectation = new ParametersExpectation(false);
+ $this->assertTrue($expectation->test(array()));
+ $this->assertTrue($expectation->test(array(1, 2)));
+ }
+
+ function testMissingParameter() {
+ $expectation = new ParametersExpectation(array(0));
+ $this->assertFalse($expectation->test(array()));
+ }
+
+ function testNullParameter() {
+ $expectation = new ParametersExpectation(array(null));
+ $this->assertTrue($expectation->test(array(null)));
+ $this->assertFalse($expectation->test(array()));
+ }
+
+ function testAnythingExpectations() {
+ $expectation = new ParametersExpectation(array(new AnythingExpectation()));
+ $this->assertFalse($expectation->test(array()));
+ $this->assertIdentical($expectation->test(array(null)), true);
+ $this->assertIdentical($expectation->test(array(13)), true);
+ }
+
+ function testOtherExpectations() {
+ $expectation = new ParametersExpectation(
+ array(new PatternExpectation('/hello/i')));
+ $this->assertFalse($expectation->test(array('Goodbye')));
+ $this->assertTrue($expectation->test(array('hello')));
+ $this->assertTrue($expectation->test(array('Hello')));
+ }
+
+ function testIdentityOnly() {
+ $expectation = new ParametersExpectation(array("0"));
+ $this->assertFalse($expectation->test(array(0)));
+ $this->assertTrue($expectation->test(array("0")));
+ }
+
+ function testLongList() {
+ $expectation = new ParametersExpectation(
+ array("0", 0, new AnythingExpectation(), false));
+ $this->assertTrue($expectation->test(array("0", 0, 37, false)));
+ $this->assertFalse($expectation->test(array("0", 0, 37, true)));
+ $this->assertFalse($expectation->test(array("0", 0, 37)));
+ }
+}
+
+class TestOfSimpleSignatureMap extends UnitTestCase {
+
+ function testEmpty() {
+ $map = new SimpleSignatureMap();
+ $this->assertFalse($map->isMatch("any", array()));
+ $this->assertNull($map->findFirstAction("any", array()));
+ }
+
+ function testDifferentCallSignaturesCanHaveDifferentReferences() {
+ $map = new SimpleSignatureMap();
+ $fred = 'Fred';
+ $jim = 'jim';
+ $map->add(array(0), $fred);
+ $map->add(array('0'), $jim);
+ $this->assertSame($fred, $map->findFirstAction(array(0)));
+ $this->assertSame($jim, $map->findFirstAction(array('0')));
+ }
+
+ function testWildcard() {
+ $fred = 'Fred';
+ $map = new SimpleSignatureMap();
+ $map->add(array(new AnythingExpectation(), 1, 3), $fred);
+ $this->assertTrue($map->isMatch(array(2, 1, 3)));
+ $this->assertSame($map->findFirstAction(array(2, 1, 3)), $fred);
+ }
+
+ function testAllWildcard() {
+ $fred = 'Fred';
+ $map = new SimpleSignatureMap();
+ $this->assertFalse($map->isMatch(array(2, 1, 3)));
+ $map->add('', $fred);
+ $this->assertTrue($map->isMatch(array(2, 1, 3)));
+ $this->assertSame($map->findFirstAction(array(2, 1, 3)), $fred);
+ }
+
+ function testOrdering() {
+ $map = new SimpleSignatureMap();
+ $map->add(array(1, 2), new SimpleByValue("1, 2"));
+ $map->add(array(1, 3), new SimpleByValue("1, 3"));
+ $map->add(array(1), new SimpleByValue("1"));
+ $map->add(array(1, 4), new SimpleByValue("1, 4"));
+ $map->add(array(new AnythingExpectation()), new SimpleByValue("Any"));
+ $map->add(array(2), new SimpleByValue("2"));
+ $map->add("", new SimpleByValue("Default"));
+ $map->add(array(), new SimpleByValue("None"));
+ $this->assertEqual($map->findFirstAction(array(1, 2)), new SimpleByValue("1, 2"));
+ $this->assertEqual($map->findFirstAction(array(1, 3)), new SimpleByValue("1, 3"));
+ $this->assertEqual($map->findFirstAction(array(1, 4)), new SimpleByValue("1, 4"));
+ $this->assertEqual($map->findFirstAction(array(1)), new SimpleByValue("1"));
+ $this->assertEqual($map->findFirstAction(array(2)), new SimpleByValue("Any"));
+ $this->assertEqual($map->findFirstAction(array(3)), new SimpleByValue("Any"));
+ $this->assertEqual($map->findFirstAction(array()), new SimpleByValue("Default"));
+ }
+}
+
+class TestOfCallSchedule extends UnitTestCase {
+ function testCanBeSetToAlwaysReturnTheSameReference() {
+ $a = 5;
+ $schedule = new SimpleCallSchedule();
+ $schedule->register('aMethod', false, new SimpleByReference($a));
+ $this->assertReference($schedule->respond(0, 'aMethod', array()), $a);
+ $this->assertReference($schedule->respond(1, 'aMethod', array()), $a);
+ }
+
+ function testSpecificSignaturesOverrideTheAlwaysCase() {
+ $any = 'any';
+ $one = 'two';
+ $schedule = new SimpleCallSchedule();
+ $schedule->register('aMethod', array(1), new SimpleByReference($one));
+ $schedule->register('aMethod', false, new SimpleByReference($any));
+ $this->assertReference($schedule->respond(0, 'aMethod', array(2)), $any);
+ $this->assertReference($schedule->respond(0, 'aMethod', array(1)), $one);
+ }
+
+ function testReturnsCanBeSetOverTime() {
+ $one = 'one';
+ $two = 'two';
+ $schedule = new SimpleCallSchedule();
+ $schedule->registerAt(0, 'aMethod', false, new SimpleByReference($one));
+ $schedule->registerAt(1, 'aMethod', false, new SimpleByReference($two));
+ $this->assertReference($schedule->respond(0, 'aMethod', array()), $one);
+ $this->assertReference($schedule->respond(1, 'aMethod', array()), $two);
+ }
+
+ function testReturnsOverTimecanBeAlteredByTheArguments() {
+ $one = '1';
+ $two = '2';
+ $two_a = '2a';
+ $schedule = new SimpleCallSchedule();
+ $schedule->registerAt(0, 'aMethod', false, new SimpleByReference($one));
+ $schedule->registerAt(1, 'aMethod', array('a'), new SimpleByReference($two_a));
+ $schedule->registerAt(1, 'aMethod', false, new SimpleByReference($two));
+ $this->assertReference($schedule->respond(0, 'aMethod', array()), $one);
+ $this->assertReference($schedule->respond(1, 'aMethod', array()), $two);
+ $this->assertReference($schedule->respond(1, 'aMethod', array('a')), $two_a);
+ }
+
+ function testCanReturnByValue() {
+ $a = 5;
+ $schedule = new SimpleCallSchedule();
+ $schedule->register('aMethod', false, new SimpleByValue($a));
+ $this->assertCopy($schedule->respond(0, 'aMethod', array()), $a);
+ }
+
+ function testCanThrowException() {
+ if (version_compare(phpversion(), '5', '>=')) {
+ $schedule = new SimpleCallSchedule();
+ $schedule->register('aMethod', false, new SimpleThrower(new Exception('Ouch')));
+ $this->expectException(new Exception('Ouch'));
+ $schedule->respond(0, 'aMethod', array());
+ }
+ }
+
+ function testCanEmitError() {
+ $schedule = new SimpleCallSchedule();
+ $schedule->register('aMethod', false, new SimpleErrorThrower('Ouch', E_USER_WARNING));
+ $this->expectError('Ouch');
+ $schedule->respond(0, 'aMethod', array());
+ }
+}
+
+class Dummy {
+ function Dummy() {
+ }
+
+ function aMethod() {
+ return true;
+ }
+
+ function &aReferenceMethod() {
+ return true;
+ }
+
+ function anotherMethod() {
+ return true;
+ }
+}
+Mock::generate('Dummy');
+Mock::generate('Dummy', 'AnotherMockDummy');
+Mock::generate('Dummy', 'MockDummyWithExtraMethods', array('extraMethod'));
+
+class TestOfMockGeneration extends UnitTestCase {
+
+ function testCloning() {
+ $mock = new MockDummy();
+ $this->assertTrue(method_exists($mock, "aMethod"));
+ $this->assertNull($mock->aMethod());
+ }
+
+ function testCloningWithExtraMethod() {
+ $mock = new MockDummyWithExtraMethods();
+ $this->assertTrue(method_exists($mock, "extraMethod"));
+ }
+
+ function testCloningWithChosenClassName() {
+ $mock = new AnotherMockDummy();
+ $this->assertTrue(method_exists($mock, "aMethod"));
+ }
+}
+
+class TestOfMockReturns extends UnitTestCase {
+
+ function testDefaultReturn() {
+ $mock = new MockDummy();
+ $mock->returnsByValue("aMethod", "aaa");
+ $this->assertIdentical($mock->aMethod(), "aaa");
+ $this->assertIdentical($mock->aMethod(), "aaa");
+ }
+
+ function testParameteredReturn() {
+ $mock = new MockDummy();
+ $mock->returnsByValue('aMethod', 'aaa', array(1, 2, 3));
+ $this->assertNull($mock->aMethod());
+ $this->assertIdentical($mock->aMethod(1, 2, 3), 'aaa');
+ }
+
+ function testSetReturnGivesObjectReference() {
+ $mock = new MockDummy();
+ $object = new Dummy();
+ $mock->returns('aMethod', $object, array(1, 2, 3));
+ $this->assertSame($mock->aMethod(1, 2, 3), $object);
+ }
+
+ function testSetReturnReferenceGivesOriginalReference() {
+ $mock = new MockDummy();
+ $object = 1;
+ $mock->returnsByReference('aReferenceMethod', $object, array(1, 2, 3));
+ $this->assertReference($mock->aReferenceMethod(1, 2, 3), $object);
+ }
+
+ function testReturnValueCanBeChosenJustByPatternMatchingArguments() {
+ $mock = new MockDummy();
+ $mock->returnsByValue(
+ "aMethod",
+ "aaa",
+ array(new PatternExpectation('/hello/i')));
+ $this->assertIdentical($mock->aMethod('Hello'), 'aaa');
+ $this->assertNull($mock->aMethod('Goodbye'));
+ }
+
+ function testMultipleMethods() {
+ $mock = new MockDummy();
+ $mock->returnsByValue("aMethod", 100, array(1));
+ $mock->returnsByValue("aMethod", 200, array(2));
+ $mock->returnsByValue("anotherMethod", 10, array(1));
+ $mock->returnsByValue("anotherMethod", 20, array(2));
+ $this->assertIdentical($mock->aMethod(1), 100);
+ $this->assertIdentical($mock->anotherMethod(1), 10);
+ $this->assertIdentical($mock->aMethod(2), 200);
+ $this->assertIdentical($mock->anotherMethod(2), 20);
+ }
+
+ function testReturnSequence() {
+ $mock = new MockDummy();
+ $mock->returnsByValueAt(0, "aMethod", "aaa");
+ $mock->returnsByValueAt(1, "aMethod", "bbb");
+ $mock->returnsByValueAt(3, "aMethod", "ddd");
+ $this->assertIdentical($mock->aMethod(), "aaa");
+ $this->assertIdentical($mock->aMethod(), "bbb");
+ $this->assertNull($mock->aMethod());
+ $this->assertIdentical($mock->aMethod(), "ddd");
+ }
+
+ function testSetReturnReferenceAtGivesOriginal() {
+ $mock = new MockDummy();
+ $object = 100;
+ $mock->returnsByReferenceAt(1, "aReferenceMethod", $object);
+ $this->assertNull($mock->aReferenceMethod());
+ $this->assertReference($mock->aReferenceMethod(), $object);
+ $this->assertNull($mock->aReferenceMethod());
+ }
+
+ function testReturnsAtGivesOriginalObjectHandle() {
+ $mock = new MockDummy();
+ $object = new Dummy();
+ $mock->returnsAt(1, "aMethod", $object);
+ $this->assertNull($mock->aMethod());
+ $this->assertSame($mock->aMethod(), $object);
+ $this->assertNull($mock->aMethod());
+ }
+
+ function testComplicatedReturnSequence() {
+ $mock = new MockDummy();
+ $object = new Dummy();
+ $mock->returnsAt(1, "aMethod", "aaa", array("a"));
+ $mock->returnsAt(1, "aMethod", "bbb");
+ $mock->returnsAt(2, "aMethod", $object, array('*', 2));
+ $mock->returnsAt(2, "aMethod", "value", array('*', 3));
+ $mock->returns("aMethod", 3, array(3));
+ $this->assertNull($mock->aMethod());
+ $this->assertEqual($mock->aMethod("a"), "aaa");
+ $this->assertSame($mock->aMethod(1, 2), $object);
+ $this->assertEqual($mock->aMethod(3), 3);
+ $this->assertNull($mock->aMethod());
+ }
+
+ function testMultipleMethodSequences() {
+ $mock = new MockDummy();
+ $mock->returnsByValueAt(0, "aMethod", "aaa");
+ $mock->returnsByValueAt(1, "aMethod", "bbb");
+ $mock->returnsByValueAt(0, "anotherMethod", "ccc");
+ $mock->returnsByValueAt(1, "anotherMethod", "ddd");
+ $this->assertIdentical($mock->aMethod(), "aaa");
+ $this->assertIdentical($mock->anotherMethod(), "ccc");
+ $this->assertIdentical($mock->aMethod(), "bbb");
+ $this->assertIdentical($mock->anotherMethod(), "ddd");
+ }
+
+ function testSequenceFallback() {
+ $mock = new MockDummy();
+ $mock->returnsByValueAt(0, "aMethod", "aaa", array('a'));
+ $mock->returnsByValueAt(1, "aMethod", "bbb", array('a'));
+ $mock->returnsByValue("aMethod", "AAA");
+ $this->assertIdentical($mock->aMethod('a'), "aaa");
+ $this->assertIdentical($mock->aMethod('b'), "AAA");
+ }
+
+ function testMethodInterference() {
+ $mock = new MockDummy();
+ $mock->returnsByValueAt(0, "anotherMethod", "aaa");
+ $mock->returnsByValue("aMethod", "AAA");
+ $this->assertIdentical($mock->aMethod(), "AAA");
+ $this->assertIdentical($mock->anotherMethod(), "aaa");
+ }
+}
+
+class TestOfMockExpectationsThatPass extends UnitTestCase {
+
+ function testAnyArgument() {
+ $mock = new MockDummy();
+ $mock->expect('aMethod', array('*'));
+ $mock->aMethod(1);
+ $mock->aMethod('hello');
+ }
+
+ function testAnyTwoArguments() {
+ $mock = new MockDummy();
+ $mock->expect('aMethod', array('*', '*'));
+ $mock->aMethod(1, 2);
+ }
+
+ function testSpecificArgument() {
+ $mock = new MockDummy();
+ $mock->expect('aMethod', array(1));
+ $mock->aMethod(1);
+ }
+
+ function testExpectation() {
+ $mock = new MockDummy();
+ $mock->expect('aMethod', array(new IsAExpectation('Dummy')));
+ $mock->aMethod(new Dummy());
+ }
+
+ function testArgumentsInSequence() {
+ $mock = new MockDummy();
+ $mock->expectAt(0, 'aMethod', array(1, 2));
+ $mock->expectAt(1, 'aMethod', array(3, 4));
+ $mock->aMethod(1, 2);
+ $mock->aMethod(3, 4);
+ }
+
+ function testAtLeastOnceSatisfiedByOneCall() {
+ $mock = new MockDummy();
+ $mock->expectAtLeastOnce('aMethod');
+ $mock->aMethod();
+ }
+
+ function testAtLeastOnceSatisfiedByTwoCalls() {
+ $mock = new MockDummy();
+ $mock->expectAtLeastOnce('aMethod');
+ $mock->aMethod();
+ $mock->aMethod();
+ }
+
+ function testOnceSatisfiedByOneCall() {
+ $mock = new MockDummy();
+ $mock->expectOnce('aMethod');
+ $mock->aMethod();
+ }
+
+ function testMinimumCallsSatisfiedByEnoughCalls() {
+ $mock = new MockDummy();
+ $mock->expectMinimumCallCount('aMethod', 1);
+ $mock->aMethod();
+ }
+
+ function testMinimumCallsSatisfiedByTooManyCalls() {
+ $mock = new MockDummy();
+ $mock->expectMinimumCallCount('aMethod', 3);
+ $mock->aMethod();
+ $mock->aMethod();
+ $mock->aMethod();
+ $mock->aMethod();
+ }
+
+ function testMaximumCallsSatisfiedByEnoughCalls() {
+ $mock = new MockDummy();
+ $mock->expectMaximumCallCount('aMethod', 1);
+ $mock->aMethod();
+ }
+
+ function testMaximumCallsSatisfiedByNoCalls() {
+ $mock = new MockDummy();
+ $mock->expectMaximumCallCount('aMethod', 1);
+ }
+}
+
+class MockWithInjectedTestCase extends SimpleMock {
+ protected function getCurrentTestCase() {
+ return SimpleTest::getContext()->getTest()->getMockedTest();
+ }
+}
+SimpleTest::setMockBaseClass('MockWithInjectedTestCase');
+Mock::generate('Dummy', 'MockDummyWithInjectedTestCase');
+SimpleTest::setMockBaseClass('SimpleMock');
+Mock::generate('SimpleTestCase');
+
+class LikeExpectation extends IdenticalExpectation {
+ function __construct($expectation) {
+ $expectation->message = '';
+ parent::__construct($expectation);
+ }
+
+ function test($compare) {
+ $compare->message = '';
+ return parent::test($compare);
+ }
+
+ function testMessage($compare) {
+ $compare->message = '';
+ return parent::testMessage($compare);
+ }
+}
+
+class TestOfMockExpectations extends UnitTestCase {
+ private $test;
+
+ function setUp() {
+ $this->test = new MockSimpleTestCase();
+ }
+
+ function getMockedTest() {
+ return $this->test;
+ }
+
+ function testSettingExpectationOnNonMethodThrowsError() {
+ $mock = new MockDummyWithInjectedTestCase();
+ $this->expectError();
+ $mock->expectMaximumCallCount('aMissingMethod', 2);
+ }
+
+ function testMaxCallsDetectsOverrun() {
+ $this->test->expectOnce('assert', array(new MemberExpectation('count', 2), 3));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expectMaximumCallCount('aMethod', 2);
+ $mock->aMethod();
+ $mock->aMethod();
+ $mock->aMethod();
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testTallyOnMaxCallsSendsPassOnUnderrun() {
+ $this->test->expectOnce('assert', array(new MemberExpectation('count', 2), 2));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expectMaximumCallCount("aMethod", 2);
+ $mock->aMethod();
+ $mock->aMethod();
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testExpectNeverDetectsOverrun() {
+ $this->test->expectOnce('assert', array(new MemberExpectation('count', 0), 1));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expectNever('aMethod');
+ $mock->aMethod();
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testTallyOnExpectNeverStillSendsPassOnUnderrun() {
+ $this->test->expectOnce('assert', array(new MemberExpectation('count', 0), 0));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expectNever('aMethod');
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testMinCalls() {
+ $this->test->expectOnce('assert', array(new MemberExpectation('count', 2), 2));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expectMinimumCallCount('aMethod', 2);
+ $mock->aMethod();
+ $mock->aMethod();
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testFailedNever() {
+ $this->test->expectOnce('assert', array(new MemberExpectation('count', 0), 1));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expectNever('aMethod');
+ $mock->aMethod();
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testUnderOnce() {
+ $this->test->expectOnce('assert', array(new MemberExpectation('count', 1), 0));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expectOnce('aMethod');
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testOverOnce() {
+ $this->test->expectOnce('assert', array(new MemberExpectation('count', 1), 2));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expectOnce('aMethod');
+ $mock->aMethod();
+ $mock->aMethod();
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testUnderAtLeastOnce() {
+ $this->test->expectOnce('assert', array(new MemberExpectation('count', 1), 0));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expectAtLeastOnce("aMethod");
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testZeroArguments() {
+ $this->test->expectOnce('assert',
+ array(new MemberExpectation('expected', array()), array(), '*'));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expect('aMethod', array());
+ $mock->aMethod();
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testExpectedArguments() {
+ $this->test->expectOnce('assert',
+ array(new MemberExpectation('expected', array(1, 2, 3)), array(1, 2, 3), '*'));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expect('aMethod', array(1, 2, 3));
+ $mock->aMethod(1, 2, 3);
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testFailedArguments() {
+ $this->test->expectOnce('assert',
+ array(new MemberExpectation('expected', array('this')), array('that'), '*'));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expect('aMethod', array('this'));
+ $mock->aMethod('that');
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testWildcardsAreTranslatedToAnythingExpectations() {
+ $this->test->expectOnce('assert',
+ array(new MemberExpectation('expected',
+ array(new AnythingExpectation(),
+ 123,
+ new AnythingExpectation())),
+ array(100, 123, 101), '*'));
+ $mock = new MockDummyWithInjectedTestCase($this);
+ $mock->expect("aMethod", array('*', 123, '*'));
+ $mock->aMethod(100, 123, 101);
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testSpecificPassingSequence() {
+ $this->test->expectAt(0, 'assert',
+ array(new MemberExpectation('expected', array(1, 2, 3)), array(1, 2, 3), '*'));
+ $this->test->expectAt(1, 'assert',
+ array(new MemberExpectation('expected', array('Hello')), array('Hello'), '*'));
+ $mock = new MockDummyWithInjectedTestCase();
+ $mock->expectAt(1, 'aMethod', array(1, 2, 3));
+ $mock->expectAt(2, 'aMethod', array('Hello'));
+ $mock->aMethod();
+ $mock->aMethod(1, 2, 3);
+ $mock->aMethod('Hello');
+ $mock->aMethod();
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+
+ function testNonArrayForExpectedParametersGivesError() {
+ $mock = new MockDummyWithInjectedTestCase();
+ $this->expectError(new PatternExpectation('/\$args.*not an array/i'));
+ $mock->expect("aMethod", "foo");
+ $mock->aMethod();
+ $mock->mock->atTestEnd('testSomething', $this->test);
+ }
+}
+
+class TestOfMockComparisons extends UnitTestCase {
+
+ function testEqualComparisonOfMocksDoesNotCrash() {
+ $expectation = new EqualExpectation(new MockDummy());
+ $this->assertTrue($expectation->test(new MockDummy(), true));
+ }
+
+ function testIdenticalComparisonOfMocksDoesNotCrash() {
+ $expectation = new IdenticalExpectation(new MockDummy());
+ $this->assertTrue($expectation->test(new MockDummy()));
+ }
+}
+
+class ClassWithSpecialMethods {
+ function __get($name) { }
+ function __set($name, $value) { }
+ function __isset($name) { }
+ function __unset($name) { }
+ function __call($method, $arguments) { }
+ function __toString() { }
+}
+Mock::generate('ClassWithSpecialMethods');
+
+class TestOfSpecialMethodsAfterPHP51 extends UnitTestCase {
+
+ function skip() {
+ $this->skipIf(version_compare(phpversion(), '5.1', '<'), '__isset and __unset overloading not tested unless PHP 5.1+');
+ }
+
+ function testCanEmulateIsset() {
+ $mock = new MockClassWithSpecialMethods();
+ $mock->returnsByValue('__isset', true);
+ $this->assertIdentical(isset($mock->a), true);
+ }
+
+ function testCanExpectUnset() {
+ $mock = new MockClassWithSpecialMethods();
+ $mock->expectOnce('__unset', array('a'));
+ unset($mock->a);
+ }
+
+}
+
+class TestOfSpecialMethods extends UnitTestCase {
+ function skip() {
+ $this->skipIf(version_compare(phpversion(), '5', '<'), 'Overloading not tested unless PHP 5+');
+ }
+
+ function testCanMockTheThingAtAll() {
+ $mock = new MockClassWithSpecialMethods();
+ }
+
+ function testReturnFromSpecialAccessor() {
+ $mock = new MockClassWithSpecialMethods();
+ $mock->returnsByValue('__get', '1st Return', array('first'));
+ $mock->returnsByValue('__get', '2nd Return', array('second'));
+ $this->assertEqual($mock->first, '1st Return');
+ $this->assertEqual($mock->second, '2nd Return');
+ }
+
+ function testcanExpectTheSettingOfValue() {
+ $mock = new MockClassWithSpecialMethods();
+ $mock->expectOnce('__set', array('a', 'A'));
+ $mock->a = 'A';
+ }
+
+ function testCanSimulateAnOverloadmethod() {
+ $mock = new MockClassWithSpecialMethods();
+ $mock->expectOnce('__call', array('amOverloaded', array('A')));
+ $mock->returnsByValue('__call', 'aaa');
+ $this->assertIdentical($mock->amOverloaded('A'), 'aaa');
+ }
+
+ function testToStringMagic() {
+ $mock = new MockClassWithSpecialMethods();
+ $mock->expectOnce('__toString');
+ $mock->returnsByValue('__toString', 'AAA');
+ ob_start();
+ print $mock;
+ $output = ob_get_contents();
+ ob_end_clean();
+ $this->assertEqual($output, 'AAA');
+ }
+}
+
+class WithStaticMethod {
+ static function aStaticMethod() { }
+}
+Mock::generate('WithStaticMethod');
+
+class TestOfMockingClassesWithStaticMethods extends UnitTestCase {
+
+ function testStaticMethodIsMockedAsStatic() {
+ $mock = new WithStaticMethod();
+ $reflection = new ReflectionClass($mock);
+ $method = $reflection->getMethod('aStaticMethod');
+ $this->assertTrue($method->isStatic());
+ }
+}
+
+class MockTestException extends Exception { }
+
+class TestOfThrowingExceptionsFromMocks extends UnitTestCase {
+
+ function testCanThrowOnMethodCall() {
+ $mock = new MockDummy();
+ $mock->throwOn('aMethod');
+ $this->expectException();
+ $mock->aMethod();
+ }
+
+ function testCanThrowSpecificExceptionOnMethodCall() {
+ $mock = new MockDummy();
+ $mock->throwOn('aMethod', new MockTestException());
+ $this->expectException();
+ $mock->aMethod();
+ }
+
+ function testThrowsOnlyWhenCallSignatureMatches() {
+ $mock = new MockDummy();
+ $mock->throwOn('aMethod', new MockTestException(), array(3));
+ $mock->aMethod(1);
+ $mock->aMethod(2);
+ $this->expectException();
+ $mock->aMethod(3);
+ }
+
+ function testCanThrowOnParticularInvocation() {
+ $mock = new MockDummy();
+ $mock->throwAt(2, 'aMethod', new MockTestException());
+ $mock->aMethod();
+ $mock->aMethod();
+ $this->expectException();
+ $mock->aMethod();
+ }
+}
+
+class TestOfThrowingErrorsFromMocks extends UnitTestCase {
+
+ function testCanGenerateErrorFromMethodCall() {
+ $mock = new MockDummy();
+ $mock->errorOn('aMethod', 'Ouch!');
+ $this->expectError('Ouch!');
+ $mock->aMethod();
+ }
+
+ function testGeneratesErrorOnlyWhenCallSignatureMatches() {
+ $mock = new MockDummy();
+ $mock->errorOn('aMethod', 'Ouch!', array(3));
+ $mock->aMethod(1);
+ $mock->aMethod(2);
+ $this->expectError();
+ $mock->aMethod(3);
+ }
+
+ function testCanGenerateErrorOnParticularInvocation() {
+ $mock = new MockDummy();
+ $mock->errorAt(2, 'aMethod', 'Ouch!');
+ $mock->aMethod();
+ $mock->aMethod();
+ $this->expectError();
+ $mock->aMethod();
+ }
+}
+
+Mock::generatePartial('Dummy', 'TestDummy', array('anotherMethod', 'aReferenceMethod'));
+
+class TestOfPartialMocks extends UnitTestCase {
+
+ function testMethodReplacementWithNoBehaviourReturnsNull() {
+ $mock = new TestDummy();
+ $this->assertEqual($mock->aMethod(99), 99);
+ $this->assertNull($mock->anotherMethod());
+ }
+
+ function testSettingReturns() {
+ $mock = new TestDummy();
+ $mock->returnsByValue('anotherMethod', 33, array(3));
+ $mock->returnsByValue('anotherMethod', 22);
+ $mock->returnsByValueAt(2, 'anotherMethod', 44, array(3));
+ $this->assertEqual($mock->anotherMethod(), 22);
+ $this->assertEqual($mock->anotherMethod(3), 33);
+ $this->assertEqual($mock->anotherMethod(3), 44);
+ }
+
+ function testSetReturnReferenceGivesOriginal() {
+ $mock = new TestDummy();
+ $object = 99;
+ $mock->returnsByReferenceAt(0, 'aReferenceMethod', $object, array(3));
+ $this->assertReference($mock->aReferenceMethod(3), $object);
+ }
+
+ function testReturnsAtGivesOriginalObjectHandle() {
+ $mock = new TestDummy();
+ $object = new Dummy();
+ $mock->returnsAt(0, 'anotherMethod', $object, array(3));
+ $this->assertSame($mock->anotherMethod(3), $object);
+ }
+
+ function testExpectations() {
+ $mock = new TestDummy();
+ $mock->expectCallCount('anotherMethod', 2);
+ $mock->expect('anotherMethod', array(77));
+ $mock->expectAt(1, 'anotherMethod', array(66));
+ $mock->anotherMethod(77);
+ $mock->anotherMethod(66);
+ }
+
+ function testSettingExpectationOnMissingMethodThrowsError() {
+ $mock = new TestDummy();
+ $this->expectError();
+ $mock->expectCallCount('aMissingMethod', 2);
+ }
+}
+
+class ConstructorSuperClass {
+ function ConstructorSuperClass() { }
+}
+
+class ConstructorSubClass extends ConstructorSuperClass { }
+
+class TestOfPHP4StyleSuperClassConstruct extends UnitTestCase {
+ function testBasicConstruct() {
+ Mock::generate('ConstructorSubClass');
+ $mock = new MockConstructorSubClass();
+ $this->assertIsA($mock, 'ConstructorSubClass');
+ $this->assertTrue(method_exists($mock, 'ConstructorSuperClass'));
+ }
+}
+
+class TestOfPHP5StaticMethodMocking extends UnitTestCase {
+ function testCanCreateAMockObjectWithStaticMethodsWithoutError() {
+ eval('
+ class SimpleObjectContainingStaticMethod {
+ static function someStatic() { }
+ }
+ ');
+ Mock::generate('SimpleObjectContainingStaticMethod');
+ }
+}
+
+class TestOfPHP5AbstractMethodMocking extends UnitTestCase {
+ function testCanCreateAMockObjectFromAnAbstractWithProperFunctionDeclarations() {
+ eval('
+ abstract class SimpleAbstractClassContainingAbstractMethods {
+ abstract function anAbstract();
+ abstract function anAbstractWithParameter($foo);
+ abstract function anAbstractWithMultipleParameters($foo, $bar);
+ }
+ ');
+ Mock::generate('SimpleAbstractClassContainingAbstractMethods');
+ $this->assertTrue(
+ method_exists(
+ // Testing with class name alone does not work in PHP 5.0
+ new MockSimpleAbstractClassContainingAbstractMethods,
+ 'anAbstract'
+ )
+ );
+ $this->assertTrue(
+ method_exists(
+ new MockSimpleAbstractClassContainingAbstractMethods,
+ 'anAbstractWithParameter'
+ )
+ );
+ $this->assertTrue(
+ method_exists(
+ new MockSimpleAbstractClassContainingAbstractMethods,
+ 'anAbstractWithMultipleParameters'
+ )
+ );
+ }
+
+ function testMethodsDefinedAsAbstractInParentShouldHaveFullSignature() {
+ eval('
+ abstract class SimpleParentAbstractClassContainingAbstractMethods {
+ abstract function anAbstract();
+ abstract function anAbstractWithParameter($foo);
+ abstract function anAbstractWithMultipleParameters($foo, $bar);
+ }
+
+ class SimpleChildAbstractClassContainingAbstractMethods extends SimpleParentAbstractClassContainingAbstractMethods {
+ function anAbstract(){}
+ function anAbstractWithParameter($foo){}
+ function anAbstractWithMultipleParameters($foo, $bar){}
+ }
+
+ class EvenDeeperEmptyChildClass extends SimpleChildAbstractClassContainingAbstractMethods {}
+ ');
+ Mock::generate('SimpleChildAbstractClassContainingAbstractMethods');
+ $this->assertTrue(
+ method_exists(
+ new MockSimpleChildAbstractClassContainingAbstractMethods,
+ 'anAbstract'
+ )
+ );
+ $this->assertTrue(
+ method_exists(
+ new MockSimpleChildAbstractClassContainingAbstractMethods,
+ 'anAbstractWithParameter'
+ )
+ );
+ $this->assertTrue(
+ method_exists(
+ new MockSimpleChildAbstractClassContainingAbstractMethods,
+ 'anAbstractWithMultipleParameters'
+ )
+ );
+ Mock::generate('EvenDeeperEmptyChildClass');
+ $this->assertTrue(
+ method_exists(
+ new MockEvenDeeperEmptyChildClass,
+ 'anAbstract'
+ )
+ );
+ $this->assertTrue(
+ method_exists(
+ new MockEvenDeeperEmptyChildClass,
+ 'anAbstractWithParameter'
+ )
+ );
+ $this->assertTrue(
+ method_exists(
+ new MockEvenDeeperEmptyChildClass,
+ 'anAbstractWithMultipleParameters'
+ )
+ );
+ }
+}
+
+class DummyWithProtected
+{
+ public function aMethodCallsProtected() { return $this->aProtectedMethod(); }
+ protected function aProtectedMethod() { return true; }
+}
+
+Mock::generatePartial('DummyWithProtected', 'TestDummyWithProtected', array('aProtectedMethod'));
+class TestOfProtectedMethodPartialMocks extends UnitTestCase
+{
+ function testProtectedMethodExists() {
+ $this->assertTrue(
+ method_exists(
+ new TestDummyWithProtected,
+ 'aProtectedMethod'
+ )
+ );
+ }
+
+ function testProtectedMethodIsCalled() {
+ $object = new DummyWithProtected();
+ $this->assertTrue($object->aMethodCallsProtected(), 'ensure original was called');
+ }
+
+ function testMockedMethodIsCalled() {
+ $object = new TestDummyWithProtected();
+ $object->returnsByValue('aProtectedMethod', false);
+ $this->assertFalse($object->aMethodCallsProtected());
+ }
+}
+
+?>
diff --git a/tests/simpletest/test/page_test.php b/tests/simpletest/test/page_test.php
new file mode 100644
index 0000000..fdc15c5
--- /dev/null
+++ b/tests/simpletest/test/page_test.php
@@ -0,0 +1,166 @@
+assertEqual($page->getTransportError(), 'No page fetched yet');
+ $this->assertIdentical($page->getRaw(), false);
+ $this->assertIdentical($page->getHeaders(), false);
+ $this->assertIdentical($page->getMimeType(), false);
+ $this->assertIdentical($page->getResponseCode(), false);
+ $this->assertIdentical($page->getAuthentication(), false);
+ $this->assertIdentical($page->getRealm(), false);
+ $this->assertFalse($page->hasFrames());
+ $this->assertIdentical($page->getUrls(), array());
+ $this->assertIdentical($page->getTitle(), false);
+ }
+}
+
+class TestOfPageHeaders extends UnitTestCase {
+
+ function testUrlAccessor() {
+ $headers = new MockSimpleHttpHeaders();
+
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('getHeaders', $headers);
+ $response->setReturnValue('getMethod', 'POST');
+ $response->setReturnValue('getUrl', new SimpleUrl('here'));
+ $response->setReturnValue('getRequestData', array('a' => 'A'));
+
+ $page = new SimplePage($response);
+ $this->assertEqual($page->getMethod(), 'POST');
+ $this->assertEqual($page->getUrl(), new SimpleUrl('here'));
+ $this->assertEqual($page->getRequestData(), array('a' => 'A'));
+ }
+
+ function testTransportError() {
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('getError', 'Ouch');
+
+ $page = new SimplePage($response);
+ $this->assertEqual($page->getTransportError(), 'Ouch');
+ }
+
+ function testHeadersAccessor() {
+ $headers = new MockSimpleHttpHeaders();
+ $headers->setReturnValue('getRaw', 'My: Headers');
+
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('getHeaders', $headers);
+
+ $page = new SimplePage($response);
+ $this->assertEqual($page->getHeaders(), 'My: Headers');
+ }
+
+ function testMimeAccessor() {
+ $headers = new MockSimpleHttpHeaders();
+ $headers->setReturnValue('getMimeType', 'text/html');
+
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('getHeaders', $headers);
+
+ $page = new SimplePage($response);
+ $this->assertEqual($page->getMimeType(), 'text/html');
+ }
+
+ function testResponseAccessor() {
+ $headers = new MockSimpleHttpHeaders();
+ $headers->setReturnValue('getResponseCode', 301);
+
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('getHeaders', $headers);
+
+ $page = new SimplePage($response);
+ $this->assertIdentical($page->getResponseCode(), 301);
+ }
+
+ function testAuthenticationAccessors() {
+ $headers = new MockSimpleHttpHeaders();
+ $headers->setReturnValue('getAuthentication', 'Basic');
+ $headers->setReturnValue('getRealm', 'Secret stuff');
+
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('getHeaders', $headers);
+
+ $page = new SimplePage($response);
+ $this->assertEqual($page->getAuthentication(), 'Basic');
+ $this->assertEqual($page->getRealm(), 'Secret stuff');
+ }
+}
+
+class TestOfHtmlStrippingAndNormalisation extends UnitTestCase {
+
+ function testImageSuppressionWhileKeepingParagraphsAndAltText() {
+ $this->assertEqual(
+ SimplePage::normalise('some text
'),
+ 'some text bar');
+ }
+
+ function testSpaceNormalisation() {
+ $this->assertEqual(
+ SimplePage::normalise("\nOne\tTwo \nThree\t"),
+ 'One Two Three');
+ }
+
+ function testMultilinesCommentSuppression() {
+ $this->assertEqual(
+ SimplePage::normalise(''),
+ '');
+ }
+
+ function testCommentSuppression() {
+ $this->assertEqual(
+ SimplePage::normalise(''),
+ '');
+ }
+
+ function testJavascriptSuppression() {
+ $this->assertEqual(
+ SimplePage::normalise(''),
+ '');
+ $this->assertEqual(
+ SimplePage::normalise(''),
+ '');
+ $this->assertEqual(
+ SimplePage::normalise(''),
+ '');
+ }
+
+ function testTagSuppression() {
+ $this->assertEqual(
+ SimplePage::normalise('Hello'),
+ 'Hello');
+ }
+
+ function testAdjoiningTagSuppression() {
+ $this->assertEqual(
+ SimplePage::normalise('HelloGoodbye'),
+ 'HelloGoodbye');
+ }
+
+ function testExtractImageAltTextWithDifferentQuotes() {
+ $this->assertEqual(
+ SimplePage::normalise(''),
+ 'One Two Three');
+ }
+
+ function testExtractImageAltTextMultipleTimes() {
+ $this->assertEqual(
+ SimplePage::normalise(''),
+ 'One Two Three');
+ }
+
+ function testHtmlEntityTranslation() {
+ $this->assertEqual(
+ SimplePage::normalise('<>"&''),
+ '<>"&\'');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/parse_error_test.php b/tests/simpletest/test/parse_error_test.php
new file mode 100644
index 0000000..c3ffb3d
--- /dev/null
+++ b/tests/simpletest/test/parse_error_test.php
@@ -0,0 +1,9 @@
+addFile('test_with_parse_error.php');
+$test->run(new HtmlReporter());
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/parsing_test.php b/tests/simpletest/test/parsing_test.php
new file mode 100644
index 0000000..2c5e6ca
--- /dev/null
+++ b/tests/simpletest/test/parsing_test.php
@@ -0,0 +1,642 @@
+whenVisiting('http://host/', 'Raw HTML');
+ $this->assertEqual($page->getRaw(), 'Raw HTML');
+ }
+
+ function testTextAccessor() {
+ $page = $this->whenVisiting('http://host/', 'Some "messy" HTML');
+ $this->assertEqual($page->getText(), 'Some "messy" HTML');
+ }
+
+ function testFramesetAbsence() {
+ $page = $this->whenVisiting('http://here/', '');
+ $this->assertFalse($page->hasFrames());
+ $this->assertIdentical($page->getFrameset(), false);
+ }
+
+ function testPageWithNoUrlsGivesEmptyArrayOfLinks() {
+ $page = $this->whenVisiting('http://here/', 'Stuff
');
+ $this->assertIdentical($page->getUrls(), array());
+ }
+
+ function testAddAbsoluteLink() {
+ $page = $this->whenVisiting('http://host',
+ 'Label');
+ $this->assertEqual(
+ $page->getUrlsByLabel('Label'),
+ array(new SimpleUrl('http://somewhere.com')));
+ }
+
+ function testUrlLabelsHaveHtmlTagsStripped() {
+ $page = $this->whenVisiting('http://host',
+ 'Label');
+ $this->assertEqual(
+ $page->getUrlsByLabel('Label'),
+ array(new SimpleUrl('http://somewhere.com')));
+ }
+
+ function testAddStrictRelativeLink() {
+ $page = $this->whenVisiting('http://host',
+ 'Label');
+ $this->assertEqual(
+ $page->getUrlsByLabel('Label'),
+ array(new SimpleUrl('http://host/somewhere.php')));
+ }
+
+ function testAddBareRelativeLink() {
+ $page = $this->whenVisiting('http://host',
+ 'Label');
+ $this->assertEqual(
+ $page->getUrlsByLabel('Label'),
+ array(new SimpleUrl('http://host/somewhere.php')));
+ }
+
+ function testAddRelativeLinkWithBaseTag() {
+ $raw = '' .
+ 'Label' .
+ '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual(
+ $page->getUrlsByLabel('Label'),
+ array(new SimpleUrl('http://www.lastcraft.com/stuff/somewhere.php')));
+ }
+
+ function testAddAbsoluteLinkWithBaseTag() {
+ $raw = '' .
+ 'Label' .
+ '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual(
+ $page->getUrlsByLabel('Label'),
+ array(new SimpleUrl('http://here.com/somewhere.php')));
+ }
+
+ function testCanFindLinkInsideForm() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual(
+ $page->getUrlsByLabel('Label'),
+ array(new SimpleUrl('http://host/somewhere.php')));
+ }
+
+ function testCanGetLinksByIdOrLabel() {
+ $raw = 'Label';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual(
+ $page->getUrlsByLabel('Label'),
+ array(new SimpleUrl('http://host/somewhere.php')));
+ $this->assertFalse($page->getUrlById(0));
+ $this->assertEqual(
+ $page->getUrlById(33),
+ new SimpleUrl('http://host/somewhere.php'));
+ }
+
+ function testCanFindLinkByNormalisedLabel() {
+ $raw = 'Long & thin';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual(
+ $page->getUrlsByLabel('Long & thin'),
+ array(new SimpleUrl('http://host/somewhere.php')));
+ }
+
+ function testCanFindLinkByImageAltText() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual(
+ array_map(array($this, 'urlToString'), $page->getUrlsByLabel('')),
+ array('http://host/somewhere.php'));
+ }
+
+ function testTitle() {
+ $page = $this->whenVisiting('http://host',
+ 'Me');
+ $this->assertEqual($page->getTitle(), 'Me');
+ }
+
+ function testTitleWithEntityReference() {
+ $page = $this->whenVisiting('http://host',
+ 'Me&Me');
+ $this->assertEqual($page->getTitle(), "Me&Me");
+ }
+
+ function testOnlyFramesInFramesetAreRecognised() {
+ $raw =
+ '' .
+ '';
+ $page = $this->whenVisiting('http://here', $raw);
+ $this->assertTrue($page->hasFrames());
+ $this->assertSameFrameset($page->getFrameset(), array(
+ 1 => new SimpleUrl('http://here/2.html'),
+ 2 => new SimpleUrl('http://here/3.html')));
+ }
+
+ function testReadsNamesInFrames() {
+ $raw =
+ '';
+ $page = $this->whenVisiting('http://here', $raw);
+ $this->assertTrue($page->hasFrames());
+ $this->assertSameFrameset($page->getFrameset(), array(
+ 1 => new SimpleUrl('http://here/1.html'),
+ 'A' => new SimpleUrl('http://here/2.html'),
+ 'B' => new SimpleUrl('http://here/3.html'),
+ 4 => new SimpleUrl('http://here/4.html')));
+ }
+
+ function testRelativeFramesRespectBaseTag() {
+ $raw = '';
+ $page = $this->whenVisiting('http://here', $raw);
+ $this->assertSameFrameset(
+ $page->getFrameset(),
+ array(1 => new SimpleUrl('https://there.com/stuff/1.html')));
+ }
+
+ function testSingleFrameInNestedFrameset() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertTrue($page->hasFrames());
+ $this->assertIdentical(
+ $page->getFrameset(),
+ array(1 => new SimpleUrl('http://host/a.html')));
+ }
+
+ function testFramesCollectedWithNestedFramesetTags() {
+ $raw = '' .
+ '' .
+ '' .
+ '' .
+ '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertTrue($page->hasFrames());
+ $this->assertIdentical($page->getFrameset(), array(
+ 1 => new SimpleUrl('http://host/a.html'),
+ 2 => new SimpleUrl('http://host/b.html'),
+ 3 => new SimpleUrl('http://host/c.html')));
+ }
+
+ function testNamedFrames() {
+ $raw = '' .
+ '' .
+ '' .
+ '' .
+ '' .
+ '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertTrue($page->hasFrames());
+ $this->assertIdentical($page->getFrameset(), array(
+ 1 => new SimpleUrl('http://host/a.html'),
+ '_one' => new SimpleUrl('http://host/b.html'),
+ 3 => new SimpleUrl('http://host/c.html'),
+ '_two' => new SimpleUrl('http://host/d.html')));
+ }
+
+ function testCanReadElementOfCompleteForm() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('here')), "Hello");
+ }
+
+ function testCanReadElementOfUnclosedForm() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertNull($page->getFormBySubmit(new SimpleByLabel('submit')));
+ $this->assertNull($page->getFormBySubmit(new SimpleByName('submit')));
+ $this->assertIsA(
+ $page->getFormBySubmit(new SimpleByLabel('Submit')),
+ 'SimpleForm');
+ }
+
+ function testConfirmSubmitAttributesAreCaseSensitive() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertIsA(
+ $page->getFormBySubmit(new SimpleByName('S')),
+ 'SimpleForm');
+ $this->assertIsA(
+ $page->getFormBySubmit(new SimpleByLabel('S')),
+ 'SimpleForm');
+ }
+
+ function testCanFindFormByImage() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertIsA(
+ $page->getFormByImage(new SimpleByLabel('Label')),
+ 'SimpleForm');
+ $this->assertIsA(
+ $page->getFormByImage(new SimpleByName('me')),
+ 'SimpleForm');
+ $this->assertIsA(
+ $page->getFormByImage(new SimpleById(100)),
+ 'SimpleForm');
+ }
+
+ function testCanFindFormByButtonTag() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertNull($page->getFormBySubmit(new SimpleByLabel('b')));
+ $this->assertNull($page->getFormBySubmit(new SimpleByLabel('B')));
+ $this->assertIsA(
+ $page->getFormBySubmit(new SimpleByName('b')),
+ 'SimpleForm');
+ $this->assertIsA(
+ $page->getFormBySubmit(new SimpleByLabel('BBB')),
+ 'SimpleForm');
+ }
+
+ function testCanFindFormById() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertNull($page->getFormById(54));
+ $this->assertIsA($page->getFormById(55), 'SimpleForm');
+ }
+
+ function testFormCanBeSubmitted() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $form = $page->getFormBySubmit(new SimpleByLabel('Submit'));
+ $this->assertEqual(
+ $form->submitButton(new SimpleByLabel('Submit')),
+ new SimpleGetEncoding(array('s' => 'Submit')));
+ }
+
+ function testUnparsedTagDoesNotCrash() {
+ $raw = '';
+ $this->whenVisiting('http://host', $raw);
+ }
+
+ function testReadingTextField() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertNull($page->getField(new SimpleByName('missing')));
+ $this->assertIdentical($page->getField(new SimpleByName('a')), '');
+ $this->assertIdentical($page->getField(new SimpleByName('b')), 'bbb');
+ }
+
+ function testEntitiesAreDecodedInDefaultTextFieldValue() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('a')), '&\'"<>');
+ }
+
+ function testReadingTextFieldIsCaseInsensitive() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertNull($page->getField(new SimpleByName('missing')));
+ $this->assertIdentical($page->getField(new SimpleByName('a')), '');
+ $this->assertIdentical($page->getField(new SimpleByName('b')), 'bbb');
+ }
+
+ function testSettingTextField() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertTrue($page->setField(new SimpleByName('a'), 'aaa'));
+ $this->assertEqual($page->getField(new SimpleByName('a')), 'aaa');
+ $this->assertTrue($page->setField(new SimpleById(3), 'bbb'));
+ $this->assertEqual($page->getField(new SimpleBYId(3)), 'bbb');
+ $this->assertFalse($page->setField(new SimpleByName('z'), 'zzz'));
+ $this->assertNull($page->getField(new SimpleByName('z')));
+ }
+
+ function testSettingTextFieldByEnclosingLabel() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('a')), 'A');
+ $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A');
+ $this->assertTrue($page->setField(new SimpleByLabel('Stuff'), 'aaa'));
+ $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'aaa');
+ }
+
+ function testLabelsWithoutForDoNotAttachToInputsWithNoId() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByLabelOrName('Text A')), 'one');
+ $this->assertEqual($page->getField(new SimpleByLabelOrName('Text B')), 'two');
+ $this->assertTrue($page->setField(new SimpleByLabelOrName('Text A'), '1'));
+ $this->assertTrue($page->setField(new SimpleByLabelOrName('Text B'), '2'));
+ $this->assertEqual($page->getField(new SimpleByLabelOrName('Text A')), '1');
+ $this->assertEqual($page->getField(new SimpleByLabelOrName('Text B')), '2');
+ }
+
+ function testGettingTextFieldByEnclosingLabelWithConflictingOtherFields() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('a')), 'A');
+ $this->assertEqual($page->getField(new SimpleByName('b')), 'B');
+ $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A');
+ }
+
+ function testSettingTextFieldByExternalLabel() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A');
+ $this->assertTrue($page->setField(new SimpleByLabel('Stuff'), 'aaa'));
+ $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'aaa');
+ }
+
+ function testReadingTextArea() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('a')), 'aaa');
+ }
+
+ function testEntitiesAreDecodedInTextareaValue() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('a')), '&\'"<>');
+ }
+
+ function testNewlinesPreservedInTextArea() {
+ $raw = "";
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('a')), "hello\r\nworld");
+ }
+
+ function testWhitespacePreservedInTextArea() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('a')), ' ');
+ }
+
+ function testComplexWhitespaceInTextArea() {
+ $raw = "\n" .
+ " \n" .
+ " \n" .
+ " \n" .
+ " \n" .
+ "";
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('c')), " ");
+ }
+
+ function testSettingTextArea() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertTrue($page->setField(new SimpleByName('a'), 'AAA'));
+ $this->assertEqual($page->getField(new SimpleByName('a')), 'AAA');
+ }
+
+ function testDontIncludeTextAreaContentInLabel() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByLabel('Text area C')), 'mouse');
+ }
+
+ function testSettingSelectionField() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('a')), 'bbb');
+ $this->assertFalse($page->setField(new SimpleByName('a'), 'ccc'));
+ $this->assertTrue($page->setField(new SimpleByName('a'), 'aaa'));
+ $this->assertEqual($page->getField(new SimpleByName('a')), 'aaa');
+ }
+
+ function testSelectionOptionsAreNormalised() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('a')), 'Big bold');
+ $this->assertTrue($page->setField(new SimpleByName('a'), 'small italic'));
+ $this->assertEqual($page->getField(new SimpleByName('a')), 'small italic');
+ }
+
+ function testCanParseBlankOptions() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertTrue($page->setField(new SimpleByName('d'), ''));
+ }
+
+ function testTwoSelectionFieldsAreIndependent() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertTrue($page->setField(new SimpleByName('d'), 'd2'));
+ $this->assertTrue($page->setField(new SimpleByName('h'), 'h1'));
+ $this->assertEqual($page->getField(new SimpleByName('d')), 'd2');
+ }
+
+ function testEmptyOptionDoesNotScrewUpTwoSelectionFields() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertTrue($page->setField(new SimpleByName('d'), 'd2'));
+ $this->assertTrue($page->setField(new SimpleByName('h'), 'h1'));
+ $this->assertEqual($page->getField(new SimpleByName('d')), 'd2');
+ }
+
+ function testSettingSelectionFieldByEnclosingLabel() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'A');
+ $this->assertTrue($page->setField(new SimpleByLabel('Stuff'), 'B'));
+ $this->assertEqual($page->getField(new SimpleByLabel('Stuff')), 'B');
+ }
+
+ function testTwoSelectionFieldsWithLabelsAreIndependent() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertTrue($page->setField(new SimpleByLabel('Labelled D'), 'd2'));
+ $this->assertTrue($page->setField(new SimpleByLabel('Labelled H'), 'h1'));
+ $this->assertEqual($page->getField(new SimpleByLabel('Labelled D')), 'd2');
+ }
+
+ function testSettingRadioButtonByEnclosingLabel() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByLabel('A')), 'a');
+ $this->assertTrue($page->setField(new SimpleBylabel('B'), 'b'));
+ $this->assertEqual($page->getField(new SimpleByLabel('B')), 'b');
+ }
+
+ function testCanParseInputsWithAllKindsOfAttributeQuoting() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByName('first')), 'one');
+ $this->assertEqual($page->getField(new SimpleByName('second')), false);
+ $this->assertEqual($page->getField(new SimpleByName('third')), 'three');
+ }
+
+ function urlToString($url) {
+ return $url->asString();
+ }
+
+ function assertSameFrameset($actual, $expected) {
+ $this->assertIdentical(array_map(array($this, 'urlToString'), $actual),
+ array_map(array($this, 'urlToString'), $expected));
+ }
+}
+
+class TestOfParsingUsingPhpParser extends TestOfParsing {
+
+ function whenVisiting($url, $content) {
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('getContent', $content);
+ $response->setReturnValue('getUrl', new SimpleUrl($url));
+ $builder = new SimplePhpPageBuilder();
+ return $builder->parse($response);
+ }
+
+ function testNastyTitle() {
+ $page = $this->whenVisiting('http://host',
+ ' Me&Me ');
+ $this->assertEqual($page->getTitle(), "Me&Me");
+ }
+
+ function testLabelShouldStopAtClosingLabelTag() {
+ $raw = '';
+ $page = $this->whenVisiting('http://host', $raw);
+ $this->assertEqual($page->getField(new SimpleByLabel('startend')), 'stuff');
+ }
+}
+
+class TestOfParsingUsingTidyParser extends TestOfParsing {
+
+ function skip() {
+ $this->skipUnless(extension_loaded('tidy'), 'Install \'tidy\' php extension to enable html tidy based parser');
+ }
+
+ function whenVisiting($url, $content) {
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('getContent', $content);
+ $response->setReturnValue('getUrl', new SimpleUrl($url));
+ $builder = new SimpleTidyPageBuilder();
+ return $builder->parse($response);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/php_parser_test.php b/tests/simpletest/test/php_parser_test.php
new file mode 100644
index 0000000..d95c7d0
--- /dev/null
+++ b/tests/simpletest/test/php_parser_test.php
@@ -0,0 +1,489 @@
+assertFalse($regex->match("Hello", $match));
+ $this->assertEqual($match, "");
+ }
+
+ function testNoSubject() {
+ $regex = new ParallelRegex(false);
+ $regex->addPattern(".*");
+ $this->assertTrue($regex->match("", $match));
+ $this->assertEqual($match, "");
+ }
+
+ function testMatchAll() {
+ $regex = new ParallelRegex(false);
+ $regex->addPattern(".*");
+ $this->assertTrue($regex->match("Hello", $match));
+ $this->assertEqual($match, "Hello");
+ }
+
+ function testCaseSensitive() {
+ $regex = new ParallelRegex(true);
+ $regex->addPattern("abc");
+ $this->assertTrue($regex->match("abcdef", $match));
+ $this->assertEqual($match, "abc");
+ $this->assertTrue($regex->match("AAABCabcdef", $match));
+ $this->assertEqual($match, "abc");
+ }
+
+ function testCaseInsensitive() {
+ $regex = new ParallelRegex(false);
+ $regex->addPattern("abc");
+ $this->assertTrue($regex->match("abcdef", $match));
+ $this->assertEqual($match, "abc");
+ $this->assertTrue($regex->match("AAABCabcdef", $match));
+ $this->assertEqual($match, "ABC");
+ }
+
+ function testMatchMultiple() {
+ $regex = new ParallelRegex(true);
+ $regex->addPattern("abc");
+ $regex->addPattern("ABC");
+ $this->assertTrue($regex->match("abcdef", $match));
+ $this->assertEqual($match, "abc");
+ $this->assertTrue($regex->match("AAABCabcdef", $match));
+ $this->assertEqual($match, "ABC");
+ $this->assertFalse($regex->match("Hello", $match));
+ }
+
+ function testPatternLabels() {
+ $regex = new ParallelRegex(false);
+ $regex->addPattern("abc", "letter");
+ $regex->addPattern("123", "number");
+ $this->assertIdentical($regex->match("abcdef", $match), "letter");
+ $this->assertEqual($match, "abc");
+ $this->assertIdentical($regex->match("0123456789", $match), "number");
+ $this->assertEqual($match, "123");
+ }
+}
+
+class TestOfStateStack extends UnitTestCase {
+
+ function testStartState() {
+ $stack = new SimpleStateStack("one");
+ $this->assertEqual($stack->getCurrent(), "one");
+ }
+
+ function testExhaustion() {
+ $stack = new SimpleStateStack("one");
+ $this->assertFalse($stack->leave());
+ }
+
+ function testStateMoves() {
+ $stack = new SimpleStateStack("one");
+ $stack->enter("two");
+ $this->assertEqual($stack->getCurrent(), "two");
+ $stack->enter("three");
+ $this->assertEqual($stack->getCurrent(), "three");
+ $this->assertTrue($stack->leave());
+ $this->assertEqual($stack->getCurrent(), "two");
+ $stack->enter("third");
+ $this->assertEqual($stack->getCurrent(), "third");
+ $this->assertTrue($stack->leave());
+ $this->assertTrue($stack->leave());
+ $this->assertEqual($stack->getCurrent(), "one");
+ }
+}
+
+class TestParser {
+
+ function accept() {
+ }
+
+ function a() {
+ }
+
+ function b() {
+ }
+}
+Mock::generate('TestParser');
+
+class TestOfLexer extends UnitTestCase {
+
+ function testEmptyPage() {
+ $handler = new MockTestParser();
+ $handler->expectNever("accept");
+ $handler->setReturnValue("accept", true);
+ $handler->expectNever("accept");
+ $handler->setReturnValue("accept", true);
+ $lexer = new SimpleLexer($handler);
+ $lexer->addPattern("a+");
+ $this->assertTrue($lexer->parse(""));
+ }
+
+ function testSinglePattern() {
+ $handler = new MockTestParser();
+ $handler->expectAt(0, "accept", array("aaa", LEXER_MATCHED));
+ $handler->expectAt(1, "accept", array("x", LEXER_UNMATCHED));
+ $handler->expectAt(2, "accept", array("a", LEXER_MATCHED));
+ $handler->expectAt(3, "accept", array("yyy", LEXER_UNMATCHED));
+ $handler->expectAt(4, "accept", array("a", LEXER_MATCHED));
+ $handler->expectAt(5, "accept", array("x", LEXER_UNMATCHED));
+ $handler->expectAt(6, "accept", array("aaa", LEXER_MATCHED));
+ $handler->expectAt(7, "accept", array("z", LEXER_UNMATCHED));
+ $handler->expectCallCount("accept", 8);
+ $handler->setReturnValue("accept", true);
+ $lexer = new SimpleLexer($handler);
+ $lexer->addPattern("a+");
+ $this->assertTrue($lexer->parse("aaaxayyyaxaaaz"));
+ }
+
+ function testMultiplePattern() {
+ $handler = new MockTestParser();
+ $target = array("a", "b", "a", "bb", "x", "b", "a", "xxxxxx", "a", "x");
+ for ($i = 0; $i < count($target); $i++) {
+ $handler->expectAt($i, "accept", array($target[$i], '*'));
+ }
+ $handler->expectCallCount("accept", count($target));
+ $handler->setReturnValue("accept", true);
+ $lexer = new SimpleLexer($handler);
+ $lexer->addPattern("a+");
+ $lexer->addPattern("b+");
+ $this->assertTrue($lexer->parse("ababbxbaxxxxxxax"));
+ }
+}
+
+class TestOfLexerModes extends UnitTestCase {
+
+ function testIsolatedPattern() {
+ $handler = new MockTestParser();
+ $handler->expectAt(0, "a", array("a", LEXER_MATCHED));
+ $handler->expectAt(1, "a", array("b", LEXER_UNMATCHED));
+ $handler->expectAt(2, "a", array("aa", LEXER_MATCHED));
+ $handler->expectAt(3, "a", array("bxb", LEXER_UNMATCHED));
+ $handler->expectAt(4, "a", array("aaa", LEXER_MATCHED));
+ $handler->expectAt(5, "a", array("x", LEXER_UNMATCHED));
+ $handler->expectAt(6, "a", array("aaaa", LEXER_MATCHED));
+ $handler->expectAt(7, "a", array("x", LEXER_UNMATCHED));
+ $handler->expectCallCount("a", 8);
+ $handler->setReturnValue("a", true);
+ $lexer = new SimpleLexer($handler, "a");
+ $lexer->addPattern("a+", "a");
+ $lexer->addPattern("b+", "b");
+ $this->assertTrue($lexer->parse("abaabxbaaaxaaaax"));
+ }
+
+ function testModeChange() {
+ $handler = new MockTestParser();
+ $handler->expectAt(0, "a", array("a", LEXER_MATCHED));
+ $handler->expectAt(1, "a", array("b", LEXER_UNMATCHED));
+ $handler->expectAt(2, "a", array("aa", LEXER_MATCHED));
+ $handler->expectAt(3, "a", array("b", LEXER_UNMATCHED));
+ $handler->expectAt(4, "a", array("aaa", LEXER_MATCHED));
+ $handler->expectAt(0, "b", array(":", LEXER_ENTER));
+ $handler->expectAt(1, "b", array("a", LEXER_UNMATCHED));
+ $handler->expectAt(2, "b", array("b", LEXER_MATCHED));
+ $handler->expectAt(3, "b", array("a", LEXER_UNMATCHED));
+ $handler->expectAt(4, "b", array("bb", LEXER_MATCHED));
+ $handler->expectAt(5, "b", array("a", LEXER_UNMATCHED));
+ $handler->expectAt(6, "b", array("bbb", LEXER_MATCHED));
+ $handler->expectAt(7, "b", array("a", LEXER_UNMATCHED));
+ $handler->expectCallCount("a", 5);
+ $handler->expectCallCount("b", 8);
+ $handler->setReturnValue("a", true);
+ $handler->setReturnValue("b", true);
+ $lexer = new SimpleLexer($handler, "a");
+ $lexer->addPattern("a+", "a");
+ $lexer->addEntryPattern(":", "a", "b");
+ $lexer->addPattern("b+", "b");
+ $this->assertTrue($lexer->parse("abaabaaa:ababbabbba"));
+ }
+
+ function testNesting() {
+ $handler = new MockTestParser();
+ $handler->setReturnValue("a", true);
+ $handler->setReturnValue("b", true);
+ $handler->expectAt(0, "a", array("aa", LEXER_MATCHED));
+ $handler->expectAt(1, "a", array("b", LEXER_UNMATCHED));
+ $handler->expectAt(2, "a", array("aa", LEXER_MATCHED));
+ $handler->expectAt(3, "a", array("b", LEXER_UNMATCHED));
+ $handler->expectAt(0, "b", array("(", LEXER_ENTER));
+ $handler->expectAt(1, "b", array("bb", LEXER_MATCHED));
+ $handler->expectAt(2, "b", array("a", LEXER_UNMATCHED));
+ $handler->expectAt(3, "b", array("bb", LEXER_MATCHED));
+ $handler->expectAt(4, "b", array(")", LEXER_EXIT));
+ $handler->expectAt(4, "a", array("aa", LEXER_MATCHED));
+ $handler->expectAt(5, "a", array("b", LEXER_UNMATCHED));
+ $handler->expectCallCount("a", 6);
+ $handler->expectCallCount("b", 5);
+ $lexer = new SimpleLexer($handler, "a");
+ $lexer->addPattern("a+", "a");
+ $lexer->addEntryPattern("(", "a", "b");
+ $lexer->addPattern("b+", "b");
+ $lexer->addExitPattern(")", "b");
+ $this->assertTrue($lexer->parse("aabaab(bbabb)aab"));
+ }
+
+ function testSingular() {
+ $handler = new MockTestParser();
+ $handler->setReturnValue("a", true);
+ $handler->setReturnValue("b", true);
+ $handler->expectAt(0, "a", array("aa", LEXER_MATCHED));
+ $handler->expectAt(1, "a", array("aa", LEXER_MATCHED));
+ $handler->expectAt(2, "a", array("xx", LEXER_UNMATCHED));
+ $handler->expectAt(3, "a", array("xx", LEXER_UNMATCHED));
+ $handler->expectAt(0, "b", array("b", LEXER_SPECIAL));
+ $handler->expectAt(1, "b", array("bbb", LEXER_SPECIAL));
+ $handler->expectCallCount("a", 4);
+ $handler->expectCallCount("b", 2);
+ $lexer = new SimpleLexer($handler, "a");
+ $lexer->addPattern("a+", "a");
+ $lexer->addSpecialPattern("b+", "a", "b");
+ $this->assertTrue($lexer->parse("aabaaxxbbbxx"));
+ }
+
+ function testUnwindTooFar() {
+ $handler = new MockTestParser();
+ $handler->setReturnValue("a", true);
+ $handler->expectAt(0, "a", array("aa", LEXER_MATCHED));
+ $handler->expectAt(1, "a", array(")", LEXER_EXIT));
+ $handler->expectCallCount("a", 2);
+ $lexer = new SimpleLexer($handler, "a");
+ $lexer->addPattern("a+", "a");
+ $lexer->addExitPattern(")", "a");
+ $this->assertFalse($lexer->parse("aa)aa"));
+ }
+}
+
+class TestOfLexerHandlers extends UnitTestCase {
+
+ function testModeMapping() {
+ $handler = new MockTestParser();
+ $handler->setReturnValue("a", true);
+ $handler->expectAt(0, "a", array("aa", LEXER_MATCHED));
+ $handler->expectAt(1, "a", array("(", LEXER_ENTER));
+ $handler->expectAt(2, "a", array("bb", LEXER_MATCHED));
+ $handler->expectAt(3, "a", array("a", LEXER_UNMATCHED));
+ $handler->expectAt(4, "a", array("bb", LEXER_MATCHED));
+ $handler->expectAt(5, "a", array(")", LEXER_EXIT));
+ $handler->expectAt(6, "a", array("b", LEXER_UNMATCHED));
+ $handler->expectCallCount("a", 7);
+ $lexer = new SimpleLexer($handler, "mode_a");
+ $lexer->addPattern("a+", "mode_a");
+ $lexer->addEntryPattern("(", "mode_a", "mode_b");
+ $lexer->addPattern("b+", "mode_b");
+ $lexer->addExitPattern(")", "mode_b");
+ $lexer->mapHandler("mode_a", "a");
+ $lexer->mapHandler("mode_b", "a");
+ $this->assertTrue($lexer->parse("aa(bbabb)b"));
+ }
+}
+
+class TestOfSimpleHtmlLexer extends UnitTestCase {
+
+ function &createParser() {
+ $parser = new MockSimpleHtmlSaxParser();
+ $parser->setReturnValue('acceptStartToken', true);
+ $parser->setReturnValue('acceptEndToken', true);
+ $parser->setReturnValue('acceptAttributeToken', true);
+ $parser->setReturnValue('acceptEntityToken', true);
+ $parser->setReturnValue('acceptTextToken', true);
+ $parser->setReturnValue('ignore', true);
+ return $parser;
+ }
+
+ function testNoContent() {
+ $parser = $this->createParser();
+ $parser->expectNever('acceptStartToken');
+ $parser->expectNever('acceptEndToken');
+ $parser->expectNever('acceptAttributeToken');
+ $parser->expectNever('acceptEntityToken');
+ $parser->expectNever('acceptTextToken');
+ $lexer = new SimpleHtmlLexer($parser);
+ $this->assertTrue($lexer->parse(''));
+ }
+
+ function testUninteresting() {
+ $parser = $this->createParser();
+ $parser->expectOnce('acceptTextToken', array('', '*'));
+ $lexer = new SimpleHtmlLexer($parser);
+ $this->assertTrue($lexer->parse(''));
+ }
+
+ function testSkipCss() {
+ $parser = $this->createParser();
+ $parser->expectNever('acceptTextToken');
+ $parser->expectAtLeastOnce('ignore');
+ $lexer = new SimpleHtmlLexer($parser);
+ $this->assertTrue($lexer->parse(""));
+ }
+
+ function testSkipJavaScript() {
+ $parser = $this->createParser();
+ $parser->expectNever('acceptTextToken');
+ $parser->expectAtLeastOnce('ignore');
+ $lexer = new SimpleHtmlLexer($parser);
+ $this->assertTrue($lexer->parse(""));
+ }
+
+ function testSkipHtmlComments() {
+ $parser = $this->createParser();
+ $parser->expectNever('acceptTextToken');
+ $parser->expectAtLeastOnce('ignore');
+ $lexer = new SimpleHtmlLexer($parser);
+ $this->assertTrue($lexer->parse(""));
+ }
+
+ function testTagWithNoAttributes() {
+ $parser = $this->createParser();
+ $parser->expectAt(0, 'acceptStartToken', array('expectAt(1, 'acceptStartToken', array('>', '*'));
+ $parser->expectCallCount('acceptStartToken', 2);
+ $parser->expectOnce('acceptTextToken', array('Hello', '*'));
+ $parser->expectOnce('acceptEndToken', array('', '*'));
+ $lexer = new SimpleHtmlLexer($parser);
+ $this->assertTrue($lexer->parse('Hello'));
+ }
+
+ function testTagWithAttributes() {
+ $parser = $this->createParser();
+ $parser->expectOnce('acceptTextToken', array('label', '*'));
+ $parser->expectAt(0, 'acceptStartToken', array('expectAt(1, 'acceptStartToken', array('href', '*'));
+ $parser->expectAt(2, 'acceptStartToken', array('>', '*'));
+ $parser->expectCallCount('acceptStartToken', 3);
+ $parser->expectAt(0, 'acceptAttributeToken', array('= "', '*'));
+ $parser->expectAt(1, 'acceptAttributeToken', array('here.html', '*'));
+ $parser->expectAt(2, 'acceptAttributeToken', array('"', '*'));
+ $parser->expectCallCount('acceptAttributeToken', 3);
+ $parser->expectOnce('acceptEndToken', array('', '*'));
+ $lexer = new SimpleHtmlLexer($parser);
+ $this->assertTrue($lexer->parse('label'));
+ }
+}
+
+class TestOfHtmlSaxParser extends UnitTestCase {
+
+ function createListener() {
+ $listener = new MockSimplePhpPageBuilder();
+ $listener->setReturnValue('startElement', true);
+ $listener->setReturnValue('addContent', true);
+ $listener->setReturnValue('endElement', true);
+ return $listener;
+ }
+
+ function testFramesetTag() {
+ $listener = $this->createListener();
+ $listener->expectOnce('startElement', array('frameset', array()));
+ $listener->expectOnce('addContent', array('Frames'));
+ $listener->expectOnce('endElement', array('frameset'));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse('Frames'));
+ }
+
+ function testTagWithUnquotedAttributes() {
+ $listener = $this->createListener();
+ $listener->expectOnce(
+ 'startElement',
+ array('input', array('name' => 'a.b.c', 'value' => 'd')));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse(''));
+ }
+
+ function testTagInsideContent() {
+ $listener = $this->createListener();
+ $listener->expectOnce('startElement', array('a', array()));
+ $listener->expectAt(0, 'addContent', array(''));
+ $listener->expectAt(1, 'addContent', array(''));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse(''));
+ }
+
+ function testTagWithInternalContent() {
+ $listener = $this->createListener();
+ $listener->expectOnce('startElement', array('a', array()));
+ $listener->expectOnce('addContent', array('label'));
+ $listener->expectOnce('endElement', array('a'));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse('label'));
+ }
+
+ function testLinkAddress() {
+ $listener = $this->createListener();
+ $listener->expectOnce('startElement', array('a', array('href' => 'here.html')));
+ $listener->expectOnce('addContent', array('label'));
+ $listener->expectOnce('endElement', array('a'));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse("label"));
+ }
+
+ function testEncodedAttribute() {
+ $listener = $this->createListener();
+ $listener->expectOnce('startElement', array('a', array('href' => 'here&there.html')));
+ $listener->expectOnce('addContent', array('label'));
+ $listener->expectOnce('endElement', array('a'));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse("label"));
+ }
+
+ function testTagWithId() {
+ $listener = $this->createListener();
+ $listener->expectOnce('startElement', array('a', array('id' => '0')));
+ $listener->expectOnce('addContent', array('label'));
+ $listener->expectOnce('endElement', array('a'));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse('label'));
+ }
+
+ function testTagWithEmptyAttributes() {
+ $listener = $this->createListener();
+ $listener->expectOnce(
+ 'startElement',
+ array('option', array('value' => '', 'selected' => '')));
+ $listener->expectOnce('addContent', array('label'));
+ $listener->expectOnce('endElement', array('option'));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse(''));
+ }
+
+ function testComplexTagWithLotsOfCaseVariations() {
+ $listener = $this->createListener();
+ $listener->expectOnce(
+ 'startElement',
+ array('a', array('href' => 'here.html', 'style' => "'cool'")));
+ $listener->expectOnce('addContent', array('label'));
+ $listener->expectOnce('endElement', array('a'));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse('label'));
+ }
+
+ function testXhtmlSelfClosingTag() {
+ $listener = $this->createListener();
+ $listener->expectOnce(
+ 'startElement',
+ array('input', array('type' => 'submit', 'name' => 'N', 'value' => 'V')));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse(''));
+ }
+
+ function testNestedFrameInFrameset() {
+ $listener = $this->createListener();
+ $listener->expectAt(0, 'startElement', array('frameset', array()));
+ $listener->expectAt(1, 'startElement', array('frame', array('src' => 'frame.html')));
+ $listener->expectCallCount('startElement', 2);
+ $listener->expectOnce('addContent', array('Hello'));
+ $listener->expectOnce('endElement', array('frameset'));
+ $parser = new SimpleHtmlSaxParser($listener);
+ $this->assertTrue($parser->parse(
+ 'Hello'));
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/recorder_test.php b/tests/simpletest/test/recorder_test.php
new file mode 100644
index 0000000..fdae4c1
--- /dev/null
+++ b/tests/simpletest/test/recorder_test.php
@@ -0,0 +1,23 @@
+addFile(dirname(__FILE__) . '/support/recorder_sample.php');
+ $recorder = new Recorder(new SimpleReporter());
+ $test->run($recorder);
+ $this->assertEqual(count($recorder->results), 2);
+ $this->assertIsA($recorder->results[0], 'SimpleResultOfPass');
+ $this->assertEqual('testTrueIsTrue', array_pop($recorder->results[0]->breadcrumb));
+ $this->assertPattern('/ at \[.*\Wrecorder_sample\.php line 7\]/', $recorder->results[0]->message);
+ $this->assertIsA($recorder->results[1], 'SimpleResultOfFail');
+ $this->assertEqual('testFalseIsTrue', array_pop($recorder->results[1]->breadcrumb));
+ $this->assertPattern("/Expected false, got \[Boolean: true\] at \[.*\Wrecorder_sample\.php line 11\]/",
+ $recorder->results[1]->message);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/reflection_php5_test.php b/tests/simpletest/test/reflection_php5_test.php
new file mode 100644
index 0000000..d9f46e6
--- /dev/null
+++ b/tests/simpletest/test/reflection_php5_test.php
@@ -0,0 +1,263 @@
+assertTrue($reflection->classOrInterfaceExists());
+ $this->assertTrue($reflection->classOrInterfaceExistsSansAutoload());
+ $this->assertFalse($reflection->isAbstract());
+ $this->assertFalse($reflection->isInterface());
+ }
+
+ function testClassNonExistence() {
+ $reflection = new SimpleReflection('UnknownThing');
+ $this->assertFalse($reflection->classOrInterfaceExists());
+ $this->assertFalse($reflection->classOrInterfaceExistsSansAutoload());
+ }
+
+ function testDetectionOfAbstractClass() {
+ $reflection = new SimpleReflection('AnyOldClass');
+ $this->assertTrue($reflection->isAbstract());
+ }
+
+ function testDetectionOfFinalMethods() {
+ $reflection = new SimpleReflection('AnyOldClass');
+ $this->assertFalse($reflection->hasFinal());
+ $reflection = new SimpleReflection('AnyOldLeafClassWithAFinal');
+ $this->assertTrue($reflection->hasFinal());
+ }
+
+ function testFindingParentClass() {
+ $reflection = new SimpleReflection('AnyOldSubclass');
+ $this->assertEqual($reflection->getParent(), 'AnyOldImplementation');
+ }
+
+ function testInterfaceExistence() {
+ $reflection = new SimpleReflection('AnyOldInterface');
+ $this->assertTrue($reflection->classOrInterfaceExists());
+ $this->assertTrue($reflection->classOrInterfaceExistsSansAutoload());
+ $this->assertTrue($reflection->isInterface());
+ }
+
+ function testMethodsListFromClass() {
+ $reflection = new SimpleReflection('AnyOldClass');
+ $this->assertIdentical($reflection->getMethods(), array('aMethod'));
+ }
+
+ function testMethodsListFromInterface() {
+ $reflection = new SimpleReflection('AnyOldInterface');
+ $this->assertIdentical($reflection->getMethods(), array('aMethod'));
+ $this->assertIdentical($reflection->getInterfaceMethods(), array('aMethod'));
+ }
+
+ function testMethodsComeFromDescendentInterfacesASWell() {
+ $reflection = new SimpleReflection('AnyDescendentInterface');
+ $this->assertIdentical($reflection->getMethods(), array('aMethod'));
+ }
+
+ function testCanSeparateInterfaceMethodsFromOthers() {
+ $reflection = new SimpleReflection('AnyOldImplementation');
+ $this->assertIdentical($reflection->getMethods(), array('aMethod', 'extraMethod'));
+ $this->assertIdentical($reflection->getInterfaceMethods(), array('aMethod'));
+ }
+
+ function testMethodsComeFromDescendentInterfacesInAbstractClass() {
+ $reflection = new SimpleReflection('AnyAbstractImplementation');
+ $this->assertIdentical($reflection->getMethods(), array('aMethod'));
+ }
+
+ function testInterfaceHasOnlyItselfToImplement() {
+ $reflection = new SimpleReflection('AnyOldInterface');
+ $this->assertEqual(
+ $reflection->getInterfaces(),
+ array('AnyOldInterface'));
+ }
+
+ function testInterfacesListedForClass() {
+ $reflection = new SimpleReflection('AnyOldImplementation');
+ $this->assertEqual(
+ $reflection->getInterfaces(),
+ array('AnyOldInterface'));
+ }
+
+ function testInterfacesListedForSubclass() {
+ $reflection = new SimpleReflection('AnyOldSubclass');
+ $this->assertEqual(
+ $reflection->getInterfaces(),
+ array('AnyOldInterface'));
+ }
+
+ function testNoParameterCreationWhenNoInterface() {
+ $reflection = new SimpleReflection('AnyOldArgumentClass');
+ $function = $reflection->getSignature('aMethod');
+ if (version_compare(phpversion(), '5.0.2', '<=')) {
+ $this->assertEqual('function amethod($argument)', strtolower($function));
+ } else {
+ $this->assertEqual('function aMethod($argument)', $function);
+ }
+ }
+
+ function testParameterCreationWithoutTypeHinting() {
+ $reflection = new SimpleReflection('AnyOldArgumentImplementation');
+ $function = $reflection->getSignature('aMethod');
+ if (version_compare(phpversion(), '5.0.2', '<=')) {
+ $this->assertEqual('function amethod(AnyOldInterface $argument)', $function);
+ } else {
+ $this->assertEqual('function aMethod(AnyOldInterface $argument)', $function);
+ }
+ }
+
+ function testParameterCreationForTypeHinting() {
+ $reflection = new SimpleReflection('AnyOldTypeHintedClass');
+ $function = $reflection->getSignature('aMethod');
+ if (version_compare(phpversion(), '5.0.2', '<=')) {
+ $this->assertEqual('function amethod(AnyOldInterface $argument)', $function);
+ } else {
+ $this->assertEqual('function aMethod(AnyOldInterface $argument)', $function);
+ }
+ }
+
+ function testIssetFunctionSignature() {
+ $reflection = new SimpleReflection('AnyOldOverloadedClass');
+ $function = $reflection->getSignature('__isset');
+ $this->assertEqual('function __isset($key)', $function);
+ }
+
+ function testUnsetFunctionSignature() {
+ $reflection = new SimpleReflection('AnyOldOverloadedClass');
+ $function = $reflection->getSignature('__unset');
+ $this->assertEqual('function __unset($key)', $function);
+ }
+
+ function testProperlyReflectsTheFinalInterfaceWhenObjectImplementsAnExtendedInterface() {
+ $reflection = new SimpleReflection('AnyDescendentImplementation');
+ $interfaces = $reflection->getInterfaces();
+ $this->assertEqual(1, count($interfaces));
+ $this->assertEqual('AnyDescendentInterface', array_shift($interfaces));
+ }
+
+ function testCreatingSignatureForAbstractMethod() {
+ $reflection = new SimpleReflection('AnotherOldAbstractClass');
+ $this->assertEqual($reflection->getSignature('aMethod'), 'function aMethod(AnyOldInterface $argument)');
+ }
+
+ function testCanProperlyGenerateStaticMethodSignatures() {
+ $reflection = new SimpleReflection('AnyOldClassWithStaticMethods');
+ $this->assertEqual('static function aStatic()', $reflection->getSignature('aStatic'));
+ $this->assertEqual(
+ 'static function aStaticWithParameters($arg1, $arg2)',
+ $reflection->getSignature('aStaticWithParameters')
+ );
+ }
+}
+
+class TestOfReflectionWithTypeHints extends UnitTestCase {
+ function skip() {
+ $this->skipIf(version_compare(phpversion(), '5.1.0', '<'), 'Reflection with type hints only tested for PHP 5.1.0 and above');
+ }
+
+ function testParameterCreationForTypeHintingWithArray() {
+ eval('interface AnyOldArrayTypeHintedInterface {
+ function amethod(array $argument);
+ }
+ class AnyOldArrayTypeHintedClass implements AnyOldArrayTypeHintedInterface {
+ function amethod(array $argument) {}
+ }');
+ $reflection = new SimpleReflection('AnyOldArrayTypeHintedClass');
+ $function = $reflection->getSignature('amethod');
+ $this->assertEqual('function amethod(array $argument)', $function);
+ }
+}
+
+class TestOfAbstractsWithAbstractMethods extends UnitTestCase {
+ function testCanProperlyGenerateAbstractMethods() {
+ $reflection = new SimpleReflection('AnyOldAbstractClassWithAbstractMethods');
+ $this->assertEqual(
+ 'function anAbstract()',
+ $reflection->getSignature('anAbstract')
+ );
+ $this->assertEqual(
+ 'function anAbstractWithParameter($foo)',
+ $reflection->getSignature('anAbstractWithParameter')
+ );
+ $this->assertEqual(
+ 'function anAbstractWithMultipleParameters($foo, $bar)',
+ $reflection->getSignature('anAbstractWithMultipleParameters')
+ );
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/remote_test.php b/tests/simpletest/test/remote_test.php
new file mode 100644
index 0000000..5f3f96a
--- /dev/null
+++ b/tests/simpletest/test/remote_test.php
@@ -0,0 +1,19 @@
+add(new RemoteTestCase($test_url . '?xml=yes', $test_url . '?xml=yes&dry=yes'));
+if (SimpleReporter::inCli()) {
+ exit ($test->run(new TextReporter()) ? 0 : 1);
+}
+$test->run(new HtmlReporter());
diff --git a/tests/simpletest/test/shell_test.php b/tests/simpletest/test/shell_test.php
new file mode 100644
index 0000000..d1d769a
--- /dev/null
+++ b/tests/simpletest/test/shell_test.php
@@ -0,0 +1,38 @@
+assertIdentical($shell->execute('echo Hello'), 0);
+ $this->assertPattern('/Hello/', $shell->getOutput());
+ }
+
+ function testBadCommand() {
+ $shell = new SimpleShell();
+ $this->assertNotEqual($ret = $shell->execute('blurgh! 2>&1'), 0);
+ }
+}
+
+class TestOfShellTesterAndShell extends ShellTestCase {
+
+ function testEcho() {
+ $this->assertTrue($this->execute('echo Hello'));
+ $this->assertExitCode(0);
+ $this->assertoutput('Hello');
+ }
+
+ function testFileExistence() {
+ $this->assertFileExists(dirname(__FILE__) . '/all_tests.php');
+ $this->assertFileNotExists('wibble');
+ }
+
+ function testFilePatterns() {
+ $this->assertFilePattern('/all[_ ]tests/i', dirname(__FILE__) . '/all_tests.php');
+ $this->assertNoFilePattern('/sputnik/i', dirname(__FILE__) . '/all_tests.php');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/shell_tester_test.php b/tests/simpletest/test/shell_tester_test.php
new file mode 100644
index 0000000..b12c602
--- /dev/null
+++ b/tests/simpletest/test/shell_tester_test.php
@@ -0,0 +1,42 @@
+mock_shell;
+ }
+
+ function testGenericEquality() {
+ $this->assertEqual('a', 'a');
+ $this->assertNotEqual('a', 'A');
+ }
+
+ function testExitCode() {
+ $this->mock_shell = new MockSimpleShell();
+ $this->mock_shell->setReturnValue('execute', 0);
+ $this->mock_shell->expectOnce('execute', array('ls'));
+ $this->assertTrue($this->execute('ls'));
+ $this->assertExitCode(0);
+ }
+
+ function testOutput() {
+ $this->mock_shell = new MockSimpleShell();
+ $this->mock_shell->setReturnValue('execute', 0);
+ $this->mock_shell->setReturnValue('getOutput', "Line 1\nLine 2\n");
+ $this->assertOutput("Line 1\nLine 2\n");
+ }
+
+ function testOutputPatterns() {
+ $this->mock_shell = new MockSimpleShell();
+ $this->mock_shell->setReturnValue('execute', 0);
+ $this->mock_shell->setReturnValue('getOutput', "Line 1\nLine 2\n");
+ $this->assertOutputPattern('/line/i');
+ $this->assertNoOutputPattern('/line 2/');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/simpletest_test.php b/tests/simpletest/test/simpletest_test.php
new file mode 100644
index 0000000..daa65c6
--- /dev/null
+++ b/tests/simpletest/test/simpletest_test.php
@@ -0,0 +1,58 @@
+fail('Should be ignored');
+ }
+}
+
+class ShouldNeverBeRunEither extends ShouldNeverBeRun { }
+
+class TestOfStackTrace extends UnitTestCase {
+
+ function testCanFindAssertInTrace() {
+ $trace = new SimpleStackTrace(array('assert'));
+ $this->assertEqual(
+ $trace->traceMethod(array(array(
+ 'file' => '/my_test.php',
+ 'line' => 24,
+ 'function' => 'assertSomething'))),
+ ' at [/my_test.php line 24]');
+ }
+}
+
+class DummyResource { }
+
+class TestOfContext extends UnitTestCase {
+
+ function testCurrentContextIsUnique() {
+ $this->assertSame(
+ SimpleTest::getContext(),
+ SimpleTest::getContext());
+ }
+
+ function testContextHoldsCurrentTestCase() {
+ $context = SimpleTest::getContext();
+ $this->assertSame($this, $context->getTest());
+ }
+
+ function testResourceIsSingleInstanceWithContext() {
+ $context = new SimpleTestContext();
+ $this->assertSame(
+ $context->get('DummyResource'),
+ $context->get('DummyResource'));
+ }
+
+ function testClearingContextResetsResources() {
+ $context = new SimpleTestContext();
+ $resource = $context->get('DummyResource');
+ $context->clear();
+ $this->assertClone($resource, $context->get('DummyResource'));
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/site/file.html b/tests/simpletest/test/site/file.html
new file mode 100644
index 0000000..cc41aee
--- /dev/null
+++ b/tests/simpletest/test/site/file.html
@@ -0,0 +1,6 @@
+
+ Link to SimpleTest
+
+ Link to SimpleTest
+
+
\ No newline at end of file
diff --git a/tests/simpletest/test/socket_test.php b/tests/simpletest/test/socket_test.php
new file mode 100644
index 0000000..729adda
--- /dev/null
+++ b/tests/simpletest/test/socket_test.php
@@ -0,0 +1,25 @@
+assertFalse($error->isError());
+ $error->setError('Ouch');
+ $this->assertTrue($error->isError());
+ $this->assertEqual($error->getError(), 'Ouch');
+ }
+
+ function testClearingError() {
+ $error = new SimpleStickyError();
+ $error->setError('Ouch');
+ $this->assertTrue($error->isError());
+ $error->clearError();
+ $this->assertFalse($error->isError());
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/support/collector/collectable.1 b/tests/simpletest/test/support/collector/collectable.1
new file mode 100644
index 0000000..e69de29
diff --git a/tests/simpletest/test/support/collector/collectable.2 b/tests/simpletest/test/support/collector/collectable.2
new file mode 100644
index 0000000..e69de29
diff --git a/tests/simpletest/test/support/empty_test_file.php b/tests/simpletest/test/support/empty_test_file.php
new file mode 100644
index 0000000..31e3f7b
--- /dev/null
+++ b/tests/simpletest/test/support/empty_test_file.php
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/tests/simpletest/test/support/failing_test.php b/tests/simpletest/test/support/failing_test.php
new file mode 100644
index 0000000..30f0d75
--- /dev/null
+++ b/tests/simpletest/test/support/failing_test.php
@@ -0,0 +1,9 @@
+assertEqual(1,2);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/support/latin1_sample b/tests/simpletest/test/support/latin1_sample
new file mode 100644
index 0000000..1903525
--- /dev/null
+++ b/tests/simpletest/test/support/latin1_sample
@@ -0,0 +1 @@
+£¹²³¼½¾@¶øþðßæ«»¢µ
\ No newline at end of file
diff --git a/tests/simpletest/test/support/passing_test.php b/tests/simpletest/test/support/passing_test.php
new file mode 100644
index 0000000..b786321
--- /dev/null
+++ b/tests/simpletest/test/support/passing_test.php
@@ -0,0 +1,9 @@
+assertEqual(2,2);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/support/recorder_sample.php b/tests/simpletest/test/support/recorder_sample.php
new file mode 100644
index 0000000..4f157f6
--- /dev/null
+++ b/tests/simpletest/test/support/recorder_sample.php
@@ -0,0 +1,14 @@
+assertTrue(true);
+ }
+
+ function testFalseIsTrue() {
+ $this->assertFalse(true);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/support/spl_examples.php b/tests/simpletest/test/support/spl_examples.php
new file mode 100644
index 0000000..45add35
--- /dev/null
+++ b/tests/simpletest/test/support/spl_examples.php
@@ -0,0 +1,15 @@
+
\ No newline at end of file
diff --git a/tests/simpletest/test/support/supplementary_upload_sample.txt b/tests/simpletest/test/support/supplementary_upload_sample.txt
new file mode 100644
index 0000000..d8aa9e8
--- /dev/null
+++ b/tests/simpletest/test/support/supplementary_upload_sample.txt
@@ -0,0 +1 @@
+Some more text content
\ No newline at end of file
diff --git a/tests/simpletest/test/support/test1.php b/tests/simpletest/test/support/test1.php
new file mode 100644
index 0000000..b414586
--- /dev/null
+++ b/tests/simpletest/test/support/test1.php
@@ -0,0 +1,7 @@
+assertEqual(3,1+2, "pass1");
+ }
+}
+?>
diff --git a/tests/simpletest/test/support/upload_sample.txt b/tests/simpletest/test/support/upload_sample.txt
new file mode 100644
index 0000000..ec98d7c
--- /dev/null
+++ b/tests/simpletest/test/support/upload_sample.txt
@@ -0,0 +1 @@
+Sample for testing file upload
\ No newline at end of file
diff --git a/tests/simpletest/test/tag_test.php b/tests/simpletest/test/tag_test.php
new file mode 100644
index 0000000..5e8a377
--- /dev/null
+++ b/tests/simpletest/test/tag_test.php
@@ -0,0 +1,554 @@
+ '1', 'b' => ''));
+ $this->assertEqual($tag->getTagName(), 'title');
+ $this->assertIdentical($tag->getAttribute('a'), '1');
+ $this->assertIdentical($tag->getAttribute('b'), '');
+ $this->assertIdentical($tag->getAttribute('c'), false);
+ $this->assertIdentical($tag->getContent(), '');
+ }
+
+ function testTitleContent() {
+ $tag = new SimpleTitleTag(array());
+ $this->assertTrue($tag->expectEndTag());
+ $tag->addContent('Hello');
+ $tag->addContent('World');
+ $this->assertEqual($tag->getText(), 'HelloWorld');
+ }
+
+ function testMessyTitleContent() {
+ $tag = new SimpleTitleTag(array());
+ $this->assertTrue($tag->expectEndTag());
+ $tag->addContent('Hello');
+ $tag->addContent('World');
+ $this->assertEqual($tag->getText(), 'HelloWorld');
+ }
+
+ function testTagWithNoEnd() {
+ $tag = new SimpleTextTag(array());
+ $this->assertFalse($tag->expectEndTag());
+ }
+
+ function testAnchorHref() {
+ $tag = new SimpleAnchorTag(array('href' => 'http://here/'));
+ $this->assertEqual($tag->getHref(), 'http://here/');
+
+ $tag = new SimpleAnchorTag(array('href' => ''));
+ $this->assertIdentical($tag->getAttribute('href'), '');
+ $this->assertIdentical($tag->getHref(), '');
+
+ $tag = new SimpleAnchorTag(array());
+ $this->assertIdentical($tag->getAttribute('href'), false);
+ $this->assertIdentical($tag->getHref(), '');
+ }
+
+ function testIsIdMatchesIdAttribute() {
+ $tag = new SimpleAnchorTag(array('href' => 'http://here/', 'id' => 7));
+ $this->assertIdentical($tag->getAttribute('id'), '7');
+ $this->assertTrue($tag->isId(7));
+ }
+}
+
+class TestOfWidget extends UnitTestCase {
+
+ function testTextEmptyDefault() {
+ $tag = new SimpleTextTag(array('type' => 'text'));
+ $this->assertIdentical($tag->getDefault(), '');
+ $this->assertIdentical($tag->getValue(), '');
+ }
+
+ function testSettingOfExternalLabel() {
+ $tag = new SimpleTextTag(array('type' => 'text'));
+ $tag->setLabel('it');
+ $this->assertTrue($tag->isLabel('it'));
+ }
+
+ function testTextDefault() {
+ $tag = new SimpleTextTag(array('value' => 'aaa'));
+ $this->assertEqual($tag->getDefault(), 'aaa');
+ $this->assertEqual($tag->getValue(), 'aaa');
+ }
+
+ function testSettingTextValue() {
+ $tag = new SimpleTextTag(array('value' => 'aaa'));
+ $tag->setValue('bbb');
+ $this->assertEqual($tag->getValue(), 'bbb');
+ $tag->resetValue();
+ $this->assertEqual($tag->getValue(), 'aaa');
+ }
+
+ function testFailToSetHiddenValue() {
+ $tag = new SimpleTextTag(array('value' => 'aaa', 'type' => 'hidden'));
+ $this->assertFalse($tag->setValue('bbb'));
+ $this->assertEqual($tag->getValue(), 'aaa');
+ }
+
+ function testSubmitDefaults() {
+ $tag = new SimpleSubmitTag(array('type' => 'submit'));
+ $this->assertIdentical($tag->getName(), false);
+ $this->assertEqual($tag->getValue(), 'Submit');
+ $this->assertFalse($tag->setValue('Cannot set this'));
+ $this->assertEqual($tag->getValue(), 'Submit');
+ $this->assertEqual($tag->getLabel(), 'Submit');
+
+ $encoding = new MockSimpleMultipartEncoding();
+ $encoding->expectNever('add');
+ $tag->write($encoding);
+ }
+
+ function testPopulatedSubmit() {
+ $tag = new SimpleSubmitTag(
+ array('type' => 'submit', 'name' => 's', 'value' => 'Ok!'));
+ $this->assertEqual($tag->getName(), 's');
+ $this->assertEqual($tag->getValue(), 'Ok!');
+ $this->assertEqual($tag->getLabel(), 'Ok!');
+
+ $encoding = new MockSimpleMultipartEncoding();
+ $encoding->expectOnce('add', array('s', 'Ok!'));
+ $tag->write($encoding);
+ }
+
+ function testImageSubmit() {
+ $tag = new SimpleImageSubmitTag(
+ array('type' => 'image', 'name' => 's', 'alt' => 'Label'));
+ $this->assertEqual($tag->getName(), 's');
+ $this->assertEqual($tag->getLabel(), 'Label');
+
+ $encoding = new MockSimpleMultipartEncoding();
+ $encoding->expectAt(0, 'add', array('s.x', 20));
+ $encoding->expectAt(1, 'add', array('s.y', 30));
+ $tag->write($encoding, 20, 30);
+ }
+
+ function testImageSubmitTitlePreferredOverAltForLabel() {
+ $tag = new SimpleImageSubmitTag(
+ array('type' => 'image', 'name' => 's', 'alt' => 'Label', 'title' => 'Title'));
+ $this->assertEqual($tag->getLabel(), 'Title');
+ }
+
+ function testButton() {
+ $tag = new SimpleButtonTag(
+ array('type' => 'submit', 'name' => 's', 'value' => 'do'));
+ $tag->addContent('I am a button');
+ $this->assertEqual($tag->getName(), 's');
+ $this->assertEqual($tag->getValue(), 'do');
+ $this->assertEqual($tag->getLabel(), 'I am a button');
+
+ $encoding = new MockSimpleMultipartEncoding();
+ $encoding->expectOnce('add', array('s', 'do'));
+ $tag->write($encoding);
+ }
+}
+
+class TestOfTextArea extends UnitTestCase {
+
+ function testDefault() {
+ $tag = new SimpleTextAreaTag(array('name' => 'a'));
+ $tag->addContent('Some text');
+ $this->assertEqual($tag->getName(), 'a');
+ $this->assertEqual($tag->getDefault(), 'Some text');
+ }
+
+ function testWrapping() {
+ $tag = new SimpleTextAreaTag(array('cols' => '10', 'wrap' => 'physical'));
+ $tag->addContent("Lot's of text that should be wrapped");
+ $this->assertEqual(
+ $tag->getDefault(),
+ "Lot's of\r\ntext that\r\nshould be\r\nwrapped");
+ $tag->setValue("New long text\r\nwith two lines");
+ $this->assertEqual(
+ $tag->getValue(),
+ "New long\r\ntext\r\nwith two\r\nlines");
+ }
+
+ function testWrappingRemovesLeadingcariageReturn() {
+ $tag = new SimpleTextAreaTag(array('cols' => '20', 'wrap' => 'physical'));
+ $tag->addContent("\rStuff");
+ $this->assertEqual($tag->getDefault(), 'Stuff');
+ $tag->setValue("\nNew stuff\n");
+ $this->assertEqual($tag->getValue(), "New stuff\r\n");
+ }
+
+ function testBreaksAreNewlineAndCarriageReturn() {
+ $tag = new SimpleTextAreaTag(array('cols' => '10'));
+ $tag->addContent("Some\nText\rwith\r\nbreaks");
+ $this->assertEqual($tag->getValue(), "Some\r\nText\r\nwith\r\nbreaks");
+ }
+}
+
+class TestOfCheckbox extends UnitTestCase {
+
+ function testCanSetCheckboxToNamedValueWithBooleanTrue() {
+ $tag = new SimpleCheckboxTag(array('name' => 'a', 'value' => 'A'));
+ $this->assertEqual($tag->getValue(), false);
+ $tag->setValue(true);
+ $this->assertIdentical($tag->getValue(), 'A');
+ }
+}
+
+class TestOfSelection extends UnitTestCase {
+
+ function testEmpty() {
+ $tag = new SimpleSelectionTag(array('name' => 'a'));
+ $this->assertIdentical($tag->getValue(), '');
+ }
+
+ function testSingle() {
+ $tag = new SimpleSelectionTag(array('name' => 'a'));
+ $option = new SimpleOptionTag(array());
+ $option->addContent('AAA');
+ $tag->addTag($option);
+ $this->assertEqual($tag->getValue(), 'AAA');
+ }
+
+ function testSingleDefault() {
+ $tag = new SimpleSelectionTag(array('name' => 'a'));
+ $option = new SimpleOptionTag(array('selected' => ''));
+ $option->addContent('AAA');
+ $tag->addTag($option);
+ $this->assertEqual($tag->getValue(), 'AAA');
+ }
+
+ function testSingleMappedDefault() {
+ $tag = new SimpleSelectionTag(array('name' => 'a'));
+ $option = new SimpleOptionTag(array('selected' => '', 'value' => 'aaa'));
+ $option->addContent('AAA');
+ $tag->addTag($option);
+ $this->assertEqual($tag->getValue(), 'aaa');
+ }
+
+ function testStartsWithDefault() {
+ $tag = new SimpleSelectionTag(array('name' => 'a'));
+ $a = new SimpleOptionTag(array());
+ $a->addContent('AAA');
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array('selected' => ''));
+ $b->addContent('BBB');
+ $tag->addTag($b);
+ $c = new SimpleOptionTag(array());
+ $c->addContent('CCC');
+ $tag->addTag($c);
+ $this->assertEqual($tag->getValue(), 'BBB');
+ }
+
+ function testSettingOption() {
+ $tag = new SimpleSelectionTag(array('name' => 'a'));
+ $a = new SimpleOptionTag(array());
+ $a->addContent('AAA');
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array('selected' => ''));
+ $b->addContent('BBB');
+ $tag->addTag($b);
+ $c = new SimpleOptionTag(array());
+ $c->addContent('CCC');
+ $tag->setValue('AAA');
+ $this->assertEqual($tag->getValue(), 'AAA');
+ }
+
+ function testSettingMappedOption() {
+ $tag = new SimpleSelectionTag(array('name' => 'a'));
+ $a = new SimpleOptionTag(array('value' => 'aaa'));
+ $a->addContent('AAA');
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array('value' => 'bbb', 'selected' => ''));
+ $b->addContent('BBB');
+ $tag->addTag($b);
+ $c = new SimpleOptionTag(array('value' => 'ccc'));
+ $c->addContent('CCC');
+ $tag->addTag($c);
+ $tag->setValue('AAA');
+ $this->assertEqual($tag->getValue(), 'aaa');
+ $tag->setValue('ccc');
+ $this->assertEqual($tag->getValue(), 'ccc');
+ }
+
+ function testSelectionDespiteSpuriousWhitespace() {
+ $tag = new SimpleSelectionTag(array('name' => 'a'));
+ $a = new SimpleOptionTag(array());
+ $a->addContent(' AAA ');
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array('selected' => ''));
+ $b->addContent(' BBB ');
+ $tag->addTag($b);
+ $c = new SimpleOptionTag(array());
+ $c->addContent(' CCC ');
+ $tag->addTag($c);
+ $this->assertEqual($tag->getValue(), ' BBB ');
+ $tag->setValue('AAA');
+ $this->assertEqual($tag->getValue(), ' AAA ');
+ }
+
+ function testFailToSetIllegalOption() {
+ $tag = new SimpleSelectionTag(array('name' => 'a'));
+ $a = new SimpleOptionTag(array());
+ $a->addContent('AAA');
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array('selected' => ''));
+ $b->addContent('BBB');
+ $tag->addTag($b);
+ $c = new SimpleOptionTag(array());
+ $c->addContent('CCC');
+ $tag->addTag($c);
+ $this->assertFalse($tag->setValue('Not present'));
+ $this->assertEqual($tag->getValue(), 'BBB');
+ }
+
+ function testNastyOptionValuesThatLookLikeFalse() {
+ $tag = new SimpleSelectionTag(array('name' => 'a'));
+ $a = new SimpleOptionTag(array('value' => '1'));
+ $a->addContent('One');
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array('value' => '0'));
+ $b->addContent('Zero');
+ $tag->addTag($b);
+ $this->assertIdentical($tag->getValue(), '1');
+ $tag->setValue('Zero');
+ $this->assertIdentical($tag->getValue(), '0');
+ }
+
+ function testBlankOption() {
+ $tag = new SimpleSelectionTag(array('name' => 'A'));
+ $a = new SimpleOptionTag(array());
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array());
+ $b->addContent('b');
+ $tag->addTag($b);
+ $this->assertIdentical($tag->getValue(), '');
+ $tag->setValue('b');
+ $this->assertIdentical($tag->getValue(), 'b');
+ $tag->setValue('');
+ $this->assertIdentical($tag->getValue(), '');
+ }
+
+ function testMultipleDefaultWithNoSelections() {
+ $tag = new MultipleSelectionTag(array('name' => 'a', 'multiple' => ''));
+ $a = new SimpleOptionTag(array());
+ $a->addContent('AAA');
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array());
+ $b->addContent('BBB');
+ $tag->addTag($b);
+ $this->assertIdentical($tag->getDefault(), array());
+ $this->assertIdentical($tag->getValue(), array());
+ }
+
+ function testMultipleDefaultWithSelections() {
+ $tag = new MultipleSelectionTag(array('name' => 'a', 'multiple' => ''));
+ $a = new SimpleOptionTag(array('selected' => ''));
+ $a->addContent('AAA');
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array('selected' => ''));
+ $b->addContent('BBB');
+ $tag->addTag($b);
+ $this->assertIdentical($tag->getDefault(), array('AAA', 'BBB'));
+ $this->assertIdentical($tag->getValue(), array('AAA', 'BBB'));
+ }
+
+ function testSettingMultiple() {
+ $tag = new MultipleSelectionTag(array('name' => 'a', 'multiple' => ''));
+ $a = new SimpleOptionTag(array('selected' => ''));
+ $a->addContent('AAA');
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array());
+ $b->addContent('BBB');
+ $tag->addTag($b);
+ $c = new SimpleOptionTag(array('selected' => '', 'value' => 'ccc'));
+ $c->addContent('CCC');
+ $tag->addTag($c);
+ $this->assertIdentical($tag->getDefault(), array('AAA', 'ccc'));
+ $this->assertTrue($tag->setValue(array('BBB', 'ccc')));
+ $this->assertIdentical($tag->getValue(), array('BBB', 'ccc'));
+ $this->assertTrue($tag->setValue(array()));
+ $this->assertIdentical($tag->getValue(), array());
+ }
+
+ function testFailToSetIllegalOptionsInMultiple() {
+ $tag = new MultipleSelectionTag(array('name' => 'a', 'multiple' => ''));
+ $a = new SimpleOptionTag(array('selected' => ''));
+ $a->addContent('AAA');
+ $tag->addTag($a);
+ $b = new SimpleOptionTag(array());
+ $b->addContent('BBB');
+ $tag->addTag($b);
+ $this->assertFalse($tag->setValue(array('CCC')));
+ $this->assertTrue($tag->setValue(array('AAA', 'BBB')));
+ $this->assertFalse($tag->setValue(array('AAA', 'CCC')));
+ }
+}
+
+class TestOfRadioGroup extends UnitTestCase {
+
+ function testEmptyGroup() {
+ $group = new SimpleRadioGroup();
+ $this->assertIdentical($group->getDefault(), false);
+ $this->assertIdentical($group->getValue(), false);
+ $this->assertFalse($group->setValue('a'));
+ }
+
+ function testReadingSingleButtonGroup() {
+ $group = new SimpleRadioGroup();
+ $group->addWidget(new SimpleRadioButtonTag(
+ array('value' => 'A', 'checked' => '')));
+ $this->assertIdentical($group->getDefault(), 'A');
+ $this->assertIdentical($group->getValue(), 'A');
+ }
+
+ function testReadingMultipleButtonGroup() {
+ $group = new SimpleRadioGroup();
+ $group->addWidget(new SimpleRadioButtonTag(
+ array('value' => 'A')));
+ $group->addWidget(new SimpleRadioButtonTag(
+ array('value' => 'B', 'checked' => '')));
+ $this->assertIdentical($group->getDefault(), 'B');
+ $this->assertIdentical($group->getValue(), 'B');
+ }
+
+ function testFailToSetUnlistedValue() {
+ $group = new SimpleRadioGroup();
+ $group->addWidget(new SimpleRadioButtonTag(array('value' => 'z')));
+ $this->assertFalse($group->setValue('a'));
+ $this->assertIdentical($group->getValue(), false);
+ }
+
+ function testSettingNewValueClearsTheOldOne() {
+ $group = new SimpleRadioGroup();
+ $group->addWidget(new SimpleRadioButtonTag(
+ array('value' => 'A')));
+ $group->addWidget(new SimpleRadioButtonTag(
+ array('value' => 'B', 'checked' => '')));
+ $this->assertTrue($group->setValue('A'));
+ $this->assertIdentical($group->getValue(), 'A');
+ }
+
+ function testIsIdMatchesAnyWidgetInSet() {
+ $group = new SimpleRadioGroup();
+ $group->addWidget(new SimpleRadioButtonTag(
+ array('value' => 'A', 'id' => 'i1')));
+ $group->addWidget(new SimpleRadioButtonTag(
+ array('value' => 'B', 'id' => 'i2')));
+ $this->assertFalse($group->isId('i0'));
+ $this->assertTrue($group->isId('i1'));
+ $this->assertTrue($group->isId('i2'));
+ }
+
+ function testIsLabelMatchesAnyWidgetInSet() {
+ $group = new SimpleRadioGroup();
+ $button1 = new SimpleRadioButtonTag(array('value' => 'A'));
+ $button1->setLabel('one');
+ $group->addWidget($button1);
+ $button2 = new SimpleRadioButtonTag(array('value' => 'B'));
+ $button2->setLabel('two');
+ $group->addWidget($button2);
+ $this->assertFalse($group->isLabel('three'));
+ $this->assertTrue($group->isLabel('one'));
+ $this->assertTrue($group->isLabel('two'));
+ }
+}
+
+class TestOfTagGroup extends UnitTestCase {
+
+ function testReadingMultipleCheckboxGroup() {
+ $group = new SimpleCheckboxGroup();
+ $group->addWidget(new SimpleCheckboxTag(array('value' => 'A')));
+ $group->addWidget(new SimpleCheckboxTag(
+ array('value' => 'B', 'checked' => '')));
+ $this->assertIdentical($group->getDefault(), 'B');
+ $this->assertIdentical($group->getValue(), 'B');
+ }
+
+ function testReadingMultipleUncheckedItems() {
+ $group = new SimpleCheckboxGroup();
+ $group->addWidget(new SimpleCheckboxTag(array('value' => 'A')));
+ $group->addWidget(new SimpleCheckboxTag(array('value' => 'B')));
+ $this->assertIdentical($group->getDefault(), false);
+ $this->assertIdentical($group->getValue(), false);
+ }
+
+ function testReadingMultipleCheckedItems() {
+ $group = new SimpleCheckboxGroup();
+ $group->addWidget(new SimpleCheckboxTag(
+ array('value' => 'A', 'checked' => '')));
+ $group->addWidget(new SimpleCheckboxTag(
+ array('value' => 'B', 'checked' => '')));
+ $this->assertIdentical($group->getDefault(), array('A', 'B'));
+ $this->assertIdentical($group->getValue(), array('A', 'B'));
+ }
+
+ function testSettingSingleValue() {
+ $group = new SimpleCheckboxGroup();
+ $group->addWidget(new SimpleCheckboxTag(array('value' => 'A')));
+ $group->addWidget(new SimpleCheckboxTag(array('value' => 'B')));
+ $this->assertTrue($group->setValue('A'));
+ $this->assertIdentical($group->getValue(), 'A');
+ $this->assertTrue($group->setValue('B'));
+ $this->assertIdentical($group->getValue(), 'B');
+ }
+
+ function testSettingMultipleValues() {
+ $group = new SimpleCheckboxGroup();
+ $group->addWidget(new SimpleCheckboxTag(array('value' => 'A')));
+ $group->addWidget(new SimpleCheckboxTag(array('value' => 'B')));
+ $this->assertTrue($group->setValue(array('A', 'B')));
+ $this->assertIdentical($group->getValue(), array('A', 'B'));
+ }
+
+ function testSettingNoValue() {
+ $group = new SimpleCheckboxGroup();
+ $group->addWidget(new SimpleCheckboxTag(array('value' => 'A')));
+ $group->addWidget(new SimpleCheckboxTag(array('value' => 'B')));
+ $this->assertTrue($group->setValue(false));
+ $this->assertIdentical($group->getValue(), false);
+ }
+
+ function testIsIdMatchesAnyIdInSet() {
+ $group = new SimpleCheckboxGroup();
+ $group->addWidget(new SimpleCheckboxTag(array('id' => 1, 'value' => 'A')));
+ $group->addWidget(new SimpleCheckboxTag(array('id' => 2, 'value' => 'B')));
+ $this->assertFalse($group->isId(0));
+ $this->assertTrue($group->isId(1));
+ $this->assertTrue($group->isId(2));
+ }
+}
+
+class TestOfUploadWidget extends UnitTestCase {
+
+ function testValueIsFilePath() {
+ $upload = new SimpleUploadTag(array('name' => 'a'));
+ $upload->setValue(dirname(__FILE__) . '/support/upload_sample.txt');
+ $this->assertEqual($upload->getValue(), dirname(__FILE__) . '/support/upload_sample.txt');
+ }
+
+ function testSubmitsFileContents() {
+ $encoding = new MockSimpleMultipartEncoding();
+ $encoding->expectOnce('attach', array(
+ 'a',
+ 'Sample for testing file upload',
+ 'upload_sample.txt'));
+ $upload = new SimpleUploadTag(array('name' => 'a'));
+ $upload->setValue(dirname(__FILE__) . '/support/upload_sample.txt');
+ $upload->write($encoding);
+ }
+}
+
+class TestOfLabelTag extends UnitTestCase {
+
+ function testLabelShouldHaveAnEndTag() {
+ $label = new SimpleLabelTag(array());
+ $this->assertTrue($label->expectEndTag());
+ }
+
+ function testContentIsTextOnly() {
+ $label = new SimpleLabelTag(array());
+ $label->addContent('Here are words');
+ $this->assertEqual($label->getText(), 'Here are words');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/test_with_parse_error.php b/tests/simpletest/test/test_with_parse_error.php
new file mode 100644
index 0000000..41a5832
--- /dev/null
+++ b/tests/simpletest/test/test_with_parse_error.php
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/tests/simpletest/test/unit_tester_test.php b/tests/simpletest/test/unit_tester_test.php
new file mode 100644
index 0000000..ce9850f
--- /dev/null
+++ b/tests/simpletest/test/unit_tester_test.php
@@ -0,0 +1,61 @@
+assertTrue($this->assertTrue(true));
+ }
+
+ function testAssertFalseReturnsAssertionAsBoolean() {
+ $this->assertTrue($this->assertFalse(false));
+ }
+
+ function testAssertEqualReturnsAssertionAsBoolean() {
+ $this->assertTrue($this->assertEqual(5, 5));
+ }
+
+ function testAssertIdenticalReturnsAssertionAsBoolean() {
+ $this->assertTrue($this->assertIdentical(5, 5));
+ }
+
+ function testCoreAssertionsDoNotThrowErrors() {
+ $this->assertIsA($this, 'UnitTestCase');
+ $this->assertNotA($this, 'WebTestCase');
+ }
+
+ function testReferenceAssertionOnObjects() {
+ $a = new ReferenceForTesting();
+ $b = $a;
+ $this->assertSame($a, $b);
+ }
+
+ function testReferenceAssertionOnScalars() {
+ $a = 25;
+ $b = &$a;
+ $this->assertReference($a, $b);
+ }
+
+ function testCloneOnObjects() {
+ $a = new ReferenceForTesting();
+ $b = new ReferenceForTesting();
+ $this->assertClone($a, $b);
+ }
+
+ function TODO_testCloneOnScalars() {
+ $a = 25;
+ $b = 25;
+ $this->assertClone($a, $b);
+ }
+
+ function testCopyOnScalars() {
+ $a = 25;
+ $b = 25;
+ $this->assertCopy($a, $b);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/unit_tests.php b/tests/simpletest/test/unit_tests.php
new file mode 100644
index 0000000..9e62129
--- /dev/null
+++ b/tests/simpletest/test/unit_tests.php
@@ -0,0 +1,49 @@
+TestSuite('Unit tests');
+ $path = dirname(__FILE__);
+ $this->addFile($path . '/errors_test.php');
+ $this->addFile($path . '/exceptions_test.php');
+ $this->addFile($path . '/arguments_test.php');
+ $this->addFile($path . '/autorun_test.php');
+ $this->addFile($path . '/compatibility_test.php');
+ $this->addFile($path . '/simpletest_test.php');
+ $this->addFile($path . '/dumper_test.php');
+ $this->addFile($path . '/expectation_test.php');
+ $this->addFile($path . '/unit_tester_test.php');
+ $this->addFile($path . '/reflection_php5_test.php');
+ $this->addFile($path . '/mock_objects_test.php');
+ $this->addFile($path . '/interfaces_test.php');
+ $this->addFile($path . '/collector_test.php');
+ $this->addFile($path . '/recorder_test.php');
+ $this->addFile($path . '/adapter_test.php');
+ $this->addFile($path . '/socket_test.php');
+ $this->addFile($path . '/encoding_test.php');
+ $this->addFile($path . '/url_test.php');
+ $this->addFile($path . '/cookies_test.php');
+ $this->addFile($path . '/http_test.php');
+ $this->addFile($path . '/authentication_test.php');
+ $this->addFile($path . '/user_agent_test.php');
+ $this->addFile($path . '/php_parser_test.php');
+ $this->addFile($path . '/parsing_test.php');
+ $this->addFile($path . '/tag_test.php');
+ $this->addFile($path . '/form_test.php');
+ $this->addFile($path . '/page_test.php');
+ $this->addFile($path . '/frames_test.php');
+ $this->addFile($path . '/browser_test.php');
+ $this->addFile($path . '/web_tester_test.php');
+ $this->addFile($path . '/shell_tester_test.php');
+ $this->addFile($path . '/xml_test.php');
+ $this->addFile($path . '/../extensions/testdox/test.php');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/url_test.php b/tests/simpletest/test/url_test.php
new file mode 100644
index 0000000..80119af
--- /dev/null
+++ b/tests/simpletest/test/url_test.php
@@ -0,0 +1,515 @@
+assertEqual($url->getScheme(), '');
+ $this->assertEqual($url->getHost(), '');
+ $this->assertEqual($url->getScheme('http'), 'http');
+ $this->assertEqual($url->getHost('localhost'), 'localhost');
+ $this->assertEqual($url->getPath(), '');
+ }
+
+ function testBasicParsing() {
+ $url = new SimpleUrl('https://www.lastcraft.com/test/');
+ $this->assertEqual($url->getScheme(), 'https');
+ $this->assertEqual($url->getHost(), 'www.lastcraft.com');
+ $this->assertEqual($url->getPath(), '/test/');
+ }
+
+ function testRelativeUrls() {
+ $url = new SimpleUrl('../somewhere.php');
+ $this->assertEqual($url->getScheme(), false);
+ $this->assertEqual($url->getHost(), false);
+ $this->assertEqual($url->getPath(), '../somewhere.php');
+ }
+
+ function testParseBareParameter() {
+ $url = new SimpleUrl('?a');
+ $this->assertEqual($url->getPath(), '');
+ $this->assertEqual($url->getEncodedRequest(), '?a');
+ $url->addRequestParameter('x', 'X');
+ $this->assertEqual($url->getEncodedRequest(), '?a=&x=X');
+ }
+
+ function testParseEmptyParameter() {
+ $url = new SimpleUrl('?a=');
+ $this->assertEqual($url->getPath(), '');
+ $this->assertEqual($url->getEncodedRequest(), '?a=');
+ $url->addRequestParameter('x', 'X');
+ $this->assertEqual($url->getEncodedRequest(), '?a=&x=X');
+ }
+
+ function testParseParameterPair() {
+ $url = new SimpleUrl('?a=A');
+ $this->assertEqual($url->getPath(), '');
+ $this->assertEqual($url->getEncodedRequest(), '?a=A');
+ $url->addRequestParameter('x', 'X');
+ $this->assertEqual($url->getEncodedRequest(), '?a=A&x=X');
+ }
+
+ function testParseMultipleParameters() {
+ $url = new SimpleUrl('?a=A&b=B');
+ $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B');
+ $url->addRequestParameter('x', 'X');
+ $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B&x=X');
+ }
+
+ function testParsingParameterMixture() {
+ $url = new SimpleUrl('?a=A&b=&c');
+ $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c');
+ $url->addRequestParameter('x', 'X');
+ $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c=&x=X');
+ }
+
+ function testAddParametersFromScratch() {
+ $url = new SimpleUrl('');
+ $url->addRequestParameter('a', 'A');
+ $this->assertEqual($url->getEncodedRequest(), '?a=A');
+ $url->addRequestParameter('b', 'B');
+ $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B');
+ $url->addRequestParameter('a', 'aaa');
+ $this->assertEqual($url->getEncodedRequest(), '?a=A&b=B&a=aaa');
+ }
+
+ function testClearingParameters() {
+ $url = new SimpleUrl('');
+ $url->addRequestParameter('a', 'A');
+ $url->clearRequest();
+ $this->assertIdentical($url->getEncodedRequest(), '');
+ }
+
+ function testEncodingParameters() {
+ $url = new SimpleUrl('');
+ $url->addRequestParameter('a', '?!"\'#~@[]{}:;<>,./|$%^&*()_+-=');
+ $this->assertIdentical(
+ $request = $url->getEncodedRequest(),
+ '?a=%3F%21%22%27%23%7E%40%5B%5D%7B%7D%3A%3B%3C%3E%2C.%2F%7C%24%25%5E%26%2A%28%29_%2B-%3D');
+ }
+
+ function testDecodingParameters() {
+ $url = new SimpleUrl('?a=%3F%21%22%27%23%7E%40%5B%5D%7B%7D%3A%3B%3C%3E%2C.%2F%7C%24%25%5E%26%2A%28%29_%2B-%3D');
+ $this->assertEqual(
+ $url->getEncodedRequest(),
+ '?a=' . urlencode('?!"\'#~@[]{}:;<>,./|$%^&*()_+-='));
+ }
+
+ function testUrlInQueryDoesNotConfuseParsing() {
+ $url = new SimpleUrl('wibble/login.php?url=http://www.google.com/moo/');
+ $this->assertFalse($url->getScheme());
+ $this->assertFalse($url->getHost());
+ $this->assertEqual($url->getPath(), 'wibble/login.php');
+ $this->assertEqual($url->getEncodedRequest(), '?url=http://www.google.com/moo/');
+ }
+
+ function testSettingCordinates() {
+ $url = new SimpleUrl('');
+ $url->setCoordinates('32', '45');
+ $this->assertIdentical($url->getX(), 32);
+ $this->assertIdentical($url->getY(), 45);
+ $this->assertEqual($url->getEncodedRequest(), '');
+ }
+
+ function testParseCordinates() {
+ $url = new SimpleUrl('?32,45');
+ $this->assertIdentical($url->getX(), 32);
+ $this->assertIdentical($url->getY(), 45);
+ }
+
+ function testClearingCordinates() {
+ $url = new SimpleUrl('?32,45');
+ $url->setCoordinates();
+ $this->assertIdentical($url->getX(), false);
+ $this->assertIdentical($url->getY(), false);
+ }
+
+ function testParsingParameterCordinateMixture() {
+ $url = new SimpleUrl('?a=A&b=&c?32,45');
+ $this->assertIdentical($url->getX(), 32);
+ $this->assertIdentical($url->getY(), 45);
+ $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c');
+ }
+
+ function testParsingParameterWithBadCordinates() {
+ $url = new SimpleUrl('?a=A&b=&c?32');
+ $this->assertIdentical($url->getX(), false);
+ $this->assertIdentical($url->getY(), false);
+ $this->assertEqual($url->getEncodedRequest(), '?a=A&b=&c?32');
+ }
+
+ function testPageSplitting() {
+ $url = new SimpleUrl('./here/../there/somewhere.php');
+ $this->assertEqual($url->getPath(), './here/../there/somewhere.php');
+ $this->assertEqual($url->getPage(), 'somewhere.php');
+ $this->assertEqual($url->getBasePath(), './here/../there/');
+ }
+
+ function testAbsolutePathPageSplitting() {
+ $url = new SimpleUrl("http://host.com/here/there/somewhere.php");
+ $this->assertEqual($url->getPath(), "/here/there/somewhere.php");
+ $this->assertEqual($url->getPage(), "somewhere.php");
+ $this->assertEqual($url->getBasePath(), "/here/there/");
+ }
+
+ function testSplittingUrlWithNoPageGivesEmptyPage() {
+ $url = new SimpleUrl('/here/there/');
+ $this->assertEqual($url->getPath(), '/here/there/');
+ $this->assertEqual($url->getPage(), '');
+ $this->assertEqual($url->getBasePath(), '/here/there/');
+ }
+
+ function testPathNormalisation() {
+ $url = new SimpleUrl();
+ $this->assertEqual(
+ $url->normalisePath('https://host.com/I/am/here/../there/somewhere.php'),
+ 'https://host.com/I/am/there/somewhere.php');
+ }
+
+ // regression test for #1535407
+ function testPathNormalisationWithSinglePeriod() {
+ $url = new SimpleUrl();
+ $this->assertEqual(
+ $url->normalisePath('https://host.com/I/am/here/./../there/somewhere.php'),
+ 'https://host.com/I/am/there/somewhere.php');
+ }
+
+ // regression test for #1852413
+ function testHostnameExtractedFromUContainingAtSign() {
+ $url = new SimpleUrl("http://localhost/name@example.com");
+ $this->assertEqual($url->getScheme(), "http");
+ $this->assertEqual($url->getUsername(), "");
+ $this->assertEqual($url->getPassword(), "");
+ $this->assertEqual($url->getHost(), "localhost");
+ $this->assertEqual($url->getPath(), "/name@example.com");
+ }
+
+ function testHostnameInLocalhost() {
+ $url = new SimpleUrl("http://localhost/name/example.com");
+ $this->assertEqual($url->getScheme(), "http");
+ $this->assertEqual($url->getUsername(), "");
+ $this->assertEqual($url->getPassword(), "");
+ $this->assertEqual($url->getHost(), "localhost");
+ $this->assertEqual($url->getPath(), "/name/example.com");
+ }
+
+ function testUsernameAndPasswordAreUrlDecoded() {
+ $url = new SimpleUrl('http://' . urlencode('test@test') .
+ ':' . urlencode('$!�@*&%') . '@www.lastcraft.com');
+ $this->assertEqual($url->getUsername(), 'test@test');
+ $this->assertEqual($url->getPassword(), '$!�@*&%');
+ }
+
+ function testBlitz() {
+ $this->assertUrl(
+ "https://username:password@www.somewhere.com:243/this/that/here.php?a=1&b=2#anchor",
+ array("https", "username", "password", "www.somewhere.com", 243, "/this/that/here.php", "com", "?a=1&b=2", "anchor"),
+ array("a" => "1", "b" => "2"));
+ $this->assertUrl(
+ "username:password@www.somewhere.com/this/that/here.php?a=1",
+ array(false, "username", "password", "www.somewhere.com", false, "/this/that/here.php", "com", "?a=1", false),
+ array("a" => "1"));
+ $this->assertUrl(
+ "username:password@somewhere.com:243?1,2",
+ array(false, "username", "password", "somewhere.com", 243, "/", "com", "", false),
+ array(),
+ array(1, 2));
+ $this->assertUrl(
+ "https://www.somewhere.com",
+ array("https", false, false, "www.somewhere.com", false, "/", "com", "", false));
+ $this->assertUrl(
+ "username@www.somewhere.com:243#anchor",
+ array(false, "username", false, "www.somewhere.com", 243, "/", "com", "", "anchor"));
+ $this->assertUrl(
+ "/this/that/here.php?a=1&b=2?3,4",
+ array(false, false, false, false, false, "/this/that/here.php", false, "?a=1&b=2", false),
+ array("a" => "1", "b" => "2"),
+ array(3, 4));
+ $this->assertUrl(
+ "username@/here.php?a=1&b=2",
+ array(false, "username", false, false, false, "/here.php", false, "?a=1&b=2", false),
+ array("a" => "1", "b" => "2"));
+ }
+
+ function testAmbiguousHosts() {
+ $this->assertUrl(
+ "tigger",
+ array(false, false, false, false, false, "tigger", false, "", false));
+ $this->assertUrl(
+ "/tigger",
+ array(false, false, false, false, false, "/tigger", false, "", false));
+ $this->assertUrl(
+ "//tigger",
+ array(false, false, false, "tigger", false, "/", false, "", false));
+ $this->assertUrl(
+ "//tigger/",
+ array(false, false, false, "tigger", false, "/", false, "", false));
+ $this->assertUrl(
+ "tigger.com",
+ array(false, false, false, "tigger.com", false, "/", "com", "", false));
+ $this->assertUrl(
+ "me.net/tigger",
+ array(false, false, false, "me.net", false, "/tigger", "net", "", false));
+ }
+
+ function testAsString() {
+ $this->assertPreserved('https://www.here.com');
+ $this->assertPreserved('http://me:secret@www.here.com');
+ $this->assertPreserved('http://here/there');
+ $this->assertPreserved('http://here/there?a=A&b=B');
+ $this->assertPreserved('http://here/there?a=1&a=2');
+ $this->assertPreserved('http://here/there?a=1&a=2?9,8');
+ $this->assertPreserved('http://host?a=1&a=2');
+ $this->assertPreserved('http://host#stuff');
+ $this->assertPreserved('http://me:secret@www.here.com/a/b/c/here.html?a=A?7,6');
+ $this->assertPreserved('http://www.here.com/?a=A__b=B');
+ $this->assertPreserved('http://www.example.com:8080/');
+ }
+
+ function testUrlWithTwoSlashesInPath() {
+ $url = new SimpleUrl('/article/categoryedit/insert//');
+ $this->assertEqual($url->getPath(), '/article/categoryedit/insert//');
+ }
+
+ function testUrlWithRequestKeyEncoded() {
+ $url = new SimpleUrl('/?foo%5B1%5D=bar');
+ $this->assertEqual($url->getEncodedRequest(), '?foo%5B1%5D=bar');
+ $url->addRequestParameter('a[1]', 'b[]');
+ $this->assertEqual($url->getEncodedRequest(), '?foo%5B1%5D=bar&a%5B1%5D=b%5B%5D');
+
+ $url = new SimpleUrl('/');
+ $url->addRequestParameter('a[1]', 'b[]');
+ $this->assertEqual($url->getEncodedRequest(), '?a%5B1%5D=b%5B%5D');
+ }
+
+ function testUrlWithRequestKeyEncodedAndParamNamLookingLikePair() {
+ $url = new SimpleUrl('/');
+ $url->addRequestParameter('foo[]=bar', '');
+ $this->assertEqual($url->getEncodedRequest(), '?foo%5B%5D%3Dbar=');
+ $url = new SimpleUrl('/?foo%5B%5D%3Dbar=');
+ $this->assertEqual($url->getEncodedRequest(), '?foo%5B%5D%3Dbar=');
+ }
+
+ function assertUrl($raw, $parts, $params = false, $coords = false) {
+ if (! is_array($params)) {
+ $params = array();
+ }
+ $url = new SimpleUrl($raw);
+ $this->assertIdentical($url->getScheme(), $parts[0], "[$raw] scheme -> %s");
+ $this->assertIdentical($url->getUsername(), $parts[1], "[$raw] username -> %s");
+ $this->assertIdentical($url->getPassword(), $parts[2], "[$raw] password -> %s");
+ $this->assertIdentical($url->getHost(), $parts[3], "[$raw] host -> %s");
+ $this->assertIdentical($url->getPort(), $parts[4], "[$raw] port -> %s");
+ $this->assertIdentical($url->getPath(), $parts[5], "[$raw] path -> %s");
+ $this->assertIdentical($url->getTld(), $parts[6], "[$raw] tld -> %s");
+ $this->assertIdentical($url->getEncodedRequest(), $parts[7], "[$raw] encoded -> %s");
+ $this->assertIdentical($url->getFragment(), $parts[8], "[$raw] fragment -> %s");
+ if ($coords) {
+ $this->assertIdentical($url->getX(), $coords[0], "[$raw] x -> %s");
+ $this->assertIdentical($url->getY(), $coords[1], "[$raw] y -> %s");
+ }
+ }
+
+ function assertPreserved($string) {
+ $url = new SimpleUrl($string);
+ $this->assertEqual($url->asString(), $string);
+ }
+}
+
+class TestOfAbsoluteUrls extends UnitTestCase {
+
+ function testDirectoriesAfterFilename() {
+ $string = '../../index.php/foo/bar';
+ $url = new SimpleUrl($string);
+ $this->assertEqual($url->asString(), $string);
+
+ $absolute = $url->makeAbsolute('http://www.domain.com/some/path/');
+ $this->assertEqual($absolute->asString(), 'http://www.domain.com/index.php/foo/bar');
+ }
+
+ function testMakingAbsolute() {
+ $url = new SimpleUrl('../there/somewhere.php');
+ $this->assertEqual($url->getPath(), '../there/somewhere.php');
+ $absolute = $url->makeAbsolute('https://host.com:1234/I/am/here/');
+ $this->assertEqual($absolute->getScheme(), 'https');
+ $this->assertEqual($absolute->getHost(), 'host.com');
+ $this->assertEqual($absolute->getPort(), 1234);
+ $this->assertEqual($absolute->getPath(), '/I/am/there/somewhere.php');
+ }
+
+ function testMakingAnEmptyUrlAbsolute() {
+ $url = new SimpleUrl('');
+ $this->assertEqual($url->getPath(), '');
+ $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html');
+ $this->assertEqual($absolute->getScheme(), 'http');
+ $this->assertEqual($absolute->getHost(), 'host.com');
+ $this->assertEqual($absolute->getPath(), '/I/am/here/page.html');
+ }
+
+ function testMakingAnEmptyUrlAbsoluteWithMissingPageName() {
+ $url = new SimpleUrl('');
+ $this->assertEqual($url->getPath(), '');
+ $absolute = $url->makeAbsolute('http://host.com/I/am/here/');
+ $this->assertEqual($absolute->getScheme(), 'http');
+ $this->assertEqual($absolute->getHost(), 'host.com');
+ $this->assertEqual($absolute->getPath(), '/I/am/here/');
+ }
+
+ function testMakingAShortQueryUrlAbsolute() {
+ $url = new SimpleUrl('?a#b');
+ $this->assertEqual($url->getPath(), '');
+ $absolute = $url->makeAbsolute('http://host.com/I/am/here/');
+ $this->assertEqual($absolute->getScheme(), 'http');
+ $this->assertEqual($absolute->getHost(), 'host.com');
+ $this->assertEqual($absolute->getPath(), '/I/am/here/');
+ $this->assertEqual($absolute->getEncodedRequest(), '?a');
+ $this->assertEqual($absolute->getFragment(), 'b');
+ }
+
+ function testMakingADirectoryUrlAbsolute() {
+ $url = new SimpleUrl('hello/');
+ $this->assertEqual($url->getPath(), 'hello/');
+ $this->assertEqual($url->getBasePath(), 'hello/');
+ $this->assertEqual($url->getPage(), '');
+ $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html');
+ $this->assertEqual($absolute->getPath(), '/I/am/here/hello/');
+ }
+
+ function testMakingARootUrlAbsolute() {
+ $url = new SimpleUrl('/');
+ $this->assertEqual($url->getPath(), '/');
+ $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html');
+ $this->assertEqual($absolute->getPath(), '/');
+ }
+
+ function testMakingARootPageUrlAbsolute() {
+ $url = new SimpleUrl('/here.html');
+ $absolute = $url->makeAbsolute('http://host.com/I/am/here/page.html');
+ $this->assertEqual($absolute->getPath(), '/here.html');
+ }
+
+ function testCarryAuthenticationFromRootPage() {
+ $url = new SimpleUrl('here.html');
+ $absolute = $url->makeAbsolute('http://test:secret@host.com/');
+ $this->assertEqual($absolute->getPath(), '/here.html');
+ $this->assertEqual($absolute->getUsername(), 'test');
+ $this->assertEqual($absolute->getPassword(), 'secret');
+ }
+
+ function testMakingCoordinateUrlAbsolute() {
+ $url = new SimpleUrl('?1,2');
+ $this->assertEqual($url->getPath(), '');
+ $absolute = $url->makeAbsolute('http://host.com/I/am/here/');
+ $this->assertEqual($absolute->getScheme(), 'http');
+ $this->assertEqual($absolute->getHost(), 'host.com');
+ $this->assertEqual($absolute->getPath(), '/I/am/here/');
+ $this->assertEqual($absolute->getX(), 1);
+ $this->assertEqual($absolute->getY(), 2);
+ }
+
+ function testMakingAbsoluteAppendedPath() {
+ $url = new SimpleUrl('./there/somewhere.php');
+ $absolute = $url->makeAbsolute('https://host.com/here/');
+ $this->assertEqual($absolute->getPath(), '/here/there/somewhere.php');
+ }
+
+ function testMakingAbsoluteBadlyFormedAppendedPath() {
+ $url = new SimpleUrl('there/somewhere.php');
+ $absolute = $url->makeAbsolute('https://host.com/here/');
+ $this->assertEqual($absolute->getPath(), '/here/there/somewhere.php');
+ }
+
+ function testMakingAbsoluteHasNoEffectWhenAlreadyAbsolute() {
+ $url = new SimpleUrl('https://test:secret@www.lastcraft.com:321/stuff/?a=1#f');
+ $absolute = $url->makeAbsolute('http://host.com/here/');
+ $this->assertEqual($absolute->getScheme(), 'https');
+ $this->assertEqual($absolute->getUsername(), 'test');
+ $this->assertEqual($absolute->getPassword(), 'secret');
+ $this->assertEqual($absolute->getHost(), 'www.lastcraft.com');
+ $this->assertEqual($absolute->getPort(), 321);
+ $this->assertEqual($absolute->getPath(), '/stuff/');
+ $this->assertEqual($absolute->getEncodedRequest(), '?a=1');
+ $this->assertEqual($absolute->getFragment(), 'f');
+ }
+
+ function testMakingAbsoluteCarriesAuthenticationWhenAlreadyAbsolute() {
+ $url = new SimpleUrl('https://www.lastcraft.com');
+ $absolute = $url->makeAbsolute('http://test:secret@host.com/here/');
+ $this->assertEqual($absolute->getHost(), 'www.lastcraft.com');
+ $this->assertEqual($absolute->getUsername(), 'test');
+ $this->assertEqual($absolute->getPassword(), 'secret');
+ }
+
+ function testMakingHostOnlyAbsoluteDoesNotCarryAnyOtherInformation() {
+ $url = new SimpleUrl('http://www.lastcraft.com');
+ $absolute = $url->makeAbsolute('https://host.com:81/here/');
+ $this->assertEqual($absolute->getScheme(), 'http');
+ $this->assertEqual($absolute->getHost(), 'www.lastcraft.com');
+ $this->assertIdentical($absolute->getPort(), false);
+ $this->assertEqual($absolute->getPath(), '/');
+ }
+}
+
+class TestOfFrameUrl extends UnitTestCase {
+
+ function testTargetAttachment() {
+ $url = new SimpleUrl('http://www.site.com/home.html');
+ $this->assertIdentical($url->getTarget(), false);
+ $url->setTarget('A frame');
+ $this->assertIdentical($url->getTarget(), 'A frame');
+ }
+}
+
+/**
+ * @note Based off of http://www.mozilla.org/quality/networking/testing/filetests.html
+ */
+class TestOfFileUrl extends UnitTestCase {
+
+ function testMinimalUrl() {
+ $url = new SimpleUrl('file:///');
+ $this->assertEqual($url->getScheme(), 'file');
+ $this->assertIdentical($url->getHost(), false);
+ $this->assertEqual($url->getPath(), '/');
+ }
+
+ function testUnixUrl() {
+ $url = new SimpleUrl('file:///fileInRoot');
+ $this->assertEqual($url->getScheme(), 'file');
+ $this->assertIdentical($url->getHost(), false);
+ $this->assertEqual($url->getPath(), '/fileInRoot');
+ }
+
+ function testDOSVolumeUrl() {
+ $url = new SimpleUrl('file:///C:/config.sys');
+ $this->assertEqual($url->getScheme(), 'file');
+ $this->assertIdentical($url->getHost(), false);
+ $this->assertEqual($url->getPath(), '/C:/config.sys');
+ }
+
+ function testDOSVolumePromotion() {
+ $url = new SimpleUrl('file://C:/config.sys');
+ $this->assertEqual($url->getScheme(), 'file');
+ $this->assertIdentical($url->getHost(), false);
+ $this->assertEqual($url->getPath(), '/C:/config.sys');
+ }
+
+ function testDOSBackslashes() {
+ $url = new SimpleUrl('file:///C:\config.sys');
+ $this->assertEqual($url->getScheme(), 'file');
+ $this->assertIdentical($url->getHost(), false);
+ $this->assertEqual($url->getPath(), '/C:/config.sys');
+ }
+
+ function testDOSDirnameAfterFile() {
+ $url = new SimpleUrl('file://C:\config.sys');
+ $this->assertEqual($url->getScheme(), 'file');
+ $this->assertIdentical($url->getHost(), false);
+ $this->assertEqual($url->getPath(), '/C:/config.sys');
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/user_agent_test.php b/tests/simpletest/test/user_agent_test.php
new file mode 100644
index 0000000..030abeb
--- /dev/null
+++ b/tests/simpletest/test/user_agent_test.php
@@ -0,0 +1,348 @@
+headers = new MockSimpleHttpHeaders();
+ $this->response = new MockSimpleHttpResponse();
+ $this->response->setReturnValue('isError', false);
+ $this->response->returns('getHeaders', new MockSimpleHttpHeaders());
+ $this->request = new MockSimpleHttpRequest();
+ $this->request->returns('fetch', $this->response);
+ }
+
+ function testGetRequestWithoutIncidentGivesNoErrors() {
+ $url = new SimpleUrl('http://test:secret@this.com/page.html');
+ $url->addRequestParameters(array('a' => 'A', 'b' => 'B'));
+
+ $agent = new MockRequestUserAgent();
+ $agent->returns('createHttpRequest', $this->request);
+ $agent->__construct();
+
+ $response = $agent->fetchResponse(
+ new SimpleUrl('http://test:secret@this.com/page.html'),
+ new SimpleGetEncoding(array('a' => 'A', 'b' => 'B')));
+ $this->assertFalse($response->isError());
+ }
+}
+
+class TestOfAdditionalHeaders extends UnitTestCase {
+
+ function testAdditionalHeaderAddedToRequest() {
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnReference('getHeaders', new MockSimpleHttpHeaders());
+
+ $request = new MockSimpleHttpRequest();
+ $request->setReturnReference('fetch', $response);
+ $request->expectOnce(
+ 'addHeaderLine',
+ array('User-Agent: SimpleTest'));
+
+ $agent = new MockRequestUserAgent();
+ $agent->setReturnReference('createHttpRequest', $request);
+ $agent->__construct();
+ $agent->addHeader('User-Agent: SimpleTest');
+ $response = $agent->fetchResponse(new SimpleUrl('http://this.host/'), new SimpleGetEncoding());
+ }
+}
+
+class TestOfBrowserCookies extends UnitTestCase {
+
+ private function createStandardResponse() {
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue("isError", false);
+ $response->setReturnValue("getContent", "stuff");
+ $response->setReturnReference("getHeaders", new MockSimpleHttpHeaders());
+ return $response;
+ }
+
+ private function createCookieSite($header_lines) {
+ $headers = new SimpleHttpHeaders($header_lines);
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue("isError", false);
+ $response->setReturnReference("getHeaders", $headers);
+ $response->setReturnValue("getContent", "stuff");
+ $request = new MockSimpleHttpRequest();
+ $request->setReturnReference("fetch", $response);
+ return $request;
+ }
+
+ private function createMockedRequestUserAgent(&$request) {
+ $agent = new MockRequestUserAgent();
+ $agent->setReturnReference('createHttpRequest', $request);
+ $agent->__construct();
+ return $agent;
+ }
+
+ function testCookieJarIsSentToRequest() {
+ $jar = new SimpleCookieJar();
+ $jar->setCookie('a', 'A');
+
+ $request = new MockSimpleHttpRequest();
+ $request->returns('fetch', $this->createStandardResponse());
+ $request->expectOnce('readCookiesFromJar', array($jar, '*'));
+
+ $agent = $this->createMockedRequestUserAgent($request);
+ $agent->setCookie('a', 'A');
+ $agent->fetchResponse(
+ new SimpleUrl('http://this.com/this/path/page.html'),
+ new SimpleGetEncoding());
+ }
+
+ function testNoCookieJarIsSentToRequestWhenCookiesAreDisabled() {
+ $request = new MockSimpleHttpRequest();
+ $request->returns('fetch', $this->createStandardResponse());
+ $request->expectNever('readCookiesFromJar');
+
+ $agent = $this->createMockedRequestUserAgent($request);
+ $agent->setCookie('a', 'A');
+ $agent->ignoreCookies();
+ $agent->fetchResponse(
+ new SimpleUrl('http://this.com/this/path/page.html'),
+ new SimpleGetEncoding());
+ }
+
+ function testReadingNewCookie() {
+ $request = $this->createCookieSite('Set-cookie: a=AAAA');
+ $agent = $this->createMockedRequestUserAgent($request);
+ $agent->fetchResponse(
+ new SimpleUrl('http://this.com/this/path/page.html'),
+ new SimpleGetEncoding());
+ $this->assertEqual($agent->getCookieValue("this.com", "this/path/", "a"), "AAAA");
+ }
+
+ function testIgnoringNewCookieWhenCookiesDisabled() {
+ $request = $this->createCookieSite('Set-cookie: a=AAAA');
+ $agent = $this->createMockedRequestUserAgent($request);
+ $agent->ignoreCookies();
+ $agent->fetchResponse(
+ new SimpleUrl('http://this.com/this/path/page.html'),
+ new SimpleGetEncoding());
+ $this->assertIdentical($agent->getCookieValue("this.com", "this/path/", "a"), false);
+ }
+
+ function testOverwriteCookieThatAlreadyExists() {
+ $request = $this->createCookieSite('Set-cookie: a=AAAA');
+ $agent = $this->createMockedRequestUserAgent($request);
+ $agent->setCookie('a', 'A');
+ $agent->fetchResponse(
+ new SimpleUrl('http://this.com/this/path/page.html'),
+ new SimpleGetEncoding());
+ $this->assertEqual($agent->getCookieValue("this.com", "this/path/", "a"), "AAAA");
+ }
+
+ function testClearCookieBySettingExpiry() {
+ $request = $this->createCookieSite('Set-cookie: a=b');
+ $agent = $this->createMockedRequestUserAgent($request);
+
+ $agent->setCookie("a", "A", "this/path/", "Wed, 25-Dec-02 04:24:21 GMT");
+ $agent->fetchResponse(
+ new SimpleUrl('http://this.com/this/path/page.html'),
+ new SimpleGetEncoding());
+ $this->assertIdentical(
+ $agent->getCookieValue("this.com", "this/path/", "a"),
+ "b");
+ $agent->restart("Wed, 25-Dec-02 04:24:20 GMT");
+ $this->assertIdentical(
+ $agent->getCookieValue("this.com", "this/path/", "a"),
+ false);
+ }
+
+ function testAgeingAndClearing() {
+ $request = $this->createCookieSite('Set-cookie: a=A; expires=Wed, 25-Dec-02 04:24:21 GMT; path=/this/path');
+ $agent = $this->createMockedRequestUserAgent($request);
+
+ $agent->fetchResponse(
+ new SimpleUrl('http://this.com/this/path/page.html'),
+ new SimpleGetEncoding());
+ $agent->restart("Wed, 25-Dec-02 04:24:20 GMT");
+ $this->assertIdentical(
+ $agent->getCookieValue("this.com", "this/path/", "a"),
+ "A");
+ $agent->ageCookies(2);
+ $agent->restart("Wed, 25-Dec-02 04:24:20 GMT");
+ $this->assertIdentical(
+ $agent->getCookieValue("this.com", "this/path/", "a"),
+ false);
+ }
+
+ function testReadingIncomingAndSettingNewCookies() {
+ $request = $this->createCookieSite('Set-cookie: a=AAA');
+ $agent = $this->createMockedRequestUserAgent($request);
+
+ $this->assertNull($agent->getBaseCookieValue("a", false));
+ $agent->fetchResponse(
+ new SimpleUrl('http://this.com/this/path/page.html'),
+ new SimpleGetEncoding());
+ $agent->setCookie("b", "BBB", "this.com", "this/path/");
+ $this->assertEqual(
+ $agent->getBaseCookieValue("a", new SimpleUrl('http://this.com/this/path/page.html')),
+ "AAA");
+ $this->assertEqual(
+ $agent->getBaseCookieValue("b", new SimpleUrl('http://this.com/this/path/page.html')),
+ "BBB");
+ }
+}
+
+class TestOfHttpRedirects extends UnitTestCase {
+
+ function createRedirect($content, $redirect) {
+ $headers = new MockSimpleHttpHeaders();
+ $headers->setReturnValue('isRedirect', (boolean)$redirect);
+ $headers->setReturnValue('getLocation', $redirect);
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('getContent', $content);
+ $response->setReturnReference('getHeaders', $headers);
+ $request = new MockSimpleHttpRequest();
+ $request->setReturnReference('fetch', $response);
+ return $request;
+ }
+
+ function testDisabledRedirects() {
+ $agent = new MockRequestUserAgent();
+ $agent->returns(
+ 'createHttpRequest',
+ $this->createRedirect('stuff', 'there.html'));
+ $agent->expectOnce('createHttpRequest');
+ $agent->__construct();
+ $agent->setMaximumRedirects(0);
+ $response = $agent->fetchResponse(new SimpleUrl('here.html'), new SimpleGetEncoding());
+ $this->assertEqual($response->getContent(), 'stuff');
+ }
+
+ function testSingleRedirect() {
+ $agent = new MockRequestUserAgent();
+ $agent->returnsAt(
+ 0,
+ 'createHttpRequest',
+ $this->createRedirect('first', 'two.html'));
+ $agent->returnsAt(
+ 1,
+ 'createHttpRequest',
+ $this->createRedirect('second', 'three.html'));
+ $agent->expectCallCount('createHttpRequest', 2);
+ $agent->__construct();
+
+ $agent->setMaximumRedirects(1);
+ $response = $agent->fetchResponse(new SimpleUrl('one.html'), new SimpleGetEncoding());
+ $this->assertEqual($response->getContent(), 'second');
+ }
+
+ function testDoubleRedirect() {
+ $agent = new MockRequestUserAgent();
+ $agent->returnsAt(
+ 0,
+ 'createHttpRequest',
+ $this->createRedirect('first', 'two.html'));
+ $agent->returnsAt(
+ 1,
+ 'createHttpRequest',
+ $this->createRedirect('second', 'three.html'));
+ $agent->returnsAt(
+ 2,
+ 'createHttpRequest',
+ $this->createRedirect('third', 'four.html'));
+ $agent->expectCallCount('createHttpRequest', 3);
+ $agent->__construct();
+
+ $agent->setMaximumRedirects(2);
+ $response = $agent->fetchResponse(new SimpleUrl('one.html'), new SimpleGetEncoding());
+ $this->assertEqual($response->getContent(), 'third');
+ }
+
+ function testSuccessAfterRedirect() {
+ $agent = new MockRequestUserAgent();
+ $agent->returnsAt(
+ 0,
+ 'createHttpRequest',
+ $this->createRedirect('first', 'two.html'));
+ $agent->returnsAt(
+ 1,
+ 'createHttpRequest',
+ $this->createRedirect('second', false));
+ $agent->returnsAt(
+ 2,
+ 'createHttpRequest',
+ $this->createRedirect('third', 'four.html'));
+ $agent->expectCallCount('createHttpRequest', 2);
+ $agent->__construct();
+
+ $agent->setMaximumRedirects(2);
+ $response = $agent->fetchResponse(new SimpleUrl('one.html'), new SimpleGetEncoding());
+ $this->assertEqual($response->getContent(), 'second');
+ }
+
+ function testRedirectChangesPostToGet() {
+ $agent = new MockRequestUserAgent();
+ $agent->returnsAt(
+ 0,
+ 'createHttpRequest',
+ $this->createRedirect('first', 'two.html'));
+ $agent->expectAt(0, 'createHttpRequest', array('*', new IsAExpectation('SimplePostEncoding')));
+ $agent->returnsAt(
+ 1,
+ 'createHttpRequest',
+ $this->createRedirect('second', 'three.html'));
+ $agent->expectAt(1, 'createHttpRequest', array('*', new IsAExpectation('SimpleGetEncoding')));
+ $agent->expectCallCount('createHttpRequest', 2);
+ $agent->__construct();
+ $agent->setMaximumRedirects(1);
+ $response = $agent->fetchResponse(new SimpleUrl('one.html'), new SimplePostEncoding());
+ }
+}
+
+class TestOfBadHosts extends UnitTestCase {
+
+ private function createSimulatedBadHost() {
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnValue('isError', true);
+ $response->setReturnValue('getError', 'Bad socket');
+ $response->setReturnValue('getContent', false);
+ $request = new MockSimpleHttpRequest();
+ $request->setReturnReference('fetch', $response);
+ return $request;
+ }
+
+ function testUntestedHost() {
+ $request = $this->createSimulatedBadHost();
+ $agent = new MockRequestUserAgent();
+ $agent->setReturnReference('createHttpRequest', $request);
+ $agent->__construct();
+ $response = $agent->fetchResponse(
+ new SimpleUrl('http://this.host/this/path/page.html'),
+ new SimpleGetEncoding());
+ $this->assertTrue($response->isError());
+ }
+}
+
+class TestOfAuthorisation extends UnitTestCase {
+
+ function testAuthenticateHeaderAdded() {
+ $response = new MockSimpleHttpResponse();
+ $response->setReturnReference('getHeaders', new MockSimpleHttpHeaders());
+
+ $request = new MockSimpleHttpRequest();
+ $request->returns('fetch', $response);
+ $request->expectOnce(
+ 'addHeaderLine',
+ array('Authorization: Basic ' . base64_encode('test:secret')));
+
+ $agent = new MockRequestUserAgent();
+ $agent->returns('createHttpRequest', $request);
+ $agent->__construct();
+ $response = $agent->fetchResponse(
+ new SimpleUrl('http://test:secret@this.host'),
+ new SimpleGetEncoding());
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/visual_test.php b/tests/simpletest/test/visual_test.php
new file mode 100644
index 0000000..6b9d085
--- /dev/null
+++ b/tests/simpletest/test/visual_test.php
@@ -0,0 +1,495 @@
+a = $a;
+ }
+}
+
+class PassingUnitTestCaseOutput extends UnitTestCase {
+
+ function testOfResults() {
+ $this->pass('Pass');
+ }
+
+ function testTrue() {
+ $this->assertTrue(true);
+ }
+
+ function testFalse() {
+ $this->assertFalse(false);
+ }
+
+ function testExpectation() {
+ $expectation = &new EqualExpectation(25, 'My expectation message: %s');
+ $this->assert($expectation, 25, 'My assert message : %s');
+ }
+
+ function testNull() {
+ $this->assertNull(null, "%s -> Pass");
+ $this->assertNotNull(false, "%s -> Pass");
+ }
+
+ function testType() {
+ $this->assertIsA("hello", "string", "%s -> Pass");
+ $this->assertIsA($this, "PassingUnitTestCaseOutput", "%s -> Pass");
+ $this->assertIsA($this, "UnitTestCase", "%s -> Pass");
+ }
+
+ function testTypeEquality() {
+ $this->assertEqual("0", 0, "%s -> Pass");
+ }
+
+ function testNullEquality() {
+ $this->assertNotEqual(null, 1, "%s -> Pass");
+ $this->assertNotEqual(1, null, "%s -> Pass");
+ }
+
+ function testIntegerEquality() {
+ $this->assertNotEqual(1, 2, "%s -> Pass");
+ }
+
+ function testStringEquality() {
+ $this->assertEqual("a", "a", "%s -> Pass");
+ $this->assertNotEqual("aa", "ab", "%s -> Pass");
+ }
+
+ function testHashEquality() {
+ $this->assertEqual(array("a" => "A", "b" => "B"), array("b" => "B", "a" => "A"), "%s -> Pass");
+ }
+
+ function testWithin() {
+ $this->assertWithinMargin(5, 5.4, 0.5, "%s -> Pass");
+ }
+
+ function testOutside() {
+ $this->assertOutsideMargin(5, 5.6, 0.5, "%s -> Pass");
+ }
+
+ function testStringIdentity() {
+ $a = "fred";
+ $b = $a;
+ $this->assertIdentical($a, $b, "%s -> Pass");
+ }
+
+ function testTypeIdentity() {
+ $a = "0";
+ $b = 0;
+ $this->assertNotIdentical($a, $b, "%s -> Pass");
+ }
+
+ function testNullIdentity() {
+ $this->assertNotIdentical(null, 1, "%s -> Pass");
+ $this->assertNotIdentical(1, null, "%s -> Pass");
+ }
+
+ function testHashIdentity() {
+ }
+
+ function testObjectEquality() {
+ $this->assertEqual(new TestDisplayClass(4), new TestDisplayClass(4), "%s -> Pass");
+ $this->assertNotEqual(new TestDisplayClass(4), new TestDisplayClass(5), "%s -> Pass");
+ }
+
+ function testObjectIndentity() {
+ $this->assertIdentical(new TestDisplayClass(false), new TestDisplayClass(false), "%s -> Pass");
+ $this->assertNotIdentical(new TestDisplayClass(false), new TestDisplayClass(0), "%s -> Pass");
+ }
+
+ function testReference() {
+ $a = "fred";
+ $b = &$a;
+ $this->assertReference($a, $b, "%s -> Pass");
+ }
+
+ function testCloneOnDifferentObjects() {
+ $a = "fred";
+ $b = $a;
+ $c = "Hello";
+ $this->assertClone($a, $b, "%s -> Pass");
+ }
+
+ function testPatterns() {
+ $this->assertPattern('/hello/i', "Hello there", "%s -> Pass");
+ $this->assertNoPattern('/hello/', "Hello there", "%s -> Pass");
+ }
+
+ function testLongStrings() {
+ $text = "";
+ for ($i = 0; $i < 10; $i++) {
+ $text .= "0123456789";
+ }
+ $this->assertEqual($text, $text);
+ }
+}
+
+class FailingUnitTestCaseOutput extends UnitTestCase {
+
+ function testOfResults() {
+ $this->fail('Fail'); // Fail.
+ }
+
+ function testTrue() {
+ $this->assertTrue(false); // Fail.
+ }
+
+ function testFalse() {
+ $this->assertFalse(true); // Fail.
+ }
+
+ function testExpectation() {
+ $expectation = &new EqualExpectation(25, 'My expectation message: %s');
+ $this->assert($expectation, 24, 'My assert message : %s'); // Fail.
+ }
+
+ function testNull() {
+ $this->assertNull(false, "%s -> Fail"); // Fail.
+ $this->assertNotNull(null, "%s -> Fail"); // Fail.
+ }
+
+ function testType() {
+ $this->assertIsA(14, "string", "%s -> Fail"); // Fail.
+ $this->assertIsA(14, "TestOfUnitTestCaseOutput", "%s -> Fail"); // Fail.
+ $this->assertIsA($this, "TestReporter", "%s -> Fail"); // Fail.
+ }
+
+ function testTypeEquality() {
+ $this->assertNotEqual("0", 0, "%s -> Fail"); // Fail.
+ }
+
+ function testNullEquality() {
+ $this->assertEqual(null, 1, "%s -> Fail"); // Fail.
+ $this->assertEqual(1, null, "%s -> Fail"); // Fail.
+ }
+
+ function testIntegerEquality() {
+ $this->assertEqual(1, 2, "%s -> Fail"); // Fail.
+ }
+
+ function testStringEquality() {
+ $this->assertNotEqual("a", "a", "%s -> Fail"); // Fail.
+ $this->assertEqual("aa", "ab", "%s -> Fail"); // Fail.
+ }
+
+ function testHashEquality() {
+ $this->assertEqual(array("a" => "A", "b" => "B"), array("b" => "B", "a" => "Z"), "%s -> Fail");
+ }
+
+ function testWithin() {
+ $this->assertWithinMargin(5, 5.6, 0.5, "%s -> Fail"); // Fail.
+ }
+
+ function testOutside() {
+ $this->assertOutsideMargin(5, 5.4, 0.5, "%s -> Fail"); // Fail.
+ }
+
+ function testStringIdentity() {
+ $a = "fred";
+ $b = $a;
+ $this->assertNotIdentical($a, $b, "%s -> Fail"); // Fail.
+ }
+
+ function testTypeIdentity() {
+ $a = "0";
+ $b = 0;
+ $this->assertIdentical($a, $b, "%s -> Fail"); // Fail.
+ }
+
+ function testNullIdentity() {
+ $this->assertIdentical(null, 1, "%s -> Fail"); // Fail.
+ $this->assertIdentical(1, null, "%s -> Fail"); // Fail.
+ }
+
+ function testHashIdentity() {
+ $this->assertIdentical(array("a" => "A", "b" => "B"), array("b" => "B", "a" => "A"), "%s -> fail"); // Fail.
+ }
+
+ function testObjectEquality() {
+ $this->assertNotEqual(new TestDisplayClass(4), new TestDisplayClass(4), "%s -> Fail"); // Fail.
+ $this->assertEqual(new TestDisplayClass(4), new TestDisplayClass(5), "%s -> Fail"); // Fail.
+ }
+
+ function testObjectIndentity() {
+ $this->assertNotIdentical(new TestDisplayClass(false), new TestDisplayClass(false), "%s -> Fail"); // Fail.
+ $this->assertIdentical(new TestDisplayClass(false), new TestDisplayClass(0), "%s -> Fail"); // Fail.
+ }
+
+ function testReference() {
+ $a = "fred";
+ $b = &$a;
+ $this->assertClone($a, $b, "%s -> Fail"); // Fail.
+ }
+
+ function testCloneOnDifferentObjects() {
+ $a = "fred";
+ $b = $a;
+ $c = "Hello";
+ $this->assertClone($a, $c, "%s -> Fail"); // Fail.
+ }
+
+ function testPatterns() {
+ $this->assertPattern('/hello/', "Hello there", "%s -> Fail"); // Fail.
+ $this->assertNoPattern('/hello/i', "Hello there", "%s -> Fail"); // Fail.
+ }
+
+ function testLongStrings() {
+ $text = "";
+ for ($i = 0; $i < 10; $i++) {
+ $text .= "0123456789";
+ }
+ $this->assertEqual($text . $text, $text . "a" . $text); // Fail.
+ }
+}
+
+class Dummy {
+ function Dummy() {
+ }
+
+ function a() {
+ }
+}
+Mock::generate('Dummy');
+
+class TestOfMockObjectsOutput extends UnitTestCase {
+
+ function testCallCounts() {
+ $dummy = &new MockDummy();
+ $dummy->expectCallCount('a', 1, 'My message: %s');
+ $dummy->a();
+ $dummy->a();
+ }
+
+ function testMinimumCallCounts() {
+ $dummy = &new MockDummy();
+ $dummy->expectMinimumCallCount('a', 2, 'My message: %s');
+ $dummy->a();
+ $dummy->a();
+ }
+
+ function testEmptyMatching() {
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array());
+ $dummy->a();
+ $dummy->a(null); // Fail.
+ }
+
+ function testEmptyMatchingWithCustomMessage() {
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array(), 'My expectation message: %s');
+ $dummy->a();
+ $dummy->a(null); // Fail.
+ }
+
+ function testNullMatching() {
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array(null));
+ $dummy->a(null);
+ $dummy->a(); // Fail.
+ }
+
+ function testBooleanMatching() {
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array(true, false));
+ $dummy->a(true, false);
+ $dummy->a(true, true); // Fail.
+ }
+
+ function testIntegerMatching() {
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array(32, 33));
+ $dummy->a(32, 33);
+ $dummy->a(32, 34); // Fail.
+ }
+
+ function testFloatMatching() {
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array(3.2, 3.3));
+ $dummy->a(3.2, 3.3);
+ $dummy->a(3.2, 3.4); // Fail.
+ }
+
+ function testStringMatching() {
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array('32', '33'));
+ $dummy->a('32', '33');
+ $dummy->a('32', '34'); // Fail.
+ }
+
+ function testEmptyMatchingWithCustomExpectationMessage() {
+ $dummy = &new MockDummy();
+ $dummy->expect(
+ 'a',
+ array(new EqualExpectation('A', 'My part expectation message: %s')),
+ 'My expectation message: %s');
+ $dummy->a('A');
+ $dummy->a('B'); // Fail.
+ }
+
+ function testArrayMatching() {
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array(array(32), array(33)));
+ $dummy->a(array(32), array(33));
+ $dummy->a(array(32), array('33')); // Fail.
+ }
+
+ function testObjectMatching() {
+ $a = new Dummy();
+ $a->a = 'a';
+ $b = new Dummy();
+ $b->b = 'b';
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array($a, $b));
+ $dummy->a($a, $b);
+ $dummy->a($a, $a); // Fail.
+ }
+
+ function testBigList() {
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array(false, 0, 1, 1.0));
+ $dummy->a(false, 0, 1, 1.0);
+ $dummy->a(true, false, 2, 2.0); // Fail.
+ }
+}
+
+class TestOfPastBugs extends UnitTestCase {
+
+ function testMixedTypes() {
+ $this->assertEqual(array(), null, "%s -> Pass");
+ $this->assertIdentical(array(), null, "%s -> Fail"); // Fail.
+ }
+
+ function testMockWildcards() {
+ $dummy = &new MockDummy();
+ $dummy->expect('a', array('*', array(33)));
+ $dummy->a(array(32), array(33));
+ $dummy->a(array(32), array('33')); // Fail.
+ }
+}
+
+class TestOfVisualShell extends ShellTestCase {
+
+ function testDump() {
+ $this->execute('ls');
+ $this->dumpOutput();
+ $this->execute('dir');
+ $this->dumpOutput();
+ }
+
+ function testDumpOfList() {
+ $this->execute('ls');
+ $this->dump($this->getOutputAsList());
+ }
+}
+
+class PassesAsWellReporter extends HtmlReporter {
+
+ protected function getCss() {
+ return parent::getCss() . ' .pass { color: darkgreen; }';
+ }
+
+ function paintPass($message) {
+ parent::paintPass($message);
+ print "Pass: ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ print " -> " . htmlentities($message) . "
\n";
+ }
+
+ function paintSignal($type, &$payload) {
+ print "$type: ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ print " -> " . htmlentities(serialize($payload)) . "
\n";
+ }
+}
+
+class TestOfSkippingNoMatterWhat extends UnitTestCase {
+ function skip() {
+ $this->skipIf(true, 'Always skipped -> %s');
+ }
+
+ function testFail() {
+ $this->fail('This really shouldn\'t have happened');
+ }
+}
+
+class TestOfSkippingOrElse extends UnitTestCase {
+ function skip() {
+ $this->skipUnless(false, 'Always skipped -> %s');
+ }
+
+ function testFail() {
+ $this->fail('This really shouldn\'t have happened');
+ }
+}
+
+class TestOfSkippingTwiceOver extends UnitTestCase {
+ function skip() {
+ $this->skipIf(true, 'First reason -> %s');
+ $this->skipIf(true, 'Second reason -> %s');
+ }
+
+ function testFail() {
+ $this->fail('This really shouldn\'t have happened');
+ }
+}
+
+class TestThatShouldNotBeSkipped extends UnitTestCase {
+ function skip() {
+ $this->skipIf(false);
+ $this->skipUnless(true);
+ }
+
+ function testFail() {
+ $this->fail('We should see this message');
+ }
+
+ function testPass() {
+ $this->pass('We should see this message');
+ }
+}
+
+$test = &new TestSuite('Visual test with 46 passes, 47 fails and 0 exceptions');
+$test->add(new PassingUnitTestCaseOutput());
+$test->add(new FailingUnitTestCaseOutput());
+$test->add(new TestOfMockObjectsOutput());
+$test->add(new TestOfPastBugs());
+$test->add(new TestOfVisualShell());
+$test->add(new TestOfSkippingNoMatterWhat());
+$test->add(new TestOfSkippingOrElse());
+$test->add(new TestOfSkippingTwiceOver());
+$test->add(new TestThatShouldNotBeSkipped());
+
+if (isset($_GET['xml']) || in_array('xml', (isset($argv) ? $argv : array()))) {
+ $reporter = new XmlReporter();
+} elseif (TextReporter::inCli()) {
+ $reporter = new TextReporter();
+} else {
+ $reporter = new PassesAsWellReporter();
+}
+if (isset($_GET['dry']) || in_array('dry', (isset($argv) ? $argv : array()))) {
+ $reporter->makeDry();
+}
+exit ($test->run($reporter) ? 0 : 1);
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/web_tester_test.php b/tests/simpletest/test/web_tester_test.php
new file mode 100644
index 0000000..8c3bf1a
--- /dev/null
+++ b/tests/simpletest/test/web_tester_test.php
@@ -0,0 +1,155 @@
+assertTrue($expectation->test('a'));
+ $this->assertTrue($expectation->test(array('a')));
+ $this->assertFalse($expectation->test('A'));
+ }
+
+ function testMatchesInteger() {
+ $expectation = new FieldExpectation('1');
+ $this->assertTrue($expectation->test('1'));
+ $this->assertTrue($expectation->test(1));
+ $this->assertTrue($expectation->test(array('1')));
+ $this->assertTrue($expectation->test(array(1)));
+ }
+
+ function testNonStringFailsExpectation() {
+ $expectation = new FieldExpectation('a');
+ $this->assertFalse($expectation->test(null));
+ }
+
+ function testUnsetFieldCanBeTestedFor() {
+ $expectation = new FieldExpectation(false);
+ $this->assertTrue($expectation->test(false));
+ }
+
+ function testMultipleValuesCanBeInAnyOrder() {
+ $expectation = new FieldExpectation(array('a', 'b'));
+ $this->assertTrue($expectation->test(array('a', 'b')));
+ $this->assertTrue($expectation->test(array('b', 'a')));
+ $this->assertFalse($expectation->test(array('a', 'a')));
+ $this->assertFalse($expectation->test('a'));
+ }
+
+ function testSingleItemCanBeArrayOrString() {
+ $expectation = new FieldExpectation(array('a'));
+ $this->assertTrue($expectation->test(array('a')));
+ $this->assertTrue($expectation->test('a'));
+ }
+}
+
+class TestOfHeaderExpectations extends UnitTestCase {
+
+ function testExpectingOnlyTheHeaderName() {
+ $expectation = new HttpHeaderExpectation('a');
+ $this->assertIdentical($expectation->test(false), false);
+ $this->assertIdentical($expectation->test('a: A'), true);
+ $this->assertIdentical($expectation->test('A: A'), true);
+ $this->assertIdentical($expectation->test('a: B'), true);
+ $this->assertIdentical($expectation->test(' a : A '), true);
+ }
+
+ function testHeaderValueAsWell() {
+ $expectation = new HttpHeaderExpectation('a', 'A');
+ $this->assertIdentical($expectation->test(false), false);
+ $this->assertIdentical($expectation->test('a: A'), true);
+ $this->assertIdentical($expectation->test('A: A'), true);
+ $this->assertIdentical($expectation->test('A: a'), false);
+ $this->assertIdentical($expectation->test('a: B'), false);
+ $this->assertIdentical($expectation->test(' a : A '), true);
+ $this->assertIdentical($expectation->test(' a : AB '), false);
+ }
+
+ function testHeaderValueWithColons() {
+ $expectation = new HttpHeaderExpectation('a', 'A:B:C');
+ $this->assertIdentical($expectation->test('a: A'), false);
+ $this->assertIdentical($expectation->test('a: A:B'), false);
+ $this->assertIdentical($expectation->test('a: A:B:C'), true);
+ $this->assertIdentical($expectation->test('a: A:B:C:D'), false);
+ }
+
+ function testMultilineSearch() {
+ $expectation = new HttpHeaderExpectation('a', 'A');
+ $this->assertIdentical($expectation->test("aa: A\r\nb: B\r\nc: C"), false);
+ $this->assertIdentical($expectation->test("aa: A\r\na: A\r\nb: B"), true);
+ }
+
+ function testMultilineSearchWithPadding() {
+ $expectation = new HttpHeaderExpectation('a', ' A ');
+ $this->assertIdentical($expectation->test("aa:A\r\nb:B\r\nc:C"), false);
+ $this->assertIdentical($expectation->test("aa:A\r\na:A\r\nb:B"), true);
+ }
+
+ function testPatternMatching() {
+ $expectation = new HttpHeaderExpectation('a', new PatternExpectation('/A/'));
+ $this->assertIdentical($expectation->test('a: A'), true);
+ $this->assertIdentical($expectation->test('A: A'), true);
+ $this->assertIdentical($expectation->test('A: a'), false);
+ $this->assertIdentical($expectation->test('a: B'), false);
+ $this->assertIdentical($expectation->test(' a : A '), true);
+ $this->assertIdentical($expectation->test(' a : AB '), true);
+ }
+
+ function testCaseInsensitivePatternMatching() {
+ $expectation = new HttpHeaderExpectation('a', new PatternExpectation('/A/i'));
+ $this->assertIdentical($expectation->test('a: a'), true);
+ $this->assertIdentical($expectation->test('a: B'), false);
+ $this->assertIdentical($expectation->test(' a : A '), true);
+ $this->assertIdentical($expectation->test(' a : BAB '), true);
+ $this->assertIdentical($expectation->test(' a : bab '), true);
+ }
+
+ function testUnwantedHeader() {
+ $expectation = new NoHttpHeaderExpectation('a');
+ $this->assertIdentical($expectation->test(''), true);
+ $this->assertIdentical($expectation->test('stuff'), true);
+ $this->assertIdentical($expectation->test('b: B'), true);
+ $this->assertIdentical($expectation->test('a: A'), false);
+ $this->assertIdentical($expectation->test('A: A'), false);
+ }
+
+ function testMultilineUnwantedSearch() {
+ $expectation = new NoHttpHeaderExpectation('a');
+ $this->assertIdentical($expectation->test("aa:A\r\nb:B\r\nc:C"), true);
+ $this->assertIdentical($expectation->test("aa:A\r\na:A\r\nb:B"), false);
+ }
+
+ function testLocationHeaderSplitsCorrectly() {
+ $expectation = new HttpHeaderExpectation('Location', 'http://here/');
+ $this->assertIdentical($expectation->test('Location: http://here/'), true);
+ }
+}
+
+class TestOfTextExpectations extends UnitTestCase {
+
+ function testMatchingSubString() {
+ $expectation = new TextExpectation('wanted');
+ $this->assertIdentical($expectation->test(''), false);
+ $this->assertIdentical($expectation->test('Wanted'), false);
+ $this->assertIdentical($expectation->test('wanted'), true);
+ $this->assertIdentical($expectation->test('the wanted text is here'), true);
+ }
+
+ function testNotMatchingSubString() {
+ $expectation = new NoTextExpectation('wanted');
+ $this->assertIdentical($expectation->test(''), true);
+ $this->assertIdentical($expectation->test('Wanted'), true);
+ $this->assertIdentical($expectation->test('wanted'), false);
+ $this->assertIdentical($expectation->test('the wanted text is here'), false);
+ }
+}
+
+class TestOfGenericAssertionsInWebTester extends WebTestCase {
+ function testEquality() {
+ $this->assertEqual('a', 'a');
+ $this->assertNotEqual('a', 'A');
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test/xml_test.php b/tests/simpletest/test/xml_test.php
new file mode 100644
index 0000000..f99e0dc
--- /dev/null
+++ b/tests/simpletest/test/xml_test.php
@@ -0,0 +1,187 @@
+ 2));
+ $this->assertEqual($nesting->getSize(), 2);
+ }
+}
+
+class TestOfXmlStructureParsing extends UnitTestCase {
+ function testValidXml() {
+ $listener = new MockSimpleScorer();
+ $listener->expectNever('paintGroupStart');
+ $listener->expectNever('paintGroupEnd');
+ $listener->expectNever('paintCaseStart');
+ $listener->expectNever('paintCaseEnd');
+ $parser = new SimpleTestXmlParser($listener);
+ $this->assertTrue($parser->parse("\n"));
+ $this->assertTrue($parser->parse("\n"));
+ $this->assertTrue($parser->parse("\n"));
+ }
+
+ function testEmptyGroup() {
+ $listener = new MockSimpleScorer();
+ $listener->expectOnce('paintGroupStart', array('a_group', 7));
+ $listener->expectOnce('paintGroupEnd', array('a_group'));
+ $parser = new SimpleTestXmlParser($listener);
+ $parser->parse("\n");
+ $parser->parse("\n");
+ $this->assertTrue($parser->parse("\n"));
+ $this->assertTrue($parser->parse("a_group\n"));
+ $this->assertTrue($parser->parse("\n"));
+ $parser->parse("\n");
+ }
+
+ function testEmptyCase() {
+ $listener = new MockSimpleScorer();
+ $listener->expectOnce('paintCaseStart', array('a_case'));
+ $listener->expectOnce('paintCaseEnd', array('a_case'));
+ $parser = new SimpleTestXmlParser($listener);
+ $parser->parse("\n");
+ $parser->parse("\n");
+ $this->assertTrue($parser->parse("\n"));
+ $this->assertTrue($parser->parse("a_case\n"));
+ $this->assertTrue($parser->parse("\n"));
+ $parser->parse("\n");
+ }
+
+ function testEmptyMethod() {
+ $listener = new MockSimpleScorer();
+ $listener->expectOnce('paintCaseStart', array('a_case'));
+ $listener->expectOnce('paintCaseEnd', array('a_case'));
+ $listener->expectOnce('paintMethodStart', array('a_method'));
+ $listener->expectOnce('paintMethodEnd', array('a_method'));
+ $parser = new SimpleTestXmlParser($listener);
+ $parser->parse("\n");
+ $parser->parse("\n");
+ $parser->parse("\n");
+ $parser->parse("a_case\n");
+ $this->assertTrue($parser->parse("\n"));
+ $this->assertTrue($parser->parse("a_method\n"));
+ $this->assertTrue($parser->parse("\n"));
+ $parser->parse("\n");
+ $parser->parse("\n");
+ }
+
+ function testNestedGroup() {
+ $listener = new MockSimpleScorer();
+ $listener->expectAt(0, 'paintGroupStart', array('a_group', 7));
+ $listener->expectAt(1, 'paintGroupStart', array('b_group', 3));
+ $listener->expectCallCount('paintGroupStart', 2);
+ $listener->expectAt(0, 'paintGroupEnd', array('b_group'));
+ $listener->expectAt(1, 'paintGroupEnd', array('a_group'));
+ $listener->expectCallCount('paintGroupEnd', 2);
+
+ $parser = new SimpleTestXmlParser($listener);
+ $parser->parse("\n");
+ $parser->parse("\n");
+
+ $this->assertTrue($parser->parse("\n"));
+ $this->assertTrue($parser->parse("a_group\n"));
+ $this->assertTrue($parser->parse("\n"));
+ $this->assertTrue($parser->parse("b_group\n"));
+ $this->assertTrue($parser->parse("\n"));
+ $this->assertTrue($parser->parse("\n"));
+ $parser->parse("\n");
+ }
+}
+
+class AnyOldSignal {
+ public $stuff = true;
+}
+
+class TestOfXmlResultsParsing extends UnitTestCase {
+
+ function sendValidStart(&$parser) {
+ $parser->parse("\n");
+ $parser->parse("\n");
+ $parser->parse("\n");
+ $parser->parse("a_case\n");
+ $parser->parse("\n");
+ $parser->parse("a_method\n");
+ }
+
+ function sendValidEnd(&$parser) {
+ $parser->parse("\n");
+ $parser->parse("\n");
+ $parser->parse("\n");
+ }
+
+ function testPass() {
+ $listener = new MockSimpleScorer();
+ $listener->expectOnce('paintPass', array('a_message'));
+ $parser = new SimpleTestXmlParser($listener);
+ $this->sendValidStart($parser);
+ $this->assertTrue($parser->parse("a_message\n"));
+ $this->sendValidEnd($parser);
+ }
+
+ function testFail() {
+ $listener = new MockSimpleScorer();
+ $listener->expectOnce('paintFail', array('a_message'));
+ $parser = new SimpleTestXmlParser($listener);
+ $this->sendValidStart($parser);
+ $this->assertTrue($parser->parse("a_message\n"));
+ $this->sendValidEnd($parser);
+ }
+
+ function testException() {
+ $listener = new MockSimpleScorer();
+ $listener->expectOnce('paintError', array('a_message'));
+ $parser = new SimpleTestXmlParser($listener);
+ $this->sendValidStart($parser);
+ $this->assertTrue($parser->parse("a_message\n"));
+ $this->sendValidEnd($parser);
+ }
+
+ function testSkip() {
+ $listener = new MockSimpleScorer();
+ $listener->expectOnce('paintSkip', array('a_message'));
+ $parser = new SimpleTestXmlParser($listener);
+ $this->sendValidStart($parser);
+ $this->assertTrue($parser->parse("a_message\n"));
+ $this->sendValidEnd($parser);
+ }
+
+ function testSignal() {
+ $signal = new AnyOldSignal();
+ $signal->stuff = "Hello";
+ $listener = new MockSimpleScorer();
+ $listener->expectOnce('paintSignal', array('a_signal', $signal));
+ $parser = new SimpleTestXmlParser($listener);
+ $this->sendValidStart($parser);
+ $this->assertTrue($parser->parse(
+ "\n"));
+ $this->sendValidEnd($parser);
+ }
+
+ function testMessage() {
+ $listener = new MockSimpleScorer();
+ $listener->expectOnce('paintMessage', array('a_message'));
+ $parser = new SimpleTestXmlParser($listener);
+ $this->sendValidStart($parser);
+ $this->assertTrue($parser->parse("a_message\n"));
+ $this->sendValidEnd($parser);
+ }
+
+ function testFormattedMessage() {
+ $listener = new MockSimpleScorer();
+ $listener->expectOnce('paintFormattedMessage', array("\na\tmessage\n"));
+ $parser = new SimpleTestXmlParser($listener);
+ $this->sendValidStart($parser);
+ $this->assertTrue($parser->parse("\n"));
+ $this->sendValidEnd($parser);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/simpletest/test_case.php b/tests/simpletest/test_case.php
new file mode 100644
index 0000000..ba023c3
--- /dev/null
+++ b/tests/simpletest/test_case.php
@@ -0,0 +1,658 @@
+label = $label;
+ }
+ }
+
+ /**
+ * Accessor for the test name for subclasses.
+ * @return string Name of the test.
+ * @access public
+ */
+ function getLabel() {
+ return $this->label ? $this->label : get_class($this);
+ }
+
+ /**
+ * This is a placeholder for skipping tests. In this
+ * method you place skipIf() and skipUnless() calls to
+ * set the skipping state.
+ * @access public
+ */
+ function skip() {
+ }
+
+ /**
+ * Will issue a message to the reporter and tell the test
+ * case to skip if the incoming flag is true.
+ * @param string $should_skip Condition causing the tests to be skipped.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function skipIf($should_skip, $message = '%s') {
+ if ($should_skip && ! $this->should_skip) {
+ $this->should_skip = true;
+ $message = sprintf($message, 'Skipping [' . get_class($this) . ']');
+ $this->reporter->paintSkip($message . $this->getAssertionLine());
+ }
+ }
+
+ /**
+ * Accessor for the private variable $_shoud_skip
+ * @access public
+ */
+ function shouldSkip() {
+ return $this->should_skip;
+ }
+
+ /**
+ * Will issue a message to the reporter and tell the test
+ * case to skip if the incoming flag is false.
+ * @param string $shouldnt_skip Condition causing the tests to be run.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function skipUnless($shouldnt_skip, $message = false) {
+ $this->skipIf(! $shouldnt_skip, $message);
+ }
+
+ /**
+ * Used to invoke the single tests.
+ * @return SimpleInvoker Individual test runner.
+ * @access public
+ */
+ function createInvoker() {
+ return new SimpleErrorTrappingInvoker(
+ new SimpleExceptionTrappingInvoker(new SimpleInvoker($this)));
+ }
+
+ /**
+ * Uses reflection to run every method within itself
+ * starting with the string "test" unless a method
+ * is specified.
+ * @param SimpleReporter $reporter Current test reporter.
+ * @return boolean True if all tests passed.
+ * @access public
+ */
+ function run($reporter) {
+ $context = SimpleTest::getContext();
+ $context->setTest($this);
+ $context->setReporter($reporter);
+ $this->reporter = $reporter;
+ $started = false;
+ foreach ($this->getTests() as $method) {
+ if ($reporter->shouldInvoke($this->getLabel(), $method)) {
+ $this->skip();
+ if ($this->should_skip) {
+ break;
+ }
+ if (! $started) {
+ $reporter->paintCaseStart($this->getLabel());
+ $started = true;
+ }
+ $invoker = $this->reporter->createInvoker($this->createInvoker());
+ $invoker->before($method);
+ $invoker->invoke($method);
+ $invoker->after($method);
+ }
+ }
+ if ($started) {
+ $reporter->paintCaseEnd($this->getLabel());
+ }
+ unset($this->reporter);
+ $context->setTest(null);
+ return $reporter->getStatus();
+ }
+
+ /**
+ * Gets a list of test names. Normally that will
+ * be all internal methods that start with the
+ * name "test". This method should be overridden
+ * if you want a different rule.
+ * @return array List of test names.
+ * @access public
+ */
+ function getTests() {
+ $methods = array();
+ foreach (get_class_methods(get_class($this)) as $method) {
+ if ($this->isTest($method)) {
+ $methods[] = $method;
+ }
+ }
+ return $methods;
+ }
+
+ /**
+ * Tests to see if the method is a test that should
+ * be run. Currently any method that starts with 'test'
+ * is a candidate unless it is the constructor.
+ * @param string $method Method name to try.
+ * @return boolean True if test method.
+ * @access protected
+ */
+ protected function isTest($method) {
+ if (strtolower(substr($method, 0, 4)) == 'test') {
+ return ! SimpleTestCompatibility::isA($this, strtolower($method));
+ }
+ return false;
+ }
+
+ /**
+ * Announces the start of the test.
+ * @param string $method Test method just started.
+ * @access public
+ */
+ function before($method) {
+ $this->reporter->paintMethodStart($method);
+ $this->observers = array();
+ }
+
+ /**
+ * Sets up unit test wide variables at the start
+ * of each test method. To be overridden in
+ * actual user test cases.
+ * @access public
+ */
+ function setUp() {
+ }
+
+ /**
+ * Clears the data set in the setUp() method call.
+ * To be overridden by the user in actual user test cases.
+ * @access public
+ */
+ function tearDown() {
+ }
+
+ /**
+ * Announces the end of the test. Includes private clean up.
+ * @param string $method Test method just finished.
+ * @access public
+ */
+ function after($method) {
+ for ($i = 0; $i < count($this->observers); $i++) {
+ $this->observers[$i]->atTestEnd($method, $this);
+ }
+ $this->reporter->paintMethodEnd($method);
+ }
+
+ /**
+ * Sets up an observer for the test end.
+ * @param object $observer Must have atTestEnd()
+ * method.
+ * @access public
+ */
+ function tell($observer) {
+ $this->observers[] = &$observer;
+ }
+
+ /**
+ * @deprecated
+ */
+ function pass($message = "Pass") {
+ if (! isset($this->reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->reporter->paintPass(
+ $message . $this->getAssertionLine());
+ return true;
+ }
+
+ /**
+ * Sends a fail event with a message.
+ * @param string $message Message to send.
+ * @access public
+ */
+ function fail($message = "Fail") {
+ if (! isset($this->reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->reporter->paintFail(
+ $message . $this->getAssertionLine());
+ return false;
+ }
+
+ /**
+ * Formats a PHP error and dispatches it to the
+ * reporter.
+ * @param integer $severity PHP error code.
+ * @param string $message Text of error.
+ * @param string $file File error occoured in.
+ * @param integer $line Line number of error.
+ * @access public
+ */
+ function error($severity, $message, $file, $line) {
+ if (! isset($this->reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->reporter->paintError(
+ "Unexpected PHP error [$message] severity [$severity] in [$file line $line]");
+ }
+
+ /**
+ * Formats an exception and dispatches it to the
+ * reporter.
+ * @param Exception $exception Object thrown.
+ * @access public
+ */
+ function exception($exception) {
+ $this->reporter->paintException($exception);
+ }
+
+ /**
+ * For user defined expansion of the available messages.
+ * @param string $type Tag for sorting the signals.
+ * @param mixed $payload Extra user specific information.
+ */
+ function signal($type, $payload) {
+ if (! isset($this->reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->reporter->paintSignal($type, $payload);
+ }
+
+ /**
+ * Runs an expectation directly, for extending the
+ * tests with new expectation classes.
+ * @param SimpleExpectation $expectation Expectation subclass.
+ * @param mixed $compare Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assert($expectation, $compare, $message = '%s') {
+ if ($expectation->test($compare)) {
+ return $this->pass(sprintf(
+ $message,
+ $expectation->overlayMessage($compare, $this->reporter->getDumper())));
+ } else {
+ return $this->fail(sprintf(
+ $message,
+ $expectation->overlayMessage($compare, $this->reporter->getDumper())));
+ }
+ }
+
+ /**
+ * Uses a stack trace to find the line of an assertion.
+ * @return string Line number of first assert*
+ * method embedded in format string.
+ * @access public
+ */
+ function getAssertionLine() {
+ $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip'));
+ return $trace->traceMethod();
+ }
+
+ /**
+ * Sends a formatted dump of a variable to the
+ * test suite for those emergency debugging
+ * situations.
+ * @param mixed $variable Variable to display.
+ * @param string $message Message to display.
+ * @return mixed The original variable.
+ * @access public
+ */
+ function dump($variable, $message = false) {
+ $dumper = $this->reporter->getDumper();
+ $formatted = $dumper->dump($variable);
+ if ($message) {
+ $formatted = $message . "\n" . $formatted;
+ }
+ $this->reporter->paintFormattedMessage($formatted);
+ return $variable;
+ }
+
+ /**
+ * Accessor for the number of subtests including myelf.
+ * @return integer Number of test cases.
+ * @access public
+ */
+ function getSize() {
+ return 1;
+ }
+}
+
+/**
+ * Helps to extract test cases automatically from a file.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class SimpleFileLoader {
+
+ /**
+ * Builds a test suite from a library of test cases.
+ * The new suite is composed into this one.
+ * @param string $test_file File name of library with
+ * test case classes.
+ * @return TestSuite The new test suite.
+ * @access public
+ */
+ function load($test_file) {
+ $existing_classes = get_declared_classes();
+ $existing_globals = get_defined_vars();
+ include_once($test_file);
+ $new_globals = get_defined_vars();
+ $this->makeFileVariablesGlobal($existing_globals, $new_globals);
+ $new_classes = array_diff(get_declared_classes(), $existing_classes);
+ if (empty($new_classes)) {
+ $new_classes = $this->scrapeClassesFromFile($test_file);
+ }
+ $classes = $this->selectRunnableTests($new_classes);
+ return $this->createSuiteFromClasses($test_file, $classes);
+ }
+
+ /**
+ * Imports new variables into the global namespace.
+ * @param hash $existing Variables before the file was loaded.
+ * @param hash $new Variables after the file was loaded.
+ * @access private
+ */
+ protected function makeFileVariablesGlobal($existing, $new) {
+ $globals = array_diff(array_keys($new), array_keys($existing));
+ foreach ($globals as $global) {
+ $GLOBALS[$global] = $new[$global];
+ }
+ }
+
+ /**
+ * Lookup classnames from file contents, in case the
+ * file may have been included before.
+ * Note: This is probably too clever by half. Figuring this
+ * out after a failed test case is going to be tricky for us,
+ * never mind the user. A test case should not be included
+ * twice anyway.
+ * @param string $test_file File name with classes.
+ * @access private
+ */
+ protected function scrapeClassesFromFile($test_file) {
+ preg_match_all('~^\s*class\s+(\w+)(\s+(extends|implements)\s+\w+)*\s*\{~mi',
+ file_get_contents($test_file),
+ $matches );
+ return $matches[1];
+ }
+
+ /**
+ * Calculates the incoming test cases. Skips abstract
+ * and ignored classes.
+ * @param array $candidates Candidate classes.
+ * @return array New classes which are test
+ * cases that shouldn't be ignored.
+ * @access public
+ */
+ function selectRunnableTests($candidates) {
+ $classes = array();
+ foreach ($candidates as $class) {
+ if (TestSuite::getBaseTestCase($class)) {
+ $reflection = new SimpleReflection($class);
+ if ($reflection->isAbstract()) {
+ SimpleTest::ignore($class);
+ } else {
+ $classes[] = $class;
+ }
+ }
+ }
+ return $classes;
+ }
+
+ /**
+ * Builds a test suite from a class list.
+ * @param string $title Title of new group.
+ * @param array $classes Test classes.
+ * @return TestSuite Group loaded with the new
+ * test cases.
+ * @access public
+ */
+ function createSuiteFromClasses($title, $classes) {
+ if (count($classes) == 0) {
+ $suite = new BadTestSuite($title, "No runnable test cases in [$title]");
+ return $suite;
+ }
+ SimpleTest::ignoreParentsIfIgnored($classes);
+ $suite = new TestSuite($title);
+ foreach ($classes as $class) {
+ if (! SimpleTest::isIgnored($class)) {
+ $suite->add($class);
+ }
+ }
+ return $suite;
+ }
+}
+
+/**
+ * This is a composite test class for combining
+ * test cases and other RunnableTest classes into
+ * a group test.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class TestSuite {
+ private $label;
+ private $test_cases;
+
+ /**
+ * Sets the name of the test suite.
+ * @param string $label Name sent at the start and end
+ * of the test.
+ * @access public
+ */
+ function TestSuite($label = false) {
+ $this->label = $label;
+ $this->test_cases = array();
+ }
+
+ /**
+ * Accessor for the test name for subclasses. If the suite
+ * wraps a single test case the label defaults to the name of that test.
+ * @return string Name of the test.
+ * @access public
+ */
+ function getLabel() {
+ if (! $this->label) {
+ return ($this->getSize() == 1) ?
+ get_class($this->test_cases[0]) : get_class($this);
+ } else {
+ return $this->label;
+ }
+ }
+
+ /**
+ * Adds a test into the suite by instance or class. The class will
+ * be instantiated if it's a test suite.
+ * @param SimpleTestCase $test_case Suite or individual test
+ * case implementing the
+ * runnable test interface.
+ * @access public
+ */
+ function add($test_case) {
+ if (! is_string($test_case)) {
+ $this->test_cases[] = $test_case;
+ } elseif (TestSuite::getBaseTestCase($test_case) == 'testsuite') {
+ $this->test_cases[] = new $test_case();
+ } else {
+ $this->test_cases[] = $test_case;
+ }
+ }
+
+ /**
+ * Builds a test suite from a library of test cases.
+ * The new suite is composed into this one.
+ * @param string $test_file File name of library with
+ * test case classes.
+ * @access public
+ */
+ function addFile($test_file) {
+ $extractor = new SimpleFileLoader();
+ $this->add($extractor->load($test_file));
+ }
+
+ /**
+ * Delegates to a visiting collector to add test
+ * files.
+ * @param string $path Path to scan from.
+ * @param SimpleCollector $collector Directory scanner.
+ * @access public
+ */
+ function collect($path, $collector) {
+ $collector->collect($this, $path);
+ }
+
+ /**
+ * Invokes run() on all of the held test cases, instantiating
+ * them if necessary.
+ * @param SimpleReporter $reporter Current test reporter.
+ * @access public
+ */
+ function run($reporter) {
+ $reporter->paintGroupStart($this->getLabel(), $this->getSize());
+ for ($i = 0, $count = count($this->test_cases); $i < $count; $i++) {
+ if (is_string($this->test_cases[$i])) {
+ $class = $this->test_cases[$i];
+ $test = new $class();
+ $test->run($reporter);
+ unset($test);
+ } else {
+ $this->test_cases[$i]->run($reporter);
+ }
+ }
+ $reporter->paintGroupEnd($this->getLabel());
+ return $reporter->getStatus();
+ }
+
+ /**
+ * Number of contained test cases.
+ * @return integer Total count of cases in the group.
+ * @access public
+ */
+ function getSize() {
+ $count = 0;
+ foreach ($this->test_cases as $case) {
+ if (is_string($case)) {
+ if (! SimpleTest::isIgnored($case)) {
+ $count++;
+ }
+ } else {
+ $count += $case->getSize();
+ }
+ }
+ return $count;
+ }
+
+ /**
+ * Test to see if a class is derived from the
+ * SimpleTestCase class.
+ * @param string $class Class name.
+ * @access public
+ */
+ static function getBaseTestCase($class) {
+ while ($class = get_parent_class($class)) {
+ $class = strtolower($class);
+ if ($class == 'simpletestcase' || $class == 'testsuite') {
+ return $class;
+ }
+ }
+ return false;
+ }
+}
+
+/**
+ * This is a failing group test for when a test suite hasn't
+ * loaded properly.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class BadTestSuite {
+ private $label;
+ private $error;
+
+ /**
+ * Sets the name of the test suite and error message.
+ * @param string $label Name sent at the start and end
+ * of the test.
+ * @access public
+ */
+ function BadTestSuite($label, $error) {
+ $this->label = $label;
+ $this->error = $error;
+ }
+
+ /**
+ * Accessor for the test name for subclasses.
+ * @return string Name of the test.
+ * @access public
+ */
+ function getLabel() {
+ return $this->label;
+ }
+
+ /**
+ * Sends a single error to the reporter.
+ * @param SimpleReporter $reporter Current test reporter.
+ * @access public
+ */
+ function run($reporter) {
+ $reporter->paintGroupStart($this->getLabel(), $this->getSize());
+ $reporter->paintFail('Bad TestSuite [' . $this->getLabel() .
+ '] with error [' . $this->error . ']');
+ $reporter->paintGroupEnd($this->getLabel());
+ return $reporter->getStatus();
+ }
+
+ /**
+ * Number of contained test cases. Always zero.
+ * @return integer Total count of cases in the group.
+ * @access public
+ */
+ function getSize() {
+ return 0;
+ }
+}
+?>
diff --git a/tests/simpletest/tidy_parser.php b/tests/simpletest/tidy_parser.php
new file mode 100644
index 0000000..3d8b4b2
--- /dev/null
+++ b/tests/simpletest/tidy_parser.php
@@ -0,0 +1,382 @@
+free();
+ }
+
+ /**
+ * Frees up any references so as to allow the PHP garbage
+ * collection from unset() to work.
+ */
+ private function free() {
+ unset($this->page);
+ $this->forms = array();
+ $this->labels = array();
+ }
+
+ /**
+ * This builder is only available if the 'tidy' extension is loaded.
+ * @return boolean True if available.
+ */
+ function can() {
+ return extension_loaded('tidy');
+ }
+
+ /**
+ * Reads the raw content the page using HTML Tidy.
+ * @param $response SimpleHttpResponse Fetched response.
+ * @return SimplePage Newly parsed page.
+ */
+ function parse($response) {
+ $this->page = new SimplePage($response);
+ $tidied = tidy_parse_string($input = $this->insertGuards($response->getContent()),
+ array('output-xml' => false, 'wrap' => '0', 'indent' => 'no'),
+ 'latin1');
+ $this->walkTree($tidied->html());
+ $this->attachLabels($this->widgets_by_id, $this->labels);
+ $this->page->setForms($this->forms);
+ $page = $this->page;
+ $this->free();
+ return $page;
+ }
+
+ /**
+ * Stops HTMLTidy stripping content that we wish to preserve.
+ * @param string The raw html.
+ * @return string The html with guard tags inserted.
+ */
+ private function insertGuards($html) {
+ return $this->insertEmptyTagGuards($this->insertTextareaSimpleWhitespaceGuards($html));
+ }
+
+ /**
+ * Removes the extra content added during the parse stage
+ * in order to preserve content we don't want stripped
+ * out by HTMLTidy.
+ * @param string The raw html.
+ * @return string The html with guard tags removed.
+ */
+ private function stripGuards($html) {
+ return $this->stripTextareaWhitespaceGuards($this->stripEmptyTagGuards($html));
+ }
+
+ /**
+ * HTML tidy strips out empty tags such as