diff --git a/composer.json b/composer.json index 6fa4a403b..67fb3246e 100644 --- a/composer.json +++ b/composer.json @@ -39,6 +39,7 @@ "sminnee/callbacklist": "^0.1.1", "symfony/cache": "^6.1", "symfony/config": "^6.1", + "symfony/dom-crawler": "^6.1", "symfony/filesystem": "^6.1", "symfony/mailer": "^6.1", "symfony/mime": "^6.1", diff --git a/src/Dev/FunctionalTest.php b/src/Dev/FunctionalTest.php index b6926dad3..81f83ae99 100644 --- a/src/Dev/FunctionalTest.php +++ b/src/Dev/FunctionalTest.php @@ -191,12 +191,13 @@ abstract class FunctionalTest extends SapphireTest implements TestOnly * @param string $formID HTML 'id' attribute of a form (loaded through a previous response) * @param string $button HTML 'name' attribute of the button (NOT the 'id' attribute) * @param array $data Map of GET/POST data. + * @param bool $withSecurityToken Submit with the form's security token if there is one. * @return HTTPResponse */ - public function submitForm($formID, $button = null, $data = []) + public function submitForm($formID, $button = null, $data = [], $withSecurityToken = true) { $this->cssParser = null; - $response = $this->mainSession->submitForm($formID, $button, $data); + $response = $this->mainSession->submitForm($formID, $button, $data, $withSecurityToken); if ($this->autoFollowRedirection && is_object($response) && $response->getHeader('Location')) { $response = $this->mainSession->followRedirection(); } diff --git a/src/Dev/TestSession.php b/src/Dev/TestSession.php index f6822f7ff..096b6da03 100644 --- a/src/Dev/TestSession.php +++ b/src/Dev/TestSession.php @@ -3,6 +3,7 @@ namespace SilverStripe\Dev; use Exception; +use InvalidArgumentException; use SilverStripe\Control\Controller; use SilverStripe\Control\Cookie_Backend; use SilverStripe\Control\Director; @@ -12,9 +13,7 @@ use SilverStripe\Control\HTTPResponse_Exception; use SilverStripe\Control\Session; use SilverStripe\Core\Extensible; use SilverStripe\Core\Injector\Injector; -use SimpleByName; -use SimplePage; -use SimplePageBuilder; +use Symfony\Component\DomCrawler\Crawler; /** * Represents a test usage session of a web-app @@ -202,41 +201,54 @@ class TestSession * Wrong: array('mycheckboxvalues' => array(1 => 'one', 2 => 'two')) * Right: array('mycheckboxvalues[1]' => 'one', 'mycheckboxvalues[2]' => 'two') * - * @see http://www.simpletest.org/en/form_testing_documentation.html - * * @param string $formID HTML 'id' attribute of a form (loaded through a previous response) * @param string $button HTML 'name' attribute of the button (NOT the 'id' attribute) * @param array $data Map of GET/POST data. + * @param bool $withSecurityToken Submit with the form's security token if there is one. * @return HTTPResponse * @throws Exception */ - public function submitForm($formID, $button = null, $data = []) + public function submitForm($formID, $button = null, $data = [], $withSecurityToken = true) { + /** @var Crawler $page */ $page = $this->lastPage(); if ($page) { - $form = $page->getFormById($formID); - if (!$form) { + try { + $formCrawler = $page->filterXPath("//form[@id='$formID']"); + $form = $formCrawler->form(); + } catch (InvalidArgumentException $e) { + // throw $e; user_error("TestSession::submitForm failed to find the form {$formID}"); } foreach ($data as $k => $v) { - $form->setField(new SimpleByName($k), $v); + if ($form->has($k)) { + $form->get($k)->setValue($v); + } } + // Add security token to submitted values + if ($withSecurityToken && $form->has('SecurityID')) { + $securityField = $page->filterXPath("//input[@id='{$formID}_SecurityID']"); + $form->get('SecurityID')->setValue($securityField->attr('value')); + } + + $values = $form->getPhpValues(); + + // Add button to submitted values if ($button) { - $submission = $form->submitButton(new SimpleByName($button)); - if (!$submission) { + $btnXpath = "//button[@name='$button'] | //input[@name='$button'][@type='button' or @type='submit']"; + if (!$formCrawler->children()->filterXPath($btnXpath)->count()) { throw new Exception("Can't find button '$button' to submit as part of test."); } - } else { - $submission = $form->submit(); + $values[$button] = true; } - $url = Director::makeRelative($form->getAction()->asString()); - - $postVars = []; - parse_str($submission->_encode() ?? '', $postVars); - return $this->post($url, $postVars); + return $this->sendRequest( + $form->getMethod(), + Director::makeRelative($form->getUri()), + $values + ); } else { user_error("TestSession::submitForm called when there is no form loaded." . " Visit the page with the form first", E_USER_WARNING); @@ -313,24 +325,13 @@ class TestSession } /** - * Get the last response as a SimplePage object + * Get a DOM Crawler for the last response * - * @return SimplePage The response if available + * @return Crawler A DOM Crawler for the given response */ public function lastPage() { - require_once("simpletest/http.php"); - require_once("simpletest/page.php"); - require_once("simpletest/form.php"); - - $builder = new SimplePageBuilder(); - if ($this->lastResponse) { - $page = &$builder->parse(new TestSession_STResponseWrapper($this->lastResponse)); - $builder->free(); - unset($builder); - - return $page; - } + return new Crawler($this->lastContent(), Director::absoluteURL($this->lastUrl())); } /** diff --git a/src/Dev/TestSession_STResponseWrapper.php b/src/Dev/TestSession_STResponseWrapper.php deleted file mode 100644 index 402080e84..000000000 --- a/src/Dev/TestSession_STResponseWrapper.php +++ /dev/null @@ -1,78 +0,0 @@ -response = $response; - } - - /** - * @return string - */ - public function getContent() - { - return $this->response->getBody(); - } - - /** - * @return string - */ - public function getError() - { - return ""; - } - - /** - * @return null - */ - public function getSent() - { - return null; - } - - /** - * @return string - */ - public function getHeaders() - { - return ""; - } - - /** - * @return string 'GET' - */ - public function getMethod() - { - return "GET"; - } - - /** - * @return string - */ - public function getUrl() - { - return ""; - } - - /** - * @return null - */ - public function getRequestData() - { - return null; - } -} diff --git a/tests/php/Core/Injector/InjectorTest.php b/tests/php/Core/Injector/InjectorTest.php index 790d31f77..9d914feeb 100644 --- a/tests/php/Core/Injector/InjectorTest.php +++ b/tests/php/Core/Injector/InjectorTest.php @@ -33,8 +33,6 @@ define('TEST_SERVICES', __DIR__ . '/AopProxyServiceTest'); /** * Tests for the dependency injector * - * Note that these are SS conversions of the existing Simpletest unit tests - * * @author marcus@silverstripe.com.au * @license BSD License http://silverstripe.org/bsd-license/ */ diff --git a/tests/php/Forms/EmailFieldTest.php b/tests/php/Forms/EmailFieldTest.php index 76912d744..3ec5a7acd 100644 --- a/tests/php/Forms/EmailFieldTest.php +++ b/tests/php/Forms/EmailFieldTest.php @@ -60,9 +60,7 @@ class EmailFieldTest extends FunctionalTest } /** - * Check that input type='email' fields are submitted by SimpleTest - * - * @see SimpleTagBuilder::_createInputTag() + * Check that input type='email' fields are submitted */ public function testEmailFieldPopulation() { diff --git a/tests/php/Forms/FormTest.php b/tests/php/Forms/FormTest.php index 6a3712508..c8ed7e7e3 100644 --- a/tests/php/Forms/FormTest.php +++ b/tests/php/Forms/FormTest.php @@ -646,14 +646,13 @@ class FormTest extends FunctionalTest count($tokenEls ?? []), 'Token form field added for controller without disableSecurityToken()' ); - $token = (string)$tokenEls[0]; $response = $this->submitForm( 'Form_Form', null, [ 'Email' => 'test@test.com', - 'SecurityID' => $token - ] + ], + withSecurityToken: true ); $this->assertEquals(200, $response->getStatusCode(), 'Submission succeeds with security token'); } diff --git a/thirdparty/simpletest/LICENSE b/thirdparty/simpletest/LICENSE deleted file mode 100644 index 09f465ab7..000000000 --- a/thirdparty/simpletest/LICENSE +++ /dev/null @@ -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. - - - Copyright (C) - - 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. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/thirdparty/simpletest/VERSION b/thirdparty/simpletest/VERSION deleted file mode 100644 index 7f207341d..000000000 --- a/thirdparty/simpletest/VERSION +++ /dev/null @@ -1 +0,0 @@ -1.0.1 \ No newline at end of file diff --git a/thirdparty/simpletest/compatibility.php b/thirdparty/simpletest/compatibility.php deleted file mode 100644 index 999d4ac96..000000000 --- a/thirdparty/simpletest/compatibility.php +++ /dev/null @@ -1,173 +0,0 @@ -= 0) { - eval('$copy = clone $object;'); - return $copy; - } - return $object; - } - - /** - * Identity test. Drops back to equality + types for PHP5 - * objects as the === operator counts as the - * stronger reference constraint. - * @param mixed $first Test subject. - * @param mixed $second Comparison object. - * @return boolean True if identical. - * @access public - * @static - */ - function isIdentical($first, $second) { - if (version_compare(phpversion() ?? '', '5') >= 0) { - return SimpleTestCompatibility::_isIdenticalType($first, $second); - } - if ($first != $second) { - return false; - } - return ($first === $second); - } - - /** - * Recursive type test. - * @param mixed $first Test subject. - * @param mixed $second Comparison object. - * @return boolean True if same type. - * @access private - * @static - */ - function _isIdenticalType($first, $second) { - if (gettype($first) != gettype($second)) { - return false; - } - if (is_object($first) && is_object($second)) { - if (get_class($first) != get_class($second)) { - return false; - } - return SimpleTestCompatibility::_isArrayOfIdenticalTypes( - get_object_vars($first), - get_object_vars($second)); - } - if (is_array($first) && is_array($second)) { - return SimpleTestCompatibility::_isArrayOfIdenticalTypes($first, $second); - } - if ($first !== $second) { - return false; - } - return true; - } - - /** - * Recursive type test for each element of an array. - * @param mixed $first Test subject. - * @param mixed $second Comparison object. - * @return boolean True if identical. - * @access private - * @static - */ - function _isArrayOfIdenticalTypes($first, $second) { - if (array_keys($first ?? []) != array_keys($second ?? [])) { - return false; - } - foreach (array_keys($first ?? []) as $key) { - $is_identical = SimpleTestCompatibility::_isIdenticalType( - $first[$key], - $second[$key]); - if (! $is_identical) { - return false; - } - } - return true; - } - - /** - * Test for two variables being aliases. - * @param mixed $first Test subject. - * @param mixed $second Comparison object. - * @return boolean True if same. - * @access public - * @static - */ - function isReference(&$first, &$second) { - if (version_compare(phpversion() ?? '', '5', '>=') && is_object($first)) { - return ($first === $second); - } - if (is_object($first) && is_object($second)) { - $id = uniqid("test"); - $first->$id = true; - $is_ref = isset($second->$id); - unset($first->$id); - return $is_ref; - } - $temp = $first; - $first = uniqid("test"); - $is_ref = ($first === $second); - $first = $temp; - 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, 0); - } elseif (function_exists('socket_set_timeout')) { - socket_set_timeout($handle, $timeout ?? 0, 0); - } elseif (function_exists('set_socket_timeout')) { - set_socket_timeout($handle, $timeout, 0); - } - } -} -?> diff --git a/thirdparty/simpletest/cookies.php b/thirdparty/simpletest/cookies.php deleted file mode 100644 index d2a9ef128..000000000 --- a/thirdparty/simpletest/cookies.php +++ /dev/null @@ -1,380 +0,0 @@ -_host = false; - $this->_name = $name; - $this->_value = $value; - $this->_path = ($path ? $this->_fixPath($path) : "/"); - $this->_expiry = false; - if (is_string($expiry)) { - $this->_expiry = strtotime($expiry ?? ''); - } elseif (is_integer($expiry)) { - $this->_expiry = $expiry; - } - $this->_is_secure = $is_secure; - } - - /** - * Sets the host. The cookie rules determine - * that the first two parts are taken for - * certain TLDs and three for others. If the - * new host does not match these rules then the - * call will fail. - * @param string $host New hostname. - * @return boolean True if hostname is valid. - * @access public - */ - function setHost($host) { - if ($host = $this->_truncateHost($host)) { - $this->_host = $host; - return true; - } - return false; - } - - /** - * Accessor for the truncated host to which this - * cookie applies. - * @return string Truncated hostname. - * @access public - */ - function getHost() { - return $this->_host; - } - - /** - * Test for a cookie being valid for a host name. - * @param string $host Host to test against. - * @return boolean True if the cookie would be valid - * here. - */ - function isValidHost($host) { - return ($this->_truncateHost($host) === $this->getHost()); - } - - /** - * Extracts just the domain part that determines a - * cookie's host validity. - * @param string $host Host name to truncate. - * @return string Domain or false on a bad host. - * @access private - */ - function _truncateHost($host) { - $tlds = SimpleUrl::getAllTopLevelDomains(); - if (preg_match('/[a-z\-]+\.(' . $tlds . ')$/i', $host ?? '', $matches)) { - return $matches[0]; - } elseif (preg_match('/[a-z\-]+\.[a-z\-]+\.[a-z\-]+$/i', $host ?? '', $matches)) { - return $matches[0]; - } - return false; - } - - /** - * Accessor for name. - * @return string Cookie key. - * @access public - */ - function getName() { - return $this->_name; - } - - /** - * Accessor for value. A deleted cookie will - * have an empty string for this. - * @return string Cookie value. - * @access public - */ - function getValue() { - return $this->_value; - } - - /** - * Accessor for path. - * @return string Valid cookie path. - * @access public - */ - function getPath() { - return $this->_path; - } - - /** - * Tests a path to see if the cookie applies - * there. The test path must be longer or - * equal to the cookie path. - * @param string $path Path to test against. - * @return boolean True if cookie valid here. - * @access public - */ - function isValidPath($path) { - return (strncmp( - $this->_fixPath($path) ?? '', - $this->getPath() ?? '', - strlen($this->getPath() ?? '')) == 0); - } - - /** - * Accessor for expiry. - * @return string Expiry string. - * @access public - */ - function getExpiry() { - if (! $this->_expiry) { - return false; - } - return gmdate("D, d M Y H:i:s", $this->_expiry) . " GMT"; - } - - /** - * Test to see if cookie is expired against - * the cookie format time or timestamp. - * Will give true for a session cookie. - * @param integer/string $now Time to test against. Result - * will be false if this time - * is later than the cookie expiry. - * Can be either a timestamp integer - * or a cookie format date. - * @access public - */ - function isExpired($now) { - if (! $this->_expiry) { - return true; - } - if (is_string($now)) { - $now = strtotime($now ?? ''); - } - return ($this->_expiry < $now); - } - - /** - * Ages the cookie by the specified number of - * seconds. - * @param integer $interval In seconds. - * @public - */ - function agePrematurely($interval) { - if ($this->_expiry) { - $this->_expiry -= $interval; - } - } - - /** - * Accessor for the secure flag. - * @return boolean True if cookie needs SSL. - * @access public - */ - function isSecure() { - return $this->_is_secure; - } - - /** - * Adds a trailing and leading slash to the path - * if missing. - * @param string $path Path to fix. - * @access private - */ - function _fixPath($path) { - if (substr($path ?? '', 0, 1) != '/') { - $path = '/' . $path; - } - if (substr($path ?? '', -1, 1) != '/') { - $path .= '/'; - } - return $path; - } -} - -/** - * Repository for cookies. This stuff is a - * tiny bit browser dependent. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleCookieJar { - var $_cookies; - - /** - * Constructor. Jar starts empty. - * @access public - */ - function __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 - */ - function _findFirstMatch($cookie) { - for ($i = 0; $i < count($this->_cookies ?? []); $i++) { - $is_match = $this->_isMatch( - $cookie, - $this->_cookies[$i]->getHost(), - $this->_cookies[$i]->getPath(), - $this->_cookies[$i]->getName()); - if ($is_match) { - return $i; - } - } - return count($this->_cookies ?? []); - } - - /** - * Reads the most specific cookie value from the - * browser cookies. Looks for the longest path that - * matches. - * @param string $host Host to search. - * @param string $path Applicable path. - * @param string $name Name of cookie to read. - * @return string False if not present, else the - * value as a string. - * @access public - */ - function getCookieValue($host, $path, $name) { - $longest_path = ''; - foreach ($this->_cookies as $cookie) { - if ($this->_isMatch($cookie, $host, $path, $name)) { - if (strlen($cookie->getPath() ?? '') > strlen($longest_path ?? '')) { - $value = $cookie->getValue(); - $longest_path = $cookie->getPath(); - } - } - } - return (isset($value) ? $value : false); - } - - /** - * Tests cookie for matching against search - * criteria. - * @param SimpleTest $cookie Cookie to test. - * @param string $host Host must match. - * @param string $path Cookie path must be shorter than - * this path. - * @param string $name Name must match. - * @return boolean True if matched. - * @access private - */ - function _isMatch($cookie, $host, $path, $name) { - if ($cookie->getName() != $name) { - return false; - } - if ($host && $cookie->getHost() && ! $cookie->isValidHost($host)) { - return false; - } - if (! $cookie->isValidPath($path)) { - return false; - } - return true; - } - - /** - * Uses a URL to sift relevant cookies by host and - * path. Results are list of strings of form "name=value". - * @param SimpleUrl $url Url to select by. - * @return array Valid name and value pairs. - * @access public - */ - function selectAsPairs($url) { - $pairs = array(); - foreach ($this->_cookies as $cookie) { - if ($this->_isMatch($cookie, $url->getHost(), $url->getPath(), $cookie->getName())) { - $pairs[] = $cookie->getName() . '=' . $cookie->getValue(); - } - } - return $pairs; - } -} -?> diff --git a/thirdparty/simpletest/encoding.php b/thirdparty/simpletest/encoding.php deleted file mode 100644 index f19cdddf3..000000000 --- a/thirdparty/simpletest/encoding.php +++ /dev/null @@ -1,552 +0,0 @@ -_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 { - var $_key; - var $_content; - var $_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 - */ - 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 - */ - 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 { - var $_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 - */ - 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 - */ - 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 POST parameters. Can include - * repeated parameters. - * @package SimpleTest - * @subpackage WebTester - */ -class SimplePostEncoding 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) { - if (is_array($query) and $this->hasMoreThanOneLevel($query)) { - $query = $this->rewriteArrayWithMultipleLevels($query); - } - parent::__construct($query); - } - - 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'; - } - - /** - * 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: application/x-www-form-urlencoded\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 for attaching to a URL. - * @return string Part of URL. - * @access public - */ - function asUrlRequest() { - return ''; - } -} - -/** - * Bundle of POST parameters in the multipart - * format. Can include file uploads. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleMultipartEncoding extends SimplePostEncoding { - var $_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->_request as $pair) { - $stream .= "--" . $this->_boundary . "\r\n"; - $stream .= $pair->asMime() . "\r\n"; - } - $stream .= "--" . $this->_boundary . "--\r\n"; - return $stream; - } -} -?> diff --git a/thirdparty/simpletest/form.php b/thirdparty/simpletest/form.php deleted file mode 100644 index 2919883ef..000000000 --- a/thirdparty/simpletest/form.php +++ /dev/null @@ -1,355 +0,0 @@ -_method = $tag->getAttribute('method'); - $this->_action = $this->_createAction($tag->getAttribute('action'), $page); - $this->_encoding = $this->_setEncodingClass($tag); - $this->_default_target = false; - $this->_id = $tag->getAttribute('id'); - $this->_buttons = array(); - $this->_images = array(); - $this->_widgets = array(); - $this->_radios = array(); - $this->_checkboxes = array(); - } - - /** - * Creates the request packet to be sent by the form. - * @param SimpleTag $tag Form tag to read. - * @return string Packet class. - * @access private - */ - function _setEncodingClass($tag) { - if (strtolower($tag->getAttribute('method') ?? '') == 'post') { - if (strtolower($tag->getAttribute('enctype') ?? '') == 'multipart/form-data') { - return 'SimpleMultipartEncoding'; - } - return '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. - */ - 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); - } - return $url; - } - - /** - * Creates the encoding for the current values in the - * form. - * @return SimpleFormEncoding Request to submit. - * @access private - */ - function _encode() { - $class = $this->_encoding; - $encoding = new $class(); - for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) { - $this->_widgets[$i]->write($encoding, 0, 0); - } - return $encoding; - } - - /** - * ID field of form for unique identification. - * @return string Unique tag ID. - * @access public - */ - function getId() { - return $this->_id; - } - - /** - * Adds a tag contents to the form. - * @param SimpleWidget $tag Input tag to add. - * @access public - */ - function addWidget(&$tag) { - if (strtolower($tag->getAttribute('type') ?? '') == 'submit') { - $this->_buttons[] = &$tag; - } elseif (strtolower($tag->getAttribute('type') ?? '') == 'image') { - $this->_images[] = &$tag; - } elseif ($tag->getName()) { - $this->_setWidget($tag); - } - } - - /** - * Sets the widget into the form, grouping radio - * buttons if any. - * @param SimpleWidget $tag Incoming form control. - * @access private - */ - function _setWidget(&$tag) { - if (strtolower($tag->getAttribute('type') ?? '') == 'radio') { - $this->_addRadioButton($tag); - } elseif (strtolower($tag->getAttribute('type') ?? '') == 'checkbox') { - $this->_addCheckbox($tag); - } else { - $this->_widgets[] = &$tag; - } - } - - /** - * Adds a radio button, building a group if necessary. - * @param SimpleRadioButtonTag $tag Incoming form control. - * @access private - */ - function _addRadioButton(&$tag) { - if (! isset($this->_radios[$tag->getName()])) { - $this->_widgets[] = new SimpleRadioGroup(); - $this->_radios[$tag->getName()] = count($this->_widgets ?? []) - 1; - } - $this->_widgets[$this->_radios[$tag->getName()]]->addWidget($tag); - } - - /** - * Adds a checkbox, making it a group on a repeated name. - * @param SimpleCheckboxTag $tag Incoming form control. - * @access private - */ - function _addCheckbox(&$tag) { - if (! isset($this->_checkboxes[$tag->getName()])) { - $this->_widgets[] = &$tag; - $this->_checkboxes[$tag->getName()] = count($this->_widgets ?? []) - 1; - } else { - $index = $this->_checkboxes[$tag->getName()]; - if (! SimpleTestCompatibility::isA($this->_widgets[$index], 'SimpleCheckboxGroup')) { - $previous = &$this->_widgets[$index]; - $this->_widgets[$index] = new SimpleCheckboxGroup(); - $this->_widgets[$index]->addWidget($previous); - } - $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, 0, 0); - if ($additional) { - $encoding->merge($additional); - } - return $encoding; - } - } - return false; - } - - /** - * Gets the submit values for an image. - * @param SimpleSelector $selector Criteria to apply. - * @param integer $x X-coordinate of click. - * @param integer $y Y-coordinate of click. - * @param hash $additional Additional data for the form. - * @return SimpleEncoding Submitted values or false - * if there is no such button in the - * form. - * @access public - */ - function submitImage($selector, $x, $y, $additional = false) { - $additional = $additional ? $additional : array(); - foreach ($this->_images as $image) { - if ($selector->isMatch($image)) { - $encoding = $this->_encode(); - $image->write($encoding, $x, $y); - if ($additional) { - $encoding->merge($additional); - } - return $encoding; - } - } - return false; - } - - /** - * Simply submits the form without the submit button - * value. Used when there is only one button or it - * is unimportant. - * @return hash Submitted values. - * @access public - */ - function submit() { - return $this->_encode(); - } -} -?> diff --git a/thirdparty/simpletest/http.php b/thirdparty/simpletest/http.php deleted file mode 100644 index 3a64efd65..000000000 --- a/thirdparty/simpletest/http.php +++ /dev/null @@ -1,624 +0,0 @@ -_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 - */ - 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 - */ - 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 - */ - function &_createSocket($scheme, $host, $port, $timeout) { - if (in_array($scheme, array('https'))) { - $socket = new SimpleSecureSocket($host, $port, $timeout); - } else { - $socket = new SimpleSocket($host, $port, $timeout); - } - return $socket; - } -} - -/** - * Creates HTTP headers for the end point of - * a HTTP request via a proxy server. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleProxyRoute extends SimpleRoute { - var $_proxy; - var $_username; - var $_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 { - var $_route; - var $_encoding; - var $_headers; - var $_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); - } - $response = &$this->_createResponse($socket); - return $response; - } - - /** - * 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 - */ - 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 - */ - function &_createResponse(&$socket) { - $response = new SimpleHttpResponse( - $socket, - $this->_route->getUrl(), - $this->_encoding); - return $response; - } -} - -/** - * Collection of header lines in the response. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleHttpHeaders { - var $_raw_headers; - var $_response_code; - var $_http_version; - var $_mime_type; - var $_location; - var $_cookies; - var $_authentication; - var $_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 (preg_split("/\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 - */ - 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 - */ - function _parseCookie($cookie_line) { - $parts = preg_split('/;/', $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 { - var $_url; - var $_encoding; - var $_sent; - var $_content; - var $_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 - */ - function _parse($raw) { - if (! $raw) { - $this->_setError('Nothing fetched'); - $this->_headers = new SimpleHttpHeaders(''); - } 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) = preg_split("/\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 - */ - 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 - */ - function _isLastPacket($packet) { - if (is_string($packet)) { - return $packet === ''; - } - return ! $packet; - } -} -?> diff --git a/thirdparty/simpletest/page.php b/thirdparty/simpletest/page.php deleted file mode 100644 index c4e5a7cc6..000000000 --- a/thirdparty/simpletest/page.php +++ /dev/null @@ -1,984 +0,0 @@ - 'SimpleAnchorTag', - 'title' => 'SimpleTitleTag', - 'base' => 'SimpleBaseTag', - 'button' => 'SimpleButtonTag', - 'textarea' => 'SimpleTextAreaTag', - 'option' => 'SimpleOptionTag', - 'label' => 'SimpleLabelTag', - 'form' => 'SimpleFormTag', - 'frame' => 'SimpleFrameTag'); - $attributes = $this->_keysToLowerCase($attributes); - if (array_key_exists($name, $map ?? [])) { - $tag_class = $map[$name]; - return new $tag_class($attributes); - } elseif ($name == 'select') { - return $this->_createSelectionTag($attributes); - } elseif ($name == 'input') { - return $this->_createInputTag($attributes); - } - return new SimpleTag($name, $attributes); - } - - /** - * Factory for selection fields. - * @param hash $attributes Element attributes. - * @return SimpleTag Tag object. - * @access protected - */ - function _createSelectionTag($attributes) { - if (isset($attributes['multiple'])) { - return new MultipleSelectionTag($attributes); - } - return new SimpleSelectionTag($attributes); - } - - /** - * Factory for input tags. - * @param hash $attributes Element attributes. - * @return SimpleTag Tag object. - * @access protected - */ - function _createInputTag($attributes) { - if (! isset($attributes['type'])) { - return new SimpleTextTag($attributes); - } - $type = strtolower(trim($attributes['type'] ?? '')); - $map = array( - 'submit' => 'SimpleSubmitTag', - 'image' => 'SimpleImageSubmitTag', - 'checkbox' => 'SimpleCheckboxTag', - 'radio' => 'SimpleRadioButtonTag', - 'text' => 'SimpleTextTag', - 'email' => 'SimpleTextTag', - 'hidden' => 'SimpleTextTag', - 'password' => 'SimpleTextTag', - 'file' => 'SimpleUploadTag'); - if (array_key_exists($type, $map ?? [])) { - $tag_class = $map[$type]; - return new $tag_class($attributes); - } - return new SimpleTextTag($attributes); - } - - /** - * Make the keys lower case for case insensitive look-ups. - * @param hash $map Hash to convert. - * @return hash Unchanged values, but keys lower case. - * @access private - */ - function _keysToLowerCase($map) { - $lower = array(); - foreach ($map as $key => $value) { - $lower[strtolower($key)] = $value; - } - return $lower; - } -} - -/** - * SAX event handler. Maintains a list of - * open tags and dispatches them as they close. - * @package SimpleTest - * @subpackage WebTester - */ -class SimplePageBuilder extends SimpleSaxListener { - var $_tags; - var $_page; - var $_private_content_tag; - - /** - * Sets the builder up empty. - * @access public - */ - function __construct() { - parent::__construct(); - } - - /** - * Frees up any references so as to allow the PHP garbage - * collection from unset() to work. - * @access public - */ - function free() { - unset($this->_tags); - unset($this->_page); - unset($this->_private_content_tags); - } - - /** - * Reads the raw content and send events - * into the page to be built. - * @param $response SimpleHttpResponse Fetched response. - * @return SimplePage Newly parsed page. - * @access public - */ - function &parse($response) { - $this->_tags = array(); - $this->_page = &$this->_createPage($response); - $parser = &$this->_createParser($this); - $parser->parse($response->getContent()); - $this->_page->acceptPageEnd(); - return $this->_page; - } - - /** - * Creates an empty page. - * @return SimplePage New unparsed page. - * @access protected - */ - function &_createPage($response) { - $page = new SimplePage($response); - return $page; - } - - /** - * Creates the parser used with the builder. - * @param $listener SimpleSaxListener Target of parser. - * @return SimpleSaxParser Parser to generate - * events for the builder. - * @access protected - */ - function &_createParser(&$listener) { - $parser = new SimpleHtmlSaxParser($listener); - return $parser; - } - - /** - * Start of element event. Opens a new tag. - * @param string $name Element name. - * @param hash $attributes Attributes without content - * are marked as true. - * @return boolean False on parse error. - * @access public - */ - function startElement($name, $attributes) { - $factory = new SimpleTagBuilder(); - $tag = $factory->createTag($name, $attributes); - if (! $tag) { - return true; - } - if ($tag->getTagName() == 'label') { - $this->_page->acceptLabelStart($tag); - $this->_openTag($tag); - return true; - } - if ($tag->getTagName() == 'form') { - $this->_page->acceptFormStart($tag); - return true; - } - if ($tag->getTagName() == 'frameset') { - $this->_page->acceptFramesetStart($tag); - return true; - } - if ($tag->getTagName() == 'frame') { - $this->_page->acceptFrame($tag); - return true; - } - if ($tag->isPrivateContent() && ! isset($this->_private_content_tag)) { - $this->_private_content_tag = &$tag; - } - if ($tag->expectEndTag()) { - $this->_openTag($tag); - return true; - } - $this->_page->acceptTag($tag); - return true; - } - - /** - * End of element event. - * @param string $name Element name. - * @return boolean False on parse error. - * @access public - */ - function endElement($name) { - if ($name == 'label') { - $this->_page->acceptLabelEnd(); - return true; - } - if ($name == 'form') { - $this->_page->acceptFormEnd(); - return true; - } - if ($name == 'frameset') { - $this->_page->acceptFramesetEnd(); - return true; - } - if ($this->_hasNamedTagOnOpenTagStack($name)) { - $tag = array_pop($this->_tags[$name]); - if ($tag->isPrivateContent() && $this->_private_content_tag->getTagName() == $name) { - unset($this->_private_content_tag); - } - $this->_addContentTagToOpenTags($tag); - $this->_page->acceptTag($tag); - return true; - } - return true; - } - - /** - * Test to see if there are any open tags awaiting - * closure that match the tag name. - * @param string $name Element name. - * @return boolean True if any are still open. - * @access private - */ - function _hasNamedTagOnOpenTagStack($name) { - return isset($this->_tags[$name]) && (count($this->_tags[$name] ?? []) > 0); - } - - /** - * Unparsed, but relevant data. The data is added - * to every open tag. - * @param string $text May include unparsed tags. - * @return boolean False on parse error. - * @access public - */ - function addContent($text) { - if (isset($this->_private_content_tag)) { - $this->_private_content_tag->addContent($text); - } else { - $this->_addContentToAllOpenTags($text); - } - return true; - } - - /** - * Any content fills all currently open tags unless it - * is part of an option tag. - * @param string $text May include unparsed tags. - * @access private - */ - function _addContentToAllOpenTags($text) { - foreach (array_keys($this->_tags ?? []) as $name) { - for ($i = 0, $count = count($this->_tags[$name]); $i < $count; $i++) { - $this->_tags[$name][$i]->addContent($text); - } - } - } - - /** - * Parsed data in tag form. The parsed tag is added - * to every open tag. Used for adding options to select - * fields only. - * @param SimpleTag $tag Option tags only. - * @access private - */ - function _addContentTagToOpenTags(&$tag) { - if ($tag->getTagName() != 'option') { - return; - } - foreach (array_keys($this->_tags ?? []) as $name) { - for ($i = 0, $count = count($this->_tags[$name]); $i < $count; $i++) { - $this->_tags[$name][$i]->addTag($tag); - } - } - } - - /** - * Opens a tag for receiving content. Multiple tags - * will be receiving input at the same time. - * @param SimpleTag $tag New content tag. - * @access private - */ - function _openTag(&$tag) { - $name = $tag->getTagName(); - if (! in_array($name, array_keys($this->_tags ?? []))) { - $this->_tags[$name] = array(); - } - $this->_tags[$name][] = &$tag; - } -} - -/** - * A wrapper for a web page. - * @package SimpleTest - * @subpackage WebTester - */ -class SimplePage { - var $_links; - var $_title; - var $_last_widget; - var $_label; - var $_left_over_labels; - var $_open_forms; - var $_complete_forms; - var $_frameset; - var $_frames; - var $_frameset_nesting_level; - var $_transport_error; - var $_raw; - var $_text; - var $_sent; - var $_headers; - var $_method; - var $_url; - var $_base = false; - var $_request_data; - - /** - * Parses a page ready to access it's contents. - * @param SimpleHttpResponse $response Result of HTTP fetch. - * @access public - */ - function __construct($response = false) { - $this->_links = array(); - $this->_title = false; - $this->_left_over_labels = array(); - $this->_open_forms = array(); - $this->_complete_forms = array(); - $this->_frameset = false; - $this->_frames = array(); - $this->_frameset_nesting_level = 0; - $this->_text = false; - if ($response) { - $this->_extractResponse($response); - } else { - $this->_noResponse(); - } - } - - /** - * Extracts all of the response information. - * @param SimpleHttpResponse $response Response being parsed. - * @access private - */ - 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 - */ - 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 = SimpleHtmlSaxParser::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() { - } - - /** - * Adds a tag to the page. - * @param SimpleTag $tag Tag to accept. - * @access public - */ - function acceptTag(&$tag) { - if ($tag->getTagName() == "a") { - $this->_addLink($tag); - } elseif ($tag->getTagName() == "base") { - $this->_setBase($tag); - } elseif ($tag->getTagName() == "title") { - $this->_setTitle($tag); - } elseif ($this->_isFormElement($tag->getTagName())) { - for ($i = 0; $i < count($this->_open_forms ?? []); $i++) { - $this->_open_forms[$i]->addWidget($tag); - } - $this->_last_widget = &$tag; - } - } - - /** - * Opens a label for a described widget. - * @param SimpleFormTag $tag Tag to accept. - * @access public - */ - function acceptLabelStart(&$tag) { - $this->_label = &$tag; - unset($this->_last_widget); - } - - /** - * Closes the most recently opened label. - * @access public - */ - function acceptLabelEnd() { - if (isset($this->_label)) { - if (isset($this->_last_widget)) { - $this->_last_widget->setLabel($this->_label->getText()); - unset($this->_last_widget); - } else { - $this->_left_over_labels[] = SimpleTestCompatibility::copy($this->_label); - } - unset($this->_label); - } - } - - /** - * Tests to see if a tag is a possible form - * element. - * @param string $name HTML element name. - * @return boolean True if form element. - * @access private - */ - function _isFormElement($name) { - return in_array($name, array('input', 'button', 'textarea', 'select')); - } - - /** - * Opens a form. New widgets go here. - * @param SimpleFormTag $tag Tag to accept. - * @access public - */ - function acceptFormStart(&$tag) { - $this->_open_forms[] = new SimpleForm($tag, $this); - } - - /** - * Closes the most recently opened form. - * @access public - */ - function acceptFormEnd() { - if (count($this->_open_forms ?? [])) { - $this->_complete_forms[] = array_pop($this->_open_forms); - } - } - - /** - * Opens a frameset. A frameset may contain nested - * frameset tags. - * @param SimpleFramesetTag $tag Tag to accept. - * @access public - */ - function acceptFramesetStart(&$tag) { - if (! $this->_isLoadingFrames()) { - $this->_frameset = &$tag; - } - $this->_frameset_nesting_level++; - } - - /** - * Closes the most recently opened frameset. - * @access public - */ - function acceptFramesetEnd() { - if ($this->_isLoadingFrames()) { - $this->_frameset_nesting_level--; - } - } - - /** - * Takes a single frame tag and stashes it in - * the current frame set. - * @param SimpleFrameTag $tag Tag to accept. - * @access public - */ - function acceptFrame(&$tag) { - if ($this->_isLoadingFrames()) { - if ($tag->getAttribute('src')) { - $this->_frames[] = &$tag; - } - } - } - - /** - * Test to see if in the middle of reading - * a frameset. - * @return boolean True if inframeset. - * @access private - */ - function _isLoadingFrames() { - if (! $this->_frameset) { - return false; - } - return ($this->_frameset_nesting_level > 0); - } - - /** - * Test to see if link is an absolute one. - * @param string $url Url to test. - * @return boolean True if absolute. - * @access 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. - * @access protected - */ - function _addLink($tag) { - $this->_links[] = $tag; - } - - /** - * Marker for end of complete page. Any work in - * progress can now be closed. - * @access public - */ - function acceptPageEnd() { - while (count($this->_open_forms ?? [])) { - $this->_complete_forms[] = array_pop($this->_open_forms); - } - foreach ($this->_left_over_labels as $label) { - for ($i = 0, $count = count($this->_complete_forms); $i < $count; $i++) { - $this->_complete_forms[$i]->attachLabelBySelector( - new SimpleById($label->getFor()), - $label->getText()); - } - } - } - - /** - * Test for the presence of a frameset. - * @return boolean True if frameset. - * @access public - */ - function hasFrames() { - return (boolean)$this->_frameset; - } - - /** - * 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->_frameset) { - 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 - */ - 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 SimpleTag $tag Base URL for page. - * @access protected - */ - function _setBase(&$tag) { - $url = $tag->getAttribute('href'); - $this->_base = new SimpleUrl($url); - } - - /** - * Sets the title tag contents. - * @param SimpleTitleTag $tag Title of page. - * @access protected - */ - 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->_complete_forms ?? []); $i++) { - if ($this->_complete_forms[$i]->hasSubmit($selector)) { - return $this->_complete_forms[$i]; - } - } - $null = null; - 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->_complete_forms ?? []); $i++) { - if ($this->_complete_forms[$i]->hasImage($selector)) { - return $this->_complete_forms[$i]; - } - } - $null = null; - 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->_complete_forms ?? []); $i++) { - if ($this->_complete_forms[$i]->getId() == $id) { - return $this->_complete_forms[$i]; - } - } - $null = null; - 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->_complete_forms ?? []); $i++) { - if ($this->_complete_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->_complete_forms ?? []); $i++) { - $value = $this->_complete_forms[$i]->getValue($selector); - if (isset($value)) { - return $value; - } - } - return null; - } -} - diff --git a/thirdparty/simpletest/parser.php b/thirdparty/simpletest/parser.php deleted file mode 100644 index e7ae6dbe9..000000000 --- a/thirdparty/simpletest/parser.php +++ /dev/null @@ -1,764 +0,0 @@ - $constant) { - if (! defined($constant)) { - define($constant, $i + 1); - } -} -/**#@-*/ - -/** - * Compounded regular expression. Any of - * the contained patterns could match and - * when one does, it's label is returned. - * @package SimpleTest - * @subpackage WebTester - */ -class ParallelRegex { - var $_patterns; - var $_labels; - var $_regex; - var $_case; - - /** - * Constructor. Starts with no patterns. - * @param boolean $case True for case sensitive, false - * for insensitive. - * @access public - */ - function __construct($case) { - $this->_case = $case; - $this->_patterns = array(); - $this->_labels = array(); - $this->_regex = null; - } - - /** - * Adds a pattern with an optional label. - * @param string $pattern Perl style regex, but ( and ) - * lose the usual meaning. - * @param string $label Label of regex to be returned - * on a match. - * @access public - */ - function addPattern($pattern, $label = true) { - $count = count($this->_patterns ?? []); - $this->_patterns[$count] = $pattern; - $this->_labels[$count] = $label; - $this->_regex = null; - } - - /** - * Attempts to match all patterns at once against - * a string. - * @param string $subject String to match against. - * @param string $match First matched portion of - * subject. - * @return boolean True on success. - * @access public - */ - function match($subject, &$match) { - if (count($this->_patterns ?? []) == 0) { - return false; - } - if (! preg_match($this->_getCompoundedRegex() ?? '', $subject ?? '', $matches)) { - $match = ''; - return false; - } - $match = $matches[0]; - for ($i = 1; $i < count($matches ?? []); $i++) { - if ($matches[$i]) { - return $this->_labels[$i - 1]; - } - } - return true; - } - - /** - * Compounds the patterns into a single - * regular expression separated with the - * "or" operator. Caches the regex. - * Will automatically escape (, ) and / tokens. - * @param array $patterns List of patterns in order. - * @access private - */ - function _getCompoundedRegex() { - if ($this->_regex == null) { - for ($i = 0, $count = count($this->_patterns); $i < $count; $i++) { - $this->_patterns[$i] = '(' . str_replace( - array('/', '(', ')'), - array('\/', '\(', '\)'), - $this->_patterns[$i] ?? '') . ')'; - } - $this->_regex = "/" . implode("|", $this->_patterns) . "/" . $this->_getPerlMatchingFlags(); - } - return $this->_regex; - } - - /** - * Accessor for perl regex mode flags to use. - * @return string Perl regex flags. - * @access private - */ - function _getPerlMatchingFlags() { - return ($this->_case ? "msS" : "msSi"); - } -} - -/** - * States for a stack machine. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleStateStack { - var $_stack; - - /** - * Constructor. Starts in named state. - * @param string $start Starting state name. - * @access public - */ - function __construct($start) { - $this->_stack = array($start); - } - - /** - * Accessor for current state. - * @return string State. - * @access public - */ - function getCurrent() { - return $this->_stack[count($this->_stack) - 1]; - } - - /** - * Adds a state to the stack and sets it - * to be the current state. - * @param string $state New state. - * @access public - */ - function enter($state) { - array_push($this->_stack, $state); - } - - /** - * Leaves the current state and reverts - * to the previous one. - * @return boolean False if we drop off - * the bottom of the list. - * @access public - */ - function leave() { - if (count($this->_stack ?? []) == 1) { - return false; - } - array_pop($this->_stack); - return true; - } -} - -/** - * Accepts text and breaks it into tokens. - * Some optimisation to make the sure the - * content is only scanned by the PHP regex - * parser once. Lexer modes must not start - * with leading underscores. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleLexer { - var $_regexes; - var $_parser; - var $_mode; - var $_mode_handlers; - var $_case; - - /** - * Sets up the lexer in case insensitive matching - * by default. - * @param SimpleSaxParser $parser Handling strategy by - * reference. - * @param string $start Starting handler. - * @param boolean $case True for case sensitive. - * @access public - */ - function __construct(&$parser, $start = "accept", $case = false) { - $this->_case = $case; - $this->_regexes = array(); - $this->_parser = &$parser; - $this->_mode = new SimpleStateStack($start); - $this->_mode_handlers = array($start => $start); - } - - /** - * Adds a token search pattern for a particular - * parsing mode. The pattern does not change the - * current mode. - * @param string $pattern Perl style regex, but ( and ) - * lose the usual meaning. - * @param string $mode Should only apply this - * pattern when dealing with - * this type of input. - * @access public - */ - function addPattern($pattern, $mode = "accept") { - if (! isset($this->_regexes[$mode])) { - $this->_regexes[$mode] = new ParallelRegex($this->_case); - } - $this->_regexes[$mode]->addPattern($pattern); - if (! isset($this->_mode_handlers[$mode])) { - $this->_mode_handlers[$mode] = $mode; - } - } - - /** - * Adds a pattern that will enter a new parsing - * mode. Useful for entering parenthesis, strings, - * tags, etc. - * @param string $pattern Perl style regex, but ( and ) - * lose the usual meaning. - * @param string $mode Should only apply this - * pattern when dealing with - * this type of input. - * @param string $new_mode Change parsing to this new - * nested mode. - * @access public - */ - function addEntryPattern($pattern, $mode, $new_mode) { - if (! isset($this->_regexes[$mode])) { - $this->_regexes[$mode] = new ParallelRegex($this->_case); - } - $this->_regexes[$mode]->addPattern($pattern, $new_mode); - if (! isset($this->_mode_handlers[$new_mode])) { - $this->_mode_handlers[$new_mode] = $new_mode; - } - } - - /** - * Adds a pattern that will exit the current mode - * and re-enter the previous one. - * @param string $pattern Perl style regex, but ( and ) - * lose the usual meaning. - * @param string $mode Mode to leave. - * @access public - */ - function addExitPattern($pattern, $mode) { - if (! isset($this->_regexes[$mode])) { - $this->_regexes[$mode] = new ParallelRegex($this->_case); - } - $this->_regexes[$mode]->addPattern($pattern, "__exit"); - if (! isset($this->_mode_handlers[$mode])) { - $this->_mode_handlers[$mode] = $mode; - } - } - - /** - * Adds a pattern that has a special mode. Acts as an entry - * and exit pattern in one go, effectively calling a special - * parser handler for this token only. - * @param string $pattern Perl style regex, but ( and ) - * lose the usual meaning. - * @param string $mode Should only apply this - * pattern when dealing with - * this type of input. - * @param string $special Use this mode for this one token. - * @access public - */ - function addSpecialPattern($pattern, $mode, $special) { - if (! isset($this->_regexes[$mode])) { - $this->_regexes[$mode] = new ParallelRegex($this->_case); - } - $this->_regexes[$mode]->addPattern($pattern, "_$special"); - if (! isset($this->_mode_handlers[$special])) { - $this->_mode_handlers[$special] = $special; - } - } - - /** - * Adds a mapping from a mode to another handler. - * @param string $mode Mode to be remapped. - * @param string $handler New target handler. - * @access public - */ - function mapHandler($mode, $handler) { - $this->_mode_handlers[$mode] = $handler; - } - - /** - * Splits the page text into tokens. Will fail - * if the handlers report an error or if no - * content is consumed. If successful then each - * unparsed and parsed token invokes a call to the - * held listener. - * @param string $raw Raw HTML text. - * @return boolean True on success, else false. - * @access public - */ - function parse($raw) { - if (! isset($this->_parser)) { - return false; - } - $length = strlen($raw ?? ''); - while (is_array($parsed = $this->_reduce($raw))) { - list($raw, $unmatched, $matched, $mode) = $parsed; - if (! $this->_dispatchTokens($unmatched, $matched, $mode)) { - return false; - } - if ($raw === '') { - return true; - } - if (strlen($raw ?? '') == $length) { - return false; - } - $length = strlen($raw ?? ''); - } - if (! $parsed) { - return false; - } - return $this->_invokeParser($raw, LEXER_UNMATCHED); - } - - /** - * Sends the matched token and any leading unmatched - * text to the parser changing the lexer to a new - * mode if one is listed. - * @param string $unmatched Unmatched leading portion. - * @param string $matched Actual token match. - * @param string $mode Mode after match. A boolean - * false mode causes no change. - * @return boolean False if there was any error - * from the parser. - * @access private - */ - function _dispatchTokens($unmatched, $matched, $mode = false) { - if (! $this->_invokeParser($unmatched, LEXER_UNMATCHED)) { - return false; - } - if (is_bool($mode)) { - return $this->_invokeParser($matched, LEXER_MATCHED); - } - if ($this->_isModeEnd($mode)) { - if (! $this->_invokeParser($matched, LEXER_EXIT)) { - return false; - } - return $this->_mode->leave(); - } - if ($this->_isSpecialMode($mode)) { - $this->_mode->enter($this->_decodeSpecial($mode)); - if (! $this->_invokeParser($matched, LEXER_SPECIAL)) { - return false; - } - return $this->_mode->leave(); - } - $this->_mode->enter($mode); - return $this->_invokeParser($matched, LEXER_ENTER); - } - - /** - * Tests to see if the new mode is actually to leave - * the current mode and pop an item from the matching - * mode stack. - * @param string $mode Mode to test. - * @return boolean True if this is the exit mode. - * @access private - */ - function _isModeEnd($mode) { - return ($mode === "__exit"); - } - - /** - * Test to see if the mode is one where this mode - * is entered for this token only and automatically - * leaves immediately afterwoods. - * @param string $mode Mode to test. - * @return boolean True if this is the exit mode. - * @access private - */ - function _isSpecialMode($mode) { - return (strncmp($mode ?? '', "_", 1) == 0); - } - - /** - * Strips the magic underscore marking single token - * modes. - * @param string $mode Mode to decode. - * @return string Underlying mode name. - * @access private - */ - function _decodeSpecial($mode) { - return substr($mode ?? '', 1); - } - - /** - * Calls the parser method named after the current - * mode. Empty content will be ignored. The lexer - * has a parser handler for each mode in the lexer. - * @param string $content Text parsed. - * @param boolean $is_match Token is recognised rather - * than unparsed data. - * @access private - */ - function _invokeParser($content, $is_match) { - if (($content === '') || ($content === false)) { - return true; - } - $handler = $this->_mode_handlers[$this->_mode->getCurrent()]; - return $this->_parser->$handler($content, $is_match); - } - - /** - * Tries to match a chunk of text and if successful - * removes the recognised chunk and any leading - * unparsed data. Empty strings will not be matched. - * @param string $raw The subject to parse. This is the - * content that will be eaten. - * @return array/boolean Three item list of unparsed - * content followed by the - * recognised token and finally the - * action the parser is to take. - * True if no match, false if there - * is a parsing error. - * @access private - */ - function _reduce($raw) { - if ($action = $this->_regexes[$this->_mode->getCurrent()]->match($raw, $match)) { - $unparsed_character_count = strpos($raw ?? '', $match ?? ''); - $unparsed = substr($raw ?? '', 0, $unparsed_character_count); - $raw = substr($raw ?? '', $unparsed_character_count + strlen($match ?? '')); - return array($raw, $unparsed, $match, $action); - } - return true; - } -} - -/** - * Breaks HTML into SAX events. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleHtmlLexer extends SimpleLexer { - - /** - * Sets up the lexer with case insensitive matching - * and adds the HTML handlers. - * @param SimpleSaxParser $parser Handling strategy by - * reference. - * @access public - */ - function __construct(&$parser) { - parent::__construct($parser, 'text'); - $this->mapHandler('text', 'acceptTextToken'); - $this->_addSkipping(); - foreach ($this->_getParsedTags() as $tag) { - $this->_addTag($tag); - } - $this->_addInTagTokens(); - } - - /** - * List of parsed tags. Others are ignored. - * @return array List of searched for tags. - * @access private - */ - function _getParsedTags() { - return array('a', 'base', 'title', 'form', 'input', 'button', 'textarea', 'select', - 'option', 'frameset', 'frame', 'label'); - } - - /** - * The lexer has to skip certain sections such - * as server code, client code and styles. - * @access private - */ - function _addSkipping() { - $this->mapHandler('css', 'ignore'); - $this->addEntryPattern('addExitPattern('', 'css'); - $this->mapHandler('js', 'ignore'); - $this->addEntryPattern('addExitPattern('', 'js'); - $this->mapHandler('comment', 'ignore'); - $this->addEntryPattern('', 'comment'); - } - - /** - * Pattern matches to start and end a tag. - * @param string $tag Name of tag to scan for. - * @access private - */ - function _addTag($tag) { - $this->addSpecialPattern("", 'text', 'acceptEndToken'); - $this->addEntryPattern("<$tag", 'text', 'tag'); - } - - /** - * Pattern matches to parse the inside of a tag - * including the attributes and their quoting. - * @access private - */ - function _addInTagTokens() { - $this->mapHandler('tag', 'acceptStartToken'); - $this->addSpecialPattern('\s+', 'tag', 'ignore'); - $this->_addAttributeTokens(); - $this->addExitPattern('/>', 'tag'); - $this->addExitPattern('>', 'tag'); - } - - /** - * Matches attributes that are either single quoted, - * double quoted or unquoted. - * @access private - */ - function _addAttributeTokens() { - $this->mapHandler('dq_attribute', 'acceptAttributeToken'); - $this->addEntryPattern('=\s*"', 'tag', 'dq_attribute'); - $this->addPattern("\\\\\"", 'dq_attribute'); - $this->addExitPattern('"', 'dq_attribute'); - $this->mapHandler('sq_attribute', 'acceptAttributeToken'); - $this->addEntryPattern("=\s*'", 'tag', 'sq_attribute'); - $this->addPattern("\\\\'", 'sq_attribute'); - $this->addExitPattern("'", 'sq_attribute'); - $this->mapHandler('uq_attribute', 'acceptAttributeToken'); - $this->addSpecialPattern('=\s*[^>\s]*', 'tag', 'uq_attribute'); - } -} - -/** - * Converts HTML tokens into selected SAX events. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleHtmlSaxParser { - var $_lexer; - var $_listener; - var $_tag; - var $_attributes; - var $_current_attribute; - - /** - * Sets the listener. - * @param SimpleSaxListener $listener SAX event handler. - * @access public - */ - function __construct(&$listener) { - $this->_listener = &$listener; - $this->_lexer = &$this->createLexer($this); - $this->_tag = ''; - $this->_attributes = array(); - $this->_current_attribute = ''; - } - - /** - * Runs the content through the lexer which - * should call back to the acceptors. - * @param string $raw Page text to parse. - * @return boolean False if parse error. - * @access public - */ - function parse($raw) { - return $this->_lexer->parse($raw); - } - - /** - * Sets up the matching lexer. Starts in 'text' mode. - * @param SimpleSaxParser $parser Event generator, usually $self. - * @return SimpleLexer Lexer suitable for this parser. - * @access public - * @static - */ - function &createLexer(&$parser) { - $lexer = new SimpleHtmlLexer($parser); - return $lexer; - } - - /** - * Accepts a token from the tag mode. If the - * starting element completes then the element - * is dispatched and the current attributes - * set back to empty. The element or attribute - * name is converted to lower case. - * @param string $token Incoming characters. - * @param integer $event Lexer event type. - * @return boolean False if parse error. - * @access public - */ - function acceptStartToken($token, $event) { - if ($event == LEXER_ENTER) { - $this->_tag = strtolower(substr($token ?? '', 1)); - return true; - } - if ($event == LEXER_EXIT) { - $success = $this->_listener->startElement( - $this->_tag, - $this->_attributes); - $this->_tag = ''; - $this->_attributes = array(); - return $success; - } - if ($token != '=') { - $this->_current_attribute = strtolower(SimpleHtmlSaxParser::decodeHtml($token) ?? ''); - $this->_attributes[$this->_current_attribute] = ''; - } - return true; - } - - /** - * Accepts a token from the end tag mode. - * The element name is converted to lower case. - * @param string $token Incoming characters. - * @param integer $event Lexer event type. - * @return boolean False if parse error. - * @access public - */ - function acceptEndToken($token, $event) { - if (! preg_match('/<\/(.*)>/', $token ?? '', $matches)) { - return false; - } - return $this->_listener->endElement(strtolower($matches[1] ?? '')); - } - - /** - * Part of the tag data. - * @param string $token Incoming characters. - * @param integer $event Lexer event type. - * @return boolean False if parse error. - * @access public - */ - function acceptAttributeToken($token, $event) { - if ($this->_current_attribute) { - if ($event == LEXER_UNMATCHED) { - $this->_attributes[$this->_current_attribute] .= - SimpleHtmlSaxParser::decodeHtml($token); - } - if ($event == LEXER_SPECIAL) { - $this->_attributes[$this->_current_attribute] .= - preg_replace('/^=\s*/' , '', SimpleHtmlSaxParser::decodeHtml($token) ?? ''); - } - } - return true; - } - - /** - * A character entity. - * @param string $token Incoming characters. - * @param integer $event Lexer event type. - * @return boolean False if parse error. - * @access public - */ - function acceptEntityToken($token, $event) { - } - - /** - * Character data between tags regarded as - * important. - * @param string $token Incoming characters. - * @param integer $event Lexer event type. - * @return boolean False if parse error. - * @access public - */ - function acceptTextToken($token, $event) { - return $this->_listener->addContent($token); - } - - /** - * Incoming data to be ignored. - * @param string $token Incoming characters. - * @param integer $event Lexer event type. - * @return boolean False if parse error. - * @access public - */ - function ignore($token, $event) { - return true; - } - - /** - * Decodes any HTML entities. - * @param string $html Incoming HTML. - * @return string Outgoing plain text. - * @access public - * @static - */ - static function decodeHtml($html) { - return html_entity_decode($html ?? '', ENT_QUOTES); - } - - /** - * 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 - */ - static function normalise($html) { - $text = preg_replace('||', '', $html ?? ''); - $text = preg_replace('|]*>.*?|', '', $text ?? ''); - $text = preg_replace('|]*alt\s*=\s*"([^"]*)"[^>]*>|', ' \1 ', $text ?? ''); - $text = preg_replace('|]*alt\s*=\s*\'([^\']*)\'[^>]*>|', ' \1 ', $text ?? ''); - $text = preg_replace('|]*alt\s*=\s*([a-zA-Z_]+)[^>]*>|', ' \1 ', $text ?? ''); - $text = preg_replace('|<[^>]*>|', '', $text ?? ''); - $text = SimpleHtmlSaxParser::decodeHtml($text); - $text = preg_replace('|\s+|', ' ', $text ?? ''); - return trim(trim($text ?? ''), "\xA0"); // TODO: The \xAO is a  . Add a test for this. - } -} - -/** - * SAX event handler. - * @package SimpleTest - * @subpackage WebTester - * @abstract - */ -class SimpleSaxListener { - - /** - * Sets the document to write to. - * @access public - */ - function __construct() { - } - - /** - * Start of element event. - * @param string $name Element name. - * @param hash $attributes Name value pairs. - * Attributes without content - * are marked as true. - * @return boolean False on parse error. - * @access public - */ - function startElement($name, $attributes) { - } - - /** - * End of element event. - * @param string $name Element name. - * @return boolean False on parse error. - * @access public - */ - function endElement($name) { - } - - /** - * Unparsed, but relevant data. - * @param string $text May include unparsed tags. - * @return boolean False on parse error. - * @access public - */ - function addContent($text) { - } -} - diff --git a/thirdparty/simpletest/selector.php b/thirdparty/simpletest/selector.php deleted file mode 100644 index 8fdfbd13e..000000000 --- a/thirdparty/simpletest/selector.php +++ /dev/null @@ -1,137 +0,0 @@ -_name = $name; - } - - 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 { - var $_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 { - var $_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 { - var $_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); - } -} -?> diff --git a/thirdparty/simpletest/socket.php b/thirdparty/simpletest/socket.php deleted file mode 100644 index 8d5b6fb5e..000000000 --- a/thirdparty/simpletest/socket.php +++ /dev/null @@ -1,216 +0,0 @@ -_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(''); - } -} - -/** - * Wrapper for TCP/IP socket. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleSocket extends SimpleStickyError { - var $_handle; - var $_is_open = false; - var $_sent = ''; - var $lock_size; - - /** - * Opens a socket for reading and writing. - * @param string $host Hostname to send request to. - * @param integer $port Port on remote machine to open. - * @param integer $timeout Connection timeout in seconds. - * @param integer $block_size Size of chunk to read. - * @access public - */ - function __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 ?? 0); - if ($raw === false) { - $this->_setError('Cannot read from socket'); - $this->close(); - } - return $raw; - } - - /** - * Accessor for socket open state. - * @return boolean True if open. - * @access public - */ - function isOpen() { - return $this->_is_open; - } - - /** - * Closes the socket preventing further reads. - * Cannot be reopened once closed. - * @return boolean True if successful. - * @access public - */ - function close() { - $this->_is_open = false; - return fclose($this->_handle); - } - - /** - * Accessor for content so far. - * @return string Bytes sent only. - * @access public - */ - function getSent() { - return $this->_sent; - } - - /** - * Actually opens the low level socket. - * @param string $host Host to connect to. - * @param integer $port Port on host. - * @param integer $error_number Recipient of error code. - * @param string $error Recipoent of error message. - * @param integer $timeout Maximum time to wait for connection. - * @access protected - */ - function _openSocket($host, $port, &$error_number, &$error, $timeout) { - return @fsockopen($host ?? '', $port ?? 0, $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); - } -} -?> diff --git a/thirdparty/simpletest/tag.php b/thirdparty/simpletest/tag.php deleted file mode 100644 index 887113a94..000000000 --- a/thirdparty/simpletest/tag.php +++ /dev/null @@ -1,1417 +0,0 @@ -_name = strtolower(trim($name ?? '')); - $this->_attributes = $attributes; - $this->_content = ''; - } - - /** - * Check to see if the tag can have both start and - * end tags with content in between. - * @return boolean True if content allowed. - * @access public - */ - function expectEndTag() { - return true; - } - - /** - * The current tag should not swallow all content for - * itself as it's searchable page content. Private - * content tags are usually widgets that contain default - * values. - * @return boolean False as content is available - * to other tags by default. - * @access public - */ - function isPrivateContent() { - return false; - } - - /** - * Appends string content to the current content. - * @param string $content Additional text. - * @access public - */ - function addContent($content) { - $this->_content .= (string)$content; - } - - /** - * Adds an enclosed tag to the content. - * @param SimpleTag $tag New tag. - * @access public - */ - function addTag(&$tag) { - } - - /** - * Accessor for tag name. - * @return string Name of tag. - * @access public - */ - function getTagName() { - return $this->_name; - } - - /** - * List of legal child elements. - * @return array List of element names. - * @access public - */ - function getChildElements() { - return array(); - } - - /** - * Accessor for an attribute. - * @param string $label Attribute name. - * @return string Attribute value. - * @access public - */ - function getAttribute($label) { - $label = strtolower($label ?? ''); - if (! isset($this->_attributes[$label])) { - return false; - } - return (string)$this->_attributes[$label]; - } - - /** - * Sets an attribute. - * @param string $label Attribute name. - * @return string $value New attribute value. - * @access protected - */ - function _setAttribute($label, $value) { - $this->_attributes[strtolower($label)] = $value; - } - - /** - * Accessor for the whole content so far. - * @return string Content as big raw string. - * @access public - */ - function getContent() { - return $this->_content; - } - - /** - * Accessor for content reduced to visible text. Acts - * like a text mode browser, normalising space and - * reducing images to their alt text. - * @return string Content as plain text. - * @access public - */ - function getText() { - return SimpleHtmlSaxParser::normalise($this->_content); - } - - /** - * Test to see if id attribute matches. - * @param string $id ID to test against. - * @return boolean True on match. - * @access public - */ - function isId($id) { - return ($this->getAttribute('id') == $id); - } -} - -/** - * Base url. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleBaseTag extends SimpleTag { - - /** - * Starts with a named tag with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('base', $attributes); - } - - /** - * Base tag is not a block tag. - * @return boolean false - * @access public - */ - function expectEndTag() { - return false; - } -} - -/** - * Page title. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleTitleTag extends SimpleTag { - - /** - * Starts with a named tag with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('title', $attributes); - } -} - -/** - * Link. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleAnchorTag extends SimpleTag { - - /** - * Starts with a named tag with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('a', $attributes); - } - - /** - * Accessor for URL as string. - * @return string Coerced as string. - * @access public - */ - function getHref() { - $url = $this->getAttribute('href'); - if (is_bool($url)) { - $url = ''; - } - return $url; - } -} - -/** - * Form element. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleWidget extends SimpleTag { - var $_value; - var $_label; - var $_is_set; - - /** - * Starts with a named tag with attributes only. - * @param string $name Tag name. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($name, $attributes) { - parent::__construct($name, $attributes); - $this->_value = false; - $this->_label = false; - $this->_is_set = false; - } - - /** - * Accessor for name submitted as the key in - * GET/POST variables hash. - * @return string Parsed value. - * @access public - */ - function getName() { - return $this->getAttribute('name'); - } - - /** - * Accessor for default value parsed with the tag. - * @return string Parsed value. - * @access public - */ - function getDefault() { - return $this->getAttribute('value'); - } - - /** - * Accessor for currently set value or default if - * none. - * @return string Value set by form or default - * if none. - * @access public - */ - function getValue() { - if (! $this->_is_set) { - return $this->getDefault(); - } - return $this->_value; - } - - /** - * Sets the current form element value. - * @param string $value New value. - * @return boolean True if allowed. - * @access public - */ - function setValue($value) { - $this->_value = $value; - $this->_is_set = true; - return true; - } - - /** - * Resets the form element value back to the - * default. - * @access public - */ - function resetValue() { - $this->_is_set = false; - } - - /** - * Allows setting of a label externally, say by a - * label tag. - * @param string $label Label to attach. - * @access public - */ - function setLabel($label) { - $this->_label = trim($label ?? ''); - } - - /** - * Reads external or internal label. - * @param string $label Label to test. - * @return boolean True is match. - * @access public - */ - function isLabel($label) { - return $this->_label == trim($label ?? ''); - } - - /** - * Dispatches the value into the form encoded packet. - * @param SimpleEncoding $encoding Form packet. - * @access public - */ - function write(&$encoding, $x, $y) { - if ($this->getName()) { - $encoding->add($this->getName(), $this->getValue()); - } - } -} - -/** - * Text, password and hidden field. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleTextTag extends SimpleWidget { - - /** - * Starts with a named tag with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('input', $attributes); - if ($this->getAttribute('value') === false) { - $this->_setAttribute('value', ''); - } - } - - /** - * Tag contains no content. - * @return boolean False. - * @access public - */ - function expectEndTag() { - return false; - } - - /** - * Sets the current form element value. Cannot - * change the value of a hidden field. - * @param string $value New value. - * @return boolean True if allowed. - * @access public - */ - function setValue($value) { - if ($this->getAttribute('type') == 'hidden') { - return false; - } - return parent::setValue($value); - } -} - -/** - * Submit button as input tag. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleSubmitTag extends SimpleWidget { - - /** - * Starts with a named tag with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('input', $attributes); - if ($this->getAttribute('value') === false) { - $this->_setAttribute('value', 'Submit'); - } - } - - /** - * Tag contains no end element. - * @return boolean False. - * @access public - */ - function expectEndTag() { - return false; - } - - /** - * Disables the setting of the button value. - * @param string $value Ignored. - * @return boolean True if allowed. - * @access public - */ - function setValue($value) { - return false; - } - - /** - * Value of browser visible text. - * @return string Visible label. - * @access public - */ - function getLabel() { - return $this->getValue(); - } - - /** - * Test for a label match when searching. - * @param string $label Label to test. - * @return boolean True on match. - * @access public - */ - function isLabel($label) { - return trim($label ?? '') == trim($this->getLabel() ?? ''); - } -} - -/** - * Image button as input tag. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleImageSubmitTag extends SimpleWidget { - - /** - * Starts with a named tag with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('input', $attributes); - } - - /** - * Tag contains no end element. - * @return boolean False. - * @access public - */ - function expectEndTag() { - return false; - } - - /** - * Disables the setting of the button value. - * @param string $value Ignored. - * @return boolean True if allowed. - * @access public - */ - function setValue($value) { - return false; - } - - /** - * Value of browser visible text. - * @return string Visible label. - * @access public - */ - function getLabel() { - if ($this->getAttribute('title')) { - return $this->getAttribute('title'); - } - return $this->getAttribute('alt'); - } - - /** - * Test for a label match when searching. - * @param string $label Label to test. - * @return boolean True on match. - * @access public - */ - function isLabel($label) { - return trim($label ?? '') == trim($this->getLabel() ?? ''); - } - - /** - * Dispatches the value into the form encoded packet. - * @param SimpleEncoding $encoding Form packet. - * @param integer $x X coordinate of click. - * @param integer $y Y coordinate of click. - * @access public - */ - function write(&$encoding, $x, $y) { - if ($this->getName()) { - $encoding->add($this->getName() . '.x', $x); - $encoding->add($this->getName() . '.y', $y); - } else { - $encoding->add('x', $x); - $encoding->add('y', $y); - } - } -} - -/** - * Submit button as button tag. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleButtonTag extends SimpleWidget { - - /** - * Starts with a named tag with attributes only. - * Defaults are very browser dependent. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('button', $attributes); - } - - /** - * Check to see if the tag can have both start and - * end tags with content in between. - * @return boolean True if content allowed. - * @access public - */ - function expectEndTag() { - return true; - } - - /** - * Disables the setting of the button value. - * @param string $value Ignored. - * @return boolean True if allowed. - * @access public - */ - function setValue($value) { - return false; - } - - /** - * Value of browser visible text. - * @return string Visible label. - * @access public - */ - function getLabel() { - return $this->getContent(); - } - - /** - * Test for a label match when searching. - * @param string $label Label to test. - * @return boolean True on match. - * @access public - */ - function isLabel($label) { - return trim($label ?? '') == trim($this->getLabel() ?? ''); - } -} - -/** - * Content tag for text area. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleTextAreaTag extends SimpleWidget { - - /** - * Starts with a named tag with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('textarea', $attributes); - } - - /** - * Accessor for starting value. - * @return string Parsed value. - * @access public - */ - function getDefault() { - return $this->_wrap(SimpleHtmlSaxParser::decodeHtml($this->getContent())); - } - - /** - * Applies word wrapping if needed. - * @param string $value New value. - * @return boolean True if allowed. - * @access public - */ - function setValue($value) { - return parent::setValue($this->_wrap($value)); - } - - /** - * Test to see if text should be wrapped. - * @return boolean True if wrapping on. - * @access private - */ - function _wrapIsEnabled() { - if ($this->getAttribute('cols')) { - $wrap = $this->getAttribute('wrap'); - if (($wrap == 'physical') || ($wrap == 'hard')) { - return true; - } - } - return false; - } - - /** - * Performs the formatting that is peculiar to - * this tag. There is strange behaviour in this - * one, including stripping a leading new line. - * Go figure. I am using Firefox as a guide. - * @param string $text Text to wrap. - * @return string Text wrapped with carriage - * returns and line feeds - * @access private - */ - function _wrap($text) { - $text = str_replace("\r\r\n", "\r\n", str_replace("\n", "\r\n", $text ?? '') ?? ''); - $text = str_replace("\r\n\n", "\r\n", str_replace("\r", "\r\n", $text ?? '') ?? ''); - if (strncmp($text ?? '', "\r\n", strlen("\r\n")) == 0) { - $text = substr($text ?? '', strlen("\r\n")); - } - if ($this->_wrapIsEnabled()) { - return wordwrap( - $text ?? '', - (integer)$this->getAttribute('cols'), - "\r\n"); - } - return $text; - } - - /** - * The content of textarea is not part of the page. - * @return boolean True. - * @access public - */ - function isPrivateContent() { - return true; - } -} - -/** - * File upload widget. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleUploadTag extends SimpleWidget { - - /** - * Starts with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('input', $attributes); - } - - /** - * Tag contains no content. - * @return boolean False. - * @access public - */ - function expectEndTag() { - return false; - } - - /** - * Dispatches the value into the form encoded packet. - * @param SimpleEncoding $encoding Form packet. - * @access public - */ - function write(&$encoding, $x, $y) { - if (! file_exists($this->getValue() ?? '')) { - return; - } - $encoding->attach( - $this->getName(), - implode('', file($this->getValue() ?? '')), - basename($this->getValue() ?? '')); - } -} - -/** - * Drop down widget. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleSelectionTag extends SimpleWidget { - var $_options; - var $_choice; - - /** - * Starts with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('select', $attributes); - $this->_options = array(); - $this->_choice = false; - } - - /** - * Adds an option tag to a selection field. - * @param SimpleOptionTag $tag New option. - * @access public - */ - function addTag(&$tag) { - if ($tag->getTagName() == 'option') { - $this->_options[] = &$tag; - } - } - - /** - * Text within the selection element is ignored. - * @param string $content Ignored. - * @access public - */ - function addContent($content) { - } - - /** - * Scans options for defaults. If none, then - * the first option is selected. - * @return string Selected field. - * @access public - */ - function getDefault() { - for ($i = 0, $count = count($this->_options); $i < $count; $i++) { - if ($this->_options[$i]->getAttribute('selected') !== false) { - return $this->_options[$i]->getDefault(); - } - } - if ($count > 0) { - return $this->_options[0]->getDefault(); - } - return ''; - } - - /** - * Can only set allowed values. - * @param string $value New choice. - * @return boolean True if allowed. - * @access public - */ - function setValue($value) { - for ($i = 0, $count = count($this->_options); $i < $count; $i++) { - if ($this->_options[$i]->isValue($value)) { - $this->_choice = $i; - return true; - } - } - return false; - } - - /** - * Accessor for current selection value. - * @return string Value attribute or - * content of opton. - * @access public - */ - function getValue() { - if ($this->_choice === false) { - return $this->getDefault(); - } - return $this->_options[$this->_choice]->getValue(); - } -} - -/** - * Drop down widget. - * @package SimpleTest - * @subpackage WebTester - */ -class MultipleSelectionTag extends SimpleWidget { - var $_options; - var $_values; - - /** - * Starts with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('select', $attributes); - $this->_options = array(); - $this->_values = false; - } - - /** - * Adds an option tag to a selection field. - * @param SimpleOptionTag $tag New option. - * @access public - */ - function addTag(&$tag) { - if ($tag->getTagName() == 'option') { - $this->_options[] = &$tag; - } - } - - /** - * Text within the selection element is ignored. - * @param string $content Ignored. - * @access public - */ - function addContent($content) { - } - - /** - * Scans options for defaults to populate the - * value array(). - * @return array Selected fields. - * @access public - */ - function getDefault() { - $default = array(); - for ($i = 0, $count = count($this->_options); $i < $count; $i++) { - if ($this->_options[$i]->getAttribute('selected') !== false) { - $default[] = $this->_options[$i]->getDefault(); - } - } - return $default; - } - - /** - * Can only set allowed values. Any illegal value - * will result in a failure, but all correct values - * will be set. - * @param array $desired New choices. - * @return boolean True if all allowed. - * @access public - */ - function setValue($desired) { - $achieved = array(); - foreach ($desired as $value) { - $success = false; - for ($i = 0, $count = count($this->_options); $i < $count; $i++) { - if ($this->_options[$i]->isValue($value)) { - $achieved[] = $this->_options[$i]->getValue(); - $success = true; - break; - } - } - if (! $success) { - return false; - } - } - $this->_values = $achieved; - return true; - } - - /** - * Accessor for current selection value. - * @return array List of currently set options. - * @access public - */ - function getValue() { - if ($this->_values === false) { - return $this->getDefault(); - } - return $this->_values; - } -} - -/** - * Option for selection field. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleOptionTag extends SimpleWidget { - - /** - * Stashes the attributes. - */ - function __construct($attributes) { - parent::__construct('option', $attributes); - } - - /** - * Does nothing. - * @param string $value Ignored. - * @return boolean Not allowed. - * @access public - */ - function setValue($value) { - return false; - } - - /** - * Test to see if a value matches the option. - * @param string $compare Value to compare with. - * @return boolean True if possible match. - * @access public - */ - function isValue($compare) { - $compare = trim($compare ?? ''); - if (trim($this->getValue() ?? '') == $compare) { - return true; - } - return trim($this->getContent() ?? '') == $compare; - } - - /** - * Accessor for starting value. Will be set to - * the option label if no value exists. - * @return string Parsed value. - * @access public - */ - function getDefault() { - if ($this->getAttribute('value') === false) { - return $this->getContent(); - } - return $this->getAttribute('value'); - } - - /** - * The content of options is not part of the page. - * @return boolean True. - * @access public - */ - function isPrivateContent() { - return true; - } -} - -/** - * Radio button. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleRadioButtonTag extends SimpleWidget { - - /** - * Stashes the attributes. - * @param array $attributes Hash of attributes. - */ - function __construct($attributes) { - parent::__construct('input', $attributes); - if ($this->getAttribute('value') === false) { - $this->_setAttribute('value', 'on'); - } - } - - /** - * Tag contains no content. - * @return boolean False. - * @access public - */ - function expectEndTag() { - return false; - } - - /** - * The only allowed value sn the one in the - * "value" attribute. - * @param string $value New value. - * @return boolean True if allowed. - * @access public - */ - function setValue($value) { - if ($value === false) { - return parent::setValue($value); - } - if ($value != $this->getAttribute('value')) { - return false; - } - return parent::setValue($value); - } - - /** - * Accessor for starting value. - * @return string Parsed value. - * @access public - */ - function getDefault() { - if ($this->getAttribute('checked') !== false) { - return $this->getAttribute('value'); - } - return false; - } -} - -/** - * Checkbox widget. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleCheckboxTag extends SimpleWidget { - - /** - * Starts with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('input', $attributes); - if ($this->getAttribute('value') === false) { - $this->_setAttribute('value', 'on'); - } - } - - /** - * Tag contains no content. - * @return boolean False. - * @access public - */ - function expectEndTag() { - return false; - } - - /** - * The only allowed value in the one in the - * "value" attribute. The default for this - * attribute is "on". If this widget is set to - * true, then the usual value will be taken. - * @param string $value New value. - * @return boolean True if allowed. - * @access public - */ - function setValue($value) { - if ($value === false) { - return parent::setValue($value); - } - if ($value === true) { - return parent::setValue($this->getAttribute('value')); - } - if ($value != $this->getAttribute('value')) { - return false; - } - return parent::setValue($value); - } - - /** - * Accessor for starting value. The default - * value is "on". - * @return string Parsed value. - * @access public - */ - function getDefault() { - if ($this->getAttribute('checked') !== false) { - return $this->getAttribute('value'); - } - return false; - } -} - -/** - * A group of multiple widgets with some shared behaviour. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleTagGroup { - var $_widgets = array(); - - /** - * Adds a tag to the group. - * @param SimpleWidget $widget - * @access public - */ - function addWidget(&$widget) { - $this->_widgets[] = &$widget; - } - - /** - * Accessor to widget set. - * @return array All widgets. - * @access protected - */ - function &_getWidgets() { - return $this->_widgets; - } - - /** - * Accessor for an attribute. - * @param string $label Attribute name. - * @return boolean Always false. - * @access public - */ - function getAttribute($label) { - return false; - } - - /** - * Fetches the name for the widget from the first - * member. - * @return string Name of widget. - * @access public - */ - function getName() { - if (count($this->_widgets ?? []) > 0) { - return $this->_widgets[0]->getName(); - } - } - - /** - * Scans the widgets for one with the appropriate - * ID field. - * @param string $id ID value to try. - * @return boolean True if matched. - * @access public - */ - function isId($id) { - for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) { - if ($this->_widgets[$i]->isId($id)) { - return true; - } - } - return false; - } - - /** - * Scans the widgets for one with the appropriate - * attached label. - * @param string $label Attached label to try. - * @return boolean True if matched. - * @access public - */ - function isLabel($label) { - for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) { - if ($this->_widgets[$i]->isLabel($label)) { - return true; - } - } - return false; - } - - /** - * Dispatches the value into the form encoded packet. - * @param SimpleEncoding $encoding Form packet. - * @access public - */ - function write(&$encoding) { - $encoding->add($this->getName(), $this->getValue()); - } -} - -/** - * A group of tags with the same name within a form. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleCheckboxGroup extends SimpleTagGroup { - - /** - * Accessor for current selected widget or false - * if none. - * @return string/array Widget values or false if none. - * @access public - */ - function getValue() { - $values = array(); - $widgets = &$this->_getWidgets(); - for ($i = 0, $count = count($widgets); $i < $count; $i++) { - if ($widgets[$i]->getValue() !== false) { - $values[] = $widgets[$i]->getValue(); - } - } - return $this->_coerceValues($values); - } - - /** - * Accessor for starting value that is active. - * @return string/array Widget values or false if none. - * @access public - */ - function getDefault() { - $values = array(); - $widgets = &$this->_getWidgets(); - for ($i = 0, $count = count($widgets); $i < $count; $i++) { - if ($widgets[$i]->getDefault() !== false) { - $values[] = $widgets[$i]->getDefault(); - } - } - return $this->_coerceValues($values); - } - - /** - * Accessor for current set values. - * @param string/array/boolean $values Either a single string, a - * hash or false for nothing set. - * @return boolean True if all values can be set. - * @access public - */ - function setValue($values) { - $values = $this->_makeArray($values); - if (! $this->_valuesArePossible($values)) { - return false; - } - $widgets = &$this->_getWidgets(); - for ($i = 0, $count = count($widgets); $i < $count; $i++) { - $possible = $widgets[$i]->getAttribute('value'); - if (in_array($widgets[$i]->getAttribute('value'), $values ?? [])) { - $widgets[$i]->setValue($possible); - } else { - $widgets[$i]->setValue(false); - } - } - return true; - } - - /** - * Tests to see if a possible value set is legal. - * @param string/array/boolean $values Either a single string, a - * hash or false for nothing set. - * @return boolean False if trying to set a - * missing value. - * @access private - */ - function _valuesArePossible($values) { - $matches = array(); - $widgets = &$this->_getWidgets(); - for ($i = 0, $count = count($widgets); $i < $count; $i++) { - $possible = $widgets[$i]->getAttribute('value'); - if (in_array($possible, $values ?? [])) { - $matches[] = $possible; - } - } - return ($values == $matches); - } - - /** - * Converts the output to an appropriate format. This means - * that no values is false, a single value is just that - * value and only two or more are contained in an array. - * @param array $values List of values of widgets. - * @return string/array/boolean Expected format for a tag. - * @access private - */ - function _coerceValues($values) { - if (count($values ?? []) == 0) { - return false; - } elseif (count($values ?? []) == 1) { - return $values[0]; - } else { - return $values; - } - } - - /** - * Converts false or string into array. The opposite of - * the coercian method. - * @param string/array/boolean $value A single item is converted - * to a one item list. False - * gives an empty list. - * @return array List of values, possibly empty. - * @access private - */ - function _makeArray($value) { - if ($value === false) { - return array(); - } - if (is_string($value)) { - return array($value); - } - return $value; - } -} - -/** - * A group of tags with the same name within a form. - * Used for radio buttons. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleRadioGroup extends SimpleTagGroup { - - /** - * Each tag is tried in turn until one is - * successfully set. The others will be - * unchecked if successful. - * @param string $value New value. - * @return boolean True if any allowed. - * @access public - */ - function setValue($value) { - if (! $this->_valueIsPossible($value)) { - return false; - } - $index = false; - $widgets = &$this->_getWidgets(); - for ($i = 0, $count = count($widgets); $i < $count; $i++) { - if (! $widgets[$i]->setValue($value)) { - $widgets[$i]->setValue(false); - } - } - return true; - } - - /** - * Tests to see if a value is allowed. - * @param string Attempted value. - * @return boolean True if a valid value. - * @access private - */ - function _valueIsPossible($value) { - $widgets = &$this->_getWidgets(); - for ($i = 0, $count = count($widgets); $i < $count; $i++) { - if ($widgets[$i]->getAttribute('value') == $value) { - return true; - } - } - return false; - } - - /** - * Accessor for current selected widget or false - * if none. - * @return string/boolean Value attribute or - * content of opton. - * @access public - */ - function getValue() { - $widgets = &$this->_getWidgets(); - for ($i = 0, $count = count($widgets); $i < $count; $i++) { - if ($widgets[$i]->getValue() !== false) { - return $widgets[$i]->getValue(); - } - } - return false; - } - - /** - * Accessor for starting value that is active. - * @return string/boolean Value of first checked - * widget or false if none. - * @access public - */ - function getDefault() { - $widgets = &$this->_getWidgets(); - for ($i = 0, $count = count($widgets); $i < $count; $i++) { - if ($widgets[$i]->getDefault() !== false) { - return $widgets[$i]->getDefault(); - } - } - return false; - } -} - -/** - * Tag to keep track of labels. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleLabelTag extends SimpleTag { - - /** - * Starts with a named tag with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('label', $attributes); - } - - /** - * Access for the ID to attach the label to. - * @return string For attribute. - * @access public - */ - function getFor() { - return $this->getAttribute('for'); - } -} - -/** - * Tag to aid parsing the form. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleFormTag extends SimpleTag { - - /** - * Starts with a named tag with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('form', $attributes); - } -} - -/** - * Tag to aid parsing the frames in a page. - * @package SimpleTest - * @subpackage WebTester - */ -class SimpleFrameTag extends SimpleTag { - - /** - * Starts with a named tag with attributes only. - * @param hash $attributes Attribute names and - * string values. - */ - function __construct($attributes) { - parent::__construct('frame', $attributes); - } - - /** - * Tag contains no content. - * @return boolean False. - * @access public - */ - function expectEndTag() { - return false; - } -} diff --git a/thirdparty/simpletest/url.php b/thirdparty/simpletest/url.php deleted file mode 100644 index 5f3a30f68..000000000 --- a/thirdparty/simpletest/url.php +++ /dev/null @@ -1,531 +0,0 @@ -_chompCoordinates($url); - $this->setCoordinates($x, $y); - $this->_scheme = $this->_chompScheme($url); - list($this->_username, $this->_password) = $this->_chompLogin($url); - $this->_host = $this->_chompHost($url); - $this->_port = false; - if (preg_match('/(.*?):(.*)/', $this->_host ?? '', $host_parts)) { - $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 - */ - 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 - */ - 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 - */ - 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 = preg_split('/:/', $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 - */ - 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 - */ - 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 - */ - 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 - */ - function _parseRequest($raw) { - $this->_raw = $raw; - $request = new SimpleGetEncoding(); - foreach (preg_split('/&/', $raw ?? '') as $pair) { - if (preg_match('/(.*?)=(.*)/', $pair ?? '', $matches)) { - $request->add($matches[1], urldecode($matches[2] ?? '')); - } elseif ($pair) { - $request->add($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(); - } - 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 - */ - 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 - */ - 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'; - } -} -?>