Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 8b890cb3eaa9e677a11febb7d0a41db22ffd7f19 0 parents
@benallfree authored
Showing with 26,639 additions and 0 deletions.
  1. +399 −0 HELP_MY_TESTS_DONT_WORK_ANYMORE
  2. +502 −0 LICENSE
  3. +102 −0 README
  4. +1 −0  VERSION
  5. +237 −0 authentication.php
  6. +99 −0 autorun.php
  7. +1,144 −0 browser.php
  8. +122 −0 collector.php
  9. +166 −0 compatibility.php
  10. +380 −0 cookies.php
  11. +163 −0 default_reporter.php
  12. +96 −0 detached.php
  13. +378 −0 docs/en/authentication_documentation.html
  14. +501 −0 docs/en/browser_documentation.html
  15. +121 −0 docs/en/docs.css
  16. +476 −0 docs/en/expectation_documentation.html
  17. +351 −0 docs/en/form_testing_documentation.html
  18. +252 −0 docs/en/group_test_documentation.html
  19. +542 −0 docs/en/index.html
  20. +870 −0 docs/en/mock_objects_documentation.html
  21. +487 −0 docs/en/overview.html
  22. +457 −0 docs/en/partial_mocks_documentation.html
  23. +616 −0 docs/en/reporter_documentation.html
  24. +442 −0 docs/en/unit_test_documentation.html
  25. +588 −0 docs/en/web_tester_documentation.html
  26. +371 −0 docs/fr/authentication_documentation.html
  27. +500 −0 docs/fr/browser_documentation.html
  28. +84 −0 docs/fr/docs.css
  29. +451 −0 docs/fr/expectation_documentation.html
  30. +353 −0 docs/fr/form_testing_documentation.html
  31. +401 −0 docs/fr/group_test_documentation.html
  32. +576 −0 docs/fr/index.html
  33. +784 −0 docs/fr/mock_objects_documentation.html
  34. +321 −0 docs/fr/overview.html
  35. +464 −0 docs/fr/partial_mocks_documentation.html
  36. +538 −0 docs/fr/reporter_documentation.html
  37. +450 −0 docs/fr/unit_test_documentation.html
  38. +570 −0 docs/fr/web_tester_documentation.html
  39. +407 −0 dumper.php
  40. +307 −0 eclipse.php
  41. +649 −0 encoding.php
  42. +267 −0 errors.php
  43. +226 −0 exceptions.php
  44. +984 −0 expectation.php
  45. +196 −0 extensions/pear_test_case.php
  46. +53 −0 extensions/testdox.php
  47. +107 −0 extensions/testdox/test.php
  48. +361 −0 form.php
  49. +592 −0 frames.php
  50. +628 −0 http.php
  51. +139 −0 invoker.php
  52. +1,641 −0 mock_objects.php
  53. +542 −0 page.php
  54. +1,054 −0 php_parser.php
  55. +136 −0 reflection_php4.php
  56. +386 −0 reflection_php5.php
  57. +115 −0 remote.php
  58. +445 −0 reporter.php
  59. +875 −0 scorer.php
  60. +141 −0 selector.php
  61. +330 −0 shell_tester.php
  62. +391 −0 simpletest.php
  63. +312 −0 socket.php
Sorry, we could not display the entire diff because it was too big.
399 HELP_MY_TESTS_DONT_WORK_ANYMORE
@@ -0,0 +1,399 @@
+Simple Test interface changes
+=============================
+Because the SimpleTest tool set is still evolving it is likely that tests
+written with earlier versions will fail with the newest ones. The most
+dramatic changes are in the alpha releases. Here is a list of possible
+problems and their fixes...
+
+assertText() no longer finds a string inside a <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.
502 LICENSE
@@ -0,0 +1,502 @@
+ 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!
102 README
@@ -0,0 +1,102 @@
+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.
1  VERSION
@@ -0,0 +1 @@
+1.1alpha3
237 authentication.php
@@ -0,0 +1,237 @@
+<?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"));
+ }
+ }
+}
+?>
99 autorun.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Autorunner which runs all tests cases found in a file
+ * that includes this module.
+ * @package SimpleTest
+ * @version $Id: autorun.php 2011 2011-04-29 08:22:48Z 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();
+register_shutdown_function('simpletest_autorun');
+
+/**
+ * Exit handler to run all recent test cases and exit system if in CLI
+ */
+function simpletest_autorun() {
+ 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()));
+}
+?>
1,144 browser.php
@@ -0,0 +1,1144 @@
+<?php
+/**
+ * Base include file for SimpleTest
+ * @package SimpleTest
+ * @subpackage WebTester
+ * @version $Id: browser.php 2013 2011-04-29 09:29:45Z pp11 $
+ */
+
+/**#@+
+ * include other SimpleTest class files
+ */
+require_once(dirname(__FILE__) . '/simpletest.php');
+require_once(dirname(__FILE__) . '/http.php');
+require_once(dirname(__FILE__) . '/encoding.php');
+require_once(dirname(__FILE__) . '/page.php');
+require_once(dirname(__FILE__) . '/php_parser.php');
+require_once(dirname(__FILE__) . '/tidy_parser.php');
+require_once(dirname(__FILE__) . '/selector.php');
+require_once(dirname(__FILE__) . '/frames.php');
+require_once(dirname(__FILE__) . '/user_agent.php');
+if (! SimpleTest::getParsers()) {
+ SimpleTest::setParsers(array(new SimpleTidyPageBuilder(), new SimplePHPPageBuilder()));
+ //SimpleTest::setParsers(array(new SimplePHPPageBuilder()));
+}
+/**#@-*/
+
+if (! defined('DEFAULT_MAX_NESTED_FRAMES')) {
+ define('DEFAULT_MAX_NESTED_FRAMES', 3);
+}
+
+/**
+ * Browser history list.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleBrowserHistory {
+ private $sequence = array();
+ private $position = -1;
+
+ /**
+ * Test for no entries yet.
+ * @return boolean True if empty.
+ * @access private
+ */
+ protected function isEmpty() {
+ return ($this->position == -1);
+ }
+
+ /**
+ * Test for being at the beginning.
+ * @return boolean True if first.
+ * @access private
+ */
+ protected function atBeginning() {
+ return ($this->position == 0) && ! $this->isEmpty();
+ }
+
+ /**
+ * Test for being at the last entry.
+ * @return boolean True if last.
+ * @access private
+ */
+ protected function atEnd() {
+ return ($this->position + 1 >= count($this->sequence)) && ! $this->isEmpty();
+ }
+
+ /**
+ * Adds a successfully fetched page to the history.
+ * @param SimpleUrl $url URL of fetch.
+ * @param SimpleEncoding $parameters Any post data with the fetch.
+ * @access public
+ */
+ function recordEntry($url, $parameters) {
+ $this->dropFuture();
+ array_push(
+ $this->sequence,
+ array('url' => $url, 'parameters' => $parameters));
+ $this->position++;
+ }
+
+ /**
+ * Last fully qualified URL for current history
+ * position.
+ * @return SimpleUrl URL for this position.
+ * @access public
+ */
+ function getUrl() {
+ if ($this->isEmpty()) {
+ return false;
+ }
+ return $this->sequence[$this->position]['url'];
+ }
+
+ /**
+ * Parameters of last fetch from current history
+ * position.
+ * @return SimpleFormEncoding Post parameters.
+ * @access public
+ */
+ function getParameters() {
+ if ($this->isEmpty()) {
+ return false;
+ }
+ return $this->sequence[$this->position]['parameters'];
+ }
+
+ /**
+ * Step back one place in the history. Stops at
+ * the first page.
+ * @return boolean True if any previous entries.
+ * @access public
+ */
+ function back() {
+ if ($this->isEmpty() || $this->atBeginning()) {
+ return false;
+ }
+ $this->position--;
+ return true;
+ }
+
+ /**
+ * Step forward one place. If already at the
+ * latest entry then nothing will happen.
+ * @return boolean True if any future entries.
+ * @access public
+ */
+ function forward() {
+ if ($this->isEmpty() || $this->atEnd()) {
+ return false;
+ }
+ $this->position++;
+ return true;
+ }
+
+ /**
+ * Ditches all future entries beyond the current
+ * point.
+ * @access private
+ */
+ protected function dropFuture() {
+ if ($this->isEmpty()) {
+ return;
+ }
+ while (! $this->atEnd()) {
+ array_pop($this->sequence);
+ }
+ }
+}
+
+/**
+ * Simulated web browser. This is an aggregate of
+ * the user agent, the HTML parsing, request history
+ * and the last header set.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleBrowser {
+ private $user_agent;
+ private $page;
+ private $history;
+ private $ignore_frames;
+ private $maximum_nested_frames;
+ private $parser;
+
+ /**
+ * Starts with a fresh browser with no
+ * cookie or any other state information. The
+ * exception is that a default proxy will be
+ * set up if specified in the options.
+ * @access public
+ */
+ function __construct() {
+ $this->user_agent = $this->createUserAgent();
+ $this->user_agent->useProxy(
+ SimpleTest::getDefaultProxy(),
+ SimpleTest::getDefaultProxyUsername(),
+ SimpleTest::getDefaultProxyPassword());
+ $this->page = new SimplePage();
+ $this->history = $this->createHistory();
+ $this->ignore_frames = false;
+ $this->maximum_nested_frames = DEFAULT_MAX_NESTED_FRAMES;
+ }
+
+ /**
+ * Creates the underlying user agent.
+ * @return SimpleFetcher Content fetcher.
+ * @access protected
+ */
+ protected function createUserAgent() {
+ return new SimpleUserAgent();
+ }
+
+ /**
+ * Creates a new empty history list.
+ * @return SimpleBrowserHistory New list.
+ * @access protected
+ */
+ protected function createHistory() {
+ return new SimpleBrowserHistory();
+ }
+
+ /**
+ * Get the HTML parser to use. Can be overridden by
+ * setParser. Otherwise scans through the available parsers and
+ * uses the first one which is available.
+ * @return object SimplePHPPageBuilder or SimpleTidyPageBuilder
+ */
+ protected function getParser() {
+ if ($this->parser) {
+ return $this->parser;
+ }
+ foreach (SimpleTest::getParsers() as $parser) {
+ if ($parser->can()) {
+ return $parser;
+ }
+ }
+ }
+
+ /**
+ * Override the default HTML parser, allowing parsers to be plugged in.
+ * @param object A parser object instance.
+ */
+ public function setParser($parser) {
+ $this->parser = $parser;
+ }
+
+ /**
+ * Disables frames support. Frames will not be fetched
+ * and the frameset page will be used instead.
+ * @access public
+ */
+ function ignoreFrames() {
+ $this->ignore_frames = true;
+ }
+
+ /**
+ * Enables frames support. Frames will be fetched from
+ * now on.
+ * @access public
+ */
+ function useFrames() {
+ $this->ignore_frames = false;
+ }
+
+ /**
+ * Switches off cookie sending and recieving.
+ * @access public
+ */
+ function ignoreCookies() {
+ $this->user_agent->ignoreCookies();
+ }
+
+ /**
+ * Switches back on the cookie sending and recieving.
+ * @access public
+ */
+ function useCookies() {
+ $this->user_agent->useCookies();
+ }
+
+ /**
+ * Parses the raw content into a page. Will load further
+ * frame pages unless frames are disabled.
+ * @param SimpleHttpResponse $response Response from fetch.
+ * @param integer $depth Nested frameset depth.
+ * @return SimplePage Parsed HTML.
+ * @access private
+ */
+ protected function parse($response, $depth = 0) {
+ $page = $this->buildPage($response);
+ if ($this->ignore_frames || ! $page->hasFrames() || ($depth > $this->maximum_nested_frames)) {
+ return $page;
+ }
+ $frameset = new SimpleFrameset($page);
+ foreach ($page->getFrameset() as $key => $url) {
+ $frame = $this->fetch($url, new SimpleGetEncoding(), $depth + 1);
+ $frameset->addFrame($frame, $key);
+ }
+ return $frameset;
+ }
+
+ /**
+ * Assembles the parsing machinery and actually parses
+ * a single page. Frees all of the builder memory and so
+ * unjams the PHP memory management.
+ * @param SimpleHttpResponse $response Response from fetch.
+ * @return SimplePage Parsed top level page.
+ */
+ protected function buildPage($response) {
+ return $this->getParser()->parse($response);
+ }
+
+ /**
+ * Fetches a page. Jointly recursive with the parse()
+ * method as it descends a frameset.
+ * @param string/SimpleUrl $url Target to fetch.
+ * @param SimpleEncoding $encoding GET/POST parameters.
+ * @param integer $depth Nested frameset depth protection.
+ * @return SimplePage Parsed page.
+ * @access private
+ */
+ protected function fetch($url, $encoding, $depth = 0) {
+ $response = $this->user_agent->fetchResponse($url, $encoding);
+ if ($response->isError()) {
+ return new SimplePage($response);
+ }
+ return $this->parse($response, $depth);
+ }
+
+ /**
+ * Fetches a page or a single frame if that is the current
+ * focus.
+ * @param SimpleUrl $url Target to fetch.
+ * @param SimpleEncoding $parameters GET/POST parameters.
+ * @return string Raw content of page.
+ * @access private
+ */
+ protected function load($url, $parameters) {
+ $frame = $url->getTarget();
+ if (! $frame || ! $this->page->hasFrames() || (strtolower($frame) == '_top')) {
+ return $this->loadPage($url, $parameters);
+ }
+ return $this->loadFrame(array($frame), $url, $parameters);
+ }
+
+ /**
+ * Fetches a page and makes it the current page/frame.
+ * @param string/SimpleUrl $url Target to fetch as string.
+ * @param SimplePostEncoding $parameters POST parameters.
+ * @return string Raw content of page.
+ * @access private
+ */
+ protected function loadPage($url, $parameters) {
+ $this->page = $this->fetch($url, $parameters);
+ $this->history->recordEntry(
+ $this->page->getUrl(),
+ $this->page->getRequestData());
+ return $this->page->getRaw();
+ }
+
+ /**
+ * Fetches a frame into the existing frameset replacing the
+ * original.
+ * @param array $frames List of names to drill down.
+ * @param string/SimpleUrl $url Target to fetch as string.
+ * @param SimpleFormEncoding $parameters POST parameters.
+ * @return string Raw content of page.
+ * @access private
+ */
+ protected function loadFrame($frames, $url, $parameters) {
+ $page = $this->fetch($url, $parameters);
+ $this->page->setFrame($frames, $page);
+ return $page->getRaw();
+ }
+
+ /**
+ * Removes expired and temporary cookies as if
+ * the browser was closed and re-opened.
+ * @param string/integer $date Time when session restarted.
+ * If omitted then all persistent
+ * cookies are kept.
+ * @access public
+ */
+ function restart($date = false) {
+ $this->user_agent->restart($date);
+ }
+
+ /**
+ * Adds a header to every fetch.
+ * @param string $header Header line to add to every
+ * request until cleared.
+ * @access public
+ */
+ function addHeader($header) {
+ $this->user_agent->addHeader($header);
+ }
+
+ /**
+ * Ages the cookies by the specified time.
+ * @param integer $interval Amount in seconds.
+ * @access public
+ */
+ function ageCookies($interval) {
+ $this->user_agent->ageCookies($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->user_agent->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->user_agent->getCookieValue($host, $path, $name);
+ }
+
+ /**
+ * Reads the current cookies for the current URL.
+ * @param string $name Key of cookie to find.
+ * @return string Null if there is no current URL, false
+ * if the cookie is not set.
+ * @access public
+ */
+ function getCurrentCookieValue($name) {
+ return $this->user_agent->getBaseCookieValue($name, $this->page->getUrl());
+ }
+
+ /**
+ * 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->user_agent->setMaximumRedirects($max);
+ }
+
+ /**
+ * Sets the maximum number of nesting of framed pages
+ * within a framed page to prevent loops.
+ * @param integer $max Highest depth allowed.
+ * @access public
+ */
+ function setMaximumNestedFrames($max) {
+ $this->maximum_nested_frames = $max;
+ }
+
+ /**
+ * Sets the socket timeout for opening a connection.
+ * @param integer $timeout Maximum time in seconds.
+ * @access public
+ */
+ function setConnectionTimeout($timeout) {
+ $this->user_agent->setConnectionTimeout($timeout);
+ }
+
+ /**
+ * 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 = false, $password = false) {
+ $this->user_agent->useProxy($proxy, $username, $password);
+ }
+
+ /**
+ * Fetches the page content with a HEAD request.
+ * Will affect cookies, but will not change the base URL.
+ * @param string/SimpleUrl $url Target to fetch as string.
+ * @param hash/SimpleHeadEncoding $parameters Additional parameters for
+ * HEAD request.
+ * @return boolean True if successful.
+ * @access public
+ */
+ function head($url, $parameters = false) {
+ if (! is_object($url)) {
+ $url = new SimpleUrl($url);
+ }
+ if ($this->getUrl()) {
+ $url = $url->makeAbsolute($this->getUrl());
+ }
+ $response = $this->user_agent->fetchResponse($url, new SimpleHeadEncoding($parameters));
+ $this->page = new SimplePage($response);
+ return ! $response->isError();
+ }
+
+ /**
+ * Fetches the page content with a simple GET request.
+ * @param string/SimpleUrl $url Target to fetch.
+ * @param hash/SimpleFormEncoding $parameters Additional parameters for
+ * GET request.
+ * @return string Content of page or false.
+ * @access public
+ */
+ function get($url, $parameters = false) {
+ if (! is_object($url)) {
+ $url = new SimpleUrl($url);
+ }
+ if ($this->getUrl()) {
+ $url = $url->makeAbsolute($this->getUrl());
+ }
+ return $this->load($url, new SimpleGetEncoding($parameters));
+ }
+
+ /**
+ * Fetches the page content with a POST request.
+ * @param string/SimpleUrl $url Target to fetch as string.
+ * @param hash/SimpleFormEncoding $parameters POST parameters or request body.
+ * @param string $content_type MIME Content-Type of the request body
+ * @return string Content of page.
+ * @access public
+ */
+ function post($url, $parameters = false, $content_type = false) {
+ if (! is_object($url)) {
+ $url = new SimpleUrl($url);
+ }
+ if ($this->getUrl()) {
+ $url = $url->makeAbsolute($this->getUrl());
+ }
+ return $this->load($url, new SimplePostEncoding($parameters, $content_type));
+ }
+
+ /**
+ * Fetches the page content with a PUT request.
+ * @param string/SimpleUrl $url Target to fetch as string.
+ * @param hash/SimpleFormEncoding $parameters PUT request body.
+ * @param string $content_type MIME Content-Type of the request body
+ * @return string Content of page.
+ * @access public
+ */
+ function put($url, $parameters = false, $content_type = false) {
+ if (! is_object($url)) {
+ $url = new SimpleUrl($url);
+ }
+ return $this->load($url, new SimplePutEncoding($parameters, $content_type));
+ }
+
+ /**
+ * Sends a DELETE request and fetches the response.
+ * @param string/SimpleUrl $url Target to fetch.
+ * @param hash/SimpleFormEncoding $parameters Additional parameters for
+ * DELETE request.
+ * @return string Content of page or false.
+ * @access public
+ */
+ function delete($url, $parameters = false) {
+ if (! is_object($url)) {
+ $url = new SimpleUrl($url);
+ }
+ return $this->load($url, new SimpleDeleteEncoding($parameters));
+ }
+
+ /**
+ * Equivalent to hitting the retry button on the
+ * browser. Will attempt to repeat the page fetch. If
+ * there is no history to repeat it will give false.
+ * @return string/boolean Content if fetch succeeded
+ * else false.
+ * @access public
+ */
+ function retry() {
+ $frames = $this->page->getFrameFocus();
+ if (count($frames) > 0) {
+ $this->loadFrame(
+ $frames,
+ $this->page->getUrl(),
+ $this->page->getRequestData());
+ return $this->page->getRaw();
+ }
+ if ($url = $this->history->getUrl()) {
+ $this->page = $this->fetch($url, $this->history->getParameters());
+ return $this->page->getRaw();
+ }
+ return false;
+ }
+
+ /**
+ * Equivalent to hitting the back button on the
+ * browser. The browser history is unchanged on
+ * failure. The page content is refetched as there
+ * is no concept of content caching in SimpleTest.
+ * @return boolean True if history entry and
+ * fetch succeeded
+ * @access public
+ */
+ function back() {
+ if (! $this->history->back()) {
+ return false;
+ }
+ $content = $this->retry();
+ if (! $content) {
+ $this->history->forward();
+ }
+ return $content;
+ }
+
+ /**
+ * Equivalent to hitting the forward button on the
+ * browser. The browser history is unchanged on
+ * failure. The page content is refetched as there
+ * is no concept of content caching in SimpleTest.
+ * @return boolean True if history entry and
+ * fetch succeeded
+ * @access public
+ */
+ function forward() {
+ if (! $this->history->forward()) {
+ return false;
+ }
+ $content = $this->retry();
+ if (! $content) {
+ $this->history->back();
+ }
+ return $content;
+ }
+
+ /**
+ * Retries a request after setting the authentication
+ * for the current realm.
+ * @param string $username Username for realm.
+ * @param string $password Password for realm.
+ * @return boolean True if successful fetch. Note
+ * that authentication may still have
+ * failed.
+ * @access public
+ */
+ function authenticate($username, $password) {
+ if (! $this->page->getRealm()) {
+ return false;
+ }
+ $url = $this->page->getUrl();
+ if (! $url) {
+ return false;
+ }
+ $this->user_agent->setIdentity(
+ $url->getHost(),
+ $this->page->getRealm(),
+ $username,
+ $password);
+ return $this->retry();
+ }
+
+ /**
+ * Accessor for a breakdown of the frameset.
+ * @return array Hash tree of frames by name
+ * or index if no name.
+ * @access public
+ */
+ function getFrames() {
+ return $this->page->getFrames();
+ }
+
+ /**
+ * Accessor for current frame focus. Will be
+ * false if no frame has focus.
+ * @return integer/string/boolean Label if any, otherwise
+ * the position in the frameset
+ * or false if none.
+ * @access public
+ */
+ function getFrameFocus() {
+ return $this->page->getFrameFocus();
+ }
+
+ /**
+ * Sets the focus by index. The integer index starts from 1.
+ * @param integer $choice Chosen frame.
+ * @return boolean True if frame exists.
+ * @access public
+ */
+ function setFrameFocusByIndex($choice) {
+ return $this->page->setFrameFocusByIndex($choice);
+ }
+
+ /**
+ * Sets the focus by name.
+ * @param string $name Chosen frame.
+ * @return boolean True if frame exists.
+ * @access public
+ */
+ function setFrameFocus($name) {
+ return $this->page->setFrameFocus($name);
+ }
+
+ /**
+ * Clears the frame focus. All frames will be searched
+ * for content.
+ * @access public
+ */
+ function clearFrameFocus() {
+ return $this->page->clearFrameFocus();
+ }
+
+ /**
+ * Accessor for last error.
+ * @return string Error from last response.
+ * @access public
+ */
+ function getTransportError() {
+ return $this->page->getTransportError();
+ }
+
+ /**
+ * Accessor for current MIME type.
+ * @return string MIME type as string; e.g. 'text/html'
+ * @access public
+ */
+ function getMimeType() {
+ return $this->page->getMimeType();
+ }
+
+ /**
+ * Accessor for last response code.
+ * @return integer Last HTTP response code received.
+ * @access public
+ */
+ function getResponseCode() {
+ return $this->page->getResponseCode();
+ }
+
+ /**
+ * Accessor for last Authentication type. Only valid
+ * straight after a challenge (401).
+ * @return string Description of challenge type.
+ * @access public
+ */
+ function getAuthentication() {
+ return $this->page->getAuthentication();
+ }
+
+ /**
+ * Accessor for last Authentication realm. Only valid
+ * straight after a challenge (401).
+ * @return string Name of security realm.
+ * @access public
+ */
+ function getRealm() {
+ return $this->page->getRealm();
+ }
+
+ /**
+ * Accessor for current URL of page or frame if
+ * focused.
+ * @return string Location of current page or frame as
+ * a string.
+ */
+ function getUrl() {
+ $url = $this->page->getUrl();
+ return $url ? $url->asString() : false;
+ }
+
+ /**
+ * Accessor for base URL of page if set via BASE tag
+ * @return string base URL
+ */
+ function getBaseUrl() {
+ $url = $this->page->getBaseUrl();
+ return $url ? $url->asString() : false;
+ }
+
+ /**
+ * Accessor for raw bytes sent down the wire.
+ * @return string Original text sent.
+ * @access public
+ */
+ function getRequest() {
+ return $this->page->getRequest();
+ }
+
+ /**
+ * Accessor for raw header information.
+ * @return string Header block.
+ * @access public
+ */
+ function getHeaders() {
+ return $this->page->getHeaders();
+ }
+
+ /**
+ * Accessor for raw page information.
+ * @return string Original text content of web page.
+ * @access public
+ */
+ function getContent() {
+ return $this->page->getRaw();
+ }
+
+ /**
+ * Accessor for plain text version of the page.
+ * @return string Normalised text representation.
+ * @access public
+ */
+ function getContentAsText() {
+ return $this->page->getText();
+ }
+
+ /**
+ * Accessor for parsed title.
+ * @return string Title or false if no title is present.
+ * @access public
+ */
+ function getTitle() {
+ return $this->page->getTitle();
+ }
+
+ /**
+ * Accessor for a list of all links in current page.
+ * @return array List of urls with scheme of
+ * http or https and hostname.
+ * @access public
+ */
+ function getUrls() {
+ return $this->page->getUrls();
+ }
+
+ /**
+ * Sets all form fields with that name.
+ * @param string $label Name or label of field in forms.
+ * @param string $value New value of field.
+ * @return boolean True if field exists, otherwise false.
+ * @access public
+ */
+ function setField($label, $value, $position=false) {
+ return $this->page->setField(new SimpleByLabelOrName($label), $value, $position);
+ }
+
+ /**
+ * Sets all form fields with that name. Will use label if
+ * one is available (not yet implemented).
+ * @param string $name Name of field in forms.
+ * @param string $value New value of field.
+ * @return boolean True if field exists, otherwise false.
+ * @access public
+ */
+ function setFieldByName($name, $value, $position=false) {
+ return $this->page->setField(new SimpleByName($name), $value, $position);
+ }
+
+ /**
+ * Sets all form fields with that id attribute.
+ * @param string/integer $id Id of field in forms.
+ * @param string $value New value of field.
+ * @return boolean True if field exists, otherwise false.
+ * @access public
+ */
+ function setFieldById($id, $value) {
+ return $this->page->setField(new SimpleById($id), $value);
+ }
+
+ /**
+ * Accessor for a form element value within the page.
+ * Finds the first match.
+ * @param string $label Field label.
+ * @return string/boolean A value if the field is
+ * present, false if unchecked
+ * and null if missing.
+ * @access public
+ */
+ function getField($label) {
+ return $this->page->getField(new SimpleByLabelOrName($label));
+ }
+
+ /**
+ * Accessor for a form element value within the page.
+ * Finds the first match.
+ * @param string $name Field name.
+ * @return string/boolean A string if the field is
+ * present, false if unchecked
+ * and null if missing.
+ * @access public
+ */
+ function getFieldByName($name) {
+ return $this->page->getField(new SimpleByName($name));
+ }
+
+ /**
+ * Accessor for a form element value within the page.
+ * @param string/integer $id Id of field in forms.
+ * @return string/boolean A string if the field is
+ * present, false if unchecked
+ * and null if missing.
+ * @access public
+ */
+ function getFieldById($id) {
+ return $this->page->getField(new SimpleById($id));
+ }
+
+ /**
+ * Clicks the submit button by label. The owning
+ * form will be submitted by this.
+ * @param string $label Button label. An unlabeled
+ * button can be triggered by 'Submit'.
+ * @param hash $additional Additional form data.
+ * @return string/boolean Page on success.
+ * @access public
+ */
+ function clickSubmit($label = 'Submit', $additional = false) {
+ if (! ($form = $this->page->getFormBySubmit(new SimpleByLabel($label)))) {
+ return false;
+ }
+ $success = $this->load(
+ $form->getAction(),
+ $form->submitButton(new SimpleByLabel($label), $additional));
+ return ($success ? $this->getContent() : $success);
+ }
+
+ /**
+ * Clicks the submit button by name attribute. The owning
+ * form will be submitted by this.
+ * @param string $name Button name.
+ * @param hash $additional Additional form data.
+ * @return string/boolean Page on success.
+ * @access public
+ */
+ function clickSubmitByName($name, $additional = false) {
+ if (! ($form = $this->page->getFormBySubmit(new SimpleByName($name)))) {
+ return false;
+ }
+ $success = $this->load(
+ $form->getAction(),
+ $form->submitButton(new SimpleByName($name), $additional));
+ return ($success ? $this->getContent() : $success);
+ }
+
+ /**
+ * Clicks the submit button by ID attribute of the button
+ * itself. The owning form will be submitted by this.
+ * @param string $id Button ID.
+ * @param hash $additional Additional form data.
+ * @return string/boolean Page on success.
+ * @access public
+ */
+ function clickSubmitById($id, $additional = false) {
+ if (! ($form = $this->page->getFormBySubmit(new SimpleById($id)))) {
+ return false;
+ }
+ $success = $this->load(
+ $form->getAction(),
+ $form->submitButton(new SimpleById($id), $additional));
+ return ($success ? $this->getContent() : $success);
+ }
+
+ /**
+ * Tests to see if a submit button exists with this
+ * label.
+ * @param string $label Button label.
+ * @return boolean True if present.
+ * @access public
+ */
+ function isSubmit($label) {
+ return (boolean)$this->page->getFormBySubmit(new SimpleByLabel($label));
+ }
+
+ /**
+ * Clicks the submit image by some kind of label. Usually
+ * the alt tag or the nearest equivalent. The owning
+ * form will be submitted by this. Clicking outside of
+ * the boundary of the coordinates will result in
+ * a failure.
+ * @param string $label ID attribute of button.
+ * @param integer $x X-coordinate of imaginary click.
+ * @param integer $y Y-coordinate of imaginary click.
+ * @param hash $additional Additional form data.
+ * @return string/boolean Page on success.
+ * @access public
+ */
+ function clickImage($label, $x = 1, $y = 1, $additional = false) {
+ if (! ($form = $this->page->getFormByImage(new SimpleByLabel($label)))) {
+ return false;
+ }
+ $success = $this->load(
+ $form->getAction(),
+ $form->submitImage(new SimpleByLabel($label), $x, $y, $additional));
+ return ($success ? $this->getContent() : $success);
+ }
+
+ /**
+ * Clicks the submit image by the name. Usually
+ * the alt tag or the nearest equivalent. The owning
+ * form will be submitted by this. Clicking outside of
+ * the boundary of the coordinates will result in
+ * a failure.
+ * @param string $name Name attribute of button.
+ * @param integer $x X-coordinate of imaginary click.
+ * @param integer $y Y-coordinate of imaginary click.
+ * @param hash $additional Additional form data.
+ * @return string/boolean Page on success.
+ * @access public
+ */
+ function clickImageByName($name, $x = 1, $y = 1, $additional = false) {
+ if (! ($form = $this->page->getFormByImage(new SimpleByName($name)))) {
+ return false;
+ }
+ $success = $this->load(
+ $form->getAction(),
+ $form->submitImage(new SimpleByName($name), $x, $y, $additional));
+ return ($success ? $this->getContent() : $success);
+ }
+