remove simpletest

This commit is contained in:
Shish 2015-08-09 12:28:09 +01:00
parent 5a466bfac3
commit e3959e5ec8
52 changed files with 0 additions and 21422 deletions

View File

@ -1,276 +0,0 @@
<?php
/*
* Name: SimpleTest integration
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Description: adds unit testing to SCore
*/
/**
* \page unittests Unit Tests
*
* Each extension should (although doesn't technically have to) come with a
* test.php file, for example ext/index/test.php. The SimpleSCoreTest
* extension will look for these files and load any SCoreWebTestCase classes
* it finds inside them, then run them and report whether or not the test
* passes.
*
* For Shimmie2 specific extensions, there is a ShimmieWebTestCase class which
* includes functions to upload and delete images.
*
* For a quick guide on the specifics of how to write tests, see \ref wut
*
*
* \page wut Writing Unit Tests
*
* Note: The unit test framework assumes a fresh, default install with an
* admin called "demo" and a user called "test". The full test suite takes
* a few minutes to run on my test VM, which is long enough that my shared
* hosting provider cuts it off half way through. Running tests for specific
* extensions (visit "/test/extension_folder_name") is generally OK though.
*
* An empty test class starts like so (assuming the extension we're writing
* tests for is called "Example")
*
* \code
* <?php
* class ExampleTest extends SCoreWebTestCase {
* public function test_blah() {
* }
* }
* ?>
* \endcode
*
* SCoreWebTestCase is for testing generic extensions, ShimmieWebTestCase is
* for imageboard-specific extensions. The name of the function doesn't matter
* as long as it begins with "test". If you want to test several parts of the
* extension independantly, you can write several functions, just make sure
* that each begins with "test".
*
* Once you're in the function, $this is a reference to a virtual web browser
* which you can control with code. The functions available are visible in the
* docs for class SCoreWebTestCase and ShimmieWebTestCase.
*
* Basically, just simulate a browsing session, making sure that everything
* is where it's supposed to be. If you can simulate a browsing session that
* triggers a bug, then it makes that bug much easier for developers to fix,
* and will make sure that it doesn't come back.
*
* \code
* <?php
* class ExampleTest extends SCoreWebTestCase {
* public function test_blah() {
* $this->get_page("my/page");
* $this->assert_title("My Page Title");
* $this->assert_text("This is my page");
* $this->click("a link to my other page");
* $this->assert_title("My Other Page");
* $this->back();
* $this->assert_title("My Page Title");
* $this->set_field("some_text", "Here is some text");
* $this->click("Send Some Text");
* $this->assert_text("Your input was: Here is some text");
* }
* }
* ?>
* \endcode
*
*/
require_once('lib/simpletest/web_tester.php');
require_once('lib/simpletest/unit_tester.php');
require_once('lib/simpletest/reporter.php');
define('USER_NAME', "test");
define('USER_PASS', "test");
define('ADMIN_NAME', "demo");
define('ADMIN_PASS', "demo");
/**
* Class SCoreWebTestCase
*
* A set of common SCore activities to test.
*/
class SCoreWebTestCase extends WebTestCase {
/**
* Click on a link or a button.
* @param string $text
* @return string
*/
public function click($text) {
return parent::click($text);
}
/**
* Click the virtual browser's back button.
* @return bool
*/
public function back() {
return parent::back();
}
/**
* Get a page based on the SCore URL, eg get_page("post/list") will do
* the right thing; no need for http:// or any such
*/
protected function get_page($page) {
// Check if we are running on the command line
if(php_sapi_name() == 'cli' || $_SERVER['HTTP_HOST'] == "<cli command>") {
$host = constant("_TRAVIS_WEBHOST");
$this->assertFalse(empty($host)); // Make sure that we know the host address.
$raw = $this->get($host."/index.php?q=".str_replace("?", "&", $page));
}
else {
$raw = $this->get(make_http(make_link($page)));
}
$this->assertNoText("Internal Error");
$this->assertNoText("Exception:");
$this->assertNoText("Error:");
$this->assertNoText("Warning:");
$this->assertNoText("Notice:");
return $raw;
}
protected function log_in_as_user() {
$this->get_page('user_admin/login');
$this->assertText("Login");
$this->setField('user', USER_NAME);
$this->setField('pass', USER_PASS);
$this->click("Log In");
}
protected function log_in_as_admin() {
$this->get_page('user_admin/login');
$this->assertText("Login");
$this->setField('user', ADMIN_NAME);
$this->setField('pass', ADMIN_PASS);
$this->click("Log In");
}
protected function log_out() {
$this->get_page('post/list');
$this->click('Log Out');
}
/**
* Look through the HTML for a form element with the name $name,
* set its value to $value
*/
protected function set_field($name, $value) {
parent::setField($name, $value);
}
protected function assert_text($text) {parent::assertText($text);}
protected function assert_title($title) {parent::assertTitle($title);}
protected function assert_no_text($text) {parent::assertNoText($text);}
protected function assert_mime($type) {parent::assertMime($type);}
protected function assert_response($code) {parent::assertResponse($code);}
}
/**
* Class ShimmieWebTestCase
*
* A set of common Shimmie activities to test.
*/
class ShimmieWebTestCase extends SCoreWebTestCase {
/**
* @param string $filename
* @param string|string[] $tags
* @return int
*/
protected function post_image($filename, $tags) {
$image_id = -1;
$this->setMaximumRedirects(0);
$this->get_page('post/list');
$this->assertText("Upload");
$this->setField("data0", $filename);
$this->setField("tags", $tags);
$this->click("Post");
$raw_headers = $this->getBrowser()->getHeaders();
$headers = explode("\n", $raw_headers);
foreach($headers as $header) {
$parts = explode(":", $header);
if(trim($parts[0]) == "X-Shimmie-Image-ID") {
$image_id = int_escape(trim($parts[1]));
}
}
// sometimes we want uploading to fail, eg
// testing for a blacklist
//$this->assertTrue($image_id > 0);
$this->setMaximumRedirects(5);
return $image_id;
}
/**
* @param int $image_id
*/
protected function delete_image($image_id) {
if($image_id > 0) {
$this->get_page('post/view/'.$image_id);
$this->clickSubmit("Delete");
// Make sure that the image is really deleted.
//$this->get_page('post/view/'.$image_id);
//$this->assert_response(404);
}
}
}
/** @private */
class TestFinder extends TestSuite {
function __construct($hint) {
if(strpos($hint, "..") !== FALSE) return;
// Select the test cases for "All" extensions.
$dir = "{".ENABLED_EXTS."}";
// Unless the user specified just a specific extension.
if(file_exists("ext/$hint/test.php")) $dir = $hint;
$this->TestSuite('All tests');
foreach(zglob("ext/$dir/test.php") as $file) {
$this->addFile($file);
}
}
}
class SimpleSCoreTest extends Extension {
public function onPageRequest(PageRequestEvent $event) {
global $page;
if($event->page_matches("test")) {
set_time_limit(0);
$page->set_title("Test Results");
$page->set_heading("Test Results");
$page->add_block(new NavBlock());
$all = new TestFinder($event->get_arg(0));
$all->run(new SCoreWebReporter($page));
}
}
public function onCommand(CommandEvent $event) {
if($event->cmd == "help") {
print " test [extension]\n";
print " run automated tests for the name extension\n\n";
}
if($event->cmd == "test") {
$all = new TestFinder($event->args[0]);
$all->run(new SCoreCLIReporter());
}
}
public function onUserBlockBuilding(UserBlockBuildingEvent $event) {
global $user;
if($user->is_admin()) {
$event->add_link("Run Tests", make_link("test/all"));
}
}
}

View File

@ -1,87 +0,0 @@
<?php
class SimpleSCoreTestTheme extends Themelet {
}
/** @private */
class SCoreWebReporter extends HtmlReporter {
var $current_html = "";
var $clear_modules = array();
var $page;
var $fails;
var $exceptions;
public function __construct(Page $page) {
$this->page = $page;
$this->fails = 0;
$this->exceptions = 0;
}
function paintHeader($test_name) {
// nowt
//parent::paintHeader($test_name);
}
function paintFooter($test_name) {
global $page;
//parent::paintFooter($test_name);
if(($this->fails + $this->exceptions) > 0) {
$style = "background: red;";
}
else {
$style = "background: green;";
}
$html = "<div style=\"padding: 4px; $style\">".
$this->getPassCount() . " passes, " .
$this->fails . " failures, " .
$this->exceptions . " exceptions" .
"<br>Passed modules: " . implode(", ", $this->clear_modules) .
"</div>";
$page->add_block(new Block("Results", $html, "main", 40));
}
function paintGroupStart($name, $size) {
parent::paintGroupStart($name, $size);
$this->current_html = "";
}
function paintGroupEnd($name) {
global $page;
$matches = array();
if(preg_match("#ext/(.*)/test.php#", $name, $matches)) {
$name = $matches[1];
$link = "<a href=\"".make_link("test/$name")."\">Test only this extension</a>";
}
parent::paintGroupEnd($name);
if($this->current_html == "") {
$this->clear_modules[] = $name;
}
else {
$this->current_html .= "<p>$link";
$page->add_block(new Block($name, $this->current_html, "main", 50));
$this->current_html = "";
}
}
function paintFail($message) {
//parent::paintFail($message);
$this->fails++; // manually do the grandparent behaviour
$message = str_replace(getcwd(), "...", $message);
$this->current_html .= "<p style='text-align: left;'><b>Fail</b>: $message";
}
function paintException($message) {
//parent::paintFail($message);
$this->exceptions++; // manually do the grandparent behaviour
$message = str_replace(getcwd(), "...", $message);
$this->current_html .= "<p style='text-align: left;'><b>Exception</b>: $message";
}
}
/** @private */
class SCoreCLIReporter extends TextReporter {
}

View File

@ -1,399 +0,0 @@
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 <script> tag
-----------------------------------------------------------
The assertText() method is intended to match only visible,
human-readable text on the web page. Therefore, the contents of script
tags should not be matched by this assertion. However there was a bug
in the text normalisation code of simpletest which meant that <script>
tags spanning multiple lines would not have their content stripped
out. If you want to check the content of a <script> tag, use
assertPattern(), or write a custom expectation.
Overloaded method not working
-----------------------------
All protected and private methods had underscores
removed. This means that any private/protected methods that
you overloaded with those names need to be updated.
Fatal error: Call to undefined method Classname::classname()
------------------------------------------------------------
SimpleTest renamed all of its constructors from
Classname to __construct; derived classes invoking
their parent constructors should replace parent::Classname()
with parent::__construct().
Custom CSS in HtmlReporter not being applied
--------------------------------------------
Batch rename of protected and private methods
means that _getCss() was renamed to getCss().
Please rename your method and it should work again.
setReturnReference() throws errors in E_STRICT
----------------------------------------------
Happens when an object is passed by reference.
This also happens with setReturnReferenceAt().
If you want to return objects then replace these
with calls to returns() and returnsAt() with the
same arguments. This change was forced in the 1.1
version for E_STRICT compatibility.
assertReference() throws errors in E_STRICT
-------------------------------------------
Due to language restrictions you cannot compare
both variables and objects in E_STRICT mode. Use
assertSame() in this mode with objects. This change
was forced the 1.1 version.
Cannot create GroupTest
-----------------------
The GroupTest has been renamed TestSuite (see below).
It was removed completely in 1.1 in favour of this
name.
No method getRelativeUrls() or getAbsoluteUrls()
------------------------------------------------
These methods were always a bit weird anyway, and
the new parsing of the base tag makes them more so.
They have been replaced with getUrls() instead. If
you want the old functionality then simply chop
off the current domain from getUrls().
Method setWildcard() removed in mocks
-------------------------------------
Even setWildcard() has been removed in 1.0.1beta now.
If you want to test explicitely for a '*' string, then
simply pass in new IdenticalExpectation('*') instead.
No method _getTest() on mocks
-----------------------------
This has finally been removed. It was a pretty esoteric
flex point anyway. It was there to allow the mocks to
work with other test tools, but no one does this.
No method assertError(), assertNoErrors(), swallowErrors()
----------------------------------------------------------
These have been deprecated in 1.0.1beta in favour of
expectError() and expectException(). assertNoErrors() is
redundant if you use expectError() as failures are now reported
immediately.
No method TestCase::signal()
----------------------------
This has been deprecated in favour of triggering an error or
throwing an exception. Deprecated as of 1.0.1beta.
No method TestCase::sendMessage()
---------------------------------
This has been deprecated as of 1.0.1beta.
Failure to connect now emits failures
-------------------------------------
It used to be that you would have to use the
getTransferError() call on the web tester to see if
there was a socket level error in a fetch. This check
is now always carried out by the WebTestCase unless
the fetch is prefaced with WebTestCase::ignoreErrors().
The ignore directive only lasts for the next fetching
action such as get() and click().
No method SimpleTestOptions::ignore()
-------------------------------------
This is deprecated in version 1.0.1beta and has been moved
to SimpleTest::ignore() as that is more readable. In
addition, parent classes are also ignored automatically.
If you are using PHP5 you can skip this directive simply
by marking your test case as abstract.
No method assertCopy()
----------------------
This is deprecated in 1.0.1 in favour of assertClone().
The assertClone() method is slightly different in that
the objects must be identical, but without being a
reference. It is thus not a strict inversion of
assertReference().
Constructor wildcard override has no effect in mocks
----------------------------------------------------
As of 1.0.1beta this is now set with setWildcard() instead
of in the constructor.
No methods setStubBaseClass()/getStubBaseClass()
------------------------------------------------
As mocks are now used instead of stubs, these methods
stopped working and are now removed as of the 1.0.1beta
release. The mock objects may be freely used instead.
No method addPartialMockCode()
------------------------------
The ability to insert arbitrary partial mock code
has been removed. This was a low value feature
causing needless complications. It was removed
in the 1.0.1beta release.
No method setMockBaseClass()
----------------------------
The ability to change the mock base class has been
scheduled for removal and is deprecated since the
1.0.1beta version. This was a rarely used feature
except as a workaround for PHP5 limitations. As
these limitations are being resolved it's hoped
that the bundled mocks can be used directly.
No class Stub
-------------
Server stubs are deprecated from 1.0.1 as the mocks now
have exactly the same interface. Just use mock objects
instead.
No class SimpleTestOptions
--------------------------
This was replced by the shorter SimpleTest in 1.0.1beta1
and is since deprecated.
No file simple_test.php
-----------------------
This was renamed test_case.php in 1.0.1beta to more accurately
reflect it's purpose. This file should never be directly
included in test suites though, as it's part of the
underlying mechanics and has a tendency to be refactored.
No class WantedPatternExpectation
---------------------------------
This was deprecated in 1.0.1alpha in favour of the simpler
name PatternExpectation.
No class NoUnwantedPatternExpectation
-------------------------------------
This was deprecated in 1.0.1alpha in favour of the simpler
name NoPatternExpectation.
No method assertNoUnwantedPattern()
-----------------------------------
This has been renamed to assertNoPattern() in 1.0.1alpha and
the old form is deprecated.
No method assertWantedPattern()
-------------------------------
This has been renamed to assertPattern() in 1.0.1alpha and
the old form is deprecated.
No method assertExpectation()
-----------------------------
This was renamed as assert() in 1.0.1alpha and the old form
has been deprecated.
No class WildcardExpectation
----------------------------
This was a mostly internal class for the mock objects. It was
renamed AnythingExpectation to bring it closer to JMock and
NMock in version 1.0.1alpha.
Missing UnitTestCase::assertErrorPattern()
------------------------------------------
This method is deprecated for version 1.0.1 onwards.
This method has been subsumed by assertError() that can now
take an expectation. Simply pass a PatternExpectation
into assertError() to simulate the old behaviour.
No HTML when matching page elements
-----------------------------------
This behaviour has been switched to using plain text as if it
were seen by the user of the browser. This means that HTML tags
are suppressed, entities are converted and whitespace is
normalised. This should make it easier to match items in forms.
Also images are replaced with their "alt" text so that they
can be matched as well.
No method SimpleRunner::_getTestCase()
--------------------------------------
This was made public as getTestCase() in 1.0RC2.
No method restartSession()
--------------------------
This was renamed to restart() in the WebTestCase, SimpleBrowser
and the underlying SimpleUserAgent in 1.0RC2. Because it was
undocumented anyway, no attempt was made at backward
compatibility.
My custom test case ignored by tally()
--------------------------------------
The _assertTrue method has had it's signature changed due to a bug
in the PHP 5.0.1 release. You must now use getTest() from within
that method to get the test case. Mock compatibility with other
unit testers is now deprecated as of 1.0.1alpha as PEAR::PHPUnit2
should soon have mock support of it's own.
Broken code extending SimpleRunner
----------------------------------
This was replaced with SimpleScorer so that I could use the runner
name in another class. This happened in RC1 development and there
is no easy backward compatibility fix. The solution is simply to
extend SimpleScorer instead.
Missing method getBaseCookieValue()
-----------------------------------
This was renamed getCurrentCookieValue() in RC1.
Missing files from the SimpleTest suite
---------------------------------------
Versions of SimpleTest prior to Beta6 required a SIMPLE_TEST constant
to point at the SimpleTest folder location before any of the toolset
was loaded. This is no longer documented as it is now unnecessary
for later versions. If you are using an earlier version you may
need this constant. Consult the documentation that was bundled with
the release that you are using or upgrade to Beta6 or later.
No method SimpleBrowser::getCurrentUrl()
--------------------------------------
This is replaced with the more versatile showRequest() for
debugging. It only existed in this context for version Beta5.
Later versions will have SimpleBrowser::getHistory() for tracking
paths through pages. It is renamed as getUrl() since 1.0RC1.
No method Stub::setStubBaseClass()
----------------------------------
This method has finally been removed in 1.0RC1. Use
SimpleTestOptions::setStubBaseClass() instead.
No class CommandLineReporter
----------------------------
This was renamed to TextReporter in Beta3 and the deprecated version
was removed in 1.0RC1.
No method requireReturn()
-------------------------
This was deprecated in Beta3 and is now removed.
No method expectCookie()
------------------------
This method was abruptly removed in Beta4 so as to simplify the internals
until another mechanism can replace it. As a workaround it is necessary
to assert that the cookie has changed by setting it before the page
fetch and then assert the desired value.
No method clickSubmitByFormId()
-------------------------------
This method had an incorrect name as no button was involved. It was
renamed to submitByFormId() in Beta4 and the old version deprecated.
Now removed.
No method paintStart() or paintEnd()
------------------------------------
You should only get this error if you have subclassed the lower level
reporting and test runner machinery. These methods have been broken
down into events for test methods, events for test cases and events
for group tests. The new methods are...
paintStart() --> paintMethodStart(), paintCaseStart(), paintGroupStart()
paintEnd() --> paintMethodEnd(), paintCaseEnd(), paintGroupEnd()
This change was made in Beta3, ironically to make it easier to subclass
the inner machinery. Simply duplicating the code you had in the previous
methods should provide a temporary fix.
No class TestDisplay
--------------------
This has been folded into SimpleReporter in Beta3 and is now deprecated.
It was removed in RC1.
No method WebTestCase::fetch()
------------------------------
This was renamed get() in Alpha8. It is removed in Beta3.
No method submit()
------------------
This has been renamed clickSubmit() in Beta1. The old method was
removed in Beta2.
No method clearHistory()
------------------------
This method is deprecated in Beta2 and removed in RC1.
No method getCallCount()
------------------------
This method has been deprecated since Beta1 and has now been
removed. There are now more ways to set expectations on counts
and so this method should be unecessery. Removed in RC1.
Cannot find file *
------------------
The following public name changes have occoured...
simple_html_test.php --> reporter.php
simple_mock.php --> mock_objects.php
simple_unit.php --> unit_tester.php
simple_web.php --> web_tester.php
The old names were deprecated in Alpha8 and removed in Beta1.
No method attachObserver()
--------------------------
Prior to the Alpha8 release the old internal observer pattern was
gutted and replaced with a visitor. This is to trade flexibility of
test case expansion against the ease of writing user interfaces.
Code such as...
$test = &new MyTestCase();
$test->attachObserver(new TestHtmlDisplay());
$test->run();
...should be rewritten as...
$test = &new MyTestCase();
$test->run(new HtmlReporter());
If you previously attached multiple observers then the workaround
is to run the tests twice, once with each, until they can be combined.
For one observer the old method is simulated in Alpha 8, but is
removed in Beta1.
No class TestHtmlDisplay
------------------------
This class has been renamed to HtmlReporter in Alpha8. It is supported,
but deprecated in Beta1 and removed in Beta2. If you have subclassed
the display for your own design, then you will have to extend this
class (HtmlReporter) instead.
If you have accessed the event queue by overriding the notify() method
then I am afraid you are in big trouble :(. The reporter is now
carried around the test suite by the runner classes and the methods
called directly. In the unlikely event that this is a problem and
you don't want to upgrade the test tool then simplest is to write your
own runner class and invoke the tests with...
$test->accept(new MyRunner(new MyReporter()));
...rather than the run method. This should be easier to extend
anyway and gives much more control. Even this method is overhauled
in Beta3 where the runner class can be set within the test case. Really
the best thing to do is to upgrade to this version as whatever you were
trying to achieve before should now be very much easier.
Missing set options method
--------------------------
All test suite options are now in one class called SimpleTestOptions.
This means that options are set differently...
GroupTest::ignore() --> SimpleTestOptions::ignore()
Mock::setMockBaseClass() --> SimpleTestOptions::setMockBaseClass()
These changed in Alpha8 and the old versions are now removed in RC1.
No method setExpected*()
------------------------
The mock expectations changed their names in Alpha4 and the old names
ceased to be supported in Alpha8. The changes are...
setExpectedArguments() --> expectArguments()
setExpectedArgumentsSequence() --> expectArgumentsAt()
setExpectedCallCount() --> expectCallCount()
setMaximumCallCount() --> expectMaximumCallCount()
The parameters remained the same.

View File

@ -1,502 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -1,102 +0,0 @@
SimpleTest
==========
You probably got this package from:
http://simpletest.org/en/download.html
If there is no licence agreement with this package please download
a version from the location above. You must read and accept that
licence to use this software. The file is titled simply LICENSE.
What is it? It's a framework for unit testing, web site testing and
mock objects for PHP 5.0.5+.
If you have used JUnit, you will find this PHP unit testing version very
similar. Also included is a mock objects and server stubs generator.
The stubs can have return values set for different arguments, can have
sequences set also by arguments and can return items by reference.
The mocks inherit all of this functionality and can also have
expectations set, again in sequences and for different arguments.
A web tester similar in concept to JWebUnit is also included. There is no
JavaScript or tables support, but forms, authentication, cookies and
frames are handled.
You can see a release schedule at http://simpletest.org/en/overview.html
which is also copied to the documentation folder with this release.
A full PHPDocumenter API documentation exists at
http://simpletest.org/api/.
The user interface is minimal in the extreme, but a lot of information
flows from the test suite. After version 1.0 we will release a better
web UI, but we are leaving XUL and GTK versions to volunteers as
everybody has their own opinion on a good GUI, and we don't want to
discourage development by shipping one with the toolkit. You can
download an Eclipse plug-in separately.
The unit tests for SimpleTest itself can be run here:
test/unit_tests.php
And tests involving live network connections as well are here:
test/all_tests.php
The full tests will typically overrun the 8Mb limit often allowed
to a PHP process. A workaround is to run the tests on the command
with a custom php.ini file or with the switch -dmemory_limit=-1
if you do not have access to your server version.
The full tests read some test data from simpletest.org. If the site
is down or has been modified for a later version then you will get
spurious errors. A unit_tests.php failure on the other hand would be
very serious. Please notify us if you find one.
Even if all of the tests run please verify that your existing test suites
also function as expected. The file:
HELP_MY_TESTS_DONT_WORK_ANYMORE
...contains information on interface changes. It also points out
deprecated interfaces, so you should read this even if all of
your current tests appear to run.
There is a documentation folder which contains the core reference information
in English and French, although this information is fairly basic.
You can find a tutorial on...
http://simpletest.org/en/first_test_tutorial.html
...to get you started and this material will eventually become included
with the project documentation. A French translation exists at:
http://simpletest.org/fr/first_test_tutorial.html
If you download and use, and possibly even extend this tool, please let us
know. Any feedback, even bad, is always welcome and we will work to get
your suggestions into the next release. Ideally please send your
comments to:
simpletest-support@lists.sourceforge.net
...so that others can read them too. We usually try to respond within 48
hours.
There is no change log except at Sourceforge. You can visit the
release notes to see the completed TODO list after each cycle and also the
status of any bugs, but if the bug is recent then it will be fixed in SVN only.
The SVN check-ins always have all the tests passing and so SVN snapshots should
be pretty usable, although the code may not look so good internally.
Oh, and one last thing: SimpleTest is called "Simple" because it should
be simple to use. We intend to add a complete set of tools for a test
first and "test as you code" type of development. "Simple" does not mean
"Lite" in this context.
Thanks to everyone who has sent comments and offered suggestions. They
really are invaluable, but sadly you are too many to mention in full.
Thanks to all on the advanced PHP forum on SitePoint, especially Harry
Fuecks. Early adopters are always an inspiration.
-- Marcus Baker, Jason Sweat, Travis Swicegood, Perrick Penet and Edward Z. Yang.

View File

@ -1 +0,0 @@
1.1.0

View File

@ -1,224 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: dumper.php 1909 2009-07-29 15:58:11Z dgheath $
*/
/**
* Parses the command line arguments.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleArguments {
private $all = array();
/**
* Parses the command line arguments. The usual formats
* are supported:
* -f value
* -f=value
* --flag=value
* --flag value
* -f (true)
* --flag (true)
* @param array $arguments Normally the PHP $argv.
*/
function __construct($arguments) {
array_shift($arguments);
while (count($arguments) > 0) {
list($key, $value) = $this->parseArgument($arguments);
$this->assign($key, $value);
}
}
/**
* Sets the value in the argments object. If multiple
* values are added under the same key, the key will
* give an array value in the order they were added.
* @param string $key The variable to assign to.
* @param string value The value that would norally
* be colected on the command line.
*/
function assign($key, $value) {
if ($this->$key === false) {
$this->all[$key] = $value;
} elseif (! is_array($this->$key)) {
$this->all[$key] = array($this->$key, $value);
} else {
$this->all[$key][] = $value;
}
}
/**
* Extracts the next key and value from the argument list.
* @param array $arguments The remaining arguments to be parsed.
* The argument list will be reduced.
* @return array Two item array of key and value.
* If no value can be found it will
* have the value true assigned instead.
*/
private function parseArgument(&$arguments) {
$argument = array_shift($arguments);
if (preg_match('/^-(\w)=(.+)$/', $argument, $matches)) {
return array($matches[1], $matches[2]);
} elseif (preg_match('/^-(\w)$/', $argument, $matches)) {
return array($matches[1], $this->nextNonFlagElseTrue($arguments));
} elseif (preg_match('/^--(\w+)=(.+)$/', $argument, $matches)) {
return array($matches[1], $matches[2]);
} elseif (preg_match('/^--(\w+)$/', $argument, $matches)) {
return array($matches[1], $this->nextNonFlagElseTrue($arguments));
}
}
/**
* Attempts to use the next argument as a value. It
* won't use what it thinks is a flag.
* @param array $arguments Remaining arguments to be parsed.
* This variable is modified if there
* is a value to be extracted.
* @return string/boolean The next value unless it's a flag.
*/
private function nextNonFlagElseTrue(&$arguments) {
return $this->valueIsNext($arguments) ? array_shift($arguments) : true;
}
/**
* Test to see if the next available argument is a valid value.
* If it starts with "-" or "--" it's a flag and doesn't count.
* @param array $arguments Remaining arguments to be parsed.
* Not affected by this call.
* boolean True if valid value.
*/
function valueIsNext($arguments) {
return isset($arguments[0]) && ! $this->isFlag($arguments[0]);
}
/**
* It's a flag if it starts with "-" or "--".
* @param string $argument Value to be tested.
* @return boolean True if it's a flag.
*/
function isFlag($argument) {
return strncmp($argument, '-', 1) == 0;
}
/**
* The arguments are available as individual member
* variables on the object.
* @param string $key Argument name.
* @return string/array/boolean Either false for no value,
* the value as a string or
* a list of multiple values if
* the flag had been specified more
* than once.
*/
function __get($key) {
if (isset($this->all[$key])) {
return $this->all[$key];
}
return false;
}
/**
* The entire argument set as a hash.
* @return hash Each argument and it's value(s).
*/
function all() {
return $this->all;
}
}
/**
* Renders the help for the command line arguments.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleHelp {
private $overview;
private $flag_sets = array();
private $explanations = array();
/**
* Sets up the top level explanation for the program.
* @param string $overview Summary of program.
*/
function __construct($overview = '') {
$this->overview = $overview;
}
/**
* Adds the explanation for a group of flags that all
* have the same function.
* @param string/array $flags Flag and alternates. Don't
* worry about leading dashes
* as these are inserted automatically.
* @param string $explanation What that flag group does.
*/
function explainFlag($flags, $explanation) {
$flags = is_array($flags) ? $flags : array($flags);
$this->flag_sets[] = $flags;
$this->explanations[] = $explanation;
}
/**
* Generates the help text.
* @returns string The complete formatted text.
*/
function render() {
$tab_stop = $this->longestFlag($this->flag_sets) + 4;
$text = $this->overview . "\n";
for ($i = 0; $i < count($this->flag_sets); $i++) {
$text .= $this->renderFlagSet($this->flag_sets[$i], $this->explanations[$i], $tab_stop);
}
return $this->noDuplicateNewLines($text);
}
/**
* Works out the longest flag for formatting purposes.
* @param array $flag_sets The internal flag set list.
*/
private function longestFlag($flag_sets) {
$longest = 0;
foreach ($flag_sets as $flags) {
foreach ($flags as $flag) {
$longest = max($longest, strlen($this->renderFlag($flag)));
}
}
return $longest;
}
/**
* Generates the text for a single flag and it's alternate flags.
* @returns string Help text for that flag group.
*/
private function renderFlagSet($flags, $explanation, $tab_stop) {
$flag = array_shift($flags);
$text = str_pad($this->renderFlag($flag), $tab_stop, ' ') . $explanation . "\n";
foreach ($flags as $flag) {
$text .= ' ' . $this->renderFlag($flag) . "\n";
}
return $text;
}
/**
* Generates the flag name including leading dashes.
* @param string $flag Just the name.
* @returns Fag with apropriate dashes.
*/
private function renderFlag($flag) {
return (strlen($flag) == 1 ? '-' : '--') . $flag;
}
/**
* Converts multiple new lines into a single new line.
* Just there to trap accidental duplicate new lines.
* @param string $text Text to clean up.
* @returns string Text with no blank lines.
*/
private function noDuplicateNewLines($text) {
return preg_replace('/(\n+)/', "\n", $text);
}
}
?>

View File

@ -1,237 +0,0 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id: authentication.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**
* include http class
*/
require_once(dirname(__FILE__) . '/http.php');
/**
* Represents a single security realm's identity.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleRealm {
private $type;
private $root;
private $username;
private $password;
/**
* Starts with the initial entry directory.
* @param string $type Authentication type for this
* realm. Only Basic authentication
* is currently supported.
* @param SimpleUrl $url Somewhere in realm.
* @access public
*/
function SimpleRealm($type, $url) {
$this->type = $type;
$this->root = $url->getBasePath();
$this->username = false;
$this->password = false;
}
/**
* Adds another location to the realm.
* @param SimpleUrl $url Somewhere in realm.
* @access public
*/
function stretch($url) {
$this->root = $this->getCommonPath($this->root, $url->getPath());
}
/**
* Finds the common starting path.
* @param string $first Path to compare.
* @param string $second Path to compare.
* @return string Common directories.
* @access private
*/
protected function getCommonPath($first, $second) {
$first = explode('/', $first);
$second = explode('/', $second);
for ($i = 0; $i < min(count($first), count($second)); $i++) {
if ($first[$i] != $second[$i]) {
return implode('/', array_slice($first, 0, $i)) . '/';
}
}
return implode('/', $first) . '/';
}
/**
* Sets the identity to try within this realm.
* @param string $username Username in authentication dialog.
* @param string $username Password in authentication dialog.
* @access public
*/
function setIdentity($username, $password) {
$this->username = $username;
$this->password = $password;
}
/**
* Accessor for current identity.
* @return string Last succesful username.
* @access public
*/
function getUsername() {
return $this->username;
}
/**
* Accessor for current identity.
* @return string Last succesful password.
* @access public
*/
function getPassword() {
return $this->password;
}
/**
* Test to see if the URL is within the directory
* tree of the realm.
* @param SimpleUrl $url URL to test.
* @return boolean True if subpath.
* @access public
*/
function isWithin($url) {
if ($this->isIn($this->root, $url->getBasePath())) {
return true;
}
if ($this->isIn($this->root, $url->getBasePath() . $url->getPage() . '/')) {
return true;
}
return false;
}
/**
* Tests to see if one string is a substring of
* another.
* @param string $part Small bit.
* @param string $whole Big bit.
* @return boolean True if the small bit is
* in the big bit.
* @access private
*/
protected function isIn($part, $whole) {
return strpos($whole, $part) === 0;
}
}
/**
* Manages security realms.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleAuthenticator {
private $realms;
/**
* Clears the realms.
* @access public
*/
function SimpleAuthenticator() {
$this->restartSession();
}
/**
* Starts with no realms set up.
* @access public
*/
function restartSession() {
$this->realms = array();
}
/**
* Adds a new realm centered the current URL.
* Browsers privatey wildly on their behaviour in this
* regard. Mozilla ignores the realm and presents
* only when challenged, wasting bandwidth. IE
* just carries on presenting until a new challenge
* occours. SimpleTest tries to follow the spirit of
* the original standards committee and treats the
* base URL as the root of a file tree shaped realm.
* @param SimpleUrl $url Base of realm.
* @param string $type Authentication type for this
* realm. Only Basic authentication
* is currently supported.
* @param string $realm Name of realm.
* @access public
*/
function addRealm($url, $type, $realm) {
$this->realms[$url->getHost()][$realm] = new SimpleRealm($type, $url);
}
/**
* Sets the current identity to be presented
* against that realm.
* @param string $host Server hosting realm.
* @param string $realm Name of realm.
* @param string $username Username for realm.
* @param string $password Password for realm.
* @access public
*/
function setIdentityForRealm($host, $realm, $username, $password) {
if (isset($this->realms[$host][$realm])) {
$this->realms[$host][$realm]->setIdentity($username, $password);
}
}
/**
* Finds the name of the realm by comparing URLs.
* @param SimpleUrl $url URL to test.
* @return SimpleRealm Name of realm.
* @access private
*/
protected function findRealmFromUrl($url) {
if (! isset($this->realms[$url->getHost()])) {
return false;
}
foreach ($this->realms[$url->getHost()] as $name => $realm) {
if ($realm->isWithin($url)) {
return $realm;
}
}
return false;
}
/**
* Presents the appropriate headers for this location.
* @param SimpleHttpRequest $request Request to modify.
* @param SimpleUrl $url Base of realm.
* @access public
*/
function addHeaders(&$request, $url) {
if ($url->getUsername() && $url->getPassword()) {
$username = $url->getUsername();
$password = $url->getPassword();
} elseif ($realm = $this->findRealmFromUrl($url)) {
$username = $realm->getUsername();
$password = $realm->getPassword();
} else {
return;
}
$this->addBasicHeaders($request, $username, $password);
}
/**
* Presents the appropriate headers for this
* location for basic authentication.
* @param SimpleHttpRequest $request Request to modify.
* @param string $username Username for realm.
* @param string $password Password for realm.
* @access public
*/
static function addBasicHeaders(&$request, $username, $password) {
if ($username && $password) {
$request->addHeaderLine(
'Authorization: Basic ' . base64_encode("$username:$password"));
}
}
}
?>

View File

@ -1,101 +0,0 @@
<?php
/**
* Autorunner which runs all tests cases found in a file
* that includes this module.
* @package SimpleTest
* @version $Id: autorun.php 2037 2011-11-30 17:58:21Z pp11 $
*/
/**#@+
* include simpletest files
*/
require_once dirname(__FILE__) . '/unit_tester.php';
require_once dirname(__FILE__) . '/mock_objects.php';
require_once dirname(__FILE__) . '/collector.php';
require_once dirname(__FILE__) . '/default_reporter.php';
/**#@-*/
$GLOBALS['SIMPLETEST_AUTORUNNER_INITIAL_CLASSES'] = get_declared_classes();
$GLOBALS['SIMPLETEST_AUTORUNNER_INITIAL_PATH'] = getcwd();
register_shutdown_function('simpletest_autorun');
/**
* Exit handler to run all recent test cases and exit system if in CLI
*/
function simpletest_autorun() {
chdir($GLOBALS['SIMPLETEST_AUTORUNNER_INITIAL_PATH']);
if (tests_have_run()) {
return;
}
$result = run_local_tests();
if (SimpleReporter::inCli()) {
exit($result ? 0 : 1);
}
}
/**
* run all recent test cases if no test has
* so far been run. Uses the DefaultReporter which can have
* it's output controlled with SimpleTest::prefer().
* @return boolean/null false if there were test failures, true if
* there were no failures, null if tests are
* already running
*/
function run_local_tests() {
try {
if (tests_have_run()) {
return;
}
$candidates = capture_new_classes();
$loader = new SimpleFileLoader();
$suite = $loader->createSuiteFromClasses(
basename(initial_file()),
$loader->selectRunnableTests($candidates));
return $suite->run(new DefaultReporter());
} catch (Exception $stack_frame_fix) {
print $stack_frame_fix->getMessage();
return false;
}
}
/**
* Checks the current test context to see if a test has
* ever been run.
* @return boolean True if tests have run.
*/
function tests_have_run() {
if ($context = SimpleTest::getContext()) {
return (boolean)$context->getTest();
}
return false;
}
/**
* The first autorun file.
* @return string Filename of first autorun script.
*/
function initial_file() {
static $file = false;
if (! $file) {
if (isset($_SERVER, $_SERVER['SCRIPT_FILENAME'])) {
$file = $_SERVER['SCRIPT_FILENAME'];
} else {
$included_files = get_included_files();
$file = reset($included_files);
}
}
return $file;
}
/**
* Every class since the first autorun include. This
* is safe enough if require_once() is always used.
* @return array Class names.
*/
function capture_new_classes() {
global $SIMPLETEST_AUTORUNNER_INITIAL_CLASSES;
return array_map('strtolower', array_diff(get_declared_classes(),
$SIMPLETEST_AUTORUNNER_INITIAL_CLASSES ?
$SIMPLETEST_AUTORUNNER_INITIAL_CLASSES : array()));
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,122 +0,0 @@
<?php
/**
* This file contains the following classes: {@link SimpleCollector},
* {@link SimplePatternCollector}.
*
* @author Travis Swicegood <development@domain51.com>
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: collector.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**
* The basic collector for {@link GroupTest}
*
* @see collect(), GroupTest::collect()
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleCollector {
/**
* Strips off any kind of slash at the end so as to normalise the path.
* @param string $path Path to normalise.
* @return string Path without trailing slash.
*/
protected function removeTrailingSlash($path) {
if (substr($path, -1) == DIRECTORY_SEPARATOR) {
return substr($path, 0, -1);
} elseif (substr($path, -1) == '/') {
return substr($path, 0, -1);
} else {
return $path;
}
}
/**
* Scans the directory and adds what it can.
* @param object $test Group test with {@link GroupTest::addTestFile()} method.
* @param string $path Directory to scan.
* @see _attemptToAdd()
*/
function collect(&$test, $path) {
$path = $this->removeTrailingSlash($path);
if ($handle = opendir($path)) {
while (($entry = readdir($handle)) !== false) {
if ($this->isHidden($entry)) {
continue;
}
$this->handle($test, $path . DIRECTORY_SEPARATOR . $entry);
}
closedir($handle);
}
}
/**
* This method determines what should be done with a given file and adds
* it via {@link GroupTest::addTestFile()} if necessary.
*
* This method should be overriden to provide custom matching criteria,
* such as pattern matching, recursive matching, etc. For an example, see
* {@link SimplePatternCollector::_handle()}.
*
* @param object $test Group test with {@link GroupTest::addTestFile()} method.
* @param string $filename A filename as generated by {@link collect()}
* @see collect()
* @access protected
*/
protected function handle(&$test, $file) {
if (is_dir($file)) {
return;
}
$test->addFile($file);
}
/**
* Tests for hidden files so as to skip them. Currently
* only tests for Unix hidden files.
* @param string $filename Plain filename.
* @return boolean True if hidden file.
* @access private
*/
protected function isHidden($filename) {
return strncmp($filename, '.', 1) == 0;
}
}
/**
* An extension to {@link SimpleCollector} that only adds files matching a
* given pattern.
*
* @package SimpleTest
* @subpackage UnitTester
* @see SimpleCollector
*/
class SimplePatternCollector extends SimpleCollector {
private $pattern;
/**
*
* @param string $pattern Perl compatible regex to test name against
* See {@link http://us4.php.net/manual/en/reference.pcre.pattern.syntax.php PHP's PCRE}
* for full documentation of valid pattern.s
*/
function __construct($pattern = '/php$/i') {
$this->pattern = $pattern;
}
/**
* Attempts to add files that match a given pattern.
*
* @see SimpleCollector::_handle()
* @param object $test Group test with {@link GroupTest::addTestFile()} method.
* @param string $path Directory to scan.
* @access protected
*/
protected function handle(&$test, $filename) {
if (preg_match($this->pattern, $filename)) {
parent::handle($test, $filename);
}
}
}
?>

View File

@ -1,166 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @version $Id: compatibility.php 1900 2009-07-29 11:44:37Z lastcraft $
*/
/**
* Static methods for compatibility between different
* PHP versions.
* @package SimpleTest
*/
class SimpleTestCompatibility {
/**
* Creates a copy whether in PHP5 or PHP4.
* @param object $object Thing to copy.
* @return object A copy.
* @access public
*/
static function copy($object) {
if (version_compare(phpversion(), '5') >= 0) {
eval('$copy = clone $object;');
return $copy;
}
return $object;
}
/**
* Identity test. Drops back to equality + types for PHP5
* objects as the === operator counts as the
* stronger reference constraint.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if identical.
* @access public
*/
static function isIdentical($first, $second) {
if (version_compare(phpversion(), '5') >= 0) {
return SimpleTestCompatibility::isIdenticalType($first, $second);
}
if ($first != $second) {
return false;
}
return ($first === $second);
}
/**
* Recursive type test.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if same type.
* @access private
*/
protected static function isIdenticalType($first, $second) {
if (gettype($first) != gettype($second)) {
return false;
}
if (is_object($first) && is_object($second)) {
if (get_class($first) != get_class($second)) {
return false;
}
return SimpleTestCompatibility::isArrayOfIdenticalTypes(
(array) $first,
(array) $second);
}
if (is_array($first) && is_array($second)) {
return SimpleTestCompatibility::isArrayOfIdenticalTypes($first, $second);
}
if ($first !== $second) {
return false;
}
return true;
}
/**
* Recursive type test for each element of an array.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if identical.
* @access private
*/
protected static function isArrayOfIdenticalTypes($first, $second) {
if (array_keys($first) != array_keys($second)) {
return false;
}
foreach (array_keys($first) as $key) {
$is_identical = SimpleTestCompatibility::isIdenticalType(
$first[$key],
$second[$key]);
if (! $is_identical) {
return false;
}
}
return true;
}
/**
* Test for two variables being aliases.
* @param mixed $first Test subject.
* @param mixed $second Comparison object.
* @return boolean True if same.
* @access public
*/
static function isReference(&$first, &$second) {
if (version_compare(phpversion(), '5', '>=') && is_object($first)) {
return ($first === $second);
}
if (is_object($first) && is_object($second)) {
$id = uniqid("test");
$first->$id = true;
$is_ref = isset($second->$id);
unset($first->$id);
return $is_ref;
}
$temp = $first;
$first = uniqid("test");
$is_ref = ($first === $second);
$first = $temp;
return $is_ref;
}
/**
* Test to see if an object is a member of a
* class hiearchy.
* @param object $object Object to test.
* @param string $class Root name of hiearchy.
* @return boolean True if class in hiearchy.
* @access public
*/
static function isA($object, $class) {
if (version_compare(phpversion(), '5') >= 0) {
if (! class_exists($class, false)) {
if (function_exists('interface_exists')) {
if (! interface_exists($class, false)) {
return false;
}
}
}
eval("\$is_a = \$object instanceof $class;");
return $is_a;
}
if (function_exists('is_a')) {
return is_a($object, $class);
}
return ((strtolower($class) == get_class($object))
or (is_subclass_of($object, $class)));
}
/**
* Sets a socket timeout for each chunk.
* @param resource $handle Socket handle.
* @param integer $timeout Limit in seconds.
* @access public
*/
static function setTimeout($handle, $timeout) {
if (function_exists('stream_set_timeout')) {
stream_set_timeout($handle, $timeout, 0);
} elseif (function_exists('socket_set_timeout')) {
socket_set_timeout($handle, $timeout, 0);
} elseif (function_exists('set_socket_timeout')) {
set_socket_timeout($handle, $timeout, 0);
}
}
}
?>

View File

@ -1,380 +0,0 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id: cookies.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/url.php');
/**#@-*/
/**
* Cookie data holder. Cookie rules are full of pretty
* arbitary stuff. I have used...
* http://wp.netscape.com/newsref/std/cookie_spec.html
* http://www.cookiecentral.com/faq/
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleCookie {
private $host;
private $name;
private $value;
private $path;
private $expiry;
private $is_secure;
/**
* Constructor. Sets the stored values.
* @param string $name Cookie key.
* @param string $value Value of cookie.
* @param string $path Cookie path if not host wide.
* @param string $expiry Expiry date as string.
* @param boolean $is_secure Currently ignored.
*/
function __construct($name, $value = false, $path = false, $expiry = false, $is_secure = false) {
$this->host = false;
$this->name = $name;
$this->value = $value;
$this->path = ($path ? $this->fixPath($path) : "/");
$this->expiry = false;
if (is_string($expiry)) {
$this->expiry = strtotime($expiry);
} elseif (is_integer($expiry)) {
$this->expiry = $expiry;
}
$this->is_secure = $is_secure;
}
/**
* Sets the host. The cookie rules determine
* that the first two parts are taken for
* certain TLDs and three for others. If the
* new host does not match these rules then the
* call will fail.
* @param string $host New hostname.
* @return boolean True if hostname is valid.
* @access public
*/
function setHost($host) {
if ($host = $this->truncateHost($host)) {
$this->host = $host;
return true;
}
return false;
}
/**
* Accessor for the truncated host to which this
* cookie applies.
* @return string Truncated hostname.
* @access public
*/
function getHost() {
return $this->host;
}
/**
* Test for a cookie being valid for a host name.
* @param string $host Host to test against.
* @return boolean True if the cookie would be valid
* here.
*/
function isValidHost($host) {
return ($this->truncateHost($host) === $this->getHost());
}
/**
* Extracts just the domain part that determines a
* cookie's host validity.
* @param string $host Host name to truncate.
* @return string Domain or false on a bad host.
* @access private
*/
protected function truncateHost($host) {
$tlds = SimpleUrl::getAllTopLevelDomains();
if (preg_match('/[a-z\-]+\.(' . $tlds . ')$/i', $host, $matches)) {
return $matches[0];
} elseif (preg_match('/[a-z\-]+\.[a-z\-]+\.[a-z\-]+$/i', $host, $matches)) {
return $matches[0];
}
return false;
}
/**
* Accessor for name.
* @return string Cookie key.
* @access public
*/
function getName() {
return $this->name;
}
/**
* Accessor for value. A deleted cookie will
* have an empty string for this.
* @return string Cookie value.
* @access public
*/
function getValue() {
return $this->value;
}
/**
* Accessor for path.
* @return string Valid cookie path.
* @access public
*/
function getPath() {
return $this->path;
}
/**
* Tests a path to see if the cookie applies
* there. The test path must be longer or
* equal to the cookie path.
* @param string $path Path to test against.
* @return boolean True if cookie valid here.
* @access public
*/
function isValidPath($path) {
return (strncmp(
$this->fixPath($path),
$this->getPath(),
strlen($this->getPath())) == 0);
}
/**
* Accessor for expiry.
* @return string Expiry string.
* @access public
*/
function getExpiry() {
if (! $this->expiry) {
return false;
}
return gmdate("D, d M Y H:i:s", $this->expiry) . " GMT";
}
/**
* Test to see if cookie is expired against
* the cookie format time or timestamp.
* Will give true for a session cookie.
* @param integer/string $now Time to test against. Result
* will be false if this time
* is later than the cookie expiry.
* Can be either a timestamp integer
* or a cookie format date.
* @access public
*/
function isExpired($now) {
if (! $this->expiry) {
return true;
}
if (is_string($now)) {
$now = strtotime($now);
}
return ($this->expiry < $now);
}
/**
* Ages the cookie by the specified number of
* seconds.
* @param integer $interval In seconds.
* @public
*/
function agePrematurely($interval) {
if ($this->expiry) {
$this->expiry -= $interval;
}
}
/**
* Accessor for the secure flag.
* @return boolean True if cookie needs SSL.
* @access public
*/
function isSecure() {
return $this->is_secure;
}
/**
* Adds a trailing and leading slash to the path
* if missing.
* @param string $path Path to fix.
* @access private
*/
protected function fixPath($path) {
if (substr($path, 0, 1) != '/') {
$path = '/' . $path;
}
if (substr($path, -1, 1) != '/') {
$path .= '/';
}
return $path;
}
}
/**
* Repository for cookies. This stuff is a
* tiny bit browser dependent.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleCookieJar {
private $cookies;
/**
* Constructor. Jar starts empty.
* @access public
*/
function __construct() {
$this->cookies = array();
}
/**
* Removes expired and temporary cookies as if
* the browser was closed and re-opened.
* @param string/integer $now Time to test expiry against.
* @access public
*/
function restartSession($date = false) {
$surviving_cookies = array();
for ($i = 0; $i < count($this->cookies); $i++) {
if (! $this->cookies[$i]->getValue()) {
continue;
}
if (! $this->cookies[$i]->getExpiry()) {
continue;
}
if ($date && $this->cookies[$i]->isExpired($date)) {
continue;
}
$surviving_cookies[] = $this->cookies[$i];
}
$this->cookies = $surviving_cookies;
}
/**
* Ages all cookies in the cookie jar.
* @param integer $interval The old session is moved
* into the past by this number
* of seconds. Cookies now over
* age will be removed.
* @access public
*/
function agePrematurely($interval) {
for ($i = 0; $i < count($this->cookies); $i++) {
$this->cookies[$i]->agePrematurely($interval);
}
}
/**
* Sets an additional cookie. If a cookie has
* the same name and path it is replaced.
* @param string $name Cookie key.
* @param string $value Value of cookie.
* @param string $host Host upon which the cookie is valid.
* @param string $path Cookie path if not host wide.
* @param string $expiry Expiry date.
* @access public
*/
function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
$cookie = new SimpleCookie($name, $value, $path, $expiry);
if ($host) {
$cookie->setHost($host);
}
$this->cookies[$this->findFirstMatch($cookie)] = $cookie;
}
/**
* Finds a matching cookie to write over or the
* first empty slot if none.
* @param SimpleCookie $cookie Cookie to write into jar.
* @return integer Available slot.
* @access private
*/
protected function findFirstMatch($cookie) {
for ($i = 0; $i < count($this->cookies); $i++) {
$is_match = $this->isMatch(
$cookie,
$this->cookies[$i]->getHost(),
$this->cookies[$i]->getPath(),
$this->cookies[$i]->getName());
if ($is_match) {
return $i;
}
}
return count($this->cookies);
}
/**
* Reads the most specific cookie value from the
* browser cookies. Looks for the longest path that
* matches.
* @param string $host Host to search.
* @param string $path Applicable path.
* @param string $name Name of cookie to read.
* @return string False if not present, else the
* value as a string.
* @access public
*/
function getCookieValue($host, $path, $name) {
$longest_path = '';
foreach ($this->cookies as $cookie) {
if ($this->isMatch($cookie, $host, $path, $name)) {
if (strlen($cookie->getPath()) > strlen($longest_path)) {
$value = $cookie->getValue();
$longest_path = $cookie->getPath();
}
}
}
return (isset($value) ? $value : false);
}
/**
* Tests cookie for matching against search
* criteria.
* @param SimpleTest $cookie Cookie to test.
* @param string $host Host must match.
* @param string $path Cookie path must be shorter than
* this path.
* @param string $name Name must match.
* @return boolean True if matched.
* @access private
*/
protected function isMatch($cookie, $host, $path, $name) {
if ($cookie->getName() != $name) {
return false;
}
if ($host && $cookie->getHost() && ! $cookie->isValidHost($host)) {
return false;
}
if (! $cookie->isValidPath($path)) {
return false;
}
return true;
}
/**
* Uses a URL to sift relevant cookies by host and
* path. Results are list of strings of form "name=value".
* @param SimpleUrl $url Url to select by.
* @return array Valid name and value pairs.
* @access public
*/
function selectAsPairs($url) {
$pairs = array();
foreach ($this->cookies as $cookie) {
if ($this->isMatch($cookie, $url->getHost(), $url->getPath(), $cookie->getName())) {
$pairs[] = $cookie->getName() . '=' . $cookie->getValue();
}
}
return $pairs;
}
}
?>

View File

@ -1,163 +0,0 @@
<?php
/**
* Optional include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: default_reporter.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/simpletest.php');
require_once(dirname(__FILE__) . '/scorer.php');
require_once(dirname(__FILE__) . '/reporter.php');
require_once(dirname(__FILE__) . '/xml.php');
/**#@-*/
/**
* Parser for command line arguments. Extracts
* the a specific test to run and engages XML
* reporting when necessary.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleCommandLineParser {
private $to_property = array(
'case' => 'case', 'c' => 'case',
'test' => 'test', 't' => 'test',
);
private $case = '';
private $test = '';
private $xml = false;
private $help = false;
private $no_skips = false;
/**
* Parses raw command line arguments into object properties.
* @param string $arguments Raw commend line arguments.
*/
function __construct($arguments) {
if (! is_array($arguments)) {
return;
}
foreach ($arguments as $i => $argument) {
if (preg_match('/^--?(test|case|t|c)=(.+)$/', $argument, $matches)) {
$property = $this->to_property[$matches[1]];
$this->$property = $matches[2];
} elseif (preg_match('/^--?(test|case|t|c)$/', $argument, $matches)) {
$property = $this->to_property[$matches[1]];
if (isset($arguments[$i + 1])) {
$this->$property = $arguments[$i + 1];
}
} elseif (preg_match('/^--?(xml|x)$/', $argument)) {
$this->xml = true;
} elseif (preg_match('/^--?(no-skip|no-skips|s)$/', $argument)) {
$this->no_skips = true;
} elseif (preg_match('/^--?(help|h)$/', $argument)) {
$this->help = true;
}
}
}
/**
* Run only this test.
* @return string Test name to run.
*/
function getTest() {
return $this->test;
}
/**
* Run only this test suite.
* @return string Test class name to run.
*/
function getTestCase() {
return $this->case;
}
/**
* Output should be XML or not.
* @return boolean True if XML desired.
*/
function isXml() {
return $this->xml;
}
/**
* Output should suppress skip messages.
* @return boolean True for no skips.
*/
function noSkips() {
return $this->no_skips;
}
/**
* Output should be a help message. Disabled during XML mode.
* @return boolean True if help message desired.
*/
function help() {
return $this->help && ! $this->xml;
}
/**
* Returns plain-text help message for command line runner.
* @return string String help message
*/
function getHelpText() {
return <<<HELP
SimpleTest command line default reporter (autorun)
Usage: php <test_file> [args...]
-c <class> Run only the test-case <class>
-t <method> Run only the test method <method>
-s Suppress skip messages
-x Return test results in XML
-h Display this help message
HELP;
}
}
/**
* The default reporter used by SimpleTest's autorun
* feature. The actual reporters used are dependency
* injected and can be overridden.
* @package SimpleTest
* @subpackage UnitTester
*/
class DefaultReporter extends SimpleReporterDecorator {
/**
* Assembles the appropriate reporter for the environment.
*/
function __construct() {
if (SimpleReporter::inCli()) {
$parser = new SimpleCommandLineParser($_SERVER['argv']);
$interfaces = $parser->isXml() ? array('XmlReporter') : array('TextReporter');
if ($parser->help()) {
// I'm not sure if we should do the echo'ing here -- ezyang
echo $parser->getHelpText();
exit(1);
}
$reporter = new SelectiveReporter(
SimpleTest::preferred($interfaces),
$parser->getTestCase(),
$parser->getTest());
if ($parser->noSkips()) {
$reporter = new NoSkipsReporter($reporter);
}
} else {
$reporter = new SelectiveReporter(
SimpleTest::preferred('HtmlReporter'),
@$_GET['c'],
@$_GET['t']);
if (@$_GET['skips'] == 'no' || @$_GET['show-skips'] == 'no') {
$reporter = new NoSkipsReporter($reporter);
}
}
parent::__construct($reporter);
}
}
?>

View File

@ -1,96 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: detached.php 1784 2008-04-26 13:07:14Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/xml.php');
require_once(dirname(__FILE__) . '/shell_tester.php');
/**#@-*/
/**
* Runs an XML formated test in a separate process.
* @package SimpleTest
* @subpackage UnitTester
*/
class DetachedTestCase {
private $command;
private $dry_command;
private $size;
/**
* Sets the location of the remote test.
* @param string $command Test script.
* @param string $dry_command Script for dry run.
* @access public
*/
function __construct($command, $dry_command = false) {
$this->command = $command;
$this->dry_command = $dry_command ? $dry_command : $command;
$this->size = false;
}
/**
* Accessor for the test name for subclasses.
* @return string Name of the test.
* @access public
*/
function getLabel() {
return $this->command;
}
/**
* Runs the top level test for this class. Currently
* reads the data as a single chunk. I'll fix this
* once I have added iteration to the browser.
* @param SimpleReporter $reporter Target of test results.
* @returns boolean True if no failures.
* @access public
*/
function run(&$reporter) {
$shell = &new SimpleShell();
$shell->execute($this->command);
$parser = &$this->createParser($reporter);
if (! $parser->parse($shell->getOutput())) {
trigger_error('Cannot parse incoming XML from [' . $this->command . ']');
return false;
}
return true;
}
/**
* Accessor for the number of subtests.
* @return integer Number of test cases.
* @access public
*/
function getSize() {
if ($this->size === false) {
$shell = &new SimpleShell();
$shell->execute($this->dry_command);
$reporter = &new SimpleReporter();
$parser = &$this->createParser($reporter);
if (! $parser->parse($shell->getOutput())) {
trigger_error('Cannot parse incoming XML from [' . $this->dry_command . ']');
return false;
}
$this->size = $reporter->getTestCaseCount();
}
return $this->size;
}
/**
* Creates the XML parser.
* @param SimpleReporter $reporter Target of test results.
* @return SimpleTestXmlListener XML reader.
* @access protected
*/
protected function &createParser(&$reporter) {
return new SimpleTestXmlParser($reporter);
}
}
?>

View File

@ -1,407 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: dumper.php 1909 2009-07-29 15:58:11Z dgheath $
*/
/**
* does type matter
*/
if (! defined('TYPE_MATTERS')) {
define('TYPE_MATTERS', true);
}
/**
* Displays variables as text and does diffs.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleDumper {
/**
* Renders a variable in a shorter form than print_r().
* @param mixed $value Variable to render as a string.
* @return string Human readable string form.
* @access public
*/
function describeValue($value) {
$type = $this->getType($value);
switch($type) {
case "Null":
return "NULL";
case "Boolean":
return "Boolean: " . ($value ? "true" : "false");
case "Array":
return "Array: " . count($value) . " items";
case "Object":
return "Object: of " . get_class($value);
case "String":
return "String: " . $this->clipString($value, 200);
default:
return "$type: $value";
}
return "Unknown";
}
/**
* Gets the string representation of a type.
* @param mixed $value Variable to check against.
* @return string Type.
* @access public
*/
function getType($value) {
if (! isset($value)) {
return "Null";
} elseif (is_bool($value)) {
return "Boolean";
} elseif (is_string($value)) {
return "String";
} elseif (is_integer($value)) {
return "Integer";
} elseif (is_float($value)) {
return "Float";
} elseif (is_array($value)) {
return "Array";
} elseif (is_resource($value)) {
return "Resource";
} elseif (is_object($value)) {
return "Object";
}
return "Unknown";
}
/**
* Creates a human readable description of the
* difference between two variables. Uses a
* dynamic call.
* @param mixed $first First variable.
* @param mixed $second Value to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Description of difference.
* @access public
*/
function describeDifference($first, $second, $identical = false) {
if ($identical) {
if (! $this->isTypeMatch($first, $second)) {
return "with type mismatch as [" . $this->describeValue($first) .
"] does not match [" . $this->describeValue($second) . "]";
}
}
$type = $this->getType($first);
if ($type == "Unknown") {
return "with unknown type";
}
$method = 'describe' . $type . 'Difference';
return $this->$method($first, $second, $identical);
}
/**
* Tests to see if types match.
* @param mixed $first First variable.
* @param mixed $second Value to compare with.
* @return boolean True if matches.
* @access private
*/
protected function isTypeMatch($first, $second) {
return ($this->getType($first) == $this->getType($second));
}
/**
* Clips a string to a maximum length.
* @param string $value String to truncate.
* @param integer $size Minimum string size to show.
* @param integer $position Centre of string section.
* @return string Shortened version.
* @access public
*/
function clipString($value, $size, $position = 0) {
$length = strlen($value);
if ($length <= $size) {
return $value;
}
$position = min($position, $length);
$start = ($size/2 > $position ? 0 : $position - $size/2);
if ($start + $size > $length) {
$start = $length - $size;
}
$value = substr($value, $start, $size);
return ($start > 0 ? "..." : "") . $value . ($start + $size < $length ? "..." : "");
}
/**
* Creates a human readable description of the
* difference between two variables. The minimal
* version.
* @param null $first First value.
* @param mixed $second Value to compare with.
* @return string Human readable description.
* @access private
*/
protected function describeGenericDifference($first, $second) {
return "as [" . $this->describeValue($first) .
"] does not match [" .
$this->describeValue($second) . "]";
}
/**
* Creates a human readable description of the
* difference between a null and another variable.
* @param null $first First null.
* @param mixed $second Null to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
protected function describeNullDifference($first, $second, $identical) {
return $this->describeGenericDifference($first, $second);
}
/**
* Creates a human readable description of the
* difference between a boolean and another variable.
* @param boolean $first First boolean.
* @param mixed $second Boolean to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
protected function describeBooleanDifference($first, $second, $identical) {
return $this->describeGenericDifference($first, $second);
}
/**
* Creates a human readable description of the
* difference between a string and another variable.
* @param string $first First string.
* @param mixed $second String to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
protected function describeStringDifference($first, $second, $identical) {
if (is_object($second) || is_array($second)) {
return $this->describeGenericDifference($first, $second);
}
$position = $this->stringDiffersAt($first, $second);
$message = "at character $position";
$message .= " with [" .
$this->clipString($first, 200, $position) . "] and [" .
$this->clipString($second, 200, $position) . "]";
return $message;
}
/**
* Creates a human readable description of the
* difference between an integer and another variable.
* @param integer $first First number.
* @param mixed $second Number to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
protected function describeIntegerDifference($first, $second, $identical) {
if (is_object($second) || is_array($second)) {
return $this->describeGenericDifference($first, $second);
}
return "because [" . $this->describeValue($first) .
"] differs from [" .
$this->describeValue($second) . "] by " .
abs($first - $second);
}
/**
* Creates a human readable description of the
* difference between two floating point numbers.
* @param float $first First float.
* @param mixed $second Float to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
protected function describeFloatDifference($first, $second, $identical) {
if (is_object($second) || is_array($second)) {
return $this->describeGenericDifference($first, $second);
}
return "because [" . $this->describeValue($first) .
"] differs from [" .
$this->describeValue($second) . "] by " .
abs($first - $second);
}
/**
* Creates a human readable description of the
* difference between two arrays.
* @param array $first First array.
* @param mixed $second Array to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
protected function describeArrayDifference($first, $second, $identical) {
if (! is_array($second)) {
return $this->describeGenericDifference($first, $second);
}
if (! $this->isMatchingKeys($first, $second, $identical)) {
return "as key list [" .
implode(", ", array_keys($first)) . "] does not match key list [" .
implode(", ", array_keys($second)) . "]";
}
foreach (array_keys($first) as $key) {
if ($identical && ($first[$key] === $second[$key])) {
continue;
}
if (! $identical && ($first[$key] == $second[$key])) {
continue;
}
return "with member [$key] " . $this->describeDifference(
$first[$key],
$second[$key],
$identical);
}
return "";
}
/**
* Compares two arrays to see if their key lists match.
* For an identical match, the ordering and types of the keys
* is significant.
* @param array $first First array.
* @param array $second Array to compare with.
* @param boolean $identical If true then type anomolies count.
* @return boolean True if matching.
* @access private
*/
protected function isMatchingKeys($first, $second, $identical) {
$first_keys = array_keys($first);
$second_keys = array_keys($second);
if ($identical) {
return ($first_keys === $second_keys);
}
sort($first_keys);
sort($second_keys);
return ($first_keys == $second_keys);
}
/**
* Creates a human readable description of the
* difference between a resource and another variable.
* @param resource $first First resource.
* @param mixed $second Resource to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
* @access private
*/
protected function describeResourceDifference($first, $second, $identical) {
return $this->describeGenericDifference($first, $second);
}
/**
* Creates a human readable description of the
* difference between two objects.
* @param object $first First object.
* @param mixed $second Object to compare with.
* @param boolean $identical If true then type anomolies count.
* @return string Human readable description.
*/
protected function describeObjectDifference($first, $second, $identical) {
if (! is_object($second)) {
return $this->describeGenericDifference($first, $second);
}
return $this->describeArrayDifference(
$this->getMembers($first),
$this->getMembers($second),
$identical);
}
/**
* Get all members of an object including private and protected ones.
* A safer form of casting to an array.
* @param object $object Object to list members of,
* including private ones.
* @return array Names and values in the object.
*/
protected function getMembers($object) {
$reflection = new ReflectionObject($object);
$members = array();
foreach ($reflection->getProperties() as $property) {
if (method_exists($property, 'setAccessible')) {
$property->setAccessible(true);
}
try {
$members[$property->getName()] = $property->getValue($object);
} catch (ReflectionException $e) {
$members[$property->getName()] =
$this->getPrivatePropertyNoMatterWhat($property->getName(), $object);
}
}
return $members;
}
/**
* Extracts a private member's value when reflection won't play ball.
* @param string $name Property name.
* @param object $object Object to read.
* @return mixed Value of property.
*/
private function getPrivatePropertyNoMatterWhat($name, $object) {
foreach ((array)$object as $mangled_name => $value) {
if ($this->unmangle($mangled_name) == $name) {
return $value;
}
}
}
/**
* Removes crud from property name after it's been converted
* to an array.
* @param string $mangled Name from array cast.
* @return string Cleaned up name.
*/
function unmangle($mangled) {
$parts = preg_split('/[^a-zA-Z0-9_\x7f-\xff]+/', $mangled);
return array_pop($parts);
}
/**
* Find the first character position that differs
* in two strings by binary chop.
* @param string $first First string.
* @param string $second String to compare with.
* @return integer Position of first differing
* character.
* @access private
*/
protected function stringDiffersAt($first, $second) {
if (! $first || ! $second) {
return 0;
}
if (strlen($first) < strlen($second)) {
list($first, $second) = array($second, $first);
}
$position = 0;
$step = strlen($first);
while ($step > 1) {
$step = (integer)(($step + 1) / 2);
if (strncmp($first, $second, $position + $step) == 0) {
$position += $step;
}
}
return $position;
}
/**
* Sends a formatted dump of a variable to a string.
* @param mixed $variable Variable to display.
* @return string Output from print_r().
* @access public
*/
function dump($variable) {
ob_start();
print_r($variable);
$formatted = ob_get_contents();
ob_end_clean();
return $formatted;
}
}
?>

View File

@ -1,307 +0,0 @@
<?php
/**
* base include file for eclipse plugin
* @package SimpleTest
* @subpackage Eclipse
* @version $Id: eclipse.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+
* simpletest include files
*/
include_once 'unit_tester.php';
include_once 'test_case.php';
include_once 'invoker.php';
include_once 'socket.php';
include_once 'mock_objects.php';
/**#@-*/
/**
* base reported class for eclipse plugin
* @package SimpleTest
* @subpackage Eclipse
*/
class EclipseReporter extends SimpleScorer {
/**
* Reporter to be run inside of Eclipse interface.
* @param object $listener Eclipse listener (?).
* @param boolean $cc Whether to include test coverage.
*/
function __construct(&$listener, $cc=false){
$this->listener = &$listener;
$this->SimpleScorer();
$this->case = "";
$this->group = "";
$this->method = "";
$this->cc = $cc;
$this->error = false;
$this->fail = false;
}
/**
* Means to display human readable object comparisons.
* @return SimpleDumper Visual comparer.
*/
function getDumper() {
return new SimpleDumper();
}
/**
* Localhost connection from Eclipse.
* @param integer $port Port to connect to Eclipse.
* @param string $host Normally localhost.
* @return SimpleSocket Connection to Eclipse.
*/
function &createListener($port, $host="127.0.0.1"){
$tmplistener = &new SimpleSocket($host, $port, 5);
return $tmplistener;
}
/**
* Wraps the test in an output buffer.
* @param SimpleInvoker $invoker Current test runner.
* @return EclipseInvoker Decorator with output buffering.
* @access public
*/
function &createInvoker(&$invoker){
$eclinvoker = &new EclipseInvoker($invoker, $this->listener);
return $eclinvoker;
}
/**
* C style escaping.
* @param string $raw String with backslashes, quotes and whitespace.
* @return string Replaced with C backslashed tokens.
*/
function escapeVal($raw){
$needle = array("\\","\"","/","\b","\f","\n","\r","\t");
$replace = array('\\\\','\"','\/','\b','\f','\n','\r','\t');
return str_replace($needle, $replace, $raw);
}
/**
* Stash the first passing item. Clicking the test
* item goes to first pass.
* @param string $message Test message, but we only wnat the first.
* @access public
*/
function paintPass($message){
if (! $this->pass){
$this->message = $this->escapeVal($message);
}
$this->pass = true;
}
/**
* Stash the first failing item. Clicking the test
* item goes to first fail.
* @param string $message Test message, but we only wnat the first.
* @access public
*/
function paintFail($message){
//only get the first failure or error
if (! $this->fail && ! $this->error){
$this->fail = true;
$this->message = $this->escapeVal($message);
$this->listener->write('{status:"fail",message:"'.$this->message.'",group:"'.$this->group.'",case:"'.$this->case.'",method:"'.$this->method.'"}');
}
}
/**
* Stash the first error. Clicking the test
* item goes to first error.
* @param string $message Test message, but we only wnat the first.
* @access public
*/
function paintError($message){
if (! $this->fail && ! $this->error){
$this->error = true;
$this->message = $this->escapeVal($message);
$this->listener->write('{status:"error",message:"'.$this->message.'",group:"'.$this->group.'",case:"'.$this->case.'",method:"'.$this->method.'"}');
}
}
/**
* Stash the first exception. Clicking the test
* item goes to first message.
* @param string $message Test message, but we only wnat the first.
* @access public
*/
function paintException($exception){
if (! $this->fail && ! $this->error){
$this->error = true;
$message = 'Unexpected exception of type[' . get_class($exception) .
'] with message [' . $exception->getMessage() . '] in [' .
$exception->getFile() .' line '. $exception->getLine() . ']';
$this->message = $this->escapeVal($message);
$this->listener->write(
'{status:"error",message:"' . $this->message . '",group:"' .
$this->group . '",case:"' . $this->case . '",method:"' . $this->method
. '"}');
}
}
/**
* We don't display any special header.
* @param string $test_name First test top level
* to start.
* @access public
*/
function paintHeader($test_name) {
}
/**
* We don't display any special footer.
* @param string $test_name The top level test.
* @access public
*/
function paintFooter($test_name) {
}
/**
* Paints nothing at the start of a test method, but stash
* the method name for later.
* @param string $test_name Name of test that is starting.
* @access public
*/
function paintMethodStart($method) {
$this->pass = false;
$this->fail = false;
$this->error = false;
$this->method = $this->escapeVal($method);
}
/**
* Only send one message if the test passes, after that
* suppress the message.
* @param string $test_name Name of test that is ending.
* @access public
*/
function paintMethodEnd($method){
if ($this->fail || $this->error || ! $this->pass){
} else {
$this->listener->write(
'{status:"pass",message:"' . $this->message . '",group:"' .
$this->group . '",case:"' . $this->case . '",method:"' .
$this->method . '"}');
}
}
/**
* Stashes the test case name for the later failure message.
* @param string $test_name Name of test or other label.
* @access public
*/
function paintCaseStart($case){
$this->case = $this->escapeVal($case);
}
/**
* Drops the name.
* @param string $test_name Name of test or other label.
* @access public
*/
function paintCaseEnd($case){
$this->case = "";
}
/**
* Stashes the name of the test suite. Starts test coverage
* if enabled.
* @param string $group Name of test or other label.
* @param integer $size Number of test cases starting.
* @access public
*/
function paintGroupStart($group, $size){
$this->group = $this->escapeVal($group);
if ($this->cc){
if (extension_loaded('xdebug')){
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
}
}
}
/**
* Paints coverage report if enabled.
* @param string $group Name of test or other label.
* @access public
*/
function paintGroupEnd($group){
$this->group = "";
$cc = "";
if ($this->cc){
if (extension_loaded('xdebug')){
$arrfiles = xdebug_get_code_coverage();
xdebug_stop_code_coverage();
$thisdir = dirname(__FILE__);
$thisdirlen = strlen($thisdir);
foreach ($arrfiles as $index=>$file){
if (substr($index, 0, $thisdirlen)===$thisdir){
continue;
}
$lcnt = 0;
$ccnt = 0;
foreach ($file as $line){
if ($line == -2){
continue;
}
$lcnt++;
if ($line==1){
$ccnt++;
}
}
if ($lcnt > 0){
$cc .= round(($ccnt/$lcnt) * 100, 2) . '%';
}else{
$cc .= "0.00%";
}
$cc.= "\t". $index . "\n";
}
}
}
$this->listener->write('{status:"coverage",message:"' .
EclipseReporter::escapeVal($cc) . '"}');
}
}
/**
* Invoker decorator for Eclipse. Captures output until
* the end of the test.
* @package SimpleTest
* @subpackage Eclipse
*/
class EclipseInvoker extends SimpleInvokerDecorator{
function __construct(&$invoker, &$listener) {
$this->listener = &$listener;
$this->SimpleInvokerDecorator($invoker);
}
/**
* Starts output buffering.
* @param string $method Test method to call.
* @access public
*/
function before($method){
ob_start();
$this->invoker->before($method);
}
/**
* Stops output buffering and send the captured output
* to the listener.
* @param string $method Test method to call.
* @access public
*/
function after($method) {
$this->invoker->after($method);
$output = ob_get_contents();
ob_end_clean();
if ($output !== ""){
$result = $this->listener->write('{status:"info",message:"' .
EclipseReporter::escapeVal($output) . '"}');
}
}
}
?>

View File

@ -1,649 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id: encoding.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/socket.php');
/**#@-*/
/**
* Single post parameter.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleEncodedPair {
private $key;
private $value;
/**
* Stashes the data for rendering later.
* @param string $key Form element name.
* @param string $value Data to send.
*/
function __construct($key, $value) {
$this->key = $key;
$this->value = $value;
}
/**
* The pair as a single string.
* @return string Encoded pair.
* @access public
*/
function asRequest() {
return urlencode($this->key) . '=' . urlencode($this->value);
}
/**
* The MIME part as a string.
* @return string MIME part encoding.
* @access public
*/
function asMime() {
$part = 'Content-Disposition: form-data; ';
$part .= "name=\"" . $this->key . "\"\r\n";
$part .= "\r\n" . $this->value;
return $part;
}
/**
* Is this the value we are looking for?
* @param string $key Identifier.
* @return boolean True if matched.
* @access public
*/
function isKey($key) {
return $key == $this->key;
}
/**
* Is this the value we are looking for?
* @return string Identifier.
* @access public
*/
function getKey() {
return $this->key;
}
/**
* Is this the value we are looking for?
* @return string Content.
* @access public
*/
function getValue() {
return $this->value;
}
}
/**
* Single post parameter.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleAttachment {
private $key;
private $content;
private $filename;
/**
* Stashes the data for rendering later.
* @param string $key Key to add value to.
* @param string $content Raw data.
* @param hash $filename Original filename.
*/
function __construct($key, $content, $filename) {
$this->key = $key;
$this->content = $content;
$this->filename = $filename;
}
/**
* The pair as a single string.
* @return string Encoded pair.
* @access public
*/
function asRequest() {
return '';
}
/**
* The MIME part as a string.
* @return string MIME part encoding.
* @access public
*/
function asMime() {
$part = 'Content-Disposition: form-data; ';
$part .= 'name="' . $this->key . '"; ';
$part .= 'filename="' . $this->filename . '"';
$part .= "\r\nContent-Type: " . $this->deduceMimeType();
$part .= "\r\n\r\n" . $this->content;
return $part;
}
/**
* Attempts to figure out the MIME type from the
* file extension and the content.
* @return string MIME type.
* @access private
*/
protected function deduceMimeType() {
if ($this->isOnlyAscii($this->content)) {
return 'text/plain';
}
return 'application/octet-stream';
}
/**
* Tests each character is in the range 0-127.
* @param string $ascii String to test.
* @access private
*/
protected function isOnlyAscii($ascii) {
for ($i = 0, $length = strlen($ascii); $i < $length; $i++) {
if (ord($ascii[$i]) > 127) {
return false;
}
}
return true;
}
/**
* Is this the value we are looking for?
* @param string $key Identifier.
* @return boolean True if matched.
* @access public
*/
function isKey($key) {
return $key == $this->key;
}
/**
* Is this the value we are looking for?
* @return string Identifier.
* @access public
*/
function getKey() {
return $this->key;
}
/**
* Is this the value we are looking for?
* @return string Content.
* @access public
*/
function getValue() {
return $this->filename;
}
}
/**
* Bundle of GET/POST parameters. Can include
* repeated parameters.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleEncoding {
private $request;
/**
* Starts empty.
* @param array $query Hash of parameters.
* Multiple values are
* as lists on a single key.
* @access public
*/
function __construct($query = false) {
if (! $query) {
$query = array();
}
$this->clear();
$this->merge($query);
}
/**
* Empties the request of parameters.
* @access public
*/
function clear() {
$this->request = array();
}
/**
* Adds a parameter to the query.
* @param string $key Key to add value to.
* @param string/array $value New data.
* @access public
*/
function add($key, $value) {
if ($value === false) {
return;
}
if (is_array($value)) {
foreach ($value as $item) {
$this->addPair($key, $item);
}
} else {
$this->addPair($key, $value);
}
}
/**
* Adds a new value into the request.
* @param string $key Key to add value to.
* @param string/array $value New data.
* @access private
*/
protected function addPair($key, $value) {
$this->request[] = new SimpleEncodedPair($key, $value);
}
/**
* Adds a MIME part to the query. Does nothing for a
* form encoded packet.
* @param string $key Key to add value to.
* @param string $content Raw data.
* @param hash $filename Original filename.
* @access public
*/
function attach($key, $content, $filename) {
$this->request[] = new SimpleAttachment($key, $content, $filename);
}
/**
* Adds a set of parameters to this query.
* @param array/SimpleQueryString $query Multiple values are
* as lists on a single key.
* @access public
*/
function merge($query) {
if (is_object($query)) {
$this->request = array_merge($this->request, $query->getAll());
} elseif (is_array($query)) {
foreach ($query as $key => $value) {
$this->add($key, $value);
}
}
}
/**
* Accessor for single value.
* @return string/array False if missing, string
* if present and array if
* multiple entries.
* @access public
*/
function getValue($key) {
$values = array();
foreach ($this->request as $pair) {
if ($pair->isKey($key)) {
$values[] = $pair->getValue();
}
}
if (count($values) == 0) {
return false;
} elseif (count($values) == 1) {
return $values[0];
} else {
return $values;
}
}
/**
* Accessor for listing of pairs.
* @return array All pair objects.
* @access public
*/
function getAll() {
return $this->request;
}
/**
* Renders the query string as a URL encoded
* request part.
* @return string Part of URL.
* @access protected
*/
protected function encode() {
$statements = array();
foreach ($this->request as $pair) {
if ($statement = $pair->asRequest()) {
$statements[] = $statement;
}
}
return implode('&', $statements);
}
}
/**
* Bundle of GET parameters. Can include
* repeated parameters.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleGetEncoding extends SimpleEncoding {
/**
* Starts empty.
* @param array $query Hash of parameters.
* Multiple values are
* as lists on a single key.
* @access public
*/
function __construct($query = false) {
parent::__construct($query);
}
/**
* HTTP request method.
* @return string Always GET.
* @access public
*/
function getMethod() {
return 'GET';
}
/**
* Writes no extra headers.
* @param SimpleSocket $socket Socket to write to.
* @access public
*/
function writeHeadersTo(&$socket) {
}
/**
* No data is sent to the socket as the data is encoded into
* the URL.
* @param SimpleSocket $socket Socket to write to.
* @access public
*/
function writeTo(&$socket) {
}
/**
* Renders the query string as a URL encoded
* request part for attaching to a URL.
* @return string Part of URL.
* @access public
*/
function asUrlRequest() {
return $this->encode();
}
}
/**
* Bundle of URL parameters for a HEAD request.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleHeadEncoding extends SimpleGetEncoding {
/**
* Starts empty.
* @param array $query Hash of parameters.
* Multiple values are
* as lists on a single key.
* @access public
*/
function __construct($query = false) {
parent::__construct($query);
}
/**
* HTTP request method.
* @return string Always HEAD.
* @access public
*/
function getMethod() {
return 'HEAD';
}
}
/**
* Bundle of URL parameters for a DELETE request.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleDeleteEncoding extends SimpleGetEncoding {
/**
* Starts empty.
* @param array $query Hash of parameters.
* Multiple values are
* as lists on a single key.
* @access public
*/
function __construct($query = false) {
parent::__construct($query);
}
/**
* HTTP request method.
* @return string Always DELETE.
* @access public
*/
function getMethod() {
return 'DELETE';
}
}
/**
* Bundles an entity-body for transporting
* a raw content payload with the request.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleEntityEncoding extends SimpleEncoding {
private $content_type;
private $body;
function __construct($query = false, $content_type = false) {
$this->content_type = $content_type;
if (is_string($query)) {
$this->body = $query;
parent::__construct();
} else {
parent::__construct($query);
}
}
/**
* Returns the media type of the entity body
* @return string
* @access public
*/
function getContentType() {
if (!$this->content_type) {
return ($this->body) ? 'text/plain' : 'application/x-www-form-urlencoded';
}
return $this->content_type;
}
/**
* Dispatches the form headers down the socket.
* @param SimpleSocket $socket Socket to write to.
* @access public
*/
function writeHeadersTo(&$socket) {
$socket->write("Content-Length: " . (integer)strlen($this->encode()) . "\r\n");
$socket->write("Content-Type: " . $this->getContentType() . "\r\n");
}
/**
* Dispatches the form data down the socket.
* @param SimpleSocket $socket Socket to write to.
* @access public
*/
function writeTo(&$socket) {
$socket->write($this->encode());
}
/**
* Renders the request body
* @return Encoded entity body
* @access protected
*/
protected function encode() {
return ($this->body) ? $this->body : parent::encode();
}
}
/**
* Bundle of POST parameters. Can include
* repeated parameters.
* @package SimpleTest
* @subpackage WebTester
*/
class SimplePostEncoding extends SimpleEntityEncoding {
/**
* Starts empty.
* @param array $query Hash of parameters.
* Multiple values are
* as lists on a single key.
* @access public
*/
function __construct($query = false, $content_type = false) {
if (is_array($query) and $this->hasMoreThanOneLevel($query)) {
$query = $this->rewriteArrayWithMultipleLevels($query);
}
parent::__construct($query, $content_type);
}
function hasMoreThanOneLevel($query) {
foreach ($query as $key => $value) {
if (is_array($value)) {
return true;
}
}
return false;
}
function rewriteArrayWithMultipleLevels($query) {
$query_ = array();
foreach ($query as $key => $value) {
if (is_array($value)) {
foreach ($value as $sub_key => $sub_value) {
$query_[$key."[".$sub_key."]"] = $sub_value;
}
} else {
$query_[$key] = $value;
}
}
if ($this->hasMoreThanOneLevel($query_)) {
$query_ = $this->rewriteArrayWithMultipleLevels($query_);
}
return $query_;
}
/**
* HTTP request method.
* @return string Always POST.
* @access public
*/
function getMethod() {
return 'POST';
}
/**
* Renders the query string as a URL encoded
* request part for attaching to a URL.
* @return string Part of URL.
* @access public
*/
function asUrlRequest() {
return '';
}
}
/**
* Encoded entity body for a PUT request.
* @package SimpleTest
* @subpackage WebTester
*/
class SimplePutEncoding extends SimpleEntityEncoding {
/**
* Starts empty.
* @param array $query Hash of parameters.
* Multiple values are
* as lists on a single key.
* @access public
*/
function __construct($query = false, $content_type = false) {
parent::__construct($query, $content_type);
}
/**
* HTTP request method.
* @return string Always PUT.
* @access public
*/
function getMethod() {
return 'PUT';
}
}
/**
* Bundle of POST parameters in the multipart
* format. Can include file uploads.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleMultipartEncoding extends SimplePostEncoding {
private $boundary;
/**
* Starts empty.
* @param array $query Hash of parameters.
* Multiple values are
* as lists on a single key.
* @access public
*/
function __construct($query = false, $boundary = false) {
parent::__construct($query);
$this->boundary = ($boundary === false ? uniqid('st') : $boundary);
}
/**
* Dispatches the form headers down the socket.
* @param SimpleSocket $socket Socket to write to.
* @access public
*/
function writeHeadersTo(&$socket) {
$socket->write("Content-Length: " . (integer)strlen($this->encode()) . "\r\n");
$socket->write("Content-Type: multipart/form-data; boundary=" . $this->boundary . "\r\n");
}
/**
* Dispatches the form data down the socket.
* @param SimpleSocket $socket Socket to write to.
* @access public
*/
function writeTo(&$socket) {
$socket->write($this->encode());
}
/**
* Renders the query string as a URL encoded
* request part.
* @return string Part of URL.
* @access public
*/
function encode() {
$stream = '';
foreach ($this->getAll() as $pair) {
$stream .= "--" . $this->boundary . "\r\n";
$stream .= $pair->asMime() . "\r\n";
}
$stream .= "--" . $this->boundary . "--\r\n";
return $stream;
}
}
?>

View File

@ -1,267 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: errors.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+
* Includes SimpleTest files.
*/
require_once dirname(__FILE__) . '/invoker.php';
require_once dirname(__FILE__) . '/test_case.php';
require_once dirname(__FILE__) . '/expectation.php';
/**#@-*/
/**
* Extension that traps errors into an error queue.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleErrorTrappingInvoker extends SimpleInvokerDecorator {
/**
* Stores the invoker to wrap.
* @param SimpleInvoker $invoker Test method runner.
*/
function __construct($invoker) {
parent::__construct($invoker);
}
/**
* Invokes a test method and dispatches any
* untrapped errors. Called back from
* the visiting runner.
* @param string $method Test method to call.
* @access public
*/
function invoke($method) {
$queue = $this->createErrorQueue();
set_error_handler('SimpleTestErrorHandler');
parent::invoke($method);
restore_error_handler();
$queue->tally();
}
/**
* Wires up the error queue for a single test.
* @return SimpleErrorQueue Queue connected to the test.
* @access private
*/
protected function createErrorQueue() {
$context = SimpleTest::getContext();
$test = $this->getTestCase();
$queue = $context->get('SimpleErrorQueue');
$queue->setTestCase($test);
return $queue;
}
}
/**
* Error queue used to record trapped
* errors.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleErrorQueue {
private $queue;
private $expectation_queue;
private $test;
private $using_expect_style = false;
/**
* Starts with an empty queue.
*/
function __construct() {
$this->clear();
}
/**
* Discards the contents of the error queue.
* @access public
*/
function clear() {
$this->queue = array();
$this->expectation_queue = array();
}
/**
* Sets the currently running test case.
* @param SimpleTestCase $test Test case to send messages to.
* @access public
*/
function setTestCase($test) {
$this->test = $test;
}
/**
* Sets up an expectation of an error. If this is
* not fulfilled at the end of the test, a failure
* will occour. If the error does happen, then this
* will cancel it out and send a pass message.
* @param SimpleExpectation $expected Expected error match.
* @param string $message Message to display.
* @access public
*/
function expectError($expected, $message) {
array_push($this->expectation_queue, array($expected, $message));
}
/**
* Adds an error to the front of the queue.
* @param integer $severity PHP error code.
* @param string $content Text of error.
* @param string $filename File error occoured in.
* @param integer $line Line number of error.
* @access public
*/
function add($severity, $content, $filename, $line) {
$content = str_replace('%', '%%', $content);
$this->testLatestError($severity, $content, $filename, $line);
}
/**
* Any errors still in the queue are sent to the test
* case. Any unfulfilled expectations trigger failures.
* @access public
*/
function tally() {
while (list($severity, $message, $file, $line) = $this->extract()) {
$severity = $this->getSeverityAsString($severity);
$this->test->error($severity, $message, $file, $line);
}
while (list($expected, $message) = $this->extractExpectation()) {
$this->test->assert($expected, false, "%s -> Expected error not caught");
}
}
/**
* Tests the error against the most recent expected
* error.
* @param integer $severity PHP error code.
* @param string $content Text of error.
* @param string $filename File error occoured in.
* @param integer $line Line number of error.
* @access private
*/
protected function testLatestError($severity, $content, $filename, $line) {
if ($expectation = $this->extractExpectation()) {
list($expected, $message) = $expectation;
$this->test->assert($expected, $content, sprintf(
$message,
"%s -> PHP error [$content] severity [" .
$this->getSeverityAsString($severity) .
"] in [$filename] line [$line]"));
} else {
$this->test->error($severity, $content, $filename, $line);
}
}
/**
* Pulls the earliest error from the queue.
* @return mixed False if none, or a list of error
* information. Elements are: severity
* as the PHP error code, the error message,
* the file with the error, the line number
* and a list of PHP super global arrays.
* @access public
*/
function extract() {
if (count($this->queue)) {
return array_shift($this->queue);
}
return false;
}
/**
* Pulls the earliest expectation from the queue.
* @return SimpleExpectation False if none.
* @access private
*/
protected function extractExpectation() {
if (count($this->expectation_queue)) {
return array_shift($this->expectation_queue);
}
return false;
}
/**
* Converts an error code into it's string
* representation.
* @param $severity PHP integer error code.
* @return String version of error code.
* @access public
*/
static function getSeverityAsString($severity) {
static $map = array(
E_STRICT => 'E_STRICT',
E_ERROR => 'E_ERROR',
E_WARNING => 'E_WARNING',
E_PARSE => 'E_PARSE',
E_NOTICE => 'E_NOTICE',
E_CORE_ERROR => 'E_CORE_ERROR',
E_CORE_WARNING => 'E_CORE_WARNING',
E_COMPILE_ERROR => 'E_COMPILE_ERROR',
E_COMPILE_WARNING => 'E_COMPILE_WARNING',
E_USER_ERROR => 'E_USER_ERROR',
E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE');
if (defined('E_RECOVERABLE_ERROR')) {
$map[E_RECOVERABLE_ERROR] = 'E_RECOVERABLE_ERROR';
}
if (defined('E_DEPRECATED')) {
$map[E_DEPRECATED] = 'E_DEPRECATED';
}
return $map[$severity];
}
}
/**
* Error handler that simply stashes any errors into the global
* error queue. Simulates the existing behaviour with respect to
* logging errors, but this feature may be removed in future.
* @param $severity PHP error code.
* @param $message Text of error.
* @param $filename File error occoured in.
* @param $line Line number of error.
* @param $super_globals Hash of PHP super global arrays.
* @access public
*/
function SimpleTestErrorHandler($severity, $message, $filename = null, $line = null, $super_globals = null, $mask = null) {
$severity = $severity & error_reporting();
if ($severity) {
restore_error_handler();
if (IsNotCausedBySimpleTest($message) && IsNotTimeZoneNag($message)) {
if (ini_get('log_errors')) {
$label = SimpleErrorQueue::getSeverityAsString($severity);
error_log("$label: $message in $filename on line $line");
}
$queue = SimpleTest::getContext()->get('SimpleErrorQueue');
$queue->add($severity, $message, $filename, $line);
}
set_error_handler('SimpleTestErrorHandler');
}
return true;
}
/**
* Certain messages can be caused by the unit tester itself.
* These have to be filtered.
* @param string $message Message to filter.
* @return boolean True if genuine failure.
*/
function IsNotCausedBySimpleTest($message) {
return ! preg_match('/returned by reference/', $message);
}
/**
* Certain messages caused by PHP are just noise.
* These have to be filtered.
* @param string $message Message to filter.
* @return boolean True if genuine failure.
*/
function IsNotTimeZoneNag($message) {
return ! preg_match('/not safe to rely .* timezone settings/', $message);
}
?>

View File

@ -1,226 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: exceptions.php 1882 2009-07-01 14:30:05Z lastcraft $
*/
/**#@+
* Include required SimpleTest files
*/
require_once dirname(__FILE__) . '/invoker.php';
require_once dirname(__FILE__) . '/expectation.php';
/**#@-*/
/**
* Extension that traps exceptions and turns them into
* an error message. PHP5 only.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleExceptionTrappingInvoker extends SimpleInvokerDecorator {
/**
* Stores the invoker to be wrapped.
* @param SimpleInvoker $invoker Test method runner.
*/
function __construct($invoker) {
parent::__construct($invoker);
}
/**
* Invokes a test method whilst trapping expected
* exceptions. Any left over unthrown exceptions
* are then reported as failures.
* @param string $method Test method to call.
*/
function invoke($method) {
$trap = SimpleTest::getContext()->get('SimpleExceptionTrap');
$trap->clear();
try {
$has_thrown = false;
parent::invoke($method);
} catch (Exception $exception) {
$has_thrown = true;
if (! $trap->isExpected($this->getTestCase(), $exception)) {
$this->getTestCase()->exception($exception);
}
$trap->clear();
}
if ($message = $trap->getOutstanding()) {
$this->getTestCase()->fail($message);
}
if ($has_thrown) {
try {
parent::getTestCase()->tearDown();
} catch (Exception $e) { }
}
}
}
/**
* Tests exceptions either by type or the exact
* exception. This could be improved to accept
* a pattern expectation to test the error
* message, but that will have to come later.
* @package SimpleTest
* @subpackage UnitTester
*/
class ExceptionExpectation extends SimpleExpectation {
private $expected;
/**
* Sets up the conditions to test against.
* If the expected value is a string, then
* it will act as a test of the class name.
* An exception as the comparison will
* trigger an identical match. Writing this
* down now makes it look doubly dumb. I hope
* come up with a better scheme later.
* @param mixed $expected A class name or an actual
* exception to compare with.
* @param string $message Message to display.
*/
function __construct($expected, $message = '%s') {
$this->expected = $expected;
parent::__construct($message);
}
/**
* Carry out the test.
* @param Exception $compare Value to check.
* @return boolean True if matched.
*/
function test($compare) {
if (is_string($this->expected)) {
return ($compare instanceof $this->expected);
}
if (get_class($compare) != get_class($this->expected)) {
return false;
}
return $compare->getMessage() == $this->expected->getMessage();
}
/**
* Create the message to display describing the test.
* @param Exception $compare Exception to match.
* @return string Final message.
*/
function testMessage($compare) {
if (is_string($this->expected)) {
return "Exception [" . $this->describeException($compare) .
"] should be type [" . $this->expected . "]";
}
return "Exception [" . $this->describeException($compare) .
"] should match [" .
$this->describeException($this->expected) . "]";
}
/**
* Summary of an Exception object.
* @param Exception $compare Exception to describe.
* @return string Text description.
*/
protected function describeException($exception) {
return get_class($exception) . ": " . $exception->getMessage();
}
}
/**
* Stores expected exceptions for when they
* get thrown. Saves the irritating try...catch
* block.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleExceptionTrap {
private $expected;
private $ignored;
private $message;
/**
* Clears down the queue ready for action.
*/
function __construct() {
$this->clear();
}
/**
* Sets up an expectation of an exception.
* This has the effect of intercepting an
* exception that matches.
* @param SimpleExpectation $expected Expected exception to match.
* @param string $message Message to display.
* @access public
*/
function expectException($expected = false, $message = '%s') {
$this->expected = $this->coerceToExpectation($expected);
$this->message = $message;
}
/**
* Adds an exception to the ignore list. This is the list
* of exceptions that when thrown do not affect the test.
* @param SimpleExpectation $ignored Exception to skip.
* @access public
*/
function ignoreException($ignored) {
$this->ignored[] = $this->coerceToExpectation($ignored);
}
/**
* Compares the expected exception with any
* in the queue. Issues a pass or fail and
* returns the state of the test.
* @param SimpleTestCase $test Test case to send messages to.
* @param Exception $exception Exception to compare.
* @return boolean False on no match.
*/
function isExpected($test, $exception) {
if ($this->expected) {
return $test->assert($this->expected, $exception, $this->message);
}
foreach ($this->ignored as $ignored) {
if ($ignored->test($exception)) {
return true;
}
}
return false;
}
/**
* Turns an expected exception into a SimpleExpectation object.
* @param mixed $exception Exception, expectation or
* class name of exception.
* @return SimpleExpectation Expectation that will match the
* exception.
*/
private function coerceToExpectation($exception) {
if ($exception === false) {
return new AnythingExpectation();
}
if (! SimpleExpectation::isExpectation($exception)) {
return new ExceptionExpectation($exception);
}
return $exception;
}
/**
* Tests for any left over exception.
* @return string/false The failure message or false if none.
*/
function getOutstanding() {
return sprintf($this->message, 'Failed to trap exception');
}
/**
* Discards the contents of the error queue.
*/
function clear() {
$this->expected = false;
$this->message = false;
$this->ignored = array();
}
}
?>

View File

@ -1,984 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: expectation.php 2009 2011-04-28 08:57:25Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/dumper.php');
require_once(dirname(__FILE__) . '/compatibility.php');
/**#@-*/
/**
* Assertion that can display failure information.
* Also includes various helper methods.
* @package SimpleTest
* @subpackage UnitTester
* @abstract
*/
class SimpleExpectation {
protected $dumper = false;
private $message;
/**
* Creates a dumper for displaying values and sets
* the test message.
* @param string $message Customised message on failure.
*/
function __construct($message = '%s') {
$this->message = $message;
}
/**
* Tests the expectation. True if correct.
* @param mixed $compare Comparison value.
* @return boolean True if correct.
* @access public
* @abstract
*/
function test($compare) {
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
* @abstract
*/
function testMessage($compare) {
}
/**
* Overlays the generated message onto the stored user
* message. An additional message can be interjected.
* @param mixed $compare Comparison value.
* @param SimpleDumper $dumper For formatting the results.
* @return string Description of success
* or failure.
* @access public
*/
function overlayMessage($compare, $dumper) {
$this->dumper = $dumper;
return sprintf($this->message, $this->testMessage($compare));
}
/**
* Accessor for the dumper.
* @return SimpleDumper Current value dumper.
* @access protected
*/
protected function getDumper() {
if (! $this->dumper) {
$dumper = new SimpleDumper();
return $dumper;
}
return $this->dumper;
}
/**
* Test to see if a value is an expectation object.
* A useful utility method.
* @param mixed $expectation Hopefully an Expectation
* class.
* @return boolean True if descended from
* this class.
* @access public
*/
static function isExpectation($expectation) {
return is_object($expectation) &&
SimpleTestCompatibility::isA($expectation, 'SimpleExpectation');
}
}
/**
* A wildcard expectation always matches.
* @package SimpleTest
* @subpackage MockObjects
*/
class AnythingExpectation extends SimpleExpectation {
/**
* Tests the expectation. Always true.
* @param mixed $compare Ignored.
* @return boolean True.
* @access public
*/
function test($compare) {
return true;
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
$dumper = $this->getDumper();
return 'Anything always matches [' . $dumper->describeValue($compare) . ']';
}
}
/**
* An expectation that never matches.
* @package SimpleTest
* @subpackage MockObjects
*/
class FailedExpectation extends SimpleExpectation {
/**
* Tests the expectation. Always false.
* @param mixed $compare Ignored.
* @return boolean True.
* @access public
*/
function test($compare) {
return false;
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of failure.
* @access public
*/
function testMessage($compare) {
$dumper = $this->getDumper();
return 'Failed expectation never matches [' . $dumper->describeValue($compare) . ']';
}
}
/**
* An expectation that passes on boolean true.
* @package SimpleTest
* @subpackage MockObjects
*/
class TrueExpectation extends SimpleExpectation {
/**
* Tests the expectation.
* @param mixed $compare Should be true.
* @return boolean True on match.
* @access public
*/
function test($compare) {
return (boolean)$compare;
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
$dumper = $this->getDumper();
return 'Expected true, got [' . $dumper->describeValue($compare) . ']';
}
}
/**
* An expectation that passes on boolean false.
* @package SimpleTest
* @subpackage MockObjects
*/
class FalseExpectation extends SimpleExpectation {
/**
* Tests the expectation.
* @param mixed $compare Should be false.
* @return boolean True on match.
* @access public
*/
function test($compare) {
return ! (boolean)$compare;
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
$dumper = $this->getDumper();
return 'Expected false, got [' . $dumper->describeValue($compare) . ']';
}
}
/**
* Test for equality.
* @package SimpleTest
* @subpackage UnitTester
*/
class EqualExpectation extends SimpleExpectation {
private $value;
/**
* Sets the value to compare against.
* @param mixed $value Test value to match.
* @param string $message Customised message on failure.
* @access public
*/
function __construct($value, $message = '%s') {
parent::__construct($message);
$this->value = $value;
}
/**
* Tests the expectation. True if it matches the
* held value.
* @param mixed $compare Comparison value.
* @return boolean True if correct.
* @access public
*/
function test($compare) {
return (($this->value == $compare) && ($compare == $this->value));
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
if ($this->test($compare)) {
return "Equal expectation [" . $this->dumper->describeValue($this->value) . "]";
} else {
return "Equal expectation fails " .
$this->dumper->describeDifference($this->value, $compare);
}
}
/**
* Accessor for comparison value.
* @return mixed Held value to compare with.
* @access protected
*/
protected function getValue() {
return $this->value;
}
}
/**
* Test for inequality.
* @package SimpleTest
* @subpackage UnitTester
*/
class NotEqualExpectation extends EqualExpectation {
/**
* Sets the value to compare against.
* @param mixed $value Test value to match.
* @param string $message Customised message on failure.
* @access public
*/
function __construct($value, $message = '%s') {
parent::__construct($value, $message);
}
/**
* Tests the expectation. True if it differs from the
* held value.
* @param mixed $compare Comparison value.
* @return boolean True if correct.
* @access public
*/
function test($compare) {
return ! parent::test($compare);
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
$dumper = $this->getDumper();
if ($this->test($compare)) {
return "Not equal expectation passes " .
$dumper->describeDifference($this->getValue(), $compare);
} else {
return "Not equal expectation fails [" .
$dumper->describeValue($this->getValue()) .
"] matches";
}
}
}
/**
* Test for being within a range.
* @package SimpleTest
* @subpackage UnitTester
*/
class WithinMarginExpectation extends SimpleExpectation {
private $upper;
private $lower;
/**
* Sets the value to compare against and the fuzziness of
* the match. Used for comparing floating point values.
* @param mixed $value Test value to match.
* @param mixed $margin Fuzziness of match.
* @param string $message Customised message on failure.
* @access public
*/
function __construct($value, $margin, $message = '%s') {
parent::__construct($message);
$this->upper = $value + $margin;
$this->lower = $value - $margin;
}
/**
* Tests the expectation. True if it matches the
* held value.
* @param mixed $compare Comparison value.
* @return boolean True if correct.
* @access public
*/
function test($compare) {
return (($compare <= $this->upper) && ($compare >= $this->lower));
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
if ($this->test($compare)) {
return $this->withinMessage($compare);
} else {
return $this->outsideMessage($compare);
}
}
/**
* Creates a the message for being within the range.
* @param mixed $compare Value being tested.
* @access private
*/
protected function withinMessage($compare) {
return "Within expectation [" . $this->dumper->describeValue($this->lower) . "] and [" .
$this->dumper->describeValue($this->upper) . "]";
}
/**
* Creates a the message for being within the range.
* @param mixed $compare Value being tested.
* @access private
*/
protected function outsideMessage($compare) {
if ($compare > $this->upper) {
return "Outside expectation " .
$this->dumper->describeDifference($compare, $this->upper);
} else {
return "Outside expectation " .
$this->dumper->describeDifference($compare, $this->lower);
}
}
}
/**
* Test for being outside of a range.
* @package SimpleTest
* @subpackage UnitTester
*/
class OutsideMarginExpectation extends WithinMarginExpectation {
/**
* Sets the value to compare against and the fuzziness of
* the match. Used for comparing floating point values.
* @param mixed $value Test value to not match.
* @param mixed $margin Fuzziness of match.
* @param string $message Customised message on failure.
* @access public
*/
function __construct($value, $margin, $message = '%s') {
parent::__construct($value, $margin, $message);
}
/**
* Tests the expectation. True if it matches the
* held value.
* @param mixed $compare Comparison value.
* @return boolean True if correct.
* @access public
*/
function test($compare) {
return ! parent::test($compare);
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
if (! $this->test($compare)) {
return $this->withinMessage($compare);
} else {
return $this->outsideMessage($compare);
}
}
}
/**
* Test for reference.
* @package SimpleTest
* @subpackage UnitTester
*/
class ReferenceExpectation {
private $value;
/**
* Sets the reference value to compare against.
* @param mixed $value Test reference to match.
* @param string $message Customised message on failure.
* @access public
*/
function __construct(&$value, $message = '%s') {
$this->message = $message;
$this->value = &$value;
}
/**
* Tests the expectation. True if it exactly
* references the held value.
* @param mixed $compare Comparison reference.
* @return boolean True if correct.
* @access public
*/
function test(&$compare) {
return SimpleTestCompatibility::isReference($this->value, $compare);
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
if ($this->test($compare)) {
return "Reference expectation [" . $this->dumper->describeValue($this->value) . "]";
} else {
return "Reference expectation fails " .
$this->dumper->describeDifference($this->value, $compare);
}
}
/**
* Overlays the generated message onto the stored user
* message. An additional message can be interjected.
* @param mixed $compare Comparison value.
* @param SimpleDumper $dumper For formatting the results.
* @return string Description of success
* or failure.
* @access public
*/
function overlayMessage($compare, $dumper) {
$this->dumper = $dumper;
return sprintf($this->message, $this->testMessage($compare));
}
/**
* Accessor for the dumper.
* @return SimpleDumper Current value dumper.
* @access protected
*/
protected function getDumper() {
if (! $this->dumper) {
$dumper = new SimpleDumper();
return $dumper;
}
return $this->dumper;
}
}
/**
* Test for identity.
* @package SimpleTest
* @subpackage UnitTester
*/
class IdenticalExpectation extends EqualExpectation {
/**
* Sets the value to compare against.
* @param mixed $value Test value to match.
* @param string $message Customised message on failure.
* @access public
*/
function __construct($value, $message = '%s') {
parent::__construct($value, $message);
}
/**
* Tests the expectation. True if it exactly
* matches the held value.
* @param mixed $compare Comparison value.
* @return boolean True if correct.
* @access public
*/
function test($compare) {
return SimpleTestCompatibility::isIdentical($this->getValue(), $compare);
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
$dumper = $this->getDumper();
if ($this->test($compare)) {
return "Identical expectation [" . $dumper->describeValue($this->getValue()) . "]";
} else {
return "Identical expectation [" . $dumper->describeValue($this->getValue()) .
"] fails with [" .
$dumper->describeValue($compare) . "] " .
$dumper->describeDifference($this->getValue(), $compare, TYPE_MATTERS);
}
}
}
/**
* Test for non-identity.
* @package SimpleTest
* @subpackage UnitTester
*/
class NotIdenticalExpectation extends IdenticalExpectation {
/**
* Sets the value to compare against.
* @param mixed $value Test value to match.
* @param string $message Customised message on failure.
* @access public
*/
function __construct($value, $message = '%s') {
parent::__construct($value, $message);
}
/**
* Tests the expectation. True if it differs from the
* held value.
* @param mixed $compare Comparison value.
* @return boolean True if correct.
* @access public
*/
function test($compare) {
return ! parent::test($compare);
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
$dumper = $this->getDumper();
if ($this->test($compare)) {
return "Not identical expectation passes " .
$dumper->describeDifference($this->getValue(), $compare, TYPE_MATTERS);
} else {
return "Not identical expectation [" . $dumper->describeValue($this->getValue()) . "] matches";
}
}
}
/**
* Test for a pattern using Perl regex rules.
* @package SimpleTest
* @subpackage UnitTester
*/
class PatternExpectation extends SimpleExpectation {
private $pattern;
/**
* Sets the value to compare against.
* @param string $pattern Pattern to search for.
* @param string $message Customised message on failure.
* @access public
*/
function __construct($pattern, $message = '%s') {
parent::__construct($message);
$this->pattern = $pattern;
}
/**
* Accessor for the pattern.
* @return string Perl regex as string.
* @access protected
*/
protected function getPattern() {
return $this->pattern;
}
/**
* Tests the expectation. True if the Perl regex
* matches the comparison value.
* @param string $compare Comparison value.
* @return boolean True if correct.
* @access public
*/
function test($compare) {
return (boolean)preg_match($this->getPattern(), $compare);
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
if ($this->test($compare)) {
return $this->describePatternMatch($this->getPattern(), $compare);
} else {
$dumper = $this->getDumper();
return "Pattern [" . $this->getPattern() .
"] not detected in [" .
$dumper->describeValue($compare) . "]";
}
}
/**
* Describes a pattern match including the string
* found and it's position.
* @param string $pattern Regex to match against.
* @param string $subject Subject to search.
* @access protected
*/
protected function describePatternMatch($pattern, $subject) {
preg_match($pattern, $subject, $matches);
$position = strpos($subject, $matches[0]);
$dumper = $this->getDumper();
return "Pattern [$pattern] detected at character [$position] in [" .
$dumper->describeValue($subject) . "] as [" .
$matches[0] . "] in region [" .
$dumper->clipString($subject, 100, $position) . "]";
}
}
/**
* Fail if a pattern is detected within the
* comparison.
* @package SimpleTest
* @subpackage UnitTester
*/
class NoPatternExpectation extends PatternExpectation {
/**
* Sets the reject pattern
* @param string $pattern Pattern to search for.
* @param string $message Customised message on failure.
* @access public
*/
function __construct($pattern, $message = '%s') {
parent::__construct($pattern, $message);
}
/**
* Tests the expectation. False if the Perl regex
* matches the comparison value.
* @param string $compare Comparison value.
* @return boolean True if correct.
* @access public
*/
function test($compare) {
return ! parent::test($compare);
}
/**
* Returns a human readable test message.
* @param string $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
if ($this->test($compare)) {
$dumper = $this->getDumper();
return "Pattern [" . $this->getPattern() .
"] not detected in [" .
$dumper->describeValue($compare) . "]";
} else {
return $this->describePatternMatch($this->getPattern(), $compare);
}
}
}
/**
* Tests either type or class name if it's an object.
* @package SimpleTest
* @subpackage UnitTester
*/
class IsAExpectation extends SimpleExpectation {
private $type;
/**
* Sets the type to compare with.
* @param string $type Type or class name.
* @param string $message Customised message on failure.
* @access public
*/
function __construct($type, $message = '%s') {
parent::__construct($message);
$this->type = $type;
}
/**
* Accessor for type to check against.
* @return string Type or class name.
* @access protected
*/
protected function getType() {
return $this->type;
}
/**
* Tests the expectation. True if the type or
* class matches the string value.
* @param string $compare Comparison value.
* @return boolean True if correct.
* @access public
*/
function test($compare) {
if (is_object($compare)) {
return SimpleTestCompatibility::isA($compare, $this->type);
} else {
$function = 'is_'.$this->canonicalType($this->type);
if (is_callable($function)) {
return $function($compare);
}
return false;
}
}
/**
* Coerces type name into a is_*() match.
* @param string $type User type.
* @return string Simpler type.
* @access private
*/
protected function canonicalType($type) {
$type = strtolower($type);
$map = array('boolean' => 'bool');
if (isset($map[$type])) {
$type = $map[$type];
}
return $type;
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
$dumper = $this->getDumper();
return "Value [" . $dumper->describeValue($compare) .
"] should be type [" . $this->type . "]";
}
}
/**
* Tests either type or class name if it's an object.
* Will succeed if the type does not match.
* @package SimpleTest
* @subpackage UnitTester
*/
class NotAExpectation extends IsAExpectation {
private $type;
/**
* Sets the type to compare with.
* @param string $type Type or class name.
* @param string $message Customised message on failure.
* @access public
*/
function __construct($type, $message = '%s') {
parent::__construct($type, $message);
}
/**
* Tests the expectation. False if the type or
* class matches the string value.
* @param string $compare Comparison value.
* @return boolean True if different.
* @access public
*/
function test($compare) {
return ! parent::test($compare);
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
* @access public
*/
function testMessage($compare) {
$dumper = $this->getDumper();
return "Value [" . $dumper->describeValue($compare) .
"] should not be type [" . $this->getType() . "]";
}
}
/**
* Tests for existance of a method in an object
* @package SimpleTest
* @subpackage UnitTester
*/
class MethodExistsExpectation extends SimpleExpectation {
private $method;
/**
* Sets the value to compare against.
* @param string $method Method to check.
* @param string $message Customised message on failure.
* @return void
*/
function __construct($method, $message = '%s') {
parent::__construct($message);
$this->method = &$method;
}
/**
* Tests the expectation. True if the method exists in the test object.
* @param string $compare Comparison method name.
* @return boolean True if correct.
*/
function test($compare) {
return (boolean)(is_object($compare) && method_exists($compare, $this->method));
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
*/
function testMessage($compare) {
$dumper = $this->getDumper();
if (! is_object($compare)) {
return 'No method on non-object [' . $dumper->describeValue($compare) . ']';
}
$method = $this->method;
return "Object [" . $dumper->describeValue($compare) .
"] should contain method [$method]";
}
}
/**
* Compares an object member's value even if private.
* @package SimpleTest
* @subpackage UnitTester
*/
class MemberExpectation extends IdenticalExpectation {
private $name;
/**
* Sets the value to compare against.
* @param string $method Method to check.
* @param string $message Customised message on failure.
* @return void
*/
function __construct($name, $expected) {
$this->name = $name;
parent::__construct($expected);
}
/**
* Tests the expectation. True if the property value is identical.
* @param object $actual Comparison object.
* @return boolean True if identical.
*/
function test($actual) {
if (! is_object($actual)) {
return false;
}
return parent::test($this->getProperty($this->name, $actual));
}
/**
* Returns a human readable test message.
* @param mixed $compare Comparison value.
* @return string Description of success
* or failure.
*/
function testMessage($actual) {
return parent::testMessage($this->getProperty($this->name, $actual));
}
/**
* Extracts the member value even if private using reflection.
* @param string $name Property name.
* @param object $object Object to read.
* @return mixed Value of property.
*/
private function getProperty($name, $object) {
$reflection = new ReflectionObject($object);
$property = $reflection->getProperty($name);
if (method_exists($property, 'setAccessible')) {
$property->setAccessible(true);
}
try {
return $property->getValue($object);
} catch (ReflectionException $e) {
return $this->getPrivatePropertyNoMatterWhat($name, $object);
}
}
/**
* Extracts a private member's value when reflection won't play ball.
* @param string $name Property name.
* @param object $object Object to read.
* @return mixed Value of property.
*/
private function getPrivatePropertyNoMatterWhat($name, $object) {
foreach ((array)$object as $mangled_name => $value) {
if ($this->unmangle($mangled_name) == $name) {
return $value;
}
}
}
/**
* Removes crud from property name after it's been converted
* to an array.
* @param string $mangled Name from array cast.
* @return string Cleaned up name.
*/
function unmangle($mangled) {
$parts = preg_split('/[^a-zA-Z0-9_\x7f-\xff]+/', $mangled);
return array_pop($parts);
}
}
?>

View File

@ -1,196 +0,0 @@
<?php
/**
* adapter for SimpleTest to use PEAR PHPUnit test cases
* @package SimpleTest
* @subpackage Extensions
* @version $Id: pear_test_case.php 1836 2008-12-21 00:02:26Z edwardzyang $
*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/../dumper.php');
require_once(dirname(__FILE__) . '/../compatibility.php');
require_once(dirname(__FILE__) . '/../test_case.php');
require_once(dirname(__FILE__) . '/../expectation.php');
/**#@-*/
/**
* Adapter for PEAR PHPUnit test case to allow
* legacy PEAR test cases to be used with SimpleTest.
* @package SimpleTest
* @subpackage Extensions
*/
class PHPUnit_TestCase extends SimpleTestCase {
private $_loosely_typed;
/**
* Constructor. Sets the test name.
* @param $label Test name to display.
* @public
*/
function __construct($label = false) {
parent::__construct($label);
$this->_loosely_typed = false;
}
/**
* Will test straight equality if set to loose
* typing, or identity if not.
* @param $first First value.
* @param $second Comparison value.
* @param $message Message to display.
* @public
*/
function assertEquals($first, $second, $message = "%s", $delta = 0) {
if ($this->_loosely_typed) {
$expectation = new EqualExpectation($first);
} else {
$expectation = new IdenticalExpectation($first);
}
$this->assert($expectation, $second, $message);
}
/**
* Passes if the value tested is not null.
* @param $value Value to test against.
* @param $message Message to display.
* @public
*/
function assertNotNull($value, $message = "%s") {
parent::assert(new TrueExpectation(), isset($value), $message);
}
/**
* Passes if the value tested is null.
* @param $value Value to test against.
* @param $message Message to display.
* @public
*/
function assertNull($value, $message = "%s") {
parent::assert(new TrueExpectation(), !isset($value), $message);
}
/**
* Identity test tests for the same object.
* @param $first First object handle.
* @param $second Hopefully the same handle.
* @param $message Message to display.
* @public
*/
function assertSame($first, $second, $message = "%s") {
$dumper = new SimpleDumper();
$message = sprintf(
$message,
"[" . $dumper->describeValue($first) .
"] and [" . $dumper->describeValue($second) .
"] should reference the same object");
return $this->assert(
new TrueExpectation(),
SimpleTestCompatibility::isReference($first, $second),
$message);
}
/**
* Inverted identity test.
* @param $first First object handle.
* @param $second Hopefully a different handle.
* @param $message Message to display.
* @public
*/
function assertNotSame($first, $second, $message = "%s") {
$dumper = new SimpleDumper();
$message = sprintf(
$message,
"[" . $dumper->describeValue($first) .
"] and [" . $dumper->describeValue($second) .
"] should not be the same object");
return $this->assert(
new falseExpectation(),
SimpleTestCompatibility::isReference($first, $second),
$message);
}
/**
* Sends pass if the test condition resolves true,
* a fail otherwise.
* @param $condition Condition to test true.
* @param $message Message to display.
* @public
*/
function assertTrue($condition, $message = "%s") {
parent::assert(new TrueExpectation(), $condition, $message);
}
/**
* Sends pass if the test condition resolves false,
* a fail otherwise.
* @param $condition Condition to test false.
* @param $message Message to display.
* @public
*/
function assertFalse($condition, $message = "%s") {
parent::assert(new FalseExpectation(), $condition, $message);
}
/**
* Tests a regex match. Needs refactoring.
* @param $pattern Regex to match.
* @param $subject String to search in.
* @param $message Message to display.
* @public
*/
function assertRegExp($pattern, $subject, $message = "%s") {
$this->assert(new PatternExpectation($pattern), $subject, $message);
}
/**
* Tests the type of a value.
* @param $value Value to take type of.
* @param $type Hoped for type.
* @param $message Message to display.
* @public
*/
function assertType($value, $type, $message = "%s") {
parent::assert(new TrueExpectation(), gettype($value) == strtolower($type), $message);
}
/**
* Sets equality operation to act as a simple equal
* comparison only, allowing a broader range of
* matches.
* @param $loosely_typed True for broader comparison.
* @public
*/
function setLooselyTyped($loosely_typed) {
$this->_loosely_typed = $loosely_typed;
}
/**
* For progress indication during
* a test amongst other things.
* @return Usually one.
* @public
*/
function countTestCases() {
return $this->getSize();
}
/**
* Accessor for name, normally just the class
* name.
* @public
*/
function getName() {
return $this->getLabel();
}
/**
* Does nothing. For compatibility only.
* @param $name Dummy
* @public
*/
function setName($name) {
}
}
?>

View File

@ -1,53 +0,0 @@
<?php
/**
* Extension for a TestDox reporter
* @package SimpleTest
* @subpackage Extensions
* @version $Id: testdox.php 2004 2010-10-31 13:44:14Z jsweat $
*/
/**
* TestDox reporter
* @package SimpleTest
* @subpackage Extensions
*/
class TestDoxReporter extends SimpleReporter
{
var $_test_case_pattern = '/^TestOf(.*)$/';
function __construct($test_case_pattern = '/^TestOf(.*)$/') {
parent::__construct();
$this->_test_case_pattern = empty($test_case_pattern) ? '/^(.*)$/' : $test_case_pattern;
}
function paintCaseStart($test_name) {
preg_match($this->_test_case_pattern, $test_name, $matches);
if (!empty($matches[1])) {
echo $matches[1] . "\n";
} else {
echo $test_name . "\n";
}
}
function paintCaseEnd($test_name) {
echo "\n";
}
function paintMethodStart($test_name) {
if (!preg_match('/^test(.*)$/i', $test_name, $matches)) {
return;
}
$test_name = $matches[1];
$test_name = preg_replace('/([A-Z])([A-Z])/', '$1 $2', $test_name);
echo '- ' . strtolower(preg_replace('/([a-zA-Z])([A-Z0-9])/', '$1 $2', $test_name));
}
function paintMethodEnd($test_name) {
echo "\n";
}
function paintFail($message) {
echo " [FAILED]";
}
}
?>

View File

@ -1,107 +0,0 @@
<?php
// $Id: test.php 1748 2008-04-14 01:50:41Z lastcraft $
require_once dirname(__FILE__) . '/../../autorun.php';
require_once dirname(__FILE__) . '/../testdox.php';
// uncomment to see test dox in action
//SimpleTest::prefer(new TestDoxReporter());
class TestOfTestDoxReporter extends UnitTestCase
{
function testIsAnInstanceOfSimpleScorerAndReporter() {
$dox = new TestDoxReporter();
$this->assertIsA($dox, 'SimpleScorer');
$this->assertIsA($dox, 'SimpleReporter');
}
function testOutputsNameOfTestCase() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintCaseStart('TestOfTestDoxReporter');
$buffer = ob_get_clean();
$this->assertPattern('/^TestDoxReporter/', $buffer);
}
function testOutputOfTestCaseNameFilteredByConstructParameter() {
$dox = new TestDoxReporter('/^(.*)Test$/');
ob_start();
$dox->paintCaseStart('SomeGreatWidgetTest');
$buffer = ob_get_clean();
$this->assertPattern('/^SomeGreatWidget/', $buffer);
}
function testIfTest_case_patternIsEmptyAssumeEverythingMatches() {
$dox = new TestDoxReporter('');
ob_start();
$dox->paintCaseStart('TestOfTestDoxReporter');
$buffer = ob_get_clean();
$this->assertPattern('/^TestOfTestDoxReporter/', $buffer);
}
function testEmptyLineInsertedWhenCaseEnds() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintCaseEnd('TestOfTestDoxReporter');
$buffer = ob_get_clean();
$this->assertEqual("\n", $buffer);
}
function testPaintsTestMethodInTestDoxFormat() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintMethodStart('testSomeGreatTestCase');
$buffer = ob_get_clean();
$this->assertEqual("- some great test case", $buffer);
unset($buffer);
$random = rand(100, 200);
ob_start();
$dox->paintMethodStart("testRandomNumberIs{$random}");
$buffer = ob_get_clean();
$this->assertEqual("- random number is {$random}", $buffer);
}
function testDoesNotOutputAnythingOnNoneTestMethods() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintMethodStart('nonMatchingMethod');
$buffer = ob_get_clean();
$this->assertEqual('', $buffer);
}
function testPaintMethodAddLineBreak() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintMethodEnd('someMethod');
$buffer = ob_get_clean();
$this->assertEqual("\n", $buffer);
}
function testProperlySpacesSingleLettersInMethodName() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintMethodStart('testAVerySimpleAgainAVerySimpleMethod');
$buffer = ob_get_clean();
$this->assertEqual('- a very simple again a very simple method', $buffer);
}
function testOnFailureThisPrintsFailureNotice() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintFail('');
$buffer = ob_get_clean();
$this->assertEqual(' [FAILED]', $buffer);
}
function testWhenMatchingMethodNamesTestPrefixIsCaseInsensitive() {
$dox = new TestDoxReporter();
ob_start();
$dox->paintMethodStart('TESTSupportsAllUppercaseTestPrefixEvenThoughIDoNotKnowWhyYouWouldDoThat');
$buffer = ob_get_clean();
$this->assertEqual(
'- supports all uppercase test prefix even though i do not know why you would do that',
$buffer
);
}
}
?>

View File

@ -1,361 +0,0 @@
<?php
/**
* Base include file for SimpleTest.
* @package SimpleTest
* @subpackage WebTester
* @version $Id: form.php 2013 2011-04-29 09:29:45Z pp11 $
*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/tag.php');
require_once(dirname(__FILE__) . '/encoding.php');
require_once(dirname(__FILE__) . '/selector.php');
/**#@-*/
/**
* Form tag class to hold widget values.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleForm {
private $method;
private $action;
private $encoding;
private $default_target;
private $id;
private $buttons;
private $images;
private $widgets;
private $radios;
private $checkboxes;
/**
* Starts with no held controls/widgets.
* @param SimpleTag $tag Form tag to read.
* @param SimplePage $page Holding page.
*/
function __construct($tag, $page) {
$this->method = $tag->getAttribute('method');
$this->action = $this->createAction($tag->getAttribute('action'), $page);
$this->encoding = $this->setEncodingClass($tag);
$this->default_target = false;
$this->id = $tag->getAttribute('id');
$this->buttons = array();
$this->images = array();
$this->widgets = array();
$this->radios = array();
$this->checkboxes = array();
}
/**
* Creates the request packet to be sent by the form.
* @param SimpleTag $tag Form tag to read.
* @return string Packet class.
* @access private
*/
protected function setEncodingClass($tag) {
if (strtolower($tag->getAttribute('method')) == 'post') {
if (strtolower($tag->getAttribute('enctype')) == 'multipart/form-data') {
return 'SimpleMultipartEncoding';
}
return 'SimplePostEncoding';
}
return 'SimpleGetEncoding';
}
/**
* Sets the frame target within a frameset.
* @param string $frame Name of frame.
* @access public
*/
function setDefaultTarget($frame) {
$this->default_target = $frame;
}
/**
* Accessor for method of form submission.
* @return string Either get or post.
* @access public
*/
function getMethod() {
return ($this->method ? strtolower($this->method) : 'get');
}
/**
* Combined action attribute with current location
* to get an absolute form target.
* @param string $action Action attribute from form tag.
* @param SimpleUrl $base Page location.
* @return SimpleUrl Absolute form target.
*/
protected function createAction($action, $page) {
if (($action === '') || ($action === false)) {
return $page->expandUrl($page->getUrl());
}
return $page->expandUrl(new SimpleUrl($action));;
}
/**
* Absolute URL of the target.
* @return SimpleUrl URL target.
* @access public
*/
function getAction() {
$url = $this->action;
if ($this->default_target && ! $url->getTarget()) {
$url->setTarget($this->default_target);
}
if ($this->getMethod() == 'get') {
$url->clearRequest();
}
return $url;
}
/**
* Creates the encoding for the current values in the
* form.
* @return SimpleFormEncoding Request to submit.
* @access private
*/
protected function encode() {
$class = $this->encoding;
$encoding = new $class();
for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
$this->widgets[$i]->write($encoding);
}
return $encoding;
}
/**
* ID field of form for unique identification.
* @return string Unique tag ID.
* @access public
*/
function getId() {
return $this->id;
}
/**
* Adds a tag contents to the form.
* @param SimpleWidget $tag Input tag to add.
*/
function addWidget($tag) {
if (strtolower($tag->getAttribute('type')) == 'submit') {
$this->buttons[] = $tag;
} elseif (strtolower($tag->getAttribute('type')) == 'image') {
$this->images[] = $tag;
} elseif ($tag->getName()) {
$this->setWidget($tag);
}
}
/**
* Sets the widget into the form, grouping radio
* buttons if any.
* @param SimpleWidget $tag Incoming form control.
* @access private
*/
protected function setWidget($tag) {
if (strtolower($tag->getAttribute('type')) == 'radio') {
$this->addRadioButton($tag);
} elseif (strtolower($tag->getAttribute('type')) == 'checkbox') {
$this->addCheckbox($tag);
} else {
$this->widgets[] = &$tag;
}
}
/**
* Adds a radio button, building a group if necessary.
* @param SimpleRadioButtonTag $tag Incoming form control.
* @access private
*/
protected function addRadioButton($tag) {
if (! isset($this->radios[$tag->getName()])) {
$this->widgets[] = new SimpleRadioGroup();
$this->radios[$tag->getName()] = count($this->widgets) - 1;
}
$this->widgets[$this->radios[$tag->getName()]]->addWidget($tag);
}
/**
* Adds a checkbox, making it a group on a repeated name.
* @param SimpleCheckboxTag $tag Incoming form control.
* @access private
*/
protected function addCheckbox($tag) {
if (! isset($this->checkboxes[$tag->getName()])) {
$this->widgets[] = $tag;
$this->checkboxes[$tag->getName()] = count($this->widgets) - 1;
} else {
$index = $this->checkboxes[$tag->getName()];
if (! SimpleTestCompatibility::isA($this->widgets[$index], 'SimpleCheckboxGroup')) {
$previous = $this->widgets[$index];
$this->widgets[$index] = new SimpleCheckboxGroup();
$this->widgets[$index]->addWidget($previous);
}
$this->widgets[$index]->addWidget($tag);
}
}
/**
* Extracts current value from form.
* @param SimpleSelector $selector Criteria to apply.
* @return string/array Value(s) as string or null
* if not set.
* @access public
*/
function getValue($selector) {
for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
if ($selector->isMatch($this->widgets[$i])) {
return $this->widgets[$i]->getValue();
}
}
foreach ($this->buttons as $button) {
if ($selector->isMatch($button)) {
return $button->getValue();
}
}
return null;
}
/**
* Sets a widget value within the form.
* @param SimpleSelector $selector Criteria to apply.
* @param string $value Value to input into the widget.
* @return boolean True if value is legal, false
* otherwise. If the field is not
* present, nothing will be set.
* @access public
*/
function setField($selector, $value, $position=false) {
$success = false;
$_position = 0;
for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
if ($selector->isMatch($this->widgets[$i])) {
$_position++;
if ($position === false or $_position === (int)$position) {
if ($this->widgets[$i]->setValue($value)) {
$success = true;
}
}
}
}
return $success;
}
/**
* Used by the page object to set widgets labels to
* external label tags.
* @param SimpleSelector $selector Criteria to apply.
* @access public
*/
function attachLabelBySelector($selector, $label) {
for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
if ($selector->isMatch($this->widgets[$i])) {
if (method_exists($this->widgets[$i], 'setLabel')) {
$this->widgets[$i]->setLabel($label);
return;
}
}
}
}
/**
* Test to see if a form has a submit button.
* @param SimpleSelector $selector Criteria to apply.
* @return boolean True if present.
* @access public
*/
function hasSubmit($selector) {
foreach ($this->buttons as $button) {
if ($selector->isMatch($button)) {
return true;
}
}
return false;
}
/**
* Test to see if a form has an image control.
* @param SimpleSelector $selector Criteria to apply.
* @return boolean True if present.
* @access public
*/
function hasImage($selector) {
foreach ($this->images as $image) {
if ($selector->isMatch($image)) {
return true;
}
}
return false;
}
/**
* Gets the submit values for a selected button.
* @param SimpleSelector $selector Criteria to apply.
* @param hash $additional Additional data for the form.
* @return SimpleEncoding Submitted values or false
* if there is no such button
* in the form.
* @access public
*/
function submitButton($selector, $additional = false) {
$additional = $additional ? $additional : array();
foreach ($this->buttons as $button) {
if ($selector->isMatch($button)) {
$encoding = $this->encode();
$button->write($encoding);
if ($additional) {
$encoding->merge($additional);
}
return $encoding;
}
}
return false;
}
/**
* Gets the submit values for an image.
* @param SimpleSelector $selector Criteria to apply.
* @param integer $x X-coordinate of click.
* @param integer $y Y-coordinate of click.
* @param hash $additional Additional data for the form.
* @return SimpleEncoding Submitted values or false
* if there is no such button in the
* form.
* @access public
*/
function submitImage($selector, $x, $y, $additional = false) {
$additional = $additional ? $additional : array();
foreach ($this->images as $image) {
if ($selector->isMatch($image)) {
$encoding = $this->encode();
$image->write($encoding, $x, $y);
if ($additional) {
$encoding->merge($additional);
}
return $encoding;
}
}
return false;
}
/**
* Simply submits the form without the submit button
* value. Used when there is only one button or it
* is unimportant.
* @return hash Submitted values.
* @access public
*/
function submit($additional = false) {
$encoding = $this->encode();
if ($additional) {
$encoding->merge($additional);
}
return $encoding;
}
}
?>

View File

@ -1,592 +0,0 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id: frames.php 1784 2008-04-26 13:07:14Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/page.php');
require_once(dirname(__FILE__) . '/user_agent.php');
/**#@-*/
/**
* A composite page. Wraps a frameset page and
* adds subframes. The original page will be
* mostly ignored. Implements the SimplePage
* interface so as to be interchangeable.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleFrameset {
private $frameset;
private $frames;
private $focus;
private $names;
/**
* Stashes the frameset page. Will make use of the
* browser to fetch the sub frames recursively.
* @param SimplePage $page Frameset page.
*/
function __construct($page) {
$this->frameset = $page;
$this->frames = array();
$this->focus = false;
$this->names = array();
}
/**
* Adds a parsed page to the frameset.
* @param SimplePage $page Frame page.
* @param string $name Name of frame in frameset.
* @access public
*/
function addFrame($page, $name = false) {
$this->frames[] = $page;
if ($name) {
$this->names[$name] = count($this->frames) - 1;
}
}
/**
* Replaces existing frame with another. If the
* frame is nested, then the call is passed down
* one level.
* @param array $path Path of frame in frameset.
* @param SimplePage $page Frame source.
* @access public
*/
function setFrame($path, $page) {
$name = array_shift($path);
if (isset($this->names[$name])) {
$index = $this->names[$name];
} else {
$index = $name - 1;
}
if (count($path) == 0) {
$this->frames[$index] = &$page;
return;
}
$this->frames[$index]->setFrame($path, $page);
}
/**
* Accessor for current frame focus. Will be
* false if no frame has focus. Will have the nested
* frame focus if any.
* @return array Labels or indexes of nested frames.
* @access public
*/
function getFrameFocus() {
if ($this->focus === false) {
return array();
}
return array_merge(
array($this->getPublicNameFromIndex($this->focus)),
$this->frames[$this->focus]->getFrameFocus());
}
/**
* Turns an internal array index into the frames list
* into a public name, or if none, then a one offset
* index.
* @param integer $subject Internal index.
* @return integer/string Public name.
* @access private
*/
protected function getPublicNameFromIndex($subject) {
foreach ($this->names as $name => $index) {
if ($subject == $index) {
return $name;
}
}
return $subject + 1;
}
/**
* Sets the focus by index. The integer index starts from 1.
* If already focused and the target frame also has frames,
* then the nested frame will be focused.
* @param integer $choice Chosen frame.
* @return boolean True if frame exists.
* @access public
*/
function setFrameFocusByIndex($choice) {
if (is_integer($this->focus)) {
if ($this->frames[$this->focus]->hasFrames()) {
return $this->frames[$this->focus]->setFrameFocusByIndex($choice);
}
}
if (($choice < 1) || ($choice > count($this->frames))) {
return false;
}
$this->focus = $choice - 1;
return true;
}
/**
* Sets the focus by name. If already focused and the
* target frame also has frames, then the nested frame
* will be focused.
* @param string $name Chosen frame.
* @return boolean True if frame exists.
* @access public
*/
function setFrameFocus($name) {
if (is_integer($this->focus)) {
if ($this->frames[$this->focus]->hasFrames()) {
return $this->frames[$this->focus]->setFrameFocus($name);
}
}
if (in_array($name, array_keys($this->names))) {
$this->focus = $this->names[$name];
return true;
}
return false;
}
/**
* Clears the frame focus.
* @access public
*/
function clearFrameFocus() {
$this->focus = false;
$this->clearNestedFramesFocus();
}
/**
* Clears the frame focus for any nested frames.
* @access private
*/
protected function clearNestedFramesFocus() {
for ($i = 0; $i < count($this->frames); $i++) {
$this->frames[$i]->clearFrameFocus();
}
}
/**
* Test for the presence of a frameset.
* @return boolean Always true.
* @access public
*/
function hasFrames() {
return true;
}
/**
* Accessor for frames information.
* @return array/string Recursive hash of frame URL strings.
* The key is either a numerical
* index or the name attribute.
* @access public
*/
function getFrames() {
$report = array();
for ($i = 0; $i < count($this->frames); $i++) {
$report[$this->getPublicNameFromIndex($i)] =
$this->frames[$i]->getFrames();
}
return $report;
}
/**
* Accessor for raw text of either all the pages or
* the frame in focus.
* @return string Raw unparsed content.
* @access public
*/
function getRaw() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getRaw();
}
$raw = '';
for ($i = 0; $i < count($this->frames); $i++) {
$raw .= $this->frames[$i]->getRaw();
}
return $raw;
}
/**
* Accessor for plain text of either all the pages or
* the frame in focus.
* @return string Plain text content.
* @access public
*/
function getText() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getText();
}
$raw = '';
for ($i = 0; $i < count($this->frames); $i++) {
$raw .= ' ' . $this->frames[$i]->getText();
}
return trim($raw);
}
/**
* Accessor for last error.
* @return string Error from last response.
* @access public
*/
function getTransportError() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getTransportError();
}
return $this->frameset->getTransportError();
}
/**
* Request method used to fetch this frame.
* @return string GET, POST or HEAD.
* @access public
*/
function getMethod() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getMethod();
}
return $this->frameset->getMethod();
}
/**
* Original resource name.
* @return SimpleUrl Current url.
* @access public
*/
function getUrl() {
if (is_integer($this->focus)) {
$url = $this->frames[$this->focus]->getUrl();
$url->setTarget($this->getPublicNameFromIndex($this->focus));
} else {
$url = $this->frameset->getUrl();
}
return $url;
}
/**
* Page base URL.
* @return SimpleUrl Current url.
* @access public
*/
function getBaseUrl() {
if (is_integer($this->focus)) {
$url = $this->frames[$this->focus]->getBaseUrl();
} else {
$url = $this->frameset->getBaseUrl();
}
return $url;
}
/**
* Expands expandomatic URLs into fully qualified
* URLs for the frameset page.
* @param SimpleUrl $url Relative URL.
* @return SimpleUrl Absolute URL.
* @access public
*/
function expandUrl($url) {
return $this->frameset->expandUrl($url);
}
/**
* Original request data.
* @return mixed Sent content.
* @access public
*/
function getRequestData() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getRequestData();
}
return $this->frameset->getRequestData();
}
/**
* Accessor for current MIME type.
* @return string MIME type as string; e.g. 'text/html'
* @access public
*/
function getMimeType() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getMimeType();
}
return $this->frameset->getMimeType();
}
/**
* Accessor for last response code.
* @return integer Last HTTP response code received.
* @access public
*/
function getResponseCode() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getResponseCode();
}
return $this->frameset->getResponseCode();
}
/**
* Accessor for last Authentication type. Only valid
* straight after a challenge (401).
* @return string Description of challenge type.
* @access public
*/
function getAuthentication() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getAuthentication();
}
return $this->frameset->getAuthentication();
}
/**
* Accessor for last Authentication realm. Only valid
* straight after a challenge (401).
* @return string Name of security realm.
* @access public
*/
function getRealm() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getRealm();
}
return $this->frameset->getRealm();
}
/**
* Accessor for outgoing header information.
* @return string Header block.
* @access public
*/
function getRequest() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getRequest();
}
return $this->frameset->getRequest();
}
/**
* Accessor for raw header information.
* @return string Header block.
* @access public
*/
function getHeaders() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getHeaders();
}
return $this->frameset->getHeaders();
}
/**
* Accessor for parsed title.
* @return string Title or false if no title is present.
* @access public
*/
function getTitle() {
return $this->frameset->getTitle();
}
/**
* Accessor for a list of all fixed links.
* @return array List of urls as strings.
* @access public
*/
function getUrls() {
if (is_integer($this->focus)) {
return $this->frames[$this->focus]->getUrls();
}
$urls = array();
foreach ($this->frames as $frame) {
$urls = array_merge($urls, $frame->getUrls());
}
return array_values(array_unique($urls));
}
/**
* Accessor for URLs by the link label. Label will match
* regardess of whitespace issues and case.
* @param string $label Text of link.
* @return array List of links with that label.
* @access public
*/
function getUrlsByLabel($label) {
if (is_integer($this->focus)) {
return $this->tagUrlsWithFrame(
$this->frames[$this->focus]->getUrlsByLabel($label),
$this->focus);
}
$urls = array();
foreach ($this->frames as $index => $frame) {
$urls = array_merge(
$urls,
$this->tagUrlsWithFrame(
$frame->getUrlsByLabel($label),
$index));
}
return $urls;
}
/**
* Accessor for a URL by the id attribute. If in a frameset
* then the first link found with that ID attribute is
* returned only. Focus on a frame if you want one from
* a specific part of the frameset.
* @param string $id Id attribute of link.
* @return string URL with that id.
* @access public
*/
function getUrlById($id) {
foreach ($this->frames as $index => $frame) {
if ($url = $frame->getUrlById($id)) {
if (! $url->gettarget()) {
$url->setTarget($this->getPublicNameFromIndex($index));
}
return $url;
}
}
return false;
}
/**
* Attaches the intended frame index to a list of URLs.
* @param array $urls List of SimpleUrls.
* @param string $frame Name of frame or index.
* @return array List of tagged URLs.
* @access private
*/
protected function tagUrlsWithFrame($urls, $frame) {
$tagged = array();
foreach ($urls as $url) {
if (! $url->getTarget()) {
$url->setTarget($this->getPublicNameFromIndex($frame));
}
$tagged[] = $url;
}
return $tagged;
}
/**
* Finds a held form by button label. Will only
* search correctly built forms.
* @param SimpleSelector $selector Button finder.
* @return SimpleForm Form object containing
* the button.
* @access public
*/
function getFormBySubmit($selector) {
return $this->findForm('getFormBySubmit', $selector);
}
/**
* Finds a held form by image using a selector.
* Will only search correctly built forms. The first
* form found either within the focused frame, or
* across frames, will be the one returned.
* @param SimpleSelector $selector Image finder.
* @return SimpleForm Form object containing
* the image.
* @access public
*/
function getFormByImage($selector) {
return $this->findForm('getFormByImage', $selector);
}
/**
* Finds a held form by the form ID. A way of
* identifying a specific form when we have control
* of the HTML code. The first form found
* either within the focused frame, or across frames,
* will be the one returned.
* @param string $id Form label.
* @return SimpleForm Form object containing the matching ID.
* @access public
*/
function getFormById($id) {
return $this->findForm('getFormById', $id);
}
/**
* General form finder. Will search all the frames or
* just the one in focus.
* @param string $method Method to use to find in a page.
* @param string $attribute Label, name or ID.
* @return SimpleForm Form object containing the matching ID.
* @access private
*/
protected function findForm($method, $attribute) {
if (is_integer($this->focus)) {
return $this->findFormInFrame(
$this->frames[$this->focus],
$this->focus,
$method,
$attribute);
}
for ($i = 0; $i < count($this->frames); $i++) {
$form = $this->findFormInFrame(
$this->frames[$i],
$i,
$method,
$attribute);
if ($form) {
return $form;
}
}
$null = null;
return $null;
}
/**
* Finds a form in a page using a form finding method. Will
* also tag the form with the frame name it belongs in.
* @param SimplePage $page Page content of frame.
* @param integer $index Internal frame representation.
* @param string $method Method to use to find in a page.
* @param string $attribute Label, name or ID.
* @return SimpleForm Form object containing the matching ID.
* @access private
*/
protected function findFormInFrame($page, $index, $method, $attribute) {
$form = $this->frames[$index]->$method($attribute);
if (isset($form)) {
$form->setDefaultTarget($this->getPublicNameFromIndex($index));
}
return $form;
}
/**
* Sets a field on each form in which the field is
* available.
* @param SimpleSelector $selector Field finder.
* @param string $value Value to set field to.
* @return boolean True if value is valid.
* @access public
*/
function setField($selector, $value) {
if (is_integer($this->focus)) {
$this->frames[$this->focus]->setField($selector, $value);
} else {
for ($i = 0; $i < count($this->frames); $i++) {
$this->frames[$i]->setField($selector, $value);
}
}
}
/**
* Accessor for a form element value within a page.
* @param SimpleSelector $selector Field finder.
* @return string/boolean A string if the field is
* present, false if unchecked
* and null if missing.
* @access public
*/
function getField($selector) {
for ($i = 0; $i < count($this->frames); $i++) {
$value = $this->frames[$i]->getField($selector);
if (isset($value)) {
return $value;
}
}
return null;
}
}
?>

View File

@ -1,628 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id: http.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/socket.php');
require_once(dirname(__FILE__) . '/cookies.php');
require_once(dirname(__FILE__) . '/url.php');
/**#@-*/
/**
* Creates HTTP headers for the end point of
* a HTTP request.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleRoute {
private $url;
/**
* Sets the target URL.
* @param SimpleUrl $url URL as object.
* @access public
*/
function __construct($url) {
$this->url = $url;
}
/**
* Resource name.
* @return SimpleUrl Current url.
* @access protected
*/
function getUrl() {
return $this->url;
}
/**
* Creates the first line which is the actual request.
* @param string $method HTTP request method, usually GET.
* @return string Request line content.
* @access protected
*/
protected function getRequestLine($method) {
return $method . ' ' . $this->url->getPath() .
$this->url->getEncodedRequest() . ' HTTP/1.0';
}
/**
* Creates the host part of the request.
* @return string Host line content.
* @access protected
*/
protected function getHostLine() {
$line = 'Host: ' . $this->url->getHost();
if ($this->url->getPort()) {
$line .= ':' . $this->url->getPort();
}
return $line;
}
/**
* Opens a socket to the route.
* @param string $method HTTP request method, usually GET.
* @param integer $timeout Connection timeout.
* @return SimpleSocket New socket.
* @access public
*/
function createConnection($method, $timeout) {
$default_port = ('https' == $this->url->getScheme()) ? 443 : 80;
$socket = $this->createSocket(
$this->url->getScheme() ? $this->url->getScheme() : 'http',
$this->url->getHost(),
$this->url->getPort() ? $this->url->getPort() : $default_port,
$timeout);
if (! $socket->isError()) {
$socket->write($this->getRequestLine($method) . "\r\n");
$socket->write($this->getHostLine() . "\r\n");
$socket->write("Connection: close\r\n");
}
return $socket;
}
/**
* Factory for socket.
* @param string $scheme Protocol to use.
* @param string $host Hostname to connect to.
* @param integer $port Remote port.
* @param integer $timeout Connection timeout.
* @return SimpleSocket/SimpleSecureSocket New socket.
* @access protected
*/
protected function createSocket($scheme, $host, $port, $timeout) {
if (in_array($scheme, array('file'))) {
return new SimpleFileSocket($this->url);
} elseif (in_array($scheme, array('https'))) {
return new SimpleSecureSocket($host, $port, $timeout);
} else {
return new SimpleSocket($host, $port, $timeout);
}
}
}
/**
* Creates HTTP headers for the end point of
* a HTTP request via a proxy server.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleProxyRoute extends SimpleRoute {
private $proxy;
private $username;
private $password;
/**
* Stashes the proxy address.
* @param SimpleUrl $url URL as object.
* @param string $proxy Proxy URL.
* @param string $username Username for autentication.
* @param string $password Password for autentication.
* @access public
*/
function __construct($url, $proxy, $username = false, $password = false) {
parent::__construct($url);
$this->proxy = $proxy;
$this->username = $username;
$this->password = $password;
}
/**
* Creates the first line which is the actual request.
* @param string $method HTTP request method, usually GET.
* @param SimpleUrl $url URL as object.
* @return string Request line content.
* @access protected
*/
function getRequestLine($method) {
$url = $this->getUrl();
$scheme = $url->getScheme() ? $url->getScheme() : 'http';
$port = $url->getPort() ? ':' . $url->getPort() : '';
return $method . ' ' . $scheme . '://' . $url->getHost() . $port .
$url->getPath() . $url->getEncodedRequest() . ' HTTP/1.0';
}
/**
* Creates the host part of the request.
* @param SimpleUrl $url URL as object.
* @return string Host line content.
* @access protected
*/
function getHostLine() {
$host = 'Host: ' . $this->proxy->getHost();
$port = $this->proxy->getPort() ? $this->proxy->getPort() : 8080;
return "$host:$port";
}
/**
* Opens a socket to the route.
* @param string $method HTTP request method, usually GET.
* @param integer $timeout Connection timeout.
* @return SimpleSocket New socket.
* @access public
*/
function createConnection($method, $timeout) {
$socket = $this->createSocket(
$this->proxy->getScheme() ? $this->proxy->getScheme() : 'http',
$this->proxy->getHost(),
$this->proxy->getPort() ? $this->proxy->getPort() : 8080,
$timeout);
if ($socket->isError()) {
return $socket;
}
$socket->write($this->getRequestLine($method) . "\r\n");
$socket->write($this->getHostLine() . "\r\n");
if ($this->username && $this->password) {
$socket->write('Proxy-Authorization: Basic ' .
base64_encode($this->username . ':' . $this->password) .
"\r\n");
}
$socket->write("Connection: close\r\n");
return $socket;
}
}
/**
* HTTP request for a web page. Factory for
* HttpResponse object.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleHttpRequest {
private $route;
private $encoding;
private $headers;
private $cookies;
/**
* Builds the socket request from the different pieces.
* These include proxy information, URL, cookies, headers,
* request method and choice of encoding.
* @param SimpleRoute $route Request route.
* @param SimpleFormEncoding $encoding Content to send with
* request.
* @access public
*/
function __construct($route, $encoding) {
$this->route = $route;
$this->encoding = $encoding;
$this->headers = array();
$this->cookies = array();
}
/**
* Dispatches the content to the route's socket.
* @param integer $timeout Connection timeout.
* @return SimpleHttpResponse A response which may only have
* an error, but hopefully has a
* complete web page.
* @access public
*/
function fetch($timeout) {
$socket = $this->route->createConnection($this->encoding->getMethod(), $timeout);
if (! $socket->isError()) {
$this->dispatchRequest($socket, $this->encoding);
}
return $this->createResponse($socket);
}
/**
* Sends the headers.
* @param SimpleSocket $socket Open socket.
* @param string $method HTTP request method,
* usually GET.
* @param SimpleFormEncoding $encoding Content to send with request.
* @access private
*/
protected function dispatchRequest($socket, $encoding) {
foreach ($this->headers as $header_line) {
$socket->write($header_line . "\r\n");
}
if (count($this->cookies) > 0) {
$socket->write("Cookie: " . implode(";", $this->cookies) . "\r\n");
}
$encoding->writeHeadersTo($socket);
$socket->write("\r\n");
$encoding->writeTo($socket);
}
/**
* Adds a header line to the request.
* @param string $header_line Text of full header line.
* @access public
*/
function addHeaderLine($header_line) {
$this->headers[] = $header_line;
}
/**
* Reads all the relevant cookies from the
* cookie jar.
* @param SimpleCookieJar $jar Jar to read
* @param SimpleUrl $url Url to use for scope.
* @access public
*/
function readCookiesFromJar($jar, $url) {
$this->cookies = $jar->selectAsPairs($url);
}
/**
* Wraps the socket in a response parser.
* @param SimpleSocket $socket Responding socket.
* @return SimpleHttpResponse Parsed response object.
* @access protected
*/
protected function createResponse($socket) {
$response = new SimpleHttpResponse(
$socket,
$this->route->getUrl(),
$this->encoding);
$socket->close();
return $response;
}
}
/**
* Collection of header lines in the response.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleHttpHeaders {
private $raw_headers;
private $response_code;
private $http_version;
private $mime_type;
private $location;
private $cookies;
private $authentication;
private $realm;
/**
* Parses the incoming header block.
* @param string $headers Header block.
* @access public
*/
function __construct($headers) {
$this->raw_headers = $headers;
$this->response_code = false;
$this->http_version = false;
$this->mime_type = '';
$this->location = false;
$this->cookies = array();
$this->authentication = false;
$this->realm = false;
foreach (explode("\r\n", $headers) as $header_line) {
$this->parseHeaderLine($header_line);
}
}
/**
* Accessor for parsed HTTP protocol version.
* @return integer HTTP error code.
* @access public
*/
function getHttpVersion() {
return $this->http_version;
}
/**
* Accessor for raw header block.
* @return string All headers as raw string.
* @access public
*/
function getRaw() {
return $this->raw_headers;
}
/**
* Accessor for parsed HTTP error code.
* @return integer HTTP error code.
* @access public
*/
function getResponseCode() {
return (integer)$this->response_code;
}
/**
* Returns the redirected URL or false if
* no redirection.
* @return string URL or false for none.
* @access public
*/
function getLocation() {
return $this->location;
}
/**
* Test to see if the response is a valid redirect.
* @return boolean True if valid redirect.
* @access public
*/
function isRedirect() {
return in_array($this->response_code, array(301, 302, 303, 307)) &&
(boolean)$this->getLocation();
}
/**
* Test to see if the response is an authentication
* challenge.
* @return boolean True if challenge.
* @access public
*/
function isChallenge() {
return ($this->response_code == 401) &&
(boolean)$this->authentication &&
(boolean)$this->realm;
}
/**
* Accessor for MIME type header information.
* @return string MIME type.
* @access public
*/
function getMimeType() {
return $this->mime_type;
}
/**
* Accessor for authentication type.
* @return string Type.
* @access public
*/
function getAuthentication() {
return $this->authentication;
}
/**
* Accessor for security realm.
* @return string Realm.
* @access public
*/
function getRealm() {
return $this->realm;
}
/**
* Writes new cookies to the cookie jar.
* @param SimpleCookieJar $jar Jar to write to.
* @param SimpleUrl $url Host and path to write under.
* @access public
*/
function writeCookiesToJar($jar, $url) {
foreach ($this->cookies as $cookie) {
$jar->setCookie(
$cookie->getName(),
$cookie->getValue(),
$url->getHost(),
$cookie->getPath(),
$cookie->getExpiry());
}
}
/**
* Called on each header line to accumulate the held
* data within the class.
* @param string $header_line One line of header.
* @access protected
*/
protected function parseHeaderLine($header_line) {
if (preg_match('/HTTP\/(\d+\.\d+)\s+(\d+)/i', $header_line, $matches)) {
$this->http_version = $matches[1];
$this->response_code = $matches[2];
}
if (preg_match('/Content-type:\s*(.*)/i', $header_line, $matches)) {
$this->mime_type = trim($matches[1]);
}
if (preg_match('/Location:\s*(.*)/i', $header_line, $matches)) {
$this->location = trim($matches[1]);
}
if (preg_match('/Set-cookie:(.*)/i', $header_line, $matches)) {
$this->cookies[] = $this->parseCookie($matches[1]);
}
if (preg_match('/WWW-Authenticate:\s+(\S+)\s+realm=\"(.*?)\"/i', $header_line, $matches)) {
$this->authentication = $matches[1];
$this->realm = trim($matches[2]);
}
}
/**
* Parse the Set-cookie content.
* @param string $cookie_line Text after "Set-cookie:"
* @return SimpleCookie New cookie object.
* @access private
*/
protected function parseCookie($cookie_line) {
$parts = explode(";", $cookie_line);
$cookie = array();
preg_match('/\s*(.*?)\s*=(.*)/', array_shift($parts), $cookie);
foreach ($parts as $part) {
if (preg_match('/\s*(.*?)\s*=(.*)/', $part, $matches)) {
$cookie[$matches[1]] = trim($matches[2]);
}
}
return new SimpleCookie(
$cookie[1],
trim($cookie[2]),
isset($cookie["path"]) ? $cookie["path"] : "",
isset($cookie["expires"]) ? $cookie["expires"] : false);
}
}
/**
* Basic HTTP response.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleHttpResponse extends SimpleStickyError {
private $url;
private $encoding;
private $sent;
private $content;
private $headers;
/**
* Constructor. Reads and parses the incoming
* content and headers.
* @param SimpleSocket $socket Network connection to fetch
* response text from.
* @param SimpleUrl $url Resource name.
* @param mixed $encoding Record of content sent.
* @access public
*/
function __construct($socket, $url, $encoding) {
parent::__construct();
$this->url = $url;
$this->encoding = $encoding;
$this->sent = $socket->getSent();
$this->content = false;
$raw = $this->readAll($socket);
if ($socket->isError()) {
$this->setError('Error reading socket [' . $socket->getError() . ']');
return;
}
$this->parse($raw);
}
/**
* Splits up the headers and the rest of the content.
* @param string $raw Content to parse.
* @access private
*/
protected function parse($raw) {
if (! $raw) {
$this->setError('Nothing fetched');
$this->headers = new SimpleHttpHeaders('');
} elseif ('file' == $this->url->getScheme()) {
$this->headers = new SimpleHttpHeaders('');
$this->content = $raw;
} elseif (! strstr($raw, "\r\n\r\n")) {
$this->setError('Could not split headers from content');
$this->headers = new SimpleHttpHeaders($raw);
} else {
list($headers, $this->content) = explode("\r\n\r\n", $raw, 2);
$this->headers = new SimpleHttpHeaders($headers);
}
}
/**
* Original request method.
* @return string GET, POST or HEAD.
* @access public
*/
function getMethod() {
return $this->encoding->getMethod();
}
/**
* Resource name.
* @return SimpleUrl Current url.
* @access public
*/
function getUrl() {
return $this->url;
}
/**
* Original request data.
* @return mixed Sent content.
* @access public
*/
function getRequestData() {
return $this->encoding;
}
/**
* Raw request that was sent down the wire.
* @return string Bytes actually sent.
* @access public
*/
function getSent() {
return $this->sent;
}
/**
* Accessor for the content after the last
* header line.
* @return string All content.
* @access public
*/
function getContent() {
return $this->content;
}
/**
* Accessor for header block. The response is the
* combination of this and the content.
* @return SimpleHeaders Wrapped header block.
* @access public
*/
function getHeaders() {
return $this->headers;
}
/**
* Accessor for any new cookies.
* @return array List of new cookies.
* @access public
*/
function getNewCookies() {
return $this->headers->getNewCookies();
}
/**
* Reads the whole of the socket output into a
* single string.
* @param SimpleSocket $socket Unread socket.
* @return string Raw output if successful
* else false.
* @access private
*/
protected function readAll($socket) {
$all = '';
while (! $this->isLastPacket($next = $socket->read())) {
$all .= $next;
}
return $all;
}
/**
* Test to see if the packet from the socket is the
* last one.
* @param string $packet Chunk to interpret.
* @return boolean True if empty or EOF.
* @access private
*/
protected function isLastPacket($packet) {
if (is_string($packet)) {
return $packet === '';
}
return ! $packet;
}
}
?>

View File

@ -1,139 +0,0 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: invoker.php 1785 2008-04-26 13:56:41Z pp11 $
*/
/**#@+
* Includes SimpleTest files and defined the root constant
* for dependent libraries.
*/
require_once(dirname(__FILE__) . '/errors.php');
require_once(dirname(__FILE__) . '/compatibility.php');
require_once(dirname(__FILE__) . '/scorer.php');
require_once(dirname(__FILE__) . '/expectation.php');
require_once(dirname(__FILE__) . '/dumper.php');
if (! defined('SIMPLE_TEST')) {
define('SIMPLE_TEST', dirname(__FILE__) . '/');
}
/**#@-*/
/**
* This is called by the class runner to run a
* single test method. Will also run the setUp()
* and tearDown() methods.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleInvoker {
private $test_case;
/**
* Stashes the test case for later.
* @param SimpleTestCase $test_case Test case to run.
*/
function __construct($test_case) {
$this->test_case = $test_case;
}
/**
* Accessor for test case being run.
* @return SimpleTestCase Test case.
* @access public
*/
function getTestCase() {
return $this->test_case;
}
/**
* Runs test level set up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function before($method) {
$this->test_case->before($method);
}
/**
* Invokes a test method and buffered with setUp()
* and tearDown() calls.
* @param string $method Test method to call.
* @access public
*/
function invoke($method) {
$this->test_case->setUp();
$this->test_case->$method();
$this->test_case->tearDown();
}
/**
* Runs test level clean up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function after($method) {
$this->test_case->after($method);
}
}
/**
* Do nothing decorator. Just passes the invocation
* straight through.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleInvokerDecorator {
private $invoker;
/**
* Stores the invoker to wrap.
* @param SimpleInvoker $invoker Test method runner.
*/
function __construct($invoker) {
$this->invoker = $invoker;
}
/**
* Accessor for test case being run.
* @return SimpleTestCase Test case.
* @access public
*/
function getTestCase() {
return $this->invoker->getTestCase();
}
/**
* Runs test level set up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function before($method) {
$this->invoker->before($method);
}
/**
* Invokes a test method and buffered with setUp()
* and tearDown() calls.
* @param string $method Test method to call.
* @access public
*/
function invoke($method) {
$this->invoker->invoke($method);
}
/**
* Runs test level clean up. Used for changing
* the mechanics of base test cases.
* @param string $method Test method to call.
* @access public
*/
function after($method) {
$this->invoker->after($method);
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,542 +0,0 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id: page.php 1938 2009-08-05 17:16:23Z dgheath $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/http.php');
require_once(dirname(__FILE__) . '/php_parser.php');
require_once(dirname(__FILE__) . '/tag.php');
require_once(dirname(__FILE__) . '/form.php');
require_once(dirname(__FILE__) . '/selector.php');
/**#@-*/
/**
* A wrapper for a web page.
* @package SimpleTest
* @subpackage WebTester
*/
class SimplePage {
private $links = array();
private $title = false;
private $last_widget;
private $label;
private $forms = array();
private $frames = array();
private $transport_error;
private $raw;
private $text = false;
private $sent;
private $headers;
private $method;
private $url;
private $base = false;
private $request_data;
/**
* Parses a page ready to access it's contents.
* @param SimpleHttpResponse $response Result of HTTP fetch.
* @access public
*/
function __construct($response = false) {
if ($response) {
$this->extractResponse($response);
} else {
$this->noResponse();
}
}
/**
* Extracts all of the response information.
* @param SimpleHttpResponse $response Response being parsed.
* @access private
*/
protected function extractResponse($response) {
$this->transport_error = $response->getError();
$this->raw = $response->getContent();
$this->sent = $response->getSent();
$this->headers = $response->getHeaders();
$this->method = $response->getMethod();
$this->url = $response->getUrl();
$this->request_data = $response->getRequestData();
}
/**
* Sets up a missing response.
* @access private
*/
protected function noResponse() {
$this->transport_error = 'No page fetched yet';
$this->raw = false;
$this->sent = false;
$this->headers = false;
$this->method = 'GET';
$this->url = false;
$this->request_data = false;
}
/**
* Original request as bytes sent down the wire.
* @return mixed Sent content.
* @access public
*/
function getRequest() {
return $this->sent;
}
/**
* Accessor for raw text of page.
* @return string Raw unparsed content.
* @access public
*/
function getRaw() {
return $this->raw;
}
/**
* Accessor for plain text of page as a text browser
* would see it.
* @return string Plain text of page.
* @access public
*/
function getText() {
if (! $this->text) {
$this->text = SimplePage::normalise($this->raw);
}
return $this->text;
}
/**
* Accessor for raw headers of page.
* @return string Header block as text.
* @access public
*/
function getHeaders() {
if ($this->headers) {
return $this->headers->getRaw();
}
return false;
}
/**
* Original request method.
* @return string GET, POST or HEAD.
* @access public
*/
function getMethod() {
return $this->method;
}
/**
* Original resource name.
* @return SimpleUrl Current url.
* @access public
*/
function getUrl() {
return $this->url;
}
/**
* Base URL if set via BASE tag page url otherwise
* @return SimpleUrl Base url.
* @access public
*/
function getBaseUrl() {
return $this->base;
}
/**
* Original request data.
* @return mixed Sent content.
* @access public
*/
function getRequestData() {
return $this->request_data;
}
/**
* Accessor for last error.
* @return string Error from last response.
* @access public
*/
function getTransportError() {
return $this->transport_error;
}
/**
* Accessor for current MIME type.
* @return string MIME type as string; e.g. 'text/html'
* @access public
*/
function getMimeType() {
if ($this->headers) {
return $this->headers->getMimeType();
}
return false;
}
/**
* Accessor for HTTP response code.
* @return integer HTTP response code received.
* @access public
*/
function getResponseCode() {
if ($this->headers) {
return $this->headers->getResponseCode();
}
return false;
}
/**
* Accessor for last Authentication type. Only valid
* straight after a challenge (401).
* @return string Description of challenge type.
* @access public
*/
function getAuthentication() {
if ($this->headers) {
return $this->headers->getAuthentication();
}
return false;
}
/**
* Accessor for last Authentication realm. Only valid
* straight after a challenge (401).
* @return string Name of security realm.
* @access public
*/
function getRealm() {
if ($this->headers) {
return $this->headers->getRealm();
}
return false;
}
/**
* Accessor for current frame focus. Will be
* false as no frames.
* @return array Always empty.
* @access public
*/
function getFrameFocus() {
return array();
}
/**
* Sets the focus by index. The integer index starts from 1.
* @param integer $choice Chosen frame.
* @return boolean Always false.
* @access public
*/
function setFrameFocusByIndex($choice) {
return false;
}
/**
* Sets the focus by name. Always fails for a leaf page.
* @param string $name Chosen frame.
* @return boolean False as no frames.
* @access public
*/
function setFrameFocus($name) {
return false;
}
/**
* Clears the frame focus. Does nothing for a leaf page.
* @access public
*/
function clearFrameFocus() {
}
/**
* TODO: write docs
*/
function setFrames($frames) {
$this->frames = $frames;
}
/**
* Test to see if link is an absolute one.
* @param string $url Url to test.
* @return boolean True if absolute.
* @access protected
*/
protected function linkIsAbsolute($url) {
$parsed = new SimpleUrl($url);
return (boolean)($parsed->getScheme() && $parsed->getHost());
}
/**
* Adds a link to the page.
* @param SimpleAnchorTag $tag Link to accept.
*/
function addLink($tag) {
$this->links[] = $tag;
}
/**
* Set the forms
* @param array $forms An array of SimpleForm objects
*/
function setForms($forms) {
$this->forms = $forms;
}
/**
* Test for the presence of a frameset.
* @return boolean True if frameset.
* @access public
*/
function hasFrames() {
return count($this->frames) > 0;
}
/**
* Accessor for frame name and source URL for every frame that
* will need to be loaded. Immediate children only.
* @return boolean/array False if no frameset or
* otherwise a hash of frame URLs.
* The key is either a numerical
* base one index or the name attribute.
* @access public
*/
function getFrameset() {
if (! $this->hasFrames()) {
return false;
}
$urls = array();
for ($i = 0; $i < count($this->frames); $i++) {
$name = $this->frames[$i]->getAttribute('name');
$url = new SimpleUrl($this->frames[$i]->getAttribute('src'));
$urls[$name ? $name : $i + 1] = $this->expandUrl($url);
}
return $urls;
}
/**
* Fetches a list of loaded frames.
* @return array/string Just the URL for a single page.
* @access public
*/
function getFrames() {
$url = $this->expandUrl($this->getUrl());
return $url->asString();
}
/**
* Accessor for a list of all links.
* @return array List of urls with scheme of
* http or https and hostname.
* @access public
*/
function getUrls() {
$all = array();
foreach ($this->links as $link) {
$url = $this->getUrlFromLink($link);
$all[] = $url->asString();
}
return $all;
}
/**
* Accessor for URLs by the link label. Label will match
* regardess of whitespace issues and case.
* @param string $label Text of link.
* @return array List of links with that label.
* @access public
*/
function getUrlsByLabel($label) {
$matches = array();
foreach ($this->links as $link) {
if ($link->getText() == $label) {
$matches[] = $this->getUrlFromLink($link);
}
}
return $matches;
}
/**
* Accessor for a URL by the id attribute.
* @param string $id Id attribute of link.
* @return SimpleUrl URL with that id of false if none.
* @access public
*/
function getUrlById($id) {
foreach ($this->links as $link) {
if ($link->getAttribute('id') === (string)$id) {
return $this->getUrlFromLink($link);
}
}
return false;
}
/**
* Converts a link tag into a target URL.
* @param SimpleAnchor $link Parsed link.
* @return SimpleUrl URL with frame target if any.
* @access private
*/
protected function getUrlFromLink($link) {
$url = $this->expandUrl($link->getHref());
if ($link->getAttribute('target')) {
$url->setTarget($link->getAttribute('target'));
}
return $url;
}
/**
* Expands expandomatic URLs into fully qualified
* URLs.
* @param SimpleUrl $url Relative URL.
* @return SimpleUrl Absolute URL.
* @access public
*/
function expandUrl($url) {
if (! is_object($url)) {
$url = new SimpleUrl($url);
}
$location = $this->getBaseUrl() ? $this->getBaseUrl() : new SimpleUrl();
return $url->makeAbsolute($location->makeAbsolute($this->getUrl()));
}
/**
* Sets the base url for the page.
* @param string $url Base URL for page.
*/
function setBase($url) {
$this->base = new SimpleUrl($url);
}
/**
* Sets the title tag contents.
* @param SimpleTitleTag $tag Title of page.
*/
function setTitle($tag) {
$this->title = $tag;
}
/**
* Accessor for parsed title.
* @return string Title or false if no title is present.
* @access public
*/
function getTitle() {
if ($this->title) {
return $this->title->getText();
}
return false;
}
/**
* Finds a held form by button label. Will only
* search correctly built forms.
* @param SimpleSelector $selector Button finder.
* @return SimpleForm Form object containing
* the button.
* @access public
*/
function getFormBySubmit($selector) {
for ($i = 0; $i < count($this->forms); $i++) {
if ($this->forms[$i]->hasSubmit($selector)) {
return $this->forms[$i];
}
}
return null;
}
/**
* Finds a held form by image using a selector.
* Will only search correctly built forms.
* @param SimpleSelector $selector Image finder.
* @return SimpleForm Form object containing
* the image.
* @access public
*/
function getFormByImage($selector) {
for ($i = 0; $i < count($this->forms); $i++) {
if ($this->forms[$i]->hasImage($selector)) {
return $this->forms[$i];
}
}
return null;
}
/**
* Finds a held form by the form ID. A way of
* identifying a specific form when we have control
* of the HTML code.
* @param string $id Form label.
* @return SimpleForm Form object containing the matching ID.
* @access public
*/
function getFormById($id) {
for ($i = 0; $i < count($this->forms); $i++) {
if ($this->forms[$i]->getId() == $id) {
return $this->forms[$i];
}
}
return null;
}
/**
* Sets a field on each form in which the field is
* available.
* @param SimpleSelector $selector Field finder.
* @param string $value Value to set field to.
* @return boolean True if value is valid.
* @access public
*/
function setField($selector, $value, $position=false) {
$is_set = false;
for ($i = 0; $i < count($this->forms); $i++) {
if ($this->forms[$i]->setField($selector, $value, $position)) {
$is_set = true;
}
}
return $is_set;
}
/**
* Accessor for a form element value within a page.
* @param SimpleSelector $selector Field finder.
* @return string/boolean A string if the field is
* present, false if unchecked
* and null if missing.
* @access public
*/
function getField($selector) {
for ($i = 0; $i < count($this->forms); $i++) {
$value = $this->forms[$i]->getValue($selector);
if (isset($value)) {
return $value;
}
}
return null;
}
/**
* Turns HTML into text browser visible text. Images
* are converted to their alt text and tags are supressed.
* Entities are converted to their visible representation.
* @param string $html HTML to convert.
* @return string Plain text.
* @access public
*/
static function normalise($html) {
$text = preg_replace('#<!--.*?-->#si', '', $html);
$text = preg_replace('#<(script|option|textarea)[^>]*>.*?</\1>#si', '', $text);
$text = preg_replace('#<img[^>]*alt\s*=\s*("([^"]*)"|\'([^\']*)\'|([a-zA-Z_]+))[^>]*>#', ' \2\3\4 ', $text);
$text = preg_replace('#<[^>]*>#', '', $text);
$text = html_entity_decode($text, ENT_QUOTES);
$text = preg_replace('#\s+#', ' ', $text);
return trim(trim($text), "\xA0"); // TODO: The \xAO is a &nbsp;. Add a test for this.
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,101 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage Extensions
* @author Rene vd O (original code)
* @author Perrick Penet
* @author Marcus Baker
* @version $Id: recorder.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/scorer.php');
/**
* A single test result.
* @package SimpleTest
* @subpackage Extensions
*/
abstract class SimpleResult {
public $time;
public $breadcrumb;
public $message;
/**
* Records the test result as public members.
* @param array $breadcrumb Test stack at the time of the event.
* @param string $message The messsage to the human.
*/
function __construct($breadcrumb, $message) {
list($this->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);
}
}
?>

View File

@ -1,136 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: reflection_php4.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**
* Version specific reflection API.
* @package SimpleTest
* @subpackage UnitTester
* @ignore duplicate with reflection_php5.php
*/
class SimpleReflection {
var $_interface;
/**
* Stashes the class/interface.
* @param string $interface Class or interface
* to inspect.
*/
function SimpleReflection($interface) {
$this->_interface = $interface;
}
/**
* Checks that a class has been declared.
* @return boolean True if defined.
* @access public
*/
function classExists() {
return class_exists($this->_interface);
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classExistsSansAutoload() {
return class_exists($this->_interface);
}
/**
* Checks that a class or interface has been
* declared.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExists() {
return class_exists($this->_interface);
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExistsSansAutoload() {
return class_exists($this->_interface);
}
/**
* Gets the list of methods on a class or
* interface.
* @returns array List of method names.
* @access public
*/
function getMethods() {
return get_class_methods($this->_interface);
}
/**
* Gets the list of interfaces from a class. If the
* class name is actually an interface then just that
* interface is returned.
* @returns array List of interfaces.
* @access public
*/
function getInterfaces() {
return array();
}
/**
* Finds the parent class name.
* @returns string Parent class name.
* @access public
*/
function getParent() {
return strtolower(get_parent_class($this->_interface));
}
/**
* Determines if the class is abstract, which for PHP 4
* will never be the case.
* @returns boolean True if abstract.
* @access public
*/
function isAbstract() {
return false;
}
/**
* 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()";
}
}
?>

View File

@ -1,386 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: reflection_php5.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**
* Version specific reflection API.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleReflection {
private $interface;
/**
* Stashes the class/interface.
* @param string $interface Class or interface
* to inspect.
*/
function __construct($interface) {
$this->interface = $interface;
}
/**
* Checks that a class has been declared. Versions
* before PHP5.0.2 need a check that it's not really
* an interface.
* @return boolean True if defined.
* @access public
*/
function classExists() {
if (! class_exists($this->interface)) {
return false;
}
$reflection = new ReflectionClass($this->interface);
return ! $reflection->isInterface();
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classExistsSansAutoload() {
return class_exists($this->interface, false);
}
/**
* Checks that a class or interface has been
* declared.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExists() {
return $this->classOrInterfaceExistsWithAutoload($this->interface, true);
}
/**
* Needed to kill the autoload feature in PHP5
* for classes created dynamically.
* @return boolean True if defined.
* @access public
*/
function classOrInterfaceExistsSansAutoload() {
return $this->classOrInterfaceExistsWithAutoload($this->interface, false);
}
/**
* Needed to select the autoload feature in PHP5
* for classes created dynamically.
* @param string $interface Class or interface name.
* @param boolean $autoload True totriggerautoload.
* @return boolean True if interface defined.
* @access private
*/
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;
}
}
?>

View File

@ -1,115 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: remote.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/browser.php');
require_once(dirname(__FILE__) . '/xml.php');
require_once(dirname(__FILE__) . '/test_case.php');
/**#@-*/
/**
* Runs an XML formated test on a remote server.
* @package SimpleTest
* @subpackage UnitTester
*/
class RemoteTestCase {
private $url;
private $dry_url;
private $size;
/**
* Sets the location of the remote test.
* @param string $url Test location.
* @param string $dry_url Location for dry run.
* @access public
*/
function __construct($url, $dry_url = false) {
$this->url = $url;
$this->dry_url = $dry_url ? $dry_url : $url;
$this->size = false;
}
/**
* Accessor for the test name for subclasses.
* @return string Name of the test.
* @access public
*/
function getLabel() {
return $this->url;
}
/**
* Runs 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;
}
}
?>

View File

@ -1,445 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: reporter.php 2005 2010-11-02 14:09:34Z lastcraft $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/scorer.php');
//require_once(dirname(__FILE__) . '/arguments.php');
/**#@-*/
/**
* Sample minimal test displayer. Generates only
* failure messages and a pass count.
* @package SimpleTest
* @subpackage UnitTester
*/
class HtmlReporter extends SimpleReporter {
private $character_set;
/**
* Does nothing yet. The first output will
* be sent on the first test start. For use
* by a web browser.
* @access public
*/
function __construct($character_set = 'ISO-8859-1') {
parent::__construct();
$this->character_set = $character_set;
}
/**
* Paints the top of the web page setting the
* title to the name of the starting test.
* @param string $test_name Name class of test.
* @access public
*/
function paintHeader($test_name) {
$this->sendNoCacheHeaders();
print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">";
print "<html>\n<head>\n<title>$test_name</title>\n";
print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=" .
$this->character_set . "\">\n";
print "<style type=\"text/css\">\n";
print $this->getCss() . "\n";
print "</style>\n";
print "</head>\n<body>\n";
print "<h1>$test_name</h1>\n";
flush();
}
/**
* 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 "<div style=\"";
print "padding: 8px; margin-top: 1em; background-color: $colour; color: white;";
print "\">";
print $this->getTestCaseProgress() . "/" . $this->getTestCaseCount();
print " test cases complete:\n";
print "<strong>" . $this->getPassCount() . "</strong> passes, ";
print "<strong>" . $this->getFailCount() . "</strong> fails and ";
print "<strong>" . $this->getExceptionCount() . "</strong> exceptions.";
print "</div>\n";
print "</body>\n</html>\n";
}
/**
* Paints the test failure with a breadcrumbs
* trail of the nesting test suites below the
* top level test.
* @param string $message Failure message displayed in
* the context of the other tests.
*/
function paintFail($message) {
parent::paintFail($message);
print "<span class=\"fail\">Fail</span>: ";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print implode(" -&gt; ", $breadcrumb);
print " -&gt; " . $this->htmlEntities($message) . "<br />\n";
}
/**
* Paints a PHP error.
* @param string $message Message is ignored.
* @access public
*/
function paintError($message) {
parent::paintError($message);
print "<span class=\"fail\">Exception</span>: ";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print implode(" -&gt; ", $breadcrumb);
print " -&gt; <strong>" . $this->htmlEntities($message) . "</strong><br />\n";
}
/**
* Paints a PHP exception.
* @param Exception $exception Exception to display.
* @access public
*/
function paintException($exception) {
parent::paintException($exception);
print "<span class=\"fail\">Exception</span>: ";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print implode(" -&gt; ", $breadcrumb);
$message = 'Unexpected exception of type [' . get_class($exception) .
'] with message ['. $exception->getMessage() .
'] in ['. $exception->getFile() .
' line ' . $exception->getLine() . ']';
print " -&gt; <strong>" . $this->htmlEntities($message) . "</strong><br />\n";
}
/**
* Prints the message for skipping tests.
* @param string $message Text of skip condition.
* @access public
*/
function paintSkip($message) {
parent::paintSkip($message);
print "<span class=\"pass\">Skipped</span>: ";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print implode(" -&gt; ", $breadcrumb);
print " -&gt; " . $this->htmlEntities($message) . "<br />\n";
}
/**
* Paints formatted text such as dumped privateiables.
* @param string $message Text to show.
* @access public
*/
function paintFormattedMessage($message) {
print '<pre>' . $this->htmlEntities($message) . '</pre>';
}
/**
* Character set adjusted entity conversion.
* @param string $message Plain text or Unicode message.
* @return string Browser readable message.
* @access protected
*/
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) { }
}
?>

View File

@ -1,875 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: scorer.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+*/
require_once(dirname(__FILE__) . '/invoker.php');
/**#@-*/
/**
* Can receive test events and display them. Display
* is achieved by making display methods available
* and visiting the incoming event.
* @package SimpleTest
* @subpackage UnitTester
* @abstract
*/
class SimpleScorer {
private $passes;
private $fails;
private $exceptions;
private $is_dry_run;
/**
* Starts the test run with no results.
* @access public
*/
function __construct() {
$this->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);
}
}
}
?>

View File

@ -1,141 +0,0 @@
<?php
/**
* Base include file for SimpleTest.
* @package SimpleTest
* @subpackage WebTester
* @version $Id: selector.php 1786 2008-04-26 17:32:20Z pp11 $
*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/tag.php');
require_once(dirname(__FILE__) . '/encoding.php');
/**#@-*/
/**
* Used to extract form elements for testing against.
* Searches by name attribute.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleByName {
private $name;
/**
* Stashes the name for later comparison.
* @param string $name Name attribute to match.
*/
function __construct($name) {
$this->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);
}
}
?>

View File

@ -1,330 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: shell_tester.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/test_case.php');
/**#@-*/
/**
* Wrapper for exec() functionality.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleShell {
private $output;
/**
* Executes the shell comand and stashes the output.
* @access public
*/
function __construct() {
$this->output = false;
}
/**
* Actually runs the command. Does not trap the
* error stream output as this need PHP 4.3+.
* @param string $command The actual command line
* to run.
* @return integer Exit code.
* @access public
*/
function execute($command) {
$this->output = false;
exec($command, $this->output, $ret);
return $ret;
}
/**
* Accessor for the last output.
* @return string Output as text.
* @access public
*/
function getOutput() {
return implode("\n", $this->output);
}
/**
* Accessor for the last output.
* @return array Output as array of lines.
* @access public
*/
function getOutputAsList() {
return $this->output;
}
}
/**
* 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();
}
}
?>

View File

@ -1,391 +0,0 @@
<?php
/**
* Global state for SimpleTest and kicker script in future versions.
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: simpletest.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/reflection_php5.php');
require_once(dirname(__FILE__) . '/default_reporter.php');
require_once(dirname(__FILE__) . '/compatibility.php');
/**#@-*/
/**
* Registry and test context. Includes a few
* global options that I'm slowly getting rid of.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleTest {
/**
* Reads the SimpleTest version from the release file.
* @return string Version string.
*/
static function getVersion() {
$content = file(dirname(__FILE__) . '/VERSION');
return trim($content[0]);
}
/**
* Sets the name of a test case to ignore, usually
* because the class is an abstract case that should
* @param string $class Add a class to ignore.
*/
static function ignore($class) {
$registry = &SimpleTest::getRegistry();
$registry['IgnoreList'][strtolower($class)] = true;
}
/**
* Scans the now complete ignore list, and adds
* all parent classes to the list. If a class
* is not a runnable test case, then it's parents
* wouldn't be either. This is syntactic sugar
* to cut down on ommissions of ignore()'s or
* missing abstract declarations. This cannot
* be done whilst loading classes wiithout forcing
* a particular order on the class declarations and
* the ignore() calls. It's just nice to have the ignore()
* calls at the top of the file before the actual declarations.
* @param array $classes Class names of interest.
*/
static function ignoreParentsIfIgnored($classes) {
$registry = &SimpleTest::getRegistry();
foreach ($classes as $class) {
if (SimpleTest::isIgnored($class)) {
$reflection = new SimpleReflection($class);
if ($parent = $reflection->getParent()) {
SimpleTest::ignore($parent);
}
}
}
}
/**
* 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();
}
}
?>

View File

@ -1,312 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage MockObjects
* @version $Id: socket.php 1953 2009-09-20 01:26:25Z jsweat $
*/
/**#@+
* include SimpleTest files
*/
require_once(dirname(__FILE__) . '/compatibility.php');
/**#@-*/
/**
* Stashes an error for later. Useful for constructors
* until PHP gets exceptions.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleStickyError {
private $error = 'Constructor not chained';
/**
* Sets the error to empty.
* @access public
*/
function __construct() {
$this->clearError();
}
/**
* Test for an outstanding error.
* @return boolean True if there is an error.
* @access public
*/
function isError() {
return ($this->error != '');
}
/**
* Accessor for an outstanding error.
* @return string Empty string if no error otherwise
* the error message.
* @access public
*/
function getError() {
return $this->error;
}
/**
* Sets the internal error.
* @param string Error message to stash.
* @access protected
*/
function setError($error) {
$this->error = $error;
}
/**
* Resets the error state to no error.
* @access protected
*/
function clearError() {
$this->setError('');
}
}
/**
* @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);
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,658 +0,0 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: test_case.php 2012 2011-04-29 08:57:00Z pp11 $
*/
/**#@+
* Includes SimpleTest files and defined the root constant
* for dependent libraries.
*/
require_once(dirname(__FILE__) . '/invoker.php');
require_once(dirname(__FILE__) . '/errors.php');
require_once(dirname(__FILE__) . '/compatibility.php');
require_once(dirname(__FILE__) . '/scorer.php');
require_once(dirname(__FILE__) . '/expectation.php');
require_once(dirname(__FILE__) . '/dumper.php');
require_once(dirname(__FILE__) . '/simpletest.php');
require_once(dirname(__FILE__) . '/exceptions.php');
require_once(dirname(__FILE__) . '/reflection_php5.php');
/**#@-*/
if (! defined('SIMPLE_TEST')) {
/**
* @ignore
*/
define('SIMPLE_TEST', dirname(__FILE__) . DIRECTORY_SEPARATOR);
}
/**
* Basic test case. This is the smallest unit of a test
* suite. It searches for
* all methods that start with the the string "test" and
* runs them. Working test cases extend this class.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleTestCase {
private $label = false;
protected $reporter;
private $observers;
private $should_skip = false;
/**
* Sets up the test with no display.
* @param string $label If no test name is given then
* the class name is used.
* @access public
*/
function __construct($label = false) {
if ($label) {
$this->label = $label;
}
}
/**
* Accessor for the test name for subclasses.
* @return string Name of the test.
* @access public
*/
function getLabel() {
return $this->label ? $this->label : get_class($this);
}
/**
* This is a placeholder for skipping tests. In this
* method you place skipIf() and skipUnless() calls to
* set the skipping state.
* @access public
*/
function skip() {
}
/**
* Will issue a message to the reporter and tell the test
* case to skip if the incoming flag is true.
* @param string $should_skip Condition causing the tests to be skipped.
* @param string $message Text of skip condition.
* @access public
*/
function skipIf($should_skip, $message = '%s') {
if ($should_skip && ! $this->should_skip) {
$this->should_skip = true;
$message = sprintf($message, 'Skipping [' . get_class($this) . ']');
$this->reporter->paintSkip($message . $this->getAssertionLine());
}
}
/**
* 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;
}
}
?>

View File

@ -1,382 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id: php_parser.php 1911 2009-07-29 16:38:04Z lastcraft $
*/
/**
* Builds the page object.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleTidyPageBuilder {
private $page;
private $forms = array();
private $labels = array();
private $widgets_by_id = array();
public function __destruct() {
$this->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 <option> which we
* need to preserve. This method inserts an additional marker.
* @param string The raw html.
* @return string The html with guards inserted.
*/
private function insertEmptyTagGuards($html) {
return preg_replace('#<(option|textarea)([^>]*)>(\s*)</(option|textarea)>#is',
'<\1\2>___EMPTY___\3</\4>',
$html);
}
/**
* HTML tidy strips out empty tags such as <option> which we
* need to preserve. This method strips additional markers
* inserted by SimpleTest to the tidy output used to make the
* tags non-empty. This ensures their preservation.
* @param string The raw html.
* @return string The html with guards removed.
*/
private function stripEmptyTagGuards($html) {
return preg_replace('#(^|>)(\s*)___EMPTY___(\s*)(</|$)#i', '\2\3', $html);
}
/**
* By parsing the XML output of tidy, we lose some whitespace
* information in textarea tags. We temporarily recode this
* data ourselves so as not to lose it.
* @param string The raw html.
* @return string The html with guards inserted.
*/
private function insertTextareaSimpleWhitespaceGuards($html) {
return preg_replace_callback('#<textarea([^>]*)>(.*?)</textarea>#is',
array($this, 'insertWhitespaceGuards'),
$html);
}
/**
* Callback for insertTextareaSimpleWhitespaceGuards().
* @param array $matches Result of preg_replace_callback().
* @return string Guard tags now replace whitespace.
*/
private function insertWhitespaceGuards($matches) {
return '<textarea' . $matches[1] . '>' .
str_replace(array("\n", "\r", "\t", ' '),
array('___NEWLINE___', '___CR___', '___TAB___', '___SPACE___'),
$matches[2]) .
'</textarea>';
}
/**
* Removes the whitespace preserving guards we added
* before parsing.
* @param string The raw html.
* @return string The html with guards removed.
*/
private function stripTextareaWhitespaceGuards($html) {
return str_replace(array('___NEWLINE___', '___CR___', '___TAB___', '___SPACE___'),
array("\n", "\r", "\t", ' '),
$html);
}
/**
* Visits the given node and all children
* @param object $node Tidy XML node.
*/
private function walkTree($node) {
if ($node->name == 'a') {
$this->page->addLink($this->tags()->createTag($node->name, (array)$node->attribute)
->addContent($this->innerHtml($node)));
} elseif ($node->name == 'base' and isset($node->attribute['href'])) {
$this->page->setBase($node->attribute['href']);
} elseif ($node->name == 'title') {
$this->page->setTitle($this->tags()->createTag($node->name, (array)$node->attribute)
->addContent($this->innerHtml($node)));
} elseif ($node->name == 'frameset') {
$this->page->setFrames($this->collectFrames($node));
} elseif ($node->name == 'form') {
$this->forms[] = $this->walkForm($node, $this->createEmptyForm($node));
} elseif ($node->name == 'label') {
$this->labels[] = $this->tags()->createTag($node->name, (array)$node->attribute)
->addContent($this->innerHtml($node));
} else {
$this->walkChildren($node);
}
}
/**
* Helper method for traversing the XML tree.
* @param object $node Tidy XML node.
*/
private function walkChildren($node) {
if ($node->hasChildren()) {
foreach ($node->child as $child) {
$this->walkTree($child);
}
}
}
/**
* Facade for forms containing preparsed widgets.
* @param object $node Tidy XML node.
* @return SimpleForm Facade for SimpleBrowser.
*/
private function createEmptyForm($node) {
return new SimpleForm($this->tags()->createTag($node->name, (array)$node->attribute), $this->page);
}
/**
* Visits the given node and all children
* @param object $node Tidy XML node.
*/
private function walkForm($node, $form, $enclosing_label = '') {
if ($node->name == 'a') {
$this->page->addLink($this->tags()->createTag($node->name, (array)$node->attribute)
->addContent($this->innerHtml($node)));
} elseif (in_array($node->name, array('input', 'button', 'textarea', 'select'))) {
$this->addWidgetToForm($node, $form, $enclosing_label);
} elseif ($node->name == 'label') {
$this->labels[] = $this->tags()->createTag($node->name, (array)$node->attribute)
->addContent($this->innerHtml($node));
if ($node->hasChildren()) {
foreach ($node->child as $child) {
$this->walkForm($child, $form, SimplePage::normalise($this->innerHtml($node)));
}
}
} elseif ($node->hasChildren()) {
foreach ($node->child as $child) {
$this->walkForm($child, $form);
}
}
return $form;
}
/**
* Tests a node for a "for" atribute. Used for
* attaching labels.
* @param object $node Tidy XML node.
* @return boolean True if the "for" attribute exists.
*/
private function hasFor($node) {
return isset($node->attribute) and $node->attribute['for'];
}
/**
* Adds the widget into the form container.
* @param object $node Tidy XML node of widget.
* @param SimpleForm $form Form to add it to.
* @param string $enclosing_label The label of any label
* tag we might be in.
*/
private function addWidgetToForm($node, $form, $enclosing_label) {
$widget = $this->tags()->createTag($node->name, $this->attributes($node));
if (! $widget) {
return;
}
$widget->setLabel($enclosing_label)
->addContent($this->innerHtml($node));
if ($node->name == 'select') {
$widget->addTags($this->collectSelectOptions($node));
}
$form->addWidget($widget);
$this->indexWidgetById($widget);
}
/**
* Fills the widget cache to speed up searching.
* @param SimpleTag $widget Parsed widget to cache.
*/
private function indexWidgetById($widget) {
$id = $widget->getAttribute('id');
if (! $id) {
return;
}
if (! isset($this->widgets_by_id[$id])) {
$this->widgets_by_id[$id] = array();
}
$this->widgets_by_id[$id][] = $widget;
}
/**
* Parses the options from inside an XML select node.
* @param object $node Tidy XML node.
* @return array List of SimpleTag options.
*/
private function collectSelectOptions($node) {
$options = array();
if ($node->name == 'option') {
$options[] = $this->tags()->createTag($node->name, $this->attributes($node))
->addContent($this->innerHtml($node));
}
if ($node->hasChildren()) {
foreach ($node->child as $child) {
$options = array_merge($options, $this->collectSelectOptions($child));
}
}
return $options;
}
/**
* Convenience method for collecting all the attributes
* of a tag. Not sure why Tidy does not have this.
* @param object $node Tidy XML node.
* @return array Hash of attribute strings.
*/
private function attributes($node) {
if (! preg_match('|<[^ ]+\s(.*?)/?>|s', $node->value, $first_tag_contents)) {
return array();
}
$attributes = array();
preg_match_all('/\S+\s*=\s*\'[^\']*\'|(\S+\s*=\s*"[^"]*")|([^ =]+\s*=\s*[^ "\']+?)|[^ "\']+/', $first_tag_contents[1], $matches);
foreach($matches[0] as $unparsed) {
$attributes = $this->mergeAttribute($attributes, $unparsed);
}
return $attributes;
}
/**
* Overlay an attribute into the attributes hash.
* @param array $attributes Current attribute list.
* @param string $raw Raw attribute string with
* both key and value.
* @return array New attribute hash.
*/
private function mergeAttribute($attributes, $raw) {
$parts = explode('=', $raw);
list($name, $value) = count($parts) == 1 ? array($parts[0], $parts[0]) : $parts;
$attributes[trim($name)] = html_entity_decode($this->dequote(trim($value)), ENT_QUOTES);
return $attributes;
}
/**
* Remove start and end quotes.
* @param string $quoted A quoted string.
* @return string Quotes are gone.
*/
private function dequote($quoted) {
if (preg_match('/^(\'([^\']*)\'|"([^"]*)")$/', $quoted, $matches)) {
return isset($matches[3]) ? $matches[3] : $matches[2];
}
return $quoted;
}
/**
* Collects frame information inside a frameset tag.
* @param object $node Tidy XML node.
* @return array List of SimpleTag frame descriptions.
*/
private function collectFrames($node) {
$frames = array();
if ($node->name == 'frame') {
$frames = array($this->tags()->createTag($node->name, (array)$node->attribute));
} else if ($node->hasChildren()) {
$frames = array();
foreach ($node->child as $child) {
$frames = array_merge($frames, $this->collectFrames($child));
}
}
return $frames;
}
/**
* Extracts the XML node text.
* @param object $node Tidy XML node.
* @return string The text only.
*/
private function innerHtml($node) {
$raw = '';
if ($node->hasChildren()) {
foreach ($node->child as $child) {
$raw .= $child->value;
}
}
return $this->stripGuards($raw);
}
/**
* Factory for parsed content holders.
* @return SimpleTagBuilder Factory.
*/
private function tags() {
return new SimpleTagBuilder();
}
/**
* Called at the end of a parse run. Attaches any
* non-wrapping labels to their form elements.
* @param array $widgets_by_id Cached SimpleTag hash.
* @param array $labels SimpleTag label elements.
*/
private function attachLabels($widgets_by_id, $labels) {
foreach ($labels as $label) {
$for = $label->getFor();
if ($for and isset($widgets_by_id[$for])) {
$text = $label->getText();
foreach ($widgets_by_id[$for] as $widget) {
$widget->setLabel($text);
}
}
}
}
}
?>

View File

@ -1,413 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: unit_tester.php 1882 2009-07-01 14:30:05Z lastcraft $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/test_case.php');
require_once(dirname(__FILE__) . '/dumper.php');
/**#@-*/
/**
* Standard unit test class for day to day testing
* of PHP code XP style. Adds some useful standard
* assertions.
* @package SimpleTest
* @subpackage UnitTester
*/
class UnitTestCase extends SimpleTestCase {
/**
* 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) {
if (! $label) {
$label = get_class($this);
}
parent::__construct($label);
}
/**
* Called from within the test methods to register
* passes and failures.
* @param boolean $result Pass on true.
* @param string $message Message to display describing
* the test state.
* @return boolean True on pass
* @access public
*/
function assertTrue($result, $message = '%s') {
return $this->assert(new TrueExpectation(), $result, $message);
}
/**
* Will be true on false and vice versa. False
* is the PHP definition of false, so that null,
* empty strings, zero and an empty array all count
* as false.
* @param boolean $result Pass on false.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertFalse($result, $message = '%s') {
return $this->assert(new FalseExpectation(), $result, $message);
}
/**
* Will be true if the value is null.
* @param null $value Supposedly null value.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertNull($value, $message = '%s') {
$dumper = new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($value) . '] should be null');
return $this->assertTrue(! isset($value), $message);
}
/**
* Will be true if the value is set.
* @param mixed $value Supposedly set value.
* @param string $message Message to display.
* @return boolean True on pass.
* @access public
*/
function assertNotNull($value, $message = '%s') {
$dumper = new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($value) . '] should not be null');
return $this->assertTrue(isset($value), $message);
}
/**
* Type and class test. Will pass if class
* matches the type name or is a subclass or
* if not an object, but the type is correct.
* @param mixed $object Object to test.
* @param string $type Type name as string.
* @param string $message Message to display.
* @return boolean True on pass.
* @access public
*/
function assertIsA($object, $type, $message = '%s') {
return $this->assert(
new IsAExpectation($type),
$object,
$message);
}
/**
* Type and class mismatch test. Will pass if class
* name or underling type does not match the one
* specified.
* @param mixed $object Object to test.
* @param string $type Type name as string.
* @param string $message Message to display.
* @return boolean True on pass.
* @access public
*/
function assertNotA($object, $type, $message = '%s') {
return $this->assert(
new NotAExpectation($type),
$object,
$message);
}
/**
* Will trigger a pass if the two parameters have
* the same value only. Otherwise a fail.
* @param mixed $first Value to compare.
* @param mixed $second Value to compare.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertEqual($first, $second, $message = '%s') {
return $this->assert(
new EqualExpectation($first),
$second,
$message);
}
/**
* Will trigger a pass if the two parameters have
* a different value. Otherwise a fail.
* @param mixed $first Value to compare.
* @param mixed $second Value to compare.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertNotEqual($first, $second, $message = '%s') {
return $this->assert(
new NotEqualExpectation($first),
$second,
$message);
}
/**
* Will trigger a pass if the if the first parameter
* is near enough to the second by the margin.
* @param mixed $first Value to compare.
* @param mixed $second Value to compare.
* @param mixed $margin Fuzziness of match.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertWithinMargin($first, $second, $margin, $message = '%s') {
return $this->assert(
new WithinMarginExpectation($first, $margin),
$second,
$message);
}
/**
* Will trigger a pass if the two parameters differ
* by more than the margin.
* @param mixed $first Value to compare.
* @param mixed $second Value to compare.
* @param mixed $margin Fuzziness of match.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertOutsideMargin($first, $second, $margin, $message = '%s') {
return $this->assert(
new OutsideMarginExpectation($first, $margin),
$second,
$message);
}
/**
* Will trigger a pass if the two parameters have
* the same value and same type. Otherwise a fail.
* @param mixed $first Value to compare.
* @param mixed $second Value to compare.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertIdentical($first, $second, $message = '%s') {
return $this->assert(
new IdenticalExpectation($first),
$second,
$message);
}
/**
* Will trigger a pass if the two parameters have
* the different value or different type.
* @param mixed $first Value to compare.
* @param mixed $second Value to compare.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertNotIdentical($first, $second, $message = '%s') {
return $this->assert(
new NotIdenticalExpectation($first),
$second,
$message);
}
/**
* Will trigger a pass if both parameters refer
* to the same object or value. Fail otherwise.
* This will cause problems testing objects under
* E_STRICT.
* TODO: Replace with expectation.
* @param mixed $first Reference to check.
* @param mixed $second Hopefully the same variable.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertReference(&$first, &$second, $message = '%s') {
$dumper = new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($first) .
'] and [' . $dumper->describeValue($second) .
'] should reference the same object');
return $this->assertTrue(
SimpleTestCompatibility::isReference($first, $second),
$message);
}
/**
* Will trigger a pass if both parameters refer
* to the same object. Fail otherwise. This has
* the same semantics at the PHPUnit assertSame.
* That is, if values are passed in it has roughly
* the same affect as assertIdentical.
* TODO: Replace with expectation.
* @param mixed $first Object reference to check.
* @param mixed $second Hopefully the same object.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertSame($first, $second, $message = '%s') {
$dumper = new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($first) .
'] and [' . $dumper->describeValue($second) .
'] should reference the same object');
return $this->assertTrue($first === $second, $message);
}
/**
* Will trigger a pass if both parameters refer
* to different objects. Fail otherwise. The objects
* have to be identical though.
* @param mixed $first Object reference to check.
* @param mixed $second Hopefully not the same object.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertClone($first, $second, $message = '%s') {
$dumper = new SimpleDumper();
$message = sprintf(
$message,
'[' . $dumper->describeValue($first) .
'] and [' . $dumper->describeValue($second) .
'] should not be the same object');
$identical = new IdenticalExpectation($first);
return $this->assertTrue(
$identical->test($second) && ! ($first === $second),
$message);
}
/**
* Will trigger a pass if both parameters refer
* to different variables. Fail otherwise. The objects
* have to be identical references though.
* This will fail under E_STRICT with objects. Use
* assertClone() for this.
* @param mixed $first Object reference to check.
* @param mixed $second Hopefully not the same object.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertCopy(&$first, &$second, $message = "%s") {
$dumper = new SimpleDumper();
$message = sprintf(
$message,
"[" . $dumper->describeValue($first) .
"] and [" . $dumper->describeValue($second) .
"] should not be the same object");
return $this->assertFalse(
SimpleTestCompatibility::isReference($first, $second),
$message);
}
/**
* Will trigger a pass if the Perl regex pattern
* is found in the subject. Fail otherwise.
* @param string $pattern Perl regex to look for including
* the regex delimiters.
* @param string $subject String to search in.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertPattern($pattern, $subject, $message = '%s') {
return $this->assert(
new PatternExpectation($pattern),
$subject,
$message);
}
/**
* Will trigger a pass if the perl regex pattern
* is not present in subject. Fail if found.
* @param string $pattern Perl regex to look for including
* the regex delimiters.
* @param string $subject String to search in.
* @param string $message Message to display.
* @return boolean True on pass
* @access public
*/
function assertNoPattern($pattern, $subject, $message = '%s') {
return $this->assert(
new NoPatternExpectation($pattern),
$subject,
$message);
}
/**
* Prepares for an error. If the error mismatches it
* passes through, otherwise it is swallowed. Any
* left over errors trigger failures.
* @param SimpleExpectation/string $expected The error to match.
* @param string $message Message on failure.
* @access public
*/
function expectError($expected = false, $message = '%s') {
$queue = SimpleTest::getContext()->get('SimpleErrorQueue');
$queue->expectError($this->coerceExpectation($expected), $message);
}
/**
* Prepares for an exception. If the error mismatches it
* passes through, otherwise it is swallowed. Any
* left over errors trigger failures.
* @param SimpleExpectation/Exception $expected The error to match.
* @param string $message Message on failure.
* @access public
*/
function expectException($expected = false, $message = '%s') {
$queue = SimpleTest::getContext()->get('SimpleExceptionTrap');
$line = $this->getAssertionLine();
$queue->expectException($expected, $message . $line);
}
/**
* Tells SimpleTest to ignore an upcoming exception as not relevant
* to the current test. It doesn't affect the test, whether thrown or
* not.
* @param SimpleExpectation/Exception $ignored The error to ignore.
* @access public
*/
function ignoreException($ignored = false) {
SimpleTest::getContext()->get('SimpleExceptionTrap')->ignoreException($ignored);
}
/**
* Creates an equality expectation if the
* object/value is not already some type
* of expectation.
* @param mixed $expected Expected value.
* @return SimpleExpectation Expectation object.
* @access private
*/
protected function coerceExpectation($expected) {
if ($expected == false) {
return new TrueExpectation();
}
if (SimpleTestCompatibility::isA($expected, 'SimpleExpectation')) {
return $expected;
}
return new EqualExpectation(
is_string($expected) ? str_replace('%', '%%', $expected) : $expected);
}
}
?>

View File

@ -1,550 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id: url.php 2011 2011-04-29 08:22:48Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/encoding.php');
/**#@-*/
/**
* URL parser to replace parse_url() PHP function which
* got broken in PHP 4.3.0. Adds some browser specific
* functionality such as expandomatics.
* Guesses a bit trying to separate the host from
* the path and tries to keep a raw, possibly unparsable,
* request string as long as possible.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleUrl {
private $scheme;
private $username;
private $password;
private $host;
private $port;
public $path;
private $request;
private $fragment;
private $x;
private $y;
private $target;
private $raw = false;
/**
* Constructor. Parses URL into sections.
* @param string $url Incoming URL.
* @access public
*/
function __construct($url = '') {
list($x, $y) = $this->chompCoordinates($url);
$this->setCoordinates($x, $y);
$this->scheme = $this->chompScheme($url);
if ($this->scheme === 'file') {
// Unescaped backslashes not used in directory separator context
// will get caught by this, but they should have been urlencoded
// anyway so we don't care. If this ends up being a problem, the
// host regexp must be modified to match for backslashes when
// the scheme is file.
$url = str_replace('\\', '/', $url);
}
list($this->username, $this->password) = $this->chompLogin($url);
$this->host = $this->chompHost($url);
$this->port = false;
if (preg_match('/(.*?):(.*)/', $this->host, $host_parts)) {
if ($this->scheme === 'file' && strlen($this->host) === 2) {
// DOS drive was placed in authority; promote it to path.
$url = '/' . $this->host . $url;
$this->host = false;
} else {
$this->host = $host_parts[1];
$this->port = (integer)$host_parts[2];
}
}
$this->path = $this->chompPath($url);
$this->request = $this->parseRequest($this->chompRequest($url));
$this->fragment = (strncmp($url, "#", 1) == 0 ? substr($url, 1) : false);
$this->target = false;
}
/**
* Extracts the X, Y coordinate pair from an image map.
* @param string $url URL so far. The coordinates will be
* removed.
* @return array X, Y as a pair of integers.
* @access private
*/
protected function chompCoordinates(&$url) {
if (preg_match('/(.*)\?(\d+),(\d+)$/', $url, $matches)) {
$url = $matches[1];
return array((integer)$matches[2], (integer)$matches[3]);
}
return array(false, false);
}
/**
* Extracts the scheme part of an incoming URL.
* @param string $url URL so far. The scheme will be
* removed.
* @return string Scheme part or false.
* @access private
*/
protected function chompScheme(&$url) {
if (preg_match('#^([^/:]*):(//)(.*)#', $url, $matches)) {
$url = $matches[2] . $matches[3];
return $matches[1];
}
return false;
}
/**
* Extracts the username and password from the
* incoming URL. The // prefix will be reattached
* to the URL after the doublet is extracted.
* @param string $url URL so far. The username and
* password are removed.
* @return array Two item list of username and
* password. Will urldecode() them.
* @access private
*/
protected function chompLogin(&$url) {
$prefix = '';
if (preg_match('#^(//)(.*)#', $url, $matches)) {
$prefix = $matches[1];
$url = $matches[2];
}
if (preg_match('#^([^/]*)@(.*)#', $url, $matches)) {
$url = $prefix . $matches[2];
$parts = explode(":", $matches[1]);
return array(
urldecode($parts[0]),
isset($parts[1]) ? urldecode($parts[1]) : false);
}
$url = $prefix . $url;
return array(false, false);
}
/**
* Extracts the host part of an incoming URL.
* Includes the port number part. Will extract
* the host if it starts with // or it has
* a top level domain or it has at least two
* dots.
* @param string $url URL so far. The host will be
* removed.
* @return string Host part guess or false.
* @access private
*/
protected function chompHost(&$url) {
if (preg_match('!^(//)(.*?)(/.*|\?.*|#.*|$)!', $url, $matches)) {
$url = $matches[3];
return $matches[2];
}
if (preg_match('!(.*?)(\.\./|\./|/|\?|#|$)(.*)!', $url, $matches)) {
$tlds = SimpleUrl::getAllTopLevelDomains();
if (preg_match('/[a-z0-9\-]+\.(' . $tlds . ')/i', $matches[1])) {
$url = $matches[2] . $matches[3];
return $matches[1];
} elseif (preg_match('/[a-z0-9\-]+\.[a-z0-9\-]+\.[a-z0-9\-]+/i', $matches[1])) {
$url = $matches[2] . $matches[3];
return $matches[1];
}
}
return false;
}
/**
* Extracts the path information from the incoming
* URL. Strips this path from the URL.
* @param string $url URL so far. The host will be
* removed.
* @return string Path part or '/'.
* @access private
*/
protected function chompPath(&$url) {
if (preg_match('/(.*?)(\?|#|$)(.*)/', $url, $matches)) {
$url = $matches[2] . $matches[3];
return ($matches[1] ? $matches[1] : '');
}
return '';
}
/**
* Strips off the request data.
* @param string $url URL so far. The request will be
* removed.
* @return string Raw request part.
* @access private
*/
protected function chompRequest(&$url) {
if (preg_match('/\?(.*?)(#|$)(.*)/', $url, $matches)) {
$url = $matches[2] . $matches[3];
return $matches[1];
}
return '';
}
/**
* Breaks the request down into an object.
* @param string $raw Raw request.
* @return SimpleFormEncoding Parsed data.
* @access private
*/
protected function parseRequest($raw) {
$this->raw = $raw;
$request = new SimpleGetEncoding();
foreach (explode("&", $raw) as $pair) {
if (preg_match('/(.*?)=(.*)/', $pair, $matches)) {
$request->add(urldecode($matches[1]), urldecode($matches[2]));
} elseif ($pair) {
$request->add(urldecode($pair), '');
}
}
return $request;
}
/**
* Accessor for protocol part.
* @param string $default Value to use if not present.
* @return string Scheme name, e.g "http".
* @access public
*/
function getScheme($default = false) {
return $this->scheme ? $this->scheme : $default;
}
/**
* Accessor for user name.
* @return string Username preceding host.
* @access public
*/
function getUsername() {
return $this->username;
}
/**
* Accessor for password.
* @return string Password preceding host.
* @access public
*/
function getPassword() {
return $this->password;
}
/**
* Accessor for hostname and port.
* @param string $default Value to use if not present.
* @return string Hostname only.
* @access public
*/
function getHost($default = false) {
return $this->host ? $this->host : $default;
}
/**
* Accessor for top level domain.
* @return string Last part of host.
* @access public
*/
function getTld() {
$path_parts = pathinfo($this->getHost());
return (isset($path_parts['extension']) ? $path_parts['extension'] : false);
}
/**
* Accessor for port number.
* @return integer TCP/IP port number.
* @access public
*/
function getPort() {
return $this->port;
}
/**
* Accessor for path.
* @return string Full path including leading slash if implied.
* @access public
*/
function getPath() {
if (! $this->path && $this->host) {
return '/';
}
return $this->path;
}
/**
* Accessor for page if any. This may be a
* directory name if ambiguious.
* @return Page name.
* @access public
*/
function getPage() {
if (! preg_match('/([^\/]*?)$/', $this->getPath(), $matches)) {
return false;
}
return $matches[1];
}
/**
* Gets the path to the page.
* @return string Path less the page.
* @access public
*/
function getBasePath() {
if (! preg_match('/(.*\/)[^\/]*?$/', $this->getPath(), $matches)) {
return false;
}
return $matches[1];
}
/**
* Accessor for fragment at end of URL after the "#".
* @return string Part after "#".
* @access public
*/
function getFragment() {
return $this->fragment;
}
/**
* Sets image coordinates. Set to false to clear
* them.
* @param integer $x Horizontal position.
* @param integer $y Vertical position.
* @access public
*/
function setCoordinates($x = false, $y = false) {
if (($x === false) || ($y === false)) {
$this->x = $this->y = false;
return;
}
$this->x = (integer)$x;
$this->y = (integer)$y;
}
/**
* Accessor for horizontal image coordinate.
* @return integer X value.
* @access public
*/
function getX() {
return $this->x;
}
/**
* Accessor for vertical image coordinate.
* @return integer Y value.
* @access public
*/
function getY() {
return $this->y;
}
/**
* Accessor for current request parameters
* in URL string form. Will return teh original request
* if at all possible even if it doesn't make much
* sense.
* @return string Form is string "?a=1&b=2", etc.
* @access public
*/
function getEncodedRequest() {
if ($this->raw) {
$encoded = $this->raw;
} else {
$encoded = $this->request->asUrlRequest();
}
if ($encoded) {
return '?' . preg_replace('/^\?/', '', $encoded);
}
return '';
}
/**
* Adds an additional parameter to the request.
* @param string $key Name of parameter.
* @param string $value Value as string.
* @access public
*/
function addRequestParameter($key, $value) {
$this->raw = false;
$this->request->add($key, $value);
}
/**
* Adds additional parameters to the request.
* @param hash/SimpleFormEncoding $parameters Additional
* parameters.
* @access public
*/
function addRequestParameters($parameters) {
$this->raw = false;
$this->request->merge($parameters);
}
/**
* Clears down all parameters.
* @access public
*/
function clearRequest() {
$this->raw = false;
$this->request = new SimpleGetEncoding();
}
/**
* Gets the frame target if present. Although
* not strictly part of the URL specification it
* acts as similarily to the browser.
* @return boolean/string Frame name or false if none.
* @access public
*/
function getTarget() {
return $this->target;
}
/**
* Attaches a frame target.
* @param string $frame Name of frame.
* @access public
*/
function setTarget($frame) {
$this->raw = false;
$this->target = $frame;
}
/**
* Renders the URL back into a string.
* @return string URL in canonical form.
* @access public
*/
function asString() {
$path = $this->path;
$scheme = $identity = $host = $port = $encoded = $fragment = '';
if ($this->username && $this->password) {
$identity = $this->username . ':' . $this->password . '@';
}
if ($this->getHost()) {
$scheme = $this->getScheme() ? $this->getScheme() : 'http';
$scheme .= '://';
$host = $this->getHost();
} elseif ($this->getScheme() === 'file') {
// Safest way; otherwise, file URLs on Windows have an extra
// leading slash. It might be possible to convert file://
// URIs to local file paths, but that requires more research.
$scheme = 'file://';
}
if ($this->getPort() && $this->getPort() != 80 ) {
$port = ':'.$this->getPort();
}
if (substr($this->path, 0, 1) == '/') {
$path = $this->normalisePath($this->path);
}
$encoded = $this->getEncodedRequest();
$fragment = $this->getFragment() ? '#'. $this->getFragment() : '';
$coords = $this->getX() === false ? '' : '?' . $this->getX() . ',' . $this->getY();
return "$scheme$identity$host$port$path$encoded$fragment$coords";
}
/**
* Replaces unknown sections to turn a relative
* URL into an absolute one. The base URL can
* be either a string or a SimpleUrl object.
* @param string/SimpleUrl $base Base URL.
* @access public
*/
function makeAbsolute($base) {
if (! is_object($base)) {
$base = new SimpleUrl($base);
}
if ($this->getHost()) {
$scheme = $this->getScheme();
$host = $this->getHost();
$port = $this->getPort() ? ':' . $this->getPort() : '';
$identity = $this->getIdentity() ? $this->getIdentity() . '@' : '';
if (! $identity) {
$identity = $base->getIdentity() ? $base->getIdentity() . '@' : '';
}
} else {
$scheme = $base->getScheme();
$host = $base->getHost();
$port = $base->getPort() ? ':' . $base->getPort() : '';
$identity = $base->getIdentity() ? $base->getIdentity() . '@' : '';
}
$path = $this->normalisePath($this->extractAbsolutePath($base));
$encoded = $this->getEncodedRequest();
$fragment = $this->getFragment() ? '#'. $this->getFragment() : '';
$coords = $this->getX() === false ? '' : '?' . $this->getX() . ',' . $this->getY();
return new SimpleUrl("$scheme://$identity$host$port$path$encoded$fragment$coords");
}
/**
* Replaces unknown sections of the path with base parts
* to return a complete absolute one.
* @param string/SimpleUrl $base Base URL.
* @param string Absolute path.
* @access private
*/
protected function extractAbsolutePath($base) {
if ($this->getHost()) {
return $this->path;
}
if (! $this->isRelativePath($this->path)) {
return $this->path;
}
if ($this->path) {
return $base->getBasePath() . $this->path;
}
return $base->getPath();
}
/**
* Simple test to see if a path part is relative.
* @param string $path Path to test.
* @return boolean True if starts with a "/".
* @access private
*/
protected function isRelativePath($path) {
return (substr($path, 0, 1) != '/');
}
/**
* Extracts the username and password for use in rendering
* a URL.
* @return string/boolean Form of username:password or false.
* @access public
*/
function getIdentity() {
if ($this->username && $this->password) {
return $this->username . ':' . $this->password;
}
return false;
}
/**
* Replaces . and .. sections of the path.
* @param string $path Unoptimised path.
* @return string Path with dots removed if possible.
* @access public
*/
function normalisePath($path) {
$path = preg_replace('|/\./|', '/', $path);
return preg_replace('|/[^/]+/\.\./|', '/', $path);
}
/**
* A pipe seperated list of all TLDs that result in two part
* domain names.
* @return string Pipe separated list.
* @access public
*/
static function getAllTopLevelDomains() {
return 'com|edu|net|org|gov|mil|int|biz|info|name|pro|aero|coop|museum';
}
}
?>

View File

@ -1,328 +0,0 @@
<?php
/**
* Base include file for SimpleTest
* @package SimpleTest
* @subpackage WebTester
* @version $Id: user_agent.php 2039 2011-11-30 18:16:15Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/cookies.php');
require_once(dirname(__FILE__) . '/http.php');
require_once(dirname(__FILE__) . '/encoding.php');
require_once(dirname(__FILE__) . '/authentication.php');
/**#@-*/
if (! defined('DEFAULT_MAX_REDIRECTS')) {
define('DEFAULT_MAX_REDIRECTS', 3);
}
if (! defined('DEFAULT_CONNECTION_TIMEOUT')) {
define('DEFAULT_CONNECTION_TIMEOUT', 15);
}
/**
* Fetches web pages whilst keeping track of
* cookies and authentication.
* @package SimpleTest
* @subpackage WebTester
*/
class SimpleUserAgent {
private $cookie_jar;
private $cookies_enabled = true;
private $authenticator;
private $max_redirects = DEFAULT_MAX_REDIRECTS;
private $proxy = false;
private $proxy_username = false;
private $proxy_password = false;
private $connection_timeout = DEFAULT_CONNECTION_TIMEOUT;
private $additional_headers = array();
/**
* Starts with no cookies, realms or proxies.
* @access public
*/
function __construct() {
$this->cookie_jar = new SimpleCookieJar();
$this->authenticator = new SimpleAuthenticator();
}
/**
* Removes expired and temporary cookies as if
* the browser was closed and re-opened. Authorisation
* has to be obtained again as well.
* @param string/integer $date Time when session restarted.
* If omitted then all persistent
* cookies are kept.
* @access public
*/
function restart($date = false) {
$this->cookie_jar->restartSession($date);
$this->authenticator->restartSession();
}
/**
* Adds a header to every fetch.
* @param string $header Header line to add to every
* request until cleared.
* @access public
*/
function addHeader($header) {
$this->additional_headers[] = $header;
}
/**
* Ages the cookies by the specified time.
* @param integer $interval Amount in seconds.
* @access public
*/
function ageCookies($interval) {
$this->cookie_jar->agePrematurely($interval);
}
/**
* Sets an additional cookie. If a cookie has
* the same name and path it is replaced.
* @param string $name Cookie key.
* @param string $value Value of cookie.
* @param string $host Host upon which the cookie is valid.
* @param string $path Cookie path if not host wide.
* @param string $expiry Expiry date.
* @access public
*/
function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
$this->cookie_jar->setCookie($name, $value, $host, $path, $expiry);
}
/**
* Reads the most specific cookie value from the
* browser cookies.
* @param string $host Host to search.
* @param string $path Applicable path.
* @param string $name Name of cookie to read.
* @return string False if not present, else the
* value as a string.
* @access public
*/
function getCookieValue($host, $path, $name) {
return $this->cookie_jar->getCookieValue($host, $path, $name);
}
/**
* Reads the current cookies within the base URL.
* @param string $name Key of cookie to find.
* @param SimpleUrl $base Base URL to search from.
* @return string/boolean Null if there is no base URL, false
* if the cookie is not set.
* @access public
*/
function getBaseCookieValue($name, $base) {
if (! $base) {
return null;
}
return $this->getCookieValue($base->getHost(), $base->getPath(), $name);
}
/**
* Switches off cookie sending and recieving.
* @access public
*/
function ignoreCookies() {
$this->cookies_enabled = false;
}
/**
* Switches back on the cookie sending and recieving.
* @access public
*/
function useCookies() {
$this->cookies_enabled = true;
}
/**
* Sets the socket timeout for opening a connection.
* @param integer $timeout Maximum time in seconds.
* @access public
*/
function setConnectionTimeout($timeout) {
$this->connection_timeout = $timeout;
}
/**
* Sets the maximum number of redirects before
* a page will be loaded anyway.
* @param integer $max Most hops allowed.
* @access public
*/
function setMaximumRedirects($max) {
$this->max_redirects = $max;
}
/**
* Sets proxy to use on all requests for when
* testing from behind a firewall. Set URL
* to false to disable.
* @param string $proxy Proxy URL.
* @param string $username Proxy username for authentication.
* @param string $password Proxy password for authentication.
* @access public
*/
function useProxy($proxy, $username, $password) {
if (! $proxy) {
$this->proxy = false;
return;
}
if ((strncmp($proxy, 'http://', 7) != 0) && (strncmp($proxy, 'https://', 8) != 0)) {
$proxy = 'http://'. $proxy;
}
$this->proxy = new SimpleUrl($proxy);
$this->proxy_username = $username;
$this->proxy_password = $password;
}
/**
* Test to see if the redirect limit is passed.
* @param integer $redirects Count so far.
* @return boolean True if over.
* @access private
*/
protected function isTooManyRedirects($redirects) {
return ($redirects > $this->max_redirects);
}
/**
* Sets the identity for the current realm.
* @param string $host Host to which realm applies.
* @param string $realm Full name of realm.
* @param string $username Username for realm.
* @param string $password Password for realm.
* @access public
*/
function setIdentity($host, $realm, $username, $password) {
$this->authenticator->setIdentityForRealm($host, $realm, $username, $password);
}
/**
* Fetches a URL as a response object. Will keep trying if redirected.
* It will also collect authentication realm information.
* @param string/SimpleUrl $url Target to fetch.
* @param SimpleEncoding $encoding Additional parameters for request.
* @return SimpleHttpResponse Hopefully the target page.
* @access public
*/
function fetchResponse($url, $encoding) {
if ($encoding->getMethod() != 'POST') {
$url->addRequestParameters($encoding);
$encoding->clear();
}
$response = $this->fetchWhileRedirected($url, $encoding);
if ($headers = $response->getHeaders()) {
if ($headers->isChallenge()) {
$this->authenticator->addRealm(
$url,
$headers->getAuthentication(),
$headers->getRealm());
}
}
return $response;
}
/**
* Fetches the page until no longer redirected or
* until the redirect limit runs out.
* @param SimpleUrl $url Target to fetch.
* @param SimpelFormEncoding $encoding Additional parameters for request.
* @return SimpleHttpResponse Hopefully the target page.
* @access private
*/
protected function fetchWhileRedirected($url, $encoding) {
$redirects = 0;
do {
$response = $this->fetch($url, $encoding);
if ($response->isError()) {
return $response;
}
$headers = $response->getHeaders();
if ($this->cookies_enabled) {
$headers->writeCookiesToJar($this->cookie_jar, $url);
}
if (! $headers->isRedirect()) {
break;
}
$location = new SimpleUrl($headers->getLocation());
$url = $location->makeAbsolute($url);
$encoding = new SimpleGetEncoding();
} while (! $this->isTooManyRedirects(++$redirects));
return $response;
}
/**
* Actually make the web request.
* @param SimpleUrl $url Target to fetch.
* @param SimpleFormEncoding $encoding Additional parameters for request.
* @return SimpleHttpResponse Headers and hopefully content.
* @access protected
*/
protected function fetch($url, $encoding) {
$request = $this->createRequest($url, $encoding);
return $request->fetch($this->connection_timeout);
}
/**
* Creates a full page request.
* @param SimpleUrl $url Target to fetch as url object.
* @param SimpleFormEncoding $encoding POST/GET parameters.
* @return SimpleHttpRequest New request.
* @access private
*/
protected function createRequest($url, $encoding) {
$request = $this->createHttpRequest($url, $encoding);
$this->addAdditionalHeaders($request);
if ($this->cookies_enabled) {
$request->readCookiesFromJar($this->cookie_jar, $url);
}
$this->authenticator->addHeaders($request, $url);
return $request;
}
/**
* Builds the appropriate HTTP request object.
* @param SimpleUrl $url Target to fetch as url object.
* @param SimpleFormEncoding $parameters POST/GET parameters.
* @return SimpleHttpRequest New request object.
* @access protected
*/
protected function createHttpRequest($url, $encoding) {
return new SimpleHttpRequest($this->createRoute($url), $encoding);
}
/**
* Sets up either a direct route or via a proxy.
* @param SimpleUrl $url Target to fetch as url object.
* @return SimpleRoute Route to take to fetch URL.
* @access protected
*/
protected function createRoute($url) {
if ($this->proxy) {
return new SimpleProxyRoute(
$url,
$this->proxy,
$this->proxy_username,
$this->proxy_password);
}
return new SimpleRoute($url);
}
/**
* Adds additional manual headers.
* @param SimpleHttpRequest $request Outgoing request.
* @access private
*/
protected function addAdditionalHeaders(&$request) {
foreach ($this->additional_headers as $header) {
$request->addHeaderLine($header);
}
}
}
?>

File diff suppressed because it is too large Load Diff

View File

@ -1,647 +0,0 @@
<?php
/**
* base include file for SimpleTest
* @package SimpleTest
* @subpackage UnitTester
* @version $Id: xml.php 1787 2008-04-26 20:35:39Z pp11 $
*/
/**#@+
* include other SimpleTest class files
*/
require_once(dirname(__FILE__) . '/scorer.php');
/**#@-*/
/**
* Creates the XML needed for remote communication
* by SimpleTest.
* @package SimpleTest
* @subpackage UnitTester
*/
class XmlReporter extends SimpleReporter {
private $indent;
private $namespace;
/**
* Sets up indentation and namespace.
* @param string $namespace Namespace to add to each tag.
* @param string $indent Indenting to add on each nesting.
* @access public
*/
function __construct($namespace = false, $indent = ' ') {
parent::__construct();
$this->namespace = ($namespace ? $namespace . ':' : '');
$this->indent = $indent;
}
/**
* Calculates the pretty printing indent level
* from the current level of nesting.
* @param integer $offset Extra indenting level.
* @return string Leading space.
* @access protected
*/
protected function getIndent($offset = 0) {
return str_repeat(
$this->indent,
count($this->getTestList()) + $offset);
}
/**
* Converts character string to parsed XML
* entities string.
* @param string text Unparsed character data.
* @return string Parsed character data.
* @access public
*/
function toParsedXml($text) {
return str_replace(
array('&', '<', '>', '"', '\''),
array('&amp;', '&lt;', '&gt;', '&quot;', '&apos;'),
$text);
}
/**
* Paints the start of a group test.
* @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) {
parent::paintGroupStart($test_name, $size);
print $this->getIndent();
print "<" . $this->namespace . "group size=\"$size\">\n";
print $this->getIndent(1);
print "<" . $this->namespace . "name>" .
$this->toParsedXml($test_name) .
"</" . $this->namespace . "name>\n";
}
/**
* Paints the end of a group test.
* @param string $test_name Name of test that is ending.
* @access public
*/
function paintGroupEnd($test_name) {
print $this->getIndent();
print "</" . $this->namespace . "group>\n";
parent::paintGroupEnd($test_name);
}
/**
* Paints the start of a test case.
* @param string $test_name Name of test that is starting.
* @access public
*/
function paintCaseStart($test_name) {
parent::paintCaseStart($test_name);
print $this->getIndent();
print "<" . $this->namespace . "case>\n";
print $this->getIndent(1);
print "<" . $this->namespace . "name>" .
$this->toParsedXml($test_name) .
"</" . $this->namespace . "name>\n";
}
/**
* Paints the end of a test case.
* @param string $test_name Name of test that is ending.
* @access public
*/
function paintCaseEnd($test_name) {
print $this->getIndent();
print "</" . $this->namespace . "case>\n";
parent::paintCaseEnd($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) {
parent::paintMethodStart($test_name);
print $this->getIndent();
print "<" . $this->namespace . "test>\n";
print $this->getIndent(1);
print "<" . $this->namespace . "name>" .
$this->toParsedXml($test_name) .
"</" . $this->namespace . "name>\n";
}
/**
* Paints the end of a test method.
* @param string $test_name Name of test that is ending.
* @param integer $progress Number of test cases ending.
* @access public
*/
function paintMethodEnd($test_name) {
print $this->getIndent();
print "</" . $this->namespace . "test>\n";
parent::paintMethodEnd($test_name);
}
/**
* Paints pass as XML.
* @param string $message Message to encode.
* @access public
*/
function paintPass($message) {
parent::paintPass($message);
print $this->getIndent(1);
print "<" . $this->namespace . "pass>";
print $this->toParsedXml($message);
print "</" . $this->namespace . "pass>\n";
}
/**
* Paints failure as XML.
* @param string $message Message to encode.
* @access public
*/
function paintFail($message) {
parent::paintFail($message);
print $this->getIndent(1);
print "<" . $this->namespace . "fail>";
print $this->toParsedXml($message);
print "</" . $this->namespace . "fail>\n";
}
/**
* Paints error as XML.
* @param string $message Message to encode.
* @access public
*/
function paintError($message) {
parent::paintError($message);
print $this->getIndent(1);
print "<" . $this->namespace . "exception>";
print $this->toParsedXml($message);
print "</" . $this->namespace . "exception>\n";
}
/**
* Paints exception as XML.
* @param Exception $exception Exception to encode.
* @access public
*/
function paintException($exception) {
parent::paintException($exception);
print $this->getIndent(1);
print "<" . $this->namespace . "exception>";
$message = 'Unexpected exception of type [' . get_class($exception) .
'] with message ['. $exception->getMessage() .
'] in ['. $exception->getFile() .
' line ' . $exception->getLine() . ']';
print $this->toParsedXml($message);
print "</" . $this->namespace . "exception>\n";
}
/**
* Paints the skipping message and tag.
* @param string $message Text to display in skip tag.
* @access public
*/
function paintSkip($message) {
parent::paintSkip($message);
print $this->getIndent(1);
print "<" . $this->namespace . "skip>";
print $this->toParsedXml($message);
print "</" . $this->namespace . "skip>\n";
}
/**
* Paints a simple supplementary message.
* @param string $message Text to display.
* @access public
*/
function paintMessage($message) {
parent::paintMessage($message);
print $this->getIndent(1);
print "<" . $this->namespace . "message>";
print $this->toParsedXml($message);
print "</" . $this->namespace . "message>\n";
}
/**
* Paints a formatted ASCII message such as a
* privateiable dump.
* @param string $message Text to display.
* @access public
*/
function paintFormattedMessage($message) {
parent::paintFormattedMessage($message);
print $this->getIndent(1);
print "<" . $this->namespace . "formatted>";
print "<![CDATA[$message]]>";
print "</" . $this->namespace . "formatted>\n";
}
/**
* Serialises the event object.
* @param string $type Event type as text.
* @param mixed $payload Message or object.
* @access public
*/
function paintSignal($type, $payload) {
parent::paintSignal($type, $payload);
print $this->getIndent(1);
print "<" . $this->namespace . "signal type=\"$type\">";
print "<![CDATA[" . serialize($payload) . "]]>";
print "</" . $this->namespace . "signal>\n";
}
/**
* Paints the test document header.
* @param string $test_name First test top level
* to start.
* @access public
* @abstract
*/
function paintHeader($test_name) {
if (! SimpleReporter::inCli()) {
header('Content-type: text/xml');
}
print "<?xml version=\"1.0\"";
if ($this->namespace) {
print " xmlns:" . $this->namespace .
"=\"www.lastcraft.com/SimpleTest/Beta3/Report\"";
}
print "?>\n";
print "<" . $this->namespace . "run>\n";
}
/**
* Paints the test document footer.
* @param string $test_name The top level test.
* @access public
* @abstract
*/
function paintFooter($test_name) {
print "</" . $this->namespace . "run>\n";
}
}
/**
* Accumulator for incoming tag. Holds the
* incoming test structure information for
* later dispatch to the reporter.
* @package SimpleTest
* @subpackage UnitTester
*/
class NestingXmlTag {
private $name;
private $attributes;
/**
* Sets the basic test information except
* the name.
* @param hash $attributes Name value pairs.
* @access public
*/
function NestingXmlTag($attributes) {
$this->name = false;
$this->attributes = $attributes;
}
/**
* Sets the test case/method name.
* @param string $name Name of test.
* @access public
*/
function setName($name) {
$this->name = $name;
}
/**
* Accessor for name.
* @return string Name of test.
* @access public
*/
function getName() {
return $this->name;
}
/**
* Accessor for attributes.
* @return hash All attributes.
* @access protected
*/
protected function getAttributes() {
return $this->attributes;
}
}
/**
* Accumulator for incoming method tag. Holds the
* incoming test structure information for
* later dispatch to the reporter.
* @package SimpleTest
* @subpackage UnitTester
*/
class NestingMethodTag extends NestingXmlTag {
/**
* Sets the basic test information except
* the name.
* @param hash $attributes Name value pairs.
* @access public
*/
function NestingMethodTag($attributes) {
$this->NestingXmlTag($attributes);
}
/**
* Signals the appropriate start event on the
* listener.
* @param SimpleReporter $listener Target for events.
* @access public
*/
function paintStart(&$listener) {
$listener->paintMethodStart($this->getName());
}
/**
* Signals the appropriate end event on the
* listener.
* @param SimpleReporter $listener Target for events.
* @access public
*/
function paintEnd(&$listener) {
$listener->paintMethodEnd($this->getName());
}
}
/**
* Accumulator for incoming case tag. Holds the
* incoming test structure information for
* later dispatch to the reporter.
* @package SimpleTest
* @subpackage UnitTester
*/
class NestingCaseTag extends NestingXmlTag {
/**
* Sets the basic test information except
* the name.
* @param hash $attributes Name value pairs.
* @access public
*/
function NestingCaseTag($attributes) {
$this->NestingXmlTag($attributes);
}
/**
* Signals the appropriate start event on the
* listener.
* @param SimpleReporter $listener Target for events.
* @access public
*/
function paintStart(&$listener) {
$listener->paintCaseStart($this->getName());
}
/**
* Signals the appropriate end event on the
* listener.
* @param SimpleReporter $listener Target for events.
* @access public
*/
function paintEnd(&$listener) {
$listener->paintCaseEnd($this->getName());
}
}
/**
* Accumulator for incoming group tag. Holds the
* incoming test structure information for
* later dispatch to the reporter.
* @package SimpleTest
* @subpackage UnitTester
*/
class NestingGroupTag extends NestingXmlTag {
/**
* Sets the basic test information except
* the name.
* @param hash $attributes Name value pairs.
* @access public
*/
function NestingGroupTag($attributes) {
$this->NestingXmlTag($attributes);
}
/**
* Signals the appropriate start event on the
* listener.
* @param SimpleReporter $listener Target for events.
* @access public
*/
function paintStart(&$listener) {
$listener->paintGroupStart($this->getName(), $this->getSize());
}
/**
* Signals the appropriate end event on the
* listener.
* @param SimpleReporter $listener Target for events.
* @access public
*/
function paintEnd(&$listener) {
$listener->paintGroupEnd($this->getName());
}
/**
* The size in the attributes.
* @return integer Value of size attribute or zero.
* @access public
*/
function getSize() {
$attributes = $this->getAttributes();
if (isset($attributes['SIZE'])) {
return (integer)$attributes['SIZE'];
}
return 0;
}
}
/**
* Parser for importing the output of the XmlReporter.
* Dispatches that output to another reporter.
* @package SimpleTest
* @subpackage UnitTester
*/
class SimpleTestXmlParser {
private $listener;
private $expat;
private $tag_stack;
private $in_content_tag;
private $content;
private $attributes;
/**
* Loads a listener with the SimpleReporter
* interface.
* @param SimpleReporter $listener Listener of tag events.
* @access public
*/
function SimpleTestXmlParser(&$listener) {
$this->listener = &$listener;
$this->expat = &$this->createParser();
$this->tag_stack = array();
$this->in_content_tag = false;
$this->content = '';
$this->attributes = array();
}
/**
* Parses a block of XML sending the results to
* the listener.
* @param string $chunk Block of text to read.
* @return boolean True if valid XML.
* @access public
*/
function parse($chunk) {
if (! xml_parse($this->expat, $chunk)) {
trigger_error('XML parse error with ' .
xml_error_string(xml_get_error_code($this->expat)));
return false;
}
return true;
}
/**
* Sets up expat as the XML parser.
* @return resource Expat handle.
* @access protected
*/
protected function &createParser() {
$expat = xml_parser_create();
xml_set_object($expat, $this);
xml_set_element_handler($expat, 'startElement', 'endElement');
xml_set_character_data_handler($expat, 'addContent');
xml_set_default_handler($expat, 'defaultContent');
return $expat;
}
/**
* Opens a new test nesting level.
* @return NestedXmlTag The group, case or method tag
* to start.
* @access private
*/
protected function pushNestingTag($nested) {
array_unshift($this->tag_stack, $nested);
}
/**
* Accessor for current test structure tag.
* @return NestedXmlTag The group, case or method tag
* being parsed.
* @access private
*/
protected function &getCurrentNestingTag() {
return $this->tag_stack[0];
}
/**
* Ends a nesting tag.
* @return NestedXmlTag The group, case or method tag
* just finished.
* @access private
*/
protected function popNestingTag() {
return array_shift($this->tag_stack);
}
/**
* Test if tag is a leaf node with only text content.
* @param string $tag XML tag name.
* @return @boolean True if leaf, false if nesting.
* @private
*/
protected function isLeaf($tag) {
return in_array($tag, array(
'NAME', 'PASS', 'FAIL', 'EXCEPTION', 'SKIP', 'MESSAGE', 'FORMATTED', 'SIGNAL'));
}
/**
* Handler for start of event element.
* @param resource $expat Parser handle.
* @param string $tag Element name.
* @param hash $attributes Name value pairs.
* Attributes without content
* are marked as true.
* @access protected
*/
protected function startElement($expat, $tag, $attributes) {
$this->attributes = $attributes;
if ($tag == 'GROUP') {
$this->pushNestingTag(new NestingGroupTag($attributes));
} elseif ($tag == 'CASE') {
$this->pushNestingTag(new NestingCaseTag($attributes));
} elseif ($tag == 'TEST') {
$this->pushNestingTag(new NestingMethodTag($attributes));
} elseif ($this->isLeaf($tag)) {
$this->in_content_tag = true;
$this->content = '';
}
}
/**
* End of element event.
* @param resource $expat Parser handle.
* @param string $tag Element name.
* @access protected
*/
protected function endElement($expat, $tag) {
$this->in_content_tag = false;
if (in_array($tag, array('GROUP', 'CASE', 'TEST'))) {
$nesting_tag = $this->popNestingTag();
$nesting_tag->paintEnd($this->listener);
} elseif ($tag == 'NAME') {
$nesting_tag = &$this->getCurrentNestingTag();
$nesting_tag->setName($this->content);
$nesting_tag->paintStart($this->listener);
} elseif ($tag == 'PASS') {
$this->listener->paintPass($this->content);
} elseif ($tag == 'FAIL') {
$this->listener->paintFail($this->content);
} elseif ($tag == 'EXCEPTION') {
$this->listener->paintError($this->content);
} elseif ($tag == 'SKIP') {
$this->listener->paintSkip($this->content);
} elseif ($tag == 'SIGNAL') {
$this->listener->paintSignal(
$this->attributes['TYPE'],
unserialize($this->content));
} elseif ($tag == 'MESSAGE') {
$this->listener->paintMessage($this->content);
} elseif ($tag == 'FORMATTED') {
$this->listener->paintFormattedMessage($this->content);
}
}
/**
* Content between start and end elements.
* @param resource $expat Parser handle.
* @param string $text Usually output messages.
* @access protected
*/
protected function addContent($expat, $text) {
if ($this->in_content_tag) {
$this->content .= $text;
}
return true;
}
/**
* XML and Doctype handler. Discards all such content.
* @param resource $expat Parser handle.
* @param string $default Text of default content.
* @access protected
*/
protected function defaultContent($expat, $default) {
}
}
?>

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 246 B

After

Width:  |  Height:  |  Size: 246 B

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB