Merge lp:pressflow/6.x-hiphop into lp:pressflow

Proposed by David Strauss
Status: Work in progress
Proposed branch: lp:pressflow/6.x-hiphop
Merge into: lp:pressflow
Diff against target: 5999 lines (+14/-5773)
28 files modified
includes/bootstrap.inc (+3/-22)
includes/common.inc (+2/-2)
includes/install.inc (+8/-10)
install.php (+1/-1)
modules/simpletest/BACKPORT.txt (+0/-49)
modules/simpletest/CHANGELOG.txt (+0/-135)
modules/simpletest/INSTALL.txt (+0/-33)
modules/simpletest/LICENSE.txt (+0/-274)
modules/simpletest/README.txt (+0/-29)
modules/simpletest/drupal_web_test_case.php (+0/-2581)
modules/simpletest/files/README.txt (+0/-6)
modules/simpletest/files/html-1.txt (+0/-1)
modules/simpletest/files/html-2.html (+0/-1)
modules/simpletest/files/javascript-1.txt (+0/-3)
modules/simpletest/files/javascript-2.script (+0/-3)
modules/simpletest/files/php-1.txt (+0/-3)
modules/simpletest/files/php-2.php (+0/-2)
modules/simpletest/files/sql-1.txt (+0/-1)
modules/simpletest/files/sql-2.sql (+0/-1)
modules/simpletest/run-tests.sh (+0/-590)
modules/simpletest/simpletest.css (+0/-74)
modules/simpletest/simpletest.info (+0/-50)
modules/simpletest/simpletest.install (+0/-301)
modules/simpletest/simpletest.js (+0/-114)
modules/simpletest/simpletest.module (+0/-533)
modules/simpletest/simpletest.pages.inc (+0/-464)
modules/simpletest/simpletest.test (+0/-372)
modules/simpletest/tests/block.test (+0/-118)
To merge this branch: bzr merge lp:pressflow/6.x-hiphop
Reviewer Review Type Date Requested Status
Pressflow Administrators Pending
Review via email: mp+19789@code.launchpad.net
To post a comment you must log in.
lp:pressflow/6.x-hiphop updated
75. By Josh Koenig

simpletest causes the hiphop build to crash as per https://bugs.edge.launchpad.net/pressflow/+bug/525101

Cutting it lets us get through a build!

76. By Josh Koenig

merging in David's changes

77. By Josh Koenig

remove foreach which produced fatal errors calling other unincluded datbases' _is_available functions

Unmerged revisions

77. By Josh Koenig

remove foreach which produced fatal errors calling other unincluded datbases' _is_available functions

76. By Josh Koenig

merging in David's changes

75. By Josh Koenig

simpletest causes the hiphop build to crash as per https://bugs.edge.launchpad.net/pressflow/+bug/525101

Cutting it lets us get through a build!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'includes/bootstrap.inc'
2--- includes/bootstrap.inc 2010-01-16 02:38:40 +0000
3+++ includes/bootstrap.inc 2010-02-21 05:03:16 +0000
4@@ -248,26 +248,7 @@
5 * The path of the matching directory.
6 */
7 function conf_path($require_settings = TRUE, $reset = FALSE) {
8- static $conf = '';
9-
10- if ($conf && !$reset) {
11- return $conf;
12- }
13-
14- $confdir = 'sites';
15- $uri = explode('/', $_SERVER['SCRIPT_NAME'] ? $_SERVER['SCRIPT_NAME'] : $_SERVER['SCRIPT_FILENAME']);
16- $server = explode('.', implode('.', array_reverse(explode(':', rtrim($_SERVER['HTTP_HOST'], '.')))));
17- for ($i = count($uri) - 1; $i > 0; $i--) {
18- for ($j = count($server); $j > 0; $j--) {
19- $dir = implode('.', array_slice($server, -$j)) . implode('.', array_slice($uri, 0, $i));
20- if (file_exists("$confdir/$dir/settings.php") || (!$require_settings && file_exists("$confdir/$dir"))) {
21- $conf = "$confdir/$dir";
22- return $conf;
23- }
24- }
25- }
26- $conf = "$confdir/default";
27- return $conf;
28+ return 'sites/default';
29 }
30
31 /**
32@@ -326,8 +307,8 @@
33 $_SERVER['HTTP_HOST'] = '';
34 }
35
36- if (file_exists('./'. conf_path() .'/settings.php')) {
37- include_once './'. conf_path() .'/settings.php';
38+ if (file_exists('./sites/default/settings.php')) {
39+ include_once './sites/default/settings.php';
40 }
41
42 // Ignore the placeholder url from default.settings.php.
43
44=== modified file 'includes/common.inc'
45--- includes/common.inc 2009-12-17 00:30:08 +0000
46+++ includes/common.inc 2010-02-21 05:03:16 +0000
47@@ -2753,8 +2753,8 @@
48 // themes as organized by a distribution. It is pristine in the same way
49 // that /modules is pristine for core; users should avoid changing anything
50 // there in favor of sites/all or sites/<domain> directories.
51- if (file_exists("profiles/$profile/$directory")) {
52- $searchdir[] = "profiles/$profile/$directory";
53+ if (file_exists("profiles/default/$directory")) {
54+ $searchdir[] = "profiles/default/$directory";
55 }
56
57 // Always search sites/all/* as well as the global directories
58
59=== modified file 'includes/install.inc'
60--- includes/install.inc 2009-02-25 22:34:15 +0000
61+++ includes/install.inc 2010-02-21 05:03:16 +0000
62@@ -152,13 +152,11 @@
63 function drupal_detect_database_types() {
64 $databases = array();
65
66- foreach (array('mysql', 'mysqli', 'pgsql') as $type) {
67- if (file_exists('./includes/install.'. $type .'.inc')) {
68- include_once './includes/install.'. $type .'.inc';
69- $function = $type .'_is_available';
70- if ($function()) {
71- $databases[$type] = $type;
72- }
73+ if (file_exists('./includes/install.mysqli.inc')) {
74+ include_once './includes/install.mysqli.inc';
75+ $function = $type .'_is_available';
76+ if ($function()) {
77+ $databases[$type] = $type;
78 }
79 }
80
81@@ -271,7 +269,7 @@
82 include_once './includes/file.inc';
83 include_once './includes/common.inc';
84
85- $profile_file = "./profiles/$profile/$profile.profile";
86+ $profile_file = "./profiles/default/default.profile";
87
88 if (!isset($profile) || !file_exists($profile_file)) {
89 install_no_profile_error();
90@@ -356,7 +354,7 @@
91 */
92 function drupal_install_system() {
93 $system_path = dirname(drupal_get_filename('module', 'system', NULL));
94- require_once './'. $system_path .'/system.install';
95+ require_once './modules/system/system.install';
96 module_invoke('system', 'install');
97 $system_versions = drupal_get_schema_versions('system');
98 $system_version = $system_versions ? max($system_versions) : SCHEMA_INSTALLED;
99@@ -669,7 +667,7 @@
100 function drupal_check_profile($profile) {
101 include_once './includes/file.inc';
102
103- $profile_file = "./profiles/$profile/$profile.profile";
104+ $profile_file = './profiles/default/default.profile';
105
106 if (!isset($profile) || !file_exists($profile_file)) {
107 install_no_profile_error();
108
109=== modified file 'install.php'
110--- install.php 2009-09-15 16:10:36 +0000
111+++ install.php 2010-02-21 05:03:16 +0000
112@@ -94,7 +94,7 @@
113 }
114
115 // Load the profile.
116- require_once "./profiles/$profile/$profile.profile";
117+ require_once "./profiles/default/default.profile";
118
119 // Locale selection
120 if (!empty($_GET['locale'])) {
121
122=== removed directory 'modules/simpletest'
123=== removed file 'modules/simpletest/BACKPORT.txt'
124--- modules/simpletest/BACKPORT.txt 2009-09-15 16:10:36 +0000
125+++ modules/simpletest/BACKPORT.txt 1970-01-01 00:00:00 +0000
126@@ -1,49 +0,0 @@
127-$Id: BACKPORT.txt,v 1.1.2.7 2009/09/14 23:03:27 boombatower Exp $
128-
129-AUTHOR
130-------
131-Jimmy Berry ("boombatower", http://drupal.org/user/214218)
132-
133-PURPOSE
134--------
135-This document describes the changes necessary to backport Drupal 7 core
136-SimpleTest for Drupal 6. This record is useful when trying to backport new
137-features from Drupal 7.
138-
139-CHANGES
140--------
141-All changes are placed bellow the line they are changing and the original line
142-is then commented out. This makes it easy to see what was done when merging
143-later changes.
144-
145-The last backported core CVS ID for the file is listed just bellow the actual
146-CVS ID with the prefix "Core: ".
147-
148-DrupalWebTestCase
149------------------
150-Document as described above.
151-
152-SimpleTest module (simpletest.module)
153--------------------------------------
154- * simpletest_get_all_tests()
155- * simpletest_run_tests()
156- * _simpletest_batch_finished()
157- * simpletest_clean_database
158- - Added simpletest_get_like_tables()
159- * simpletest_clean_temporary_directory()
160- * simpletest_test_form()
161- * _drupal_decode_exception()
162- * Added hook_form_system_modules_alter()
163-
164-SimpleTest installer (simpletest.install)
165------------------------------------------
166- * Added update hook.
167- * Added requirements check for configuration file modifications.
168-
169-JavaScript (simpletest.js)
170---------------------------
171- * Changed function attach syntax in both behaviors.
172-
173-CLI script (run-tests.sh)
174--------------------------
175- * Backported database calls.
176
177=== removed file 'modules/simpletest/CHANGELOG.txt'
178--- modules/simpletest/CHANGELOG.txt 2009-09-15 16:10:36 +0000
179+++ modules/simpletest/CHANGELOG.txt 1970-01-01 00:00:00 +0000
180@@ -1,135 +0,0 @@
181-// $Id: CHANGELOG.txt,v 1.1.2.97 2009/09/14 23:22:56 boombatower Exp $
182-
183-SimpleTest 6.x-2.9, 2009-09-14
184-------------------------------
185-- Changes:
186- * #576256: Theme laying needs to be initialized during setUp().
187- * Correct comment on previous workaround.
188- * #400296 by neilnz: Make simpletest_get_like_tables() work in MySQL and PostgreSQL.
189- * #573822: Update SimpleTestMailCaptureTestCase from simpletest.test.
190- * #577324 by Dave Reid: Module tests with extending submodule tests not included correctly.
191-- Bugs:
192- * #442890: HEAD info left in simpletest.info.
193- * #474394 by RockyRoad: block.test should treat delta as string.
194-- Backports:
195- * #335756: SimpleTest: $this->originalFileDirectory should be set before
196- installation to ensure non-standard directories are picked up.
197- * #567422: Fresh backport of Drupal 7 SimpleTest.
198- * #545228: Missing D7 constants.
199- * Remove simpletest.function.inc.
200- * Correct file_scan_directory() $mask parameter API change.
201- * Correct another 'class' atrribute as array().
202- * Update files.
203- * Changes to install.php included in D6 core patch.
204- * #577496: drupal_mail_wrapper() conflicts.
205-
206-SimpleTest 6.x-2.8, 2009-04-23
207-------------------------------
208-- Bugs:
209- * #382334: drupalGetNodeByTitle uses node_load_multiple in 6.x.
210- * #385152: Clear user_access() cache.
211- * Change file in drupalGetTestFiles() to use ereg() format used in Drupal 6.
212- * #430512 by soxofaan: Drupal 7 style database code in run-tests.sh.
213- * #430682: backport: run-tests.sh does not work with non-default server port.
214-- Changes:
215- * #346844: Clear language statics to remove locale module errors.
216- * #400296 by carlos8f: Use "SHOW TABLES" in simpletest_get_like_tables().
217- * #390232: Update 313902-2.patch to D6.10 misc/drupal.js
218- * #409372 by Dave Reid: Hide modules that have hidden = TRUE on admin/build/modules.
219- * #415864: Backport sample files.
220- * #400296: Revert: Use "SHOW TABLES" in simpletest_get_like_tables().
221- * #409294 by wlp1979: Add extra condition to getAssertionCall() for DrupalWebTestCaseCore.
222- * Merge DrupalWebTestCase change into DrupalWebTestCaseCore.
223- * Move "core" directory files into root.
224- * #442436: Full backport of Drupal 7 SimpleTest and common.inc functions.
225-
226-SimpleTest 6.x-2.7, 2009-02-16
227-------------------------------
228-- Bugs:
229- * #372697: Content type created but not "appearing".
230- * #373722: Table {node_revision} doesn't exist
231-- Changes:
232- * #370966: Ignore 1.x style tests.
233- * Format fix.
234- * #373172: Add curl requirement to documentation.
235-
236-SimpleTest 6.x-2.6, 2009-02-07
237-------------------------------
238-- Complete backport of Drupal 7.x SimpleTest module. (voids all backports).
239- * Added header to all relevant files.
240- * Updated INSTALL.txt.
241- * #369952: Clarify INSTALL.txt.
242- * Add drupalLogout() override.
243- * Add equivilent auto-clear user code.
244- * #359577: Add run-tests.sh to 6--2 branch.
245-- Backports:
246- * #305150: Keep running tests checked.
247- * #313902: DX: Show fatal errors in tests. (Added to INSTALL.txt)
248- * #304940: SimpleTest shouldn't try to upload non files.
249- * #308186: cURL 7.18.2 and SimpleTest module bitterly despise one another. (again?)
250- * #330582: Retrieve HTTP response headers.
251- * #336043: Simpletest speedup: skip call to curlExec() in curlConnect().
252-- Changes:
253- * #334679 by hass: improve update path from 5.x and 6.x-1.x to 6.x-2.x.
254-
255-SimpleTest 6.x-2.5, 2008-10-22
256-------------------------------
257-- Backports:
258- * #308668: Make test selection page work with non-JS.
259- * #316344: Add meta refresh support to SimpleTest.
260- * #320127: error in drupal_web_test_case.php.
261- * #320161: drupalGetTestFiles does not sort files correctly.
262- * #320374: Simpletest now fails with max_allowed_packet = 1M.
263- * #322779: Simpletest calls file_check_directory incorrectly.
264-- Changes:
265- * #319682: Install.txt refers to non-existent admin page.
266- * #323405: Remove bogus version = VERSION line from .info file.
267-
268-SimpleTest 6.x-2.4, 2008-09-22
269-------------------------------
270-- Bugs:
271- * #310427: settings.php check doesn't work properly.
272-- Backports:
273- * #305077: Rework simpletest backend.
274- * #308399: The simpletest error handler is broken for PHP functions.
275- * #308262: Clean-up and documentation of simpletest.js.
276- * #308186: cURL 7.18.2 and SimpleTest module bitterly despise one another.
277- * #295697: update cURL requirement.
278- * #299186: assertFieldByXPath does not work for selects or textareas with value.
279- * #308272: Improve test selection page.
280- * #255613: Update clickLink() to use drupalGet() and clean-up code.
281-- Changes:
282- * #310783: Fix up requirements check for settings.php.
283-
284-SimpleTest 6.x-2.3, 2008-09-15
285-------------------------------
286-- Backports:
287- * #297869: Add xpath method to SimpleTest.
288- * #297894: Add assertLink and assertNoLink to SimpleTest.
289- * #298137: drupalCreateContentType() should reset node permissions.
290- * #268148: Don't verify SSL certificates.
291- * #293099: Clarify form documentation and error handling.
292- * #296027: {simpletest} indexes come with wrong array expression.
293- * #299461: assertEqual() does not work with arrays.
294- * #246261: Simpletest-light doesn't handle selects with <optgroup>'s correctly.
295-- Changes:
296- * #297890: Add notice to INSTALL.txt instructing users on Windows to
297- encode settings file with the UNIX standard.
298- * #302606: Usability: improve installation error message.
299-
300-SimpleTest 6.x-2.2, 2008-08-15
301-------------------------------
302-- Bugs:
303- * #292062: fixed role creation permission check for 6.x style.
304-- Backports:
305- * #290316: test_id field name corrected.
306- * #293500: change message field to type text.
307- * #268063: added instruction in INSTALL.txt about hidden property.
308- * #291750: remove results after displayed.
309-- Changes:
310- * #295001: clarified INSTALL.txt and installation requirements message.
311- * Updated README.txt with issue information.
312-
313-SimpleTest 6.x-2.1, 2008-08-05
314-------------------------------
315-- Complete backport of Drupal 7.x SimpleTest module.
316
317=== removed file 'modules/simpletest/INSTALL.txt'
318--- modules/simpletest/INSTALL.txt 2009-09-11 00:40:07 +0000
319+++ modules/simpletest/INSTALL.txt 1970-01-01 00:00:00 +0000
320@@ -1,33 +0,0 @@
321-$Id: INSTALL.txt,v 1.6.4.16 2009/09/05 13:34:10 boombatower Exp $
322-
323-AUTHOR
324-------
325-Jimmy Berry ("boombatower", http://drupal.org/user/214218)
326-
327-REQUIREMENTS
328-------------
329-The php-curl library is required for SimpleTest to function.
330-
331-INSTALLATION
332-------------
333-1. Apply the D6-core-simpletest.patch file to the Drupal 6 core.
334-
335-2. (Optional)
336- Apply the "Show fatal errors in tests" batch to misc/drupal.js if you want
337- the reason for test failure to be displayed on the batch API screen. The
338- patch can be found at:
339- http://drupal.org/files/issues/simpletest_drupal.js_.patch.
340-
341-3. (Optional)
342- Move/Copy the run-tests.sh file into the Drupal scripts folder. The script
343- allows the tests to be run from the command line.
344-
345-4. Go to Administer >> Site building >> Modules (admin/build/modules) and
346- enable the SimpleTest module.
347-
348-5. Go to Administer >> Site building >> Testing (admin/build/testing) to
349- begin using the module.
350-
351-6. (Optional)
352- Go to Administer >> Help >> SimpleTest (admin/help/simpletest)
353- for more information on how to use the SimpleTest module.
354
355=== removed file 'modules/simpletest/LICENSE.txt'
356--- modules/simpletest/LICENSE.txt 2009-02-26 00:33:44 +0000
357+++ modules/simpletest/LICENSE.txt 1970-01-01 00:00:00 +0000
358@@ -1,274 +0,0 @@
359-GNU GENERAL PUBLIC LICENSE
360-
361- Version 2, June 1991
362-
363-Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
364-Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
365-verbatim copies of this license document, but changing it is not allowed.
366-
367- Preamble
368-
369-The licenses for most software are designed to take away your freedom to
370-share and change it. By contrast, the GNU General Public License is
371-intended to guarantee your freedom to share and change free software--to
372-make sure the software is free for all its users. This General Public License
373-applies to most of the Free Software Foundation's software and to any other
374-program whose authors commit to using it. (Some other Free Software
375-Foundation software is covered by the GNU Library General Public License
376-instead.) You can apply it to your programs, too.
377-
378-When we speak of free software, we are referring to freedom, not price. Our
379-General Public Licenses are designed to make sure that you have the
380-freedom to distribute copies of free software (and charge for this service if
381-you wish), that you receive source code or can get it if you want it, that you
382-can change the software or use pieces of it in new free programs; and that
383-you know you can do these things.
384-
385-To protect your rights, we need to make restrictions that forbid anyone to
386-deny you these rights or to ask you to surrender the rights. These restrictions
387-translate to certain responsibilities for you if you distribute copies of the
388-software, or if you modify it.
389-
390-For example, if you distribute copies of such a program, whether gratis or for
391-a fee, you must give the recipients all the rights that you have. You must make
392-sure that they, too, receive or can get the source code. And you must show
393-them these terms so they know their rights.
394-
395-We protect your rights with two steps: (1) copyright the software, and (2)
396-offer you this license which gives you legal permission to copy, distribute
397-and/or modify the software.
398-
399-Also, for each author's protection and ours, we want to make certain that
400-everyone understands that there is no warranty for this free software. If the
401-software is modified by someone else and passed on, we want its recipients
402-to know that what they have is not the original, so that any problems
403-introduced by others will not reflect on the original authors' reputations.
404-
405-Finally, any free program is threatened constantly by software patents. We
406-wish to avoid the danger that redistributors of a free program will individually
407-obtain patent licenses, in effect making the program proprietary. To prevent
408-this, we have made it clear that any patent must be licensed for everyone's
409-free use or not licensed at all.
410-
411-The precise terms and conditions for copying, distribution and modification
412-follow.
413-
414- GNU GENERAL PUBLIC LICENSE
415- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
416- MODIFICATION
417-
418-0. This License applies to any program or other work which contains a notice
419-placed by the copyright holder saying it may be distributed under the terms
420-of this General Public License. The "Program", below, refers to any such
421-program or work, and a "work based on the Program" means either the
422-Program or any derivative work under copyright law: that is to say, a work
423-containing the Program or a portion of it, either verbatim or with
424-modifications and/or translated into another language. (Hereinafter, translation
425-is included without limitation in the term "modification".) Each licensee is
426-addressed as "you".
427-
428-Activities other than copying, distribution and modification are not covered
429-by this License; they are outside its scope. The act of running the Program is
430-not restricted, and the output from the Program is covered only if its contents
431-constitute a work based on the Program (independent of having been made
432-by running the Program). Whether that is true depends on what the Program
433-does.
434-
435-1. You may copy and distribute verbatim copies of the Program's source
436-code as you receive it, in any medium, provided that you conspicuously and
437-appropriately publish on each copy an appropriate copyright notice and
438-disclaimer of warranty; keep intact all the notices that refer to this License
439-and to the absence of any warranty; and give any other recipients of the
440-Program a copy of this License along with the Program.
441-
442-You may charge a fee for the physical act of transferring a copy, and you
443-may at your option offer warranty protection in exchange for a fee.
444-
445-2. You may modify your copy or copies of the Program or any portion of it,
446-thus forming a work based on the Program, and copy and distribute such
447-modifications or work under the terms of Section 1 above, provided that you
448-also meet all of these conditions:
449-
450-a) You must cause the modified files to carry prominent notices stating that
451-you changed the files and the date of any change.
452-
453-b) You must cause any work that you distribute or publish, that in whole or in
454-part contains or is derived from the Program or any part thereof, to be
455-licensed as a whole at no charge to all third parties under the terms of this
456-License.
457-
458-c) If the modified program normally reads commands interactively when run,
459-you must cause it, when started running for such interactive use in the most
460-ordinary way, to print or display an announcement including an appropriate
461-copyright notice and a notice that there is no warranty (or else, saying that
462-you provide a warranty) and that users may redistribute the program under
463-these conditions, and telling the user how to view a copy of this License.
464-(Exception: if the Program itself is interactive but does not normally print such
465-an announcement, your work based on the Program is not required to print
466-an announcement.)
467-
468-These requirements apply to the modified work as a whole. If identifiable
469-sections of that work are not derived from the Program, and can be
470-reasonably considered independent and separate works in themselves, then
471-this License, and its terms, do not apply to those sections when you distribute
472-them as separate works. But when you distribute the same sections as part
473-of a whole which is a work based on the Program, the distribution of the
474-whole must be on the terms of this License, whose permissions for other
475-licensees extend to the entire whole, and thus to each and every part
476-regardless of who wrote it.
477-
478-Thus, it is not the intent of this section to claim rights or contest your rights to
479-work written entirely by you; rather, the intent is to exercise the right to
480-control the distribution of derivative or collective works based on the
481-Program.
482-
483-In addition, mere aggregation of another work not based on the Program
484-with the Program (or with a work based on the Program) on a volume of a
485-storage or distribution medium does not bring the other work under the scope
486-of this License.
487-
488-3. You may copy and distribute the Program (or a work based on it, under
489-Section 2) in object code or executable form under the terms of Sections 1
490-and 2 above provided that you also do one of the following:
491-
492-a) Accompany it with the complete corresponding machine-readable source
493-code, which must be distributed under the terms of Sections 1 and 2 above
494-on a medium customarily used for software interchange; or,
495-
496-b) Accompany it with a written offer, valid for at least three years, to give
497-any third party, for a charge no more than your cost of physically performing
498-source distribution, a complete machine-readable copy of the corresponding
499-source code, to be distributed under the terms of Sections 1 and 2 above on
500-a medium customarily used for software interchange; or,
501-
502-c) Accompany it with the information you received as to the offer to distribute
503-corresponding source code. (This alternative is allowed only for
504-noncommercial distribution and only if you received the program in object
505-code or executable form with such an offer, in accord with Subsection b
506-above.)
507-
508-The source code for a work means the preferred form of the work for
509-making modifications to it. For an executable work, complete source code
510-means all the source code for all modules it contains, plus any associated
511-interface definition files, plus the scripts used to control compilation and
512-installation of the executable. However, as a special exception, the source
513-code distributed need not include anything that is normally distributed (in
514-either source or binary form) with the major components (compiler, kernel,
515-and so on) of the operating system on which the executable runs, unless that
516-component itself accompanies the executable.
517-
518-If distribution of executable or object code is made by offering access to
519-copy from a designated place, then offering equivalent access to copy the
520-source code from the same place counts as distribution of the source code,
521-even though third parties are not compelled to copy the source along with the
522-object code.
523-
524-4. You may not copy, modify, sublicense, or distribute the Program except as
525-expressly provided under this License. Any attempt otherwise to copy,
526-modify, sublicense or distribute the Program is void, and will automatically
527-terminate your rights under this License. However, parties who have received
528-copies, or rights, from you under this License will not have their licenses
529-terminated so long as such parties remain in full compliance.
530-
531-5. You are not required to accept this License, since you have not signed it.
532-However, nothing else grants you permission to modify or distribute the
533-Program or its derivative works. These actions are prohibited by law if you
534-do not accept this License. Therefore, by modifying or distributing the
535-Program (or any work based on the Program), you indicate your acceptance
536-of this License to do so, and all its terms and conditions for copying,
537-distributing or modifying the Program or works based on it.
538-
539-6. Each time you redistribute the Program (or any work based on the
540-Program), the recipient automatically receives a license from the original
541-licensor to copy, distribute or modify the Program subject to these terms and
542-conditions. You may not impose any further restrictions on the recipients'
543-exercise of the rights granted herein. You are not responsible for enforcing
544-compliance by third parties to this License.
545-
546-7. If, as a consequence of a court judgment or allegation of patent
547-infringement or for any other reason (not limited to patent issues), conditions
548-are imposed on you (whether by court order, agreement or otherwise) that
549-contradict the conditions of this License, they do not excuse you from the
550-conditions of this License. If you cannot distribute so as to satisfy
551-simultaneously your obligations under this License and any other pertinent
552-obligations, then as a consequence you may not distribute the Program at all.
553-For example, if a patent license would not permit royalty-free redistribution
554-of the Program by all those who receive copies directly or indirectly through
555-you, then the only way you could satisfy both it and this License would be to
556-refrain entirely from distribution of the Program.
557-
558-If any portion of this section is held invalid or unenforceable under any
559-particular circumstance, the balance of the section is intended to apply and
560-the section as a whole is intended to apply in other circumstances.
561-
562-It is not the purpose of this section to induce you to infringe any patents or
563-other property right claims or to contest validity of any such claims; this
564-section has the sole purpose of protecting the integrity of the free software
565-distribution system, which is implemented by public license practices. Many
566-people have made generous contributions to the wide range of software
567-distributed through that system in reliance on consistent application of that
568-system; it is up to the author/donor to decide if he or she is willing to
569-distribute software through any other system and a licensee cannot impose
570-that choice.
571-
572-This section is intended to make thoroughly clear what is believed to be a
573-consequence of the rest of this License.
574-
575-8. If the distribution and/or use of the Program is restricted in certain
576-countries either by patents or by copyrighted interfaces, the original copyright
577-holder who places the Program under this License may add an explicit
578-geographical distribution limitation excluding those countries, so that
579-distribution is permitted only in or among countries not thus excluded. In such
580-case, this License incorporates the limitation as if written in the body of this
581-License.
582-
583-9. The Free Software Foundation may publish revised and/or new versions
584-of the General Public License from time to time. Such new versions will be
585-similar in spirit to the present version, but may differ in detail to address new
586-problems or concerns.
587-
588-Each version is given a distinguishing version number. If the Program specifies
589-a version number of this License which applies to it and "any later version",
590-you have the option of following the terms and conditions either of that
591-version or of any later version published by the Free Software Foundation. If
592-the Program does not specify a version number of this License, you may
593-choose any version ever published by the Free Software Foundation.
594-
595-10. If you wish to incorporate parts of the Program into other free programs
596-whose distribution conditions are different, write to the author to ask for
597-permission. For software which is copyrighted by the Free Software
598-Foundation, write to the Free Software Foundation; we sometimes make
599-exceptions for this. Our decision will be guided by the two goals of
600-preserving the free status of all derivatives of our free software and of
601-promoting the sharing and reuse of software generally.
602-
603- NO WARRANTY
604-
605-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
606-THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
607-PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
608-STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
609-OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
610-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
611-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
612-OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
613-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
614-PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
615-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
616-NECESSARY SERVICING, REPAIR OR CORRECTION.
617-
618-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
619-AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
620-ANY OTHER PARTY WHO MAY MODIFY AND/OR
621-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
622-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
623-SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
624-ARISING OUT OF THE USE OR INABILITY TO USE THE
625-PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
626-OR DATA BEING RENDERED INACCURATE OR LOSSES
627-SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
628-PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
629-IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
630-THE POSSIBILITY OF SUCH DAMAGES.
631-
632- END OF TERMS AND CONDITIONS
633
634=== removed file 'modules/simpletest/README.txt'
635--- modules/simpletest/README.txt 2009-04-27 17:27:02 +0000
636+++ modules/simpletest/README.txt 1970-01-01 00:00:00 +0000
637@@ -1,29 +0,0 @@
638-$Id: README.txt,v 1.12.4.4 2009/03/28 03:35:17 boombatower Exp $
639-
640-AUTHOR
641-------
642-Jimmy Berry ("boombatower", http://drupal.org/user/214218)
643-
644-PROJECT PAGE
645-------------
646-If you need more information, have an issue, or feature request please
647-visit the project page at: http://drupal.org/project/simpletest.
648-
649-DESCRIPTION
650------------
651-SimpleTest 6.x-2.x is a backport of Drupal 7 core SimpleTest and has the same
652-requirements as Drupal 7 SimpleTest.
653-
654-STATUS
655-------
656-Drupal 7 core SimpleTest developement is backported regularly. To find out when
657-the code was last backport check the CHANGELOG.txt or version release date.
658-
659-ISSUES
660-------
661-If you encounter issues please try and confirm they are Drupal 6 specifc. This
662-module has only required changes made in order for it to function in Drupal 6.
663-Any issues that are related to the Drupal 6 backport may be posted to:
664-http://drupal.org/project/issues/simpletest, but any issues with API or general
665-concerns should be posted to the SimpleTest core issue queue:
666-http://tinyurl.com/simpletest-core.
667
668=== removed file 'modules/simpletest/drupal_web_test_case.php'
669--- modules/simpletest/drupal_web_test_case.php 2009-09-24 16:31:42 +0000
670+++ modules/simpletest/drupal_web_test_case.php 1970-01-01 00:00:00 +0000
671@@ -1,2581 +0,0 @@
672-<?php
673-// $Id: drupal_web_test_case.php,v 1.2.2.3.2.43 2009/09/14 23:22:56 boombatower Exp $
674-// Core: Id: drupal_web_test_case.php,v 1.146 2009/08/31 18:30:26 webchick Exp $
675-
676-/**
677- * @file
678- * Provide required modifications to Drupal 7 core DrupalWebTestCase in order
679- * for it to function properly in Drupal 6.
680- *
681- * Copyright 2008-2009 by Jimmy Berry ("boombatower", http://drupal.org/user/214218)
682- */
683-
684-module_load_include('function.inc', 'simpletest');
685-
686-/**
687- * Base class for Drupal tests.
688- *
689- * Do not extend this class, use one of the subclasses in this file.
690- */
691-abstract class DrupalTestCase {
692- /**
693- * The test run ID.
694- *
695- * @var string
696- */
697- protected $testId;
698-
699- /**
700- * The original database prefix, before it was changed for testing purposes.
701- *
702- * @var string
703- */
704- protected $originalPrefix = NULL;
705-
706- /**
707- * The original file directory, before it was changed for testing purposes.
708- *
709- * @var string
710- */
711- protected $originalFileDirectory = NULL;
712-
713- /**
714- * Time limit for the test.
715- */
716- protected $timeLimit = 180;
717-
718- /**
719- * Current results of this test case.
720- *
721- * @var Array
722- */
723- public $results = array(
724- '#pass' => 0,
725- '#fail' => 0,
726- '#exception' => 0,
727- '#debug' => 0,
728- );
729-
730- /**
731- * Assertions thrown in that test case.
732- *
733- * @var Array
734- */
735- protected $assertions = array();
736-
737- /**
738- * This class is skipped when looking for the source of an assertion.
739- *
740- * When displaying which function an assert comes from, it's not too useful
741- * to see "drupalWebTestCase->drupalLogin()', we would like to see the test
742- * that called it. So we need to skip the classes defining these helper
743- * methods.
744- */
745- protected $skipClasses = array(__CLASS__ => TRUE);
746-
747- /**
748- * Constructor for DrupalWebTestCase.
749- *
750- * @param $test_id
751- * Tests with the same id are reported together.
752- */
753- public function __construct($test_id = NULL) {
754- $this->testId = $test_id;
755- }
756-
757- /**
758- * Internal helper: stores the assert.
759- *
760- * @param $status
761- * Can be 'pass', 'fail', 'exception'.
762- * TRUE is a synonym for 'pass', FALSE for 'fail'.
763- * @param $message
764- * The message string.
765- * @param $group
766- * Which group this assert belongs to.
767- * @param $caller
768- * By default, the assert comes from a function whose name starts with
769- * 'test'. Instead, you can specify where this assert originates from
770- * by passing in an associative array as $caller. Key 'file' is
771- * the name of the source file, 'line' is the line number and 'function'
772- * is the caller function itself.
773- */
774- protected function assert($status, $message = '', $group = 'Other', array $caller = NULL) {
775- global $db_prefix;
776-
777- // Convert boolean status to string status.
778- if (is_bool($status)) {
779- $status = $status ? 'pass' : 'fail';
780- }
781-
782- // Increment summary result counter.
783- $this->results['#' . $status]++;
784-
785- // Get the function information about the call to the assertion method.
786- if (!$caller) {
787- $caller = $this->getAssertionCall();
788- }
789-
790- // Switch to non-testing database to store results in.
791- $current_db_prefix = $db_prefix;
792- $db_prefix = $this->originalPrefix;
793-
794- // Creation assertion array that can be displayed while tests are running.
795- $this->assertions[] = $assertion = array(
796- 'test_id' => $this->testId,
797- 'test_class' => get_class($this),
798- 'status' => $status,
799- 'message' => $message,
800- 'message_group' => $group,
801- 'function' => $caller['function'],
802- 'line' => $caller['line'],
803- 'file' => $caller['file'],
804- );
805-
806- // Store assertion for display after the test has completed.
807-// db_insert('simpletest')
808-// ->fields($assertion)
809-// ->execute();
810- db_query("INSERT INTO {simpletest}
811- (test_id, test_class, status, message, message_group, function, line, file)
812- VALUES (%d, '%s', '%s', '%s', '%s', '%s', %d, '%s')", array_values($assertion));
813-
814- // Return to testing prefix.
815- $db_prefix = $current_db_prefix;
816- // We do not use a ternary operator here to allow a breakpoint on
817- // test failure.
818- if ($status == 'pass') {
819- return TRUE;
820- }
821- else {
822- return FALSE;
823- }
824- }
825-
826- /**
827- * Store an assertion from outside the testing context.
828- *
829- * This is useful for inserting assertions that can only be recorded after
830- * the test case has been destroyed, such as PHP fatal errors. The caller
831- * information is not automatically gathered since the caller is most likely
832- * inserting the assertion on behalf of other code. In all other respects
833- * the method behaves just like DrupalTestCase::assert() in terms of storing
834- * the assertion.
835- *
836- * @see DrupalTestCase::assert()
837- */
838- public static function insertAssert($test_id, $test_class, $status, $message = '', $group = 'Other', array $caller = array()) {
839- // Convert boolean status to string status.
840- if (is_bool($status)) {
841- $status = $status ? 'pass' : 'fail';
842- }
843-
844- $caller += array(
845- 'function' => t('Unknown'),
846- 'line' => 0,
847- 'file' => t('Unknown'),
848- );
849-
850- $assertion = array(
851- 'test_id' => $test_id,
852- 'test_class' => $test_class,
853- 'status' => $status,
854- 'message' => $message,
855- 'message_group' => $group,
856- 'function' => $caller['function'],
857- 'line' => $caller['line'],
858- 'file' => $caller['file'],
859- );
860-
861-// db_insert('simpletest')
862-// ->fields($assertion)
863-// ->execute();
864- db_query("INSERT INTO {simpletest}
865- (test_id, test_class, status, message, message_group, function, line, file)
866- VALUES (%d, '%s', '%s', '%s', '%s', '%s', %d, '%s')", array_values($assertion));
867- }
868-
869- /**
870- * Cycles through backtrace until the first non-assertion method is found.
871- *
872- * @return
873- * Array representing the true caller.
874- */
875- protected function getAssertionCall() {
876- $backtrace = debug_backtrace();
877-
878- // The first element is the call. The second element is the caller.
879- // We skip calls that occurred in one of the methods of our base classes
880- // or in an assertion function.
881- while (($caller = $backtrace[1]) &&
882- ((isset($caller['class']) && isset($this->skipClasses[$caller['class']])) ||
883- substr($caller['function'], 0, 6) == 'assert')) {
884- // We remove that call.
885- array_shift($backtrace);
886- }
887-
888- return _drupal_get_last_caller($backtrace);
889- }
890-
891- /**
892- * Check to see if a value is not false (not an empty string, 0, NULL, or FALSE).
893- *
894- * @param $value
895- * The value on which the assertion is to be done.
896- * @param $message
897- * The message to display along with the assertion.
898- * @param $group
899- * The type of assertion - examples are "Browser", "PHP".
900- * @return
901- * TRUE if the assertion succeeded, FALSE otherwise.
902- */
903- protected function assertTrue($value, $message = '', $group = 'Other') {
904- return $this->assert((bool) $value, $message ? $message : t('Value is TRUE'), $group);
905- }
906-
907- /**
908- * Check to see if a value is false (an empty string, 0, NULL, or FALSE).
909- *
910- * @param $value
911- * The value on which the assertion is to be done.
912- * @param $message
913- * The message to display along with the assertion.
914- * @param $group
915- * The type of assertion - examples are "Browser", "PHP".
916- * @return
917- * TRUE if the assertion succeeded, FALSE otherwise.
918- */
919- protected function assertFalse($value, $message = '', $group = 'Other') {
920- return $this->assert(!$value, $message ? $message : t('Value is FALSE'), $group);
921- }
922-
923- /**
924- * Check to see if a value is NULL.
925- *
926- * @param $value
927- * The value on which the assertion is to be done.
928- * @param $message
929- * The message to display along with the assertion.
930- * @param $group
931- * The type of assertion - examples are "Browser", "PHP".
932- * @return
933- * TRUE if the assertion succeeded, FALSE otherwise.
934- */
935- protected function assertNull($value, $message = '', $group = 'Other') {
936- return $this->assert(!isset($value), $message ? $message : t('Value is NULL'), $group);
937- }
938-
939- /**
940- * Check to see if a value is not NULL.
941- *
942- * @param $value
943- * The value on which the assertion is to be done.
944- * @param $message
945- * The message to display along with the assertion.
946- * @param $group
947- * The type of assertion - examples are "Browser", "PHP".
948- * @return
949- * TRUE if the assertion succeeded, FALSE otherwise.
950- */
951- protected function assertNotNull($value, $message = '', $group = 'Other') {
952- return $this->assert(isset($value), $message ? $message : t('Value is not NULL'), $group);
953- }
954-
955- /**
956- * Check to see if two values are equal.
957- *
958- * @param $first
959- * The first value to check.
960- * @param $second
961- * The second value to check.
962- * @param $message
963- * The message to display along with the assertion.
964- * @param $group
965- * The type of assertion - examples are "Browser", "PHP".
966- * @return
967- * TRUE if the assertion succeeded, FALSE otherwise.
968- */
969- protected function assertEqual($first, $second, $message = '', $group = 'Other') {
970- return $this->assert($first == $second, $message ? $message : t('First value is equal to second value'), $group);
971- }
972-
973- /**
974- * Check to see if two values are not equal.
975- *
976- * @param $first
977- * The first value to check.
978- * @param $second
979- * The second value to check.
980- * @param $message
981- * The message to display along with the assertion.
982- * @param $group
983- * The type of assertion - examples are "Browser", "PHP".
984- * @return
985- * TRUE if the assertion succeeded, FALSE otherwise.
986- */
987- protected function assertNotEqual($first, $second, $message = '', $group = 'Other') {
988- return $this->assert($first != $second, $message ? $message : t('First value is not equal to second value'), $group);
989- }
990-
991- /**
992- * Check to see if two values are identical.
993- *
994- * @param $first
995- * The first value to check.
996- * @param $second
997- * The second value to check.
998- * @param $message
999- * The message to display along with the assertion.
1000- * @param $group
1001- * The type of assertion - examples are "Browser", "PHP".
1002- * @return
1003- * TRUE if the assertion succeeded, FALSE otherwise.
1004- */
1005- protected function assertIdentical($first, $second, $message = '', $group = 'Other') {
1006- return $this->assert($first === $second, $message ? $message : t('First value is identical to second value'), $group);
1007- }
1008-
1009- /**
1010- * Check to see if two values are not identical.
1011- *
1012- * @param $first
1013- * The first value to check.
1014- * @param $second
1015- * The second value to check.
1016- * @param $message
1017- * The message to display along with the assertion.
1018- * @param $group
1019- * The type of assertion - examples are "Browser", "PHP".
1020- * @return
1021- * TRUE if the assertion succeeded, FALSE otherwise.
1022- */
1023- protected function assertNotIdentical($first, $second, $message = '', $group = 'Other') {
1024- return $this->assert($first !== $second, $message ? $message : t('First value is not identical to second value'), $group);
1025- }
1026-
1027- /**
1028- * Fire an assertion that is always positive.
1029- *
1030- * @param $message
1031- * The message to display along with the assertion.
1032- * @param $group
1033- * The type of assertion - examples are "Browser", "PHP".
1034- * @return
1035- * TRUE.
1036- */
1037- protected function pass($message = NULL, $group = 'Other') {
1038- return $this->assert(TRUE, $message, $group);
1039- }
1040-
1041- /**
1042- * Fire an assertion that is always negative.
1043- *
1044- * @param $message
1045- * The message to display along with the assertion.
1046- * @param $group
1047- * The type of assertion - examples are "Browser", "PHP".
1048- * @return
1049- * FALSE.
1050- */
1051- protected function fail($message = NULL, $group = 'Other') {
1052- return $this->assert(FALSE, $message, $group);
1053- }
1054-
1055- /**
1056- * Fire an error assertion.
1057- *
1058- * @param $message
1059- * The message to display along with the assertion.
1060- * @param $group
1061- * The type of assertion - examples are "Browser", "PHP".
1062- * @param $caller
1063- * The caller of the error.
1064- * @return
1065- * FALSE.
1066- */
1067- protected function error($message = '', $group = 'Other', array $caller = NULL) {
1068- if ($group == 'User notice') {
1069- // Since 'User notice' is set by trigger_error() which is used for debug
1070- // set the message to a status of 'debug'.
1071- return $this->assert('debug', $message, 'Debug', $caller);
1072- }
1073-
1074- return $this->assert('exception', $message, $group, $caller);
1075- }
1076-
1077- /**
1078- * Run all tests in this class.
1079- */
1080- public function run() {
1081- // Initialize verbose debugging.
1082- simpletest_verbose(NULL, file_directory_path(), get_class($this));
1083-
1084- // HTTP auth settings (<username>:<password>) for the simpletest browser
1085- // when sending requests to the test site.
1086- $username = variable_get('simpletest_username', NULL);
1087- $password = variable_get('simpletest_password', NULL);
1088- if ($username && $password) {
1089- $this->httpauth_credentials = $username . ':' . $password;
1090- }
1091-
1092- set_error_handler(array($this, 'errorHandler'));
1093- $methods = array();
1094- // Iterate through all the methods in this class.
1095- foreach (get_class_methods(get_class($this)) as $method) {
1096- // If the current method starts with "test", run it - it's a test.
1097- if (strtolower(substr($method, 0, 4)) == 'test') {
1098- $this->setUp();
1099- try {
1100- $this->$method();
1101- // Finish up.
1102- }
1103- catch (Exception $e) {
1104- $this->exceptionHandler($e);
1105- }
1106- $this->tearDown();
1107- }
1108- }
1109- // Clear out the error messages and restore error handler.
1110- drupal_get_messages();
1111- restore_error_handler();
1112- }
1113-
1114- /**
1115- * Handle errors.
1116- *
1117- * Because this is registered in set_error_handler(), it has to be public.
1118- * @see set_error_handler
1119- *
1120- */
1121- public function errorHandler($severity, $message, $file = NULL, $line = NULL) {
1122- if ($severity & error_reporting()) {
1123- $error_map = array(
1124- E_STRICT => 'Run-time notice',
1125- E_WARNING => 'Warning',
1126- E_NOTICE => 'Notice',
1127- E_CORE_ERROR => 'Core error',
1128- E_CORE_WARNING => 'Core warning',
1129- E_USER_ERROR => 'User error',
1130- E_USER_WARNING => 'User warning',
1131- E_USER_NOTICE => 'User notice',
1132- E_RECOVERABLE_ERROR => 'Recoverable error',
1133- );
1134-
1135- $backtrace = debug_backtrace();
1136- $this->error($message, $error_map[$severity], _drupal_get_last_caller($backtrace));
1137- }
1138- return TRUE;
1139- }
1140-
1141- /**
1142- * Handle exceptions.
1143- *
1144- * @see set_exception_handler
1145- */
1146- protected function exceptionHandler($exception) {
1147- $backtrace = $exception->getTrace();
1148- // Push on top of the backtrace the call that generated the exception.
1149- array_unshift($backtrace, array(
1150- 'line' => $exception->getLine(),
1151- 'file' => $exception->getFile(),
1152- ));
1153- $this->error($exception->getMessage(), 'Uncaught exception', _drupal_get_last_caller($backtrace));
1154- }
1155-
1156- /**
1157- * Generates a random string of ASCII characters of codes 32 to 126.
1158- *
1159- * The generated string includes alpha-numeric characters and common misc
1160- * characters. Use this method when testing general input where the content
1161- * is not restricted.
1162- *
1163- * @param $length
1164- * Length of random string to generate which will be appended to $db_prefix.
1165- * @return
1166- * Randomly generated string.
1167- */
1168- public static function randomString($length = 8) {
1169- global $db_prefix;
1170-
1171- $str = '';
1172- for ($i = 0; $i < $length; $i++) {
1173- $str .= chr(mt_rand(32, 126));
1174- }
1175- return str_replace('simpletest', 's', $db_prefix) . $str;
1176- }
1177-
1178- /**
1179- * Generates a random string containing letters and numbers.
1180- *
1181- * The letters may be upper or lower case. This method is better for
1182- * restricted inputs that do not accept certain characters. For example,
1183- * when testing input fields that require machine readable values (ie without
1184- * spaces and non-standard characters) this method is best.
1185- *
1186- * @param $length
1187- * Length of random string to generate which will be appended to $db_prefix.
1188- * @return
1189- * Randomly generated string.
1190- */
1191- public static function randomName($length = 8) {
1192- global $db_prefix;
1193-
1194- $values = array_merge(range(65, 90), range(97, 122), range(48, 57));
1195- $max = count($values) - 1;
1196- $str = '';
1197- for ($i = 0; $i < $length; $i++) {
1198- $str .= chr($values[mt_rand(0, $max)]);
1199- }
1200- return str_replace('simpletest', 's', $db_prefix) . $str;
1201- }
1202-
1203-}
1204-
1205-/**
1206- * Test case for Drupal unit tests.
1207- *
1208- * These tests can not access the database nor files. Calling any Drupal
1209- * function that needs the database will throw exceptions. These include
1210- * watchdog(), function_exists(), module_implements(),
1211- * module_invoke_all() etc.
1212- */
1213-class DrupalUnitTestCase extends DrupalTestCase {
1214-
1215- /**
1216- * Constructor for DrupalUnitTestCase.
1217- */
1218- function __construct($test_id = NULL) {
1219- parent::__construct($test_id);
1220- $this->skipClasses[__CLASS__] = TRUE;
1221- }
1222-
1223- function setUp() {
1224- global $db_prefix, $conf;
1225-
1226- // Store necessary current values before switching to prefixed database.
1227- $this->originalPrefix = $db_prefix;
1228- $this->originalFileDirectory = file_directory_path();
1229-
1230- // Generate temporary prefixed database to ensure that tests have a clean starting point.
1231- $db_prefix = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}');
1232- $conf['file_public_path'] = $this->originalFileDirectory . '/' . $db_prefix;
1233-
1234- // If locale is enabled then t() will try to access the database and
1235- // subsequently will fail as the database is not accessible.
1236- $module_list = module_list();
1237- if (isset($module_list['locale'])) {
1238- $this->originalModuleList = $module_list;
1239- unset($module_list['locale']);
1240- module_list(TRUE, FALSE, FALSE, $module_list);
1241- }
1242- }
1243-
1244- function tearDown() {
1245- global $db_prefix, $conf;
1246- if (preg_match('/simpletest\d+/', $db_prefix)) {
1247- $conf['file_public_path'] = $this->originalFileDirectory;
1248- // Return the database prefix to the original.
1249- $db_prefix = $this->originalPrefix;
1250- // Restore modules if necessary.
1251- if (isset($this->originalModuleList)) {
1252- module_list(TRUE, FALSE, FALSE, $this->originalModuleList);
1253- }
1254- }
1255- }
1256-}
1257-
1258-/**
1259- * Test case for typical Drupal tests.
1260- */
1261-class DrupalWebTestCase extends DrupalTestCase {
1262- /**
1263- * The URL currently loaded in the internal browser.
1264- *
1265- * @var string
1266- */
1267- protected $url;
1268-
1269- /**
1270- * The handle of the current cURL connection.
1271- *
1272- * @var resource
1273- */
1274- protected $curlHandle;
1275-
1276- /**
1277- * The headers of the page currently loaded in the internal browser.
1278- *
1279- * @var Array
1280- */
1281- protected $headers;
1282-
1283- /**
1284- * The content of the page currently loaded in the internal browser.
1285- *
1286- * @var string
1287- */
1288- protected $content;
1289-
1290- /**
1291- * The content of the page currently loaded in the internal browser (plain text version).
1292- *
1293- * @var string
1294- */
1295- protected $plainTextContent;
1296-
1297- /**
1298- * The parsed version of the page.
1299- *
1300- * @var SimpleXMLElement
1301- */
1302- protected $elements = NULL;
1303-
1304- /**
1305- * The current user logged in using the internal browser.
1306- *
1307- * @var bool
1308- */
1309- protected $loggedInUser = FALSE;
1310-
1311- /**
1312- * The current cookie file used by cURL.
1313- *
1314- * We do not reuse the cookies in further runs, so we do not need a file
1315- * but we still need cookie handling, so we set the jar to NULL.
1316- */
1317- protected $cookieFile = NULL;
1318-
1319- /**
1320- * Additional cURL options.
1321- *
1322- * DrupalWebTestCase itself never sets this but always obeys what is set.
1323- */
1324- protected $additionalCurlOptions = array();
1325-
1326- /**
1327- * The original user, before it was changed to a clean uid = 1 for testing purposes.
1328- *
1329- * @var object
1330- */
1331- protected $originalUser = NULL;
1332-
1333- /**
1334- * HTTP authentication credentials (<username>:<password>).
1335- */
1336- protected $httpauth_credentials = NULL;
1337-
1338- /**
1339- * The current session name, if available.
1340- */
1341- protected $session_name = NULL;
1342-
1343- /**
1344- * The current session ID, if available.
1345- */
1346- protected $session_id = NULL;
1347-
1348- /**
1349- * Constructor for DrupalWebTestCase.
1350- */
1351- function __construct($test_id = NULL) {
1352- parent::__construct($test_id);
1353- $this->skipClasses[__CLASS__] = TRUE;
1354- }
1355-
1356- /**
1357- * Get a node from the database based on its title.
1358- *
1359- * @param title
1360- * A node title, usually generated by $this->randomName().
1361- *
1362- * @return
1363- * A node object matching $title.
1364- */
1365- function drupalGetNodeByTitle($title) {
1366-// $nodes = node_load_multiple(array(), array('title' => $title));
1367-// // Load the first node returned from the database.
1368-// $returned_node = reset($nodes);
1369-// return $returned_node;
1370- return node_load(array('title' => $title));
1371- }
1372-
1373- /**
1374- * Creates a node based on default settings.
1375- *
1376- * @param $settings
1377- * An associative array of settings to change from the defaults, keys are
1378- * node properties, for example 'title' => 'Hello, world!'.
1379- * @return
1380- * Created node object.
1381- */
1382- protected function drupalCreateNode($settings = array()) {
1383- // Populate defaults array.
1384- $settings += array(
1385- 'body' => $this->randomName(32),
1386- 'title' => $this->randomName(8),
1387- 'comment' => 2,
1388- 'changed' => time(),
1389- 'format' => FILTER_FORMAT_DEFAULT,
1390- 'moderate' => 0,
1391- 'promote' => 0,
1392- 'revision' => 1,
1393- 'log' => '',
1394- 'status' => 1,
1395- 'sticky' => 0,
1396- 'type' => 'page',
1397- 'revisions' => NULL,
1398- 'taxonomy' => NULL,
1399- );
1400-
1401- // Use the original node's created time for existing nodes.
1402- if (isset($settings['created']) && !isset($settings['date'])) {
1403- $settings['date'] = format_date($settings['created'], 'custom', 'Y-m-d H:i:s O');
1404- }
1405-
1406- // If the node's user uid is not specified manually, use the currently
1407- // logged in user if available, or else the user running the test.
1408- if (!isset($settings['uid'])) {
1409- if ($this->loggedInUser) {
1410- $settings['uid'] = $this->loggedInUser->uid;
1411- }
1412- else {
1413- global $user;
1414- $settings['uid'] = $user->uid;
1415- }
1416- }
1417-
1418-// // Merge body field value and format separately.
1419-// $body = array(
1420-// 'value' => $this->randomName(32),
1421-// 'format' => FILTER_FORMAT_DEFAULT
1422-// );
1423-// $settings['body'][FIELD_LANGUAGE_NONE][0] += $body;
1424-
1425- $node = (object) $settings;
1426- node_save($node);
1427-
1428- // Small hack to link revisions to our test user.
1429-// db_update('node_revision')
1430-// ->fields(array('uid' => $node->uid))
1431-// ->condition('vid', $node->vid)
1432-// ->execute();
1433- db_query('UPDATE {node_revisions} SET uid = %d WHERE vid = %d', $node->uid, $node->vid);
1434- return $node;
1435- }
1436-
1437- /**
1438- * Creates a custom content type based on default settings.
1439- *
1440- * @param $settings
1441- * An array of settings to change from the defaults.
1442- * Example: 'type' => 'foo'.
1443- * @return
1444- * Created content type.
1445- */
1446- protected function drupalCreateContentType($settings = array()) {
1447- // Find a non-existent random type name.
1448- do {
1449-// $name = strtolower($this->randomName(8));
1450-// } while (node_type_get_type($name));
1451- $name = strtolower($this->randomName(3, 'type_'));
1452- } while (node_get_types('type', $name));
1453-
1454- // Populate defaults array.
1455- $defaults = array(
1456- 'type' => $name,
1457- 'name' => $name,
1458- 'description' => '',
1459- 'help' => '',
1460- 'min_word_count' => 0, // Drupal 6.
1461- 'title_label' => 'Title',
1462- 'body_label' => 'Body',
1463- 'has_title' => 1,
1464- 'has_body' => 1,
1465- );
1466- // Imposed values for a custom type.
1467- $forced = array(
1468- 'orig_type' => '',
1469- 'old_type' => '',
1470- 'module' => 'node',
1471- 'custom' => 1,
1472- 'modified' => 1,
1473- 'locked' => 0,
1474- );
1475- $type = $forced + $settings + $defaults;
1476- $type = (object)$type;
1477-
1478- $saved_type = node_type_save($type);
1479- node_types_rebuild();
1480- menu_rebuild(); // Drupal 6.
1481-
1482- $this->assertEqual($saved_type, SAVED_NEW, t('Created content type %type.', array('%type' => $type->type)));
1483-
1484- // Reset permissions so that permissions for this content type are available.
1485- $this->checkPermissions(array(), TRUE);
1486-
1487- return $type;
1488- }
1489-
1490- /**
1491- * Get a list files that can be used in tests.
1492- *
1493- * @param $type
1494- * File type, possible values: 'binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'.
1495- * @param $size
1496- * File size in bytes to match. Please check the tests/files folder.
1497- * @return
1498- * List of files that match filter.
1499- */
1500- protected function drupalGetTestFiles($type, $size = NULL) {
1501- $files = array();
1502-
1503- // Make sure type is valid.
1504- if (in_array($type, array('binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'))) {
1505- // Use original file directory instead of one created during setUp().
1506- $path = $this->originalFileDirectory . '/simpletest';
1507-// $files = file_scan_directory($path, '/' . $type . '\-.*/');
1508- $files = file_scan_directory($path, '' . $type . '\-.*');
1509-
1510- // If size is set then remove any files that are not of that size.
1511- if ($size !== NULL) {
1512- foreach ($files as $file) {
1513-// $stats = stat($file->uri);
1514- $stats = stat($file->filename);
1515- if ($stats['size'] != $size) {
1516-// unset($files[$file->uri]);
1517- unset($files[$file->filename]);
1518- }
1519- }
1520- }
1521- }
1522- usort($files, array($this, 'drupalCompareFiles'));
1523- return $files;
1524- }
1525-
1526- /**
1527- * Compare two files based on size and file name.
1528- */
1529- protected function drupalCompareFiles($file1, $file2) {
1530-// $compare_size = filesize($file1->uri) - filesize($file2->uri);
1531- $compare_size = filesize($file1->filename) - filesize($file2->filename);
1532- if ($compare_size) {
1533- // Sort by file size.
1534- return $compare_size;
1535- }
1536- else {
1537- // The files were the same size, so sort alphabetically.
1538- return strnatcmp($file1->name, $file2->name);
1539- }
1540- }
1541-
1542- /**
1543- * Create a user with a given set of permissions. The permissions correspond to the
1544- * names given on the privileges page.
1545- *
1546- * @param $permissions
1547- * Array of permission names to assign to user.
1548- * @return
1549- * A fully loaded user object with pass_raw property, or FALSE if account
1550- * creation fails.
1551- */
1552- protected function drupalCreateUser($permissions = array('access comments', 'access content', 'post comments', 'post comments without approval')) {
1553- // Create a role with the given permission set.
1554- if (!($rid = $this->drupalCreateRole($permissions))) {
1555- return FALSE;
1556- }
1557-
1558- // Create a user assigned to that role.
1559- $edit = array();
1560- $edit['name'] = $this->randomName();
1561- $edit['mail'] = $edit['name'] . '@example.com';
1562- $edit['roles'] = array($rid => $rid);
1563- $edit['pass'] = user_password();
1564- $edit['status'] = 1;
1565-
1566- $account = user_save('', $edit);
1567-
1568- $this->assertTrue(!empty($account->uid), t('User created with name %name and pass %pass', array('%name' => $edit['name'], '%pass' => $edit['pass'])), t('User login'));
1569- if (empty($account->uid)) {
1570- return FALSE;
1571- }
1572-
1573- // Add the raw password so that we can log in as this user.
1574- $account->pass_raw = $edit['pass'];
1575- return $account;
1576- }
1577-
1578- /**
1579- * Internal helper function; Create a role with specified permissions.
1580- *
1581- * @param $permissions
1582- * Array of permission names to assign to role.
1583- * @param $name
1584- * (optional) String for the name of the role. Defaults to a random string.
1585- * @return
1586- * Role ID of newly created role, or FALSE if role creation failed.
1587- */
1588- protected function drupalCreateRole(array $permissions, $name = NULL) {
1589- // Generate random name if it was not passed.
1590- if (!$name) {
1591- $name = $this->randomName();
1592- }
1593-
1594- // Check the all the permissions strings are valid.
1595- if (!$this->checkPermissions($permissions)) {
1596- return FALSE;
1597- }
1598-
1599- // Create new role.
1600-// $role = new stdClass();
1601-// $role->name = $name;
1602-// user_role_save($role);
1603-// user_role_set_permissions($role->name, $permissions);
1604- db_query("INSERT INTO {role} (name) VALUES ('%s')", $name);
1605- $role = db_fetch_object(db_query("SELECT * FROM {role} WHERE name = '%s'", $name));
1606-
1607- $this->assertTrue(isset($role->rid), t('Created role of name: @name, id: @rid', array('@name' => $name, '@rid' => (isset($role->rid) ? $role->rid : t('-n/a-')))), t('Role'));
1608- if ($role && !empty($role->rid)) {
1609-// $count = db_query('SELECT COUNT(*) FROM {role_permission} WHERE rid = :rid', array(':rid' => $role->rid))->fetchField();
1610-// $this->assertTrue($count == count($permissions), t('Created permissions: @perms', array('@perms' => implode(', ', $permissions))), t('Role'));
1611-
1612- // Assign permissions to role and mark it for clean-up.
1613- db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", $role->rid, implode(', ', $permissions));
1614- $perm = db_result(db_query("SELECT perm FROM {permission} WHERE rid = %d", $role->rid));
1615- $this->assertTrue(count(explode(', ', $perm)) == count($permissions), t('Created permissions: @perms', array('@perms' => implode(', ', $permissions))), t('Role'));
1616- return $role->rid;
1617- }
1618- else {
1619- return FALSE;
1620- }
1621- }
1622-
1623- /**
1624- * Check to make sure that the array of permissions are valid.
1625- *
1626- * @param $permissions
1627- * Permissions to check.
1628- * @param $reset
1629- * Reset cached available permissions.
1630- * @return
1631- * TRUE or FALSE depending on whether the permissions are valid.
1632- */
1633- protected function checkPermissions(array $permissions, $reset = FALSE) {
1634-// $available = &drupal_static(__FUNCTION__);
1635- static $available;
1636-
1637- if (!isset($available) || $reset) {
1638-// $available = array_keys(module_invoke_all('permission'));
1639- $available = module_invoke_all('perm');
1640- }
1641-
1642- $valid = TRUE;
1643- foreach ($permissions as $permission) {
1644- if (!in_array($permission, $available)) {
1645- $this->fail(t('Invalid permission %permission.', array('%permission' => $permission)), t('Role'));
1646- $valid = FALSE;
1647- }
1648- }
1649- return $valid;
1650- }
1651-
1652- /**
1653- * Log in a user with the internal browser.
1654- *
1655- * If a user is already logged in, then the current user is logged out before
1656- * logging in the specified user.
1657- *
1658- * Please note that neither the global $user nor the passed in user object is
1659- * populated with data of the logged in user. If you need full access to the
1660- * user object after logging in, it must be updated manually. If you also need
1661- * access to the plain-text password of the user (set by drupalCreateUser()),
1662- * e.g. to login the same user again, then it must be re-assigned manually.
1663- * For example:
1664- * @code
1665- * // Create a user.
1666- * $account = $this->drupalCreateUser(array());
1667- * $this->drupalLogin($account);
1668- * // Load real user object.
1669- * $pass_raw = $account->pass_raw;
1670- * $account = user_load($account->uid);
1671- * $account->pass_raw = $pass_raw;
1672- * @endcode
1673- *
1674- * @param $user
1675- * User object representing the user to login.
1676- *
1677- * @see drupalCreateUser()
1678- */
1679- protected function drupalLogin(stdClass $user) {
1680- if ($this->loggedInUser) {
1681- $this->drupalLogout();
1682- }
1683-
1684- $edit = array(
1685- 'name' => $user->name,
1686- 'pass' => $user->pass_raw
1687- );
1688- $this->drupalPost('user', $edit, t('Log in'));
1689-
1690- // If a "log out" link appears on the page, it is almost certainly because
1691- // the login was successful.
1692- $pass = $this->assertLink(t('Log out'), 0, t('User %name successfully logged in.', array('%name' => $user->name)), t('User login'));
1693-
1694- if ($pass) {
1695- $this->loggedInUser = $user;
1696- }
1697- }
1698-
1699- /**
1700- * Generate a token for the currently logged in user.
1701- */
1702- protected function drupalGetToken($value = '') {
1703- $private_key = drupal_get_private_key();
1704- return md5($this->session_id . $value . $private_key);
1705- }
1706-
1707- /*
1708- * Logs a user out of the internal browser, then check the login page to confirm logout.
1709- */
1710- protected function drupalLogout() {
1711- // Make a request to the logout page, and redirect to the user page, the
1712- // idea being if you were properly logged out you should be seeing a login
1713- // screen.
1714-// $this->drupalGet('user/logout', array('query' => 'destination=user'));
1715- $this->drupalGet('logout', array('query' => 'destination=user'));
1716- $pass = $this->assertField('name', t('Username field found.'), t('Logout'));
1717- $pass = $pass && $this->assertField('pass', t('Password field found.'), t('Logout'));
1718-
1719- if ($pass) {
1720- $this->loggedInUser = FALSE;
1721- }
1722- }
1723-
1724- /**
1725- * Generates a random database prefix, runs the install scripts on the
1726- * prefixed database and enable the specified modules. After installation
1727- * many caches are flushed and the internal browser is setup so that the
1728- * page requests will run on the new prefix. A temporary files directory
1729- * is created with the same name as the database prefix.
1730- *
1731- * @param ...
1732- * List of modules to enable for the duration of the test.
1733- */
1734- protected function setUp() {
1735- global $db_prefix, $user, $language;
1736-
1737- // Store necessary current values before switching to prefixed database.
1738- $this->originalLanguage = $language;
1739-// $this->originalLanguageDefault = variable_get('language_default');
1740- $this->originalPrefix = $db_prefix;
1741- $this->originalFileDirectory = file_directory_path();
1742-// $this->originalProfile = drupal_get_profile();
1743- $clean_url_original = variable_get('clean_url', 0);
1744-
1745- // Must reset locale here, since schema calls t(). (Drupal 6)
1746- if (module_exists('locale')) {
1747- $language = (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0, 'javascript' => '');
1748- locale(NULL, NULL, TRUE);
1749- }
1750-
1751- // Generate temporary prefixed database to ensure that tests have a clean starting point.
1752-// $db_prefix_new = Database::getConnection()->prefixTables('{simpletest' . mt_rand(1000, 1000000) . '}');
1753- $db_prefix_new = $db_prefix . 'simpletest' . mt_rand(1000, 1000000);
1754-
1755- // Workaround to insure we init the theme layer before going into prefixed
1756- // environment. (Drupal 6)
1757- $this->pass(t('Starting run with db_prefix %prefix', array('%prefix' => $db_prefix_new)), 'System');
1758-
1759-// db_update('simpletest_test_id')
1760-// ->fields(array('last_prefix' => $db_prefix_new))
1761-// ->condition('test_id', $this->testId)
1762-// ->execute();
1763- db_query("UPDATE {simpletest_test_id}
1764- SET last_prefix = '%s'
1765- WHERE test_id = %d", $db_prefix_new, $this->testId);
1766- $db_prefix = $db_prefix_new;
1767-
1768- // Create test directory ahead of installation so fatal errors and debug
1769- // information can be logged during installation process.
1770- $directory = $this->originalFileDirectory . '/simpletest/' . substr($db_prefix, 10);
1771-// file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
1772- file_check_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
1773-
1774- // Log fatal errors.
1775- ini_set('log_errors', 1);
1776- ini_set('error_log', $directory . '/error.log');
1777-
1778-// include_once DRUPAL_ROOT . '/includes/install.inc';
1779- include_once './includes/install.inc';
1780- drupal_install_system();
1781-
1782-// $this->preloadRegistry();
1783-
1784-// // Include the default profile
1785-// variable_set('install_profile', 'default');
1786-// $profile_details = install_profile_info('default', 'en');
1787-
1788- // Add the specified modules to the list of modules in the default profile.
1789- // Install the modules specified by the default profile.
1790-// drupal_install_modules($profile_details['dependencies'], TRUE);
1791- drupal_install_modules(drupal_verify_profile('default', 'en'));
1792-
1793-// node_type_clear();
1794-
1795- // Install additional modules one at a time in order to make sure that the
1796- // list of modules is updated between each module's installation.
1797- $modules = func_get_args();
1798- foreach ($modules as $module) {
1799-// drupal_install_modules(array($module), TRUE);
1800- drupal_install_modules(array($module));
1801- }
1802-
1803- // Because the schema is static cached, we need to flush
1804- // it between each run. If we don't, then it will contain
1805- // stale data for the previous run's database prefix and all
1806- // calls to it will fail.
1807- drupal_get_schema(NULL, TRUE);
1808-
1809- // Run default profile tasks.
1810-// $install_state = array();
1811-// drupal_install_modules(array('default'), TRUE);
1812- $task = 'profile';
1813- default_profile_tasks($task, '');
1814-
1815- // Rebuild caches.
1816-// node_types_rebuild();
1817- actions_synchronize();
1818- _drupal_flush_css_js();
1819- $this->refreshVariables();
1820- $this->checkPermissions(array(), TRUE);
1821- user_access(NULL, NULL, TRUE); // Drupal 6.
1822-
1823- // Log in with a clean $user.
1824- $this->originalUser = $user;
1825-// drupal_save_session(FALSE);
1826-// $user = user_load(1);
1827- session_save_session(FALSE);
1828- $user = user_load(array('uid' => 1));
1829-
1830- // Restore necessary variables.
1831- variable_set('install_profile', 'default');
1832- variable_set('install_task', 'profile-finished');
1833- variable_set('clean_url', $clean_url_original);
1834- variable_set('site_mail', 'simpletest@example.com');
1835- variable_set('smtp_library', drupal_get_path('module', 'simpletest') . '/simpletest.test');
1836-
1837- // Use temporary files directory with the same prefix as the database.
1838- $directory = $this->originalFileDirectory . '/' . $db_prefix;
1839-
1840- // Set path variables
1841- variable_set('file_directory_path', $directory);
1842-
1843- // Create the directories
1844- file_check_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
1845-
1846- set_time_limit($this->timeLimit);
1847- }
1848-
1849- /**
1850- * Refresh the in-memory set of variables. Useful after a page request is made
1851- * that changes a variable in a different thread.
1852- *
1853- * In other words calling a settings page with $this->drupalPost() with a changed
1854- * value would update a variable to reflect that change, but in the thread that
1855- * made the call (thread running the test) the changed variable would not be
1856- * picked up.
1857- *
1858- * This method clears the variables cache and loads a fresh copy from the database
1859- * to ensure that the most up-to-date set of variables is loaded.
1860- */
1861- protected function refreshVariables() {
1862- global $conf;
1863- cache_clear_all('variables', 'cache');
1864- $conf = variable_init();
1865- }
1866-
1867- /**
1868- * Delete created files and temporary files directory, delete the tables created by setUp(),
1869- * and reset the database prefix.
1870- */
1871- protected function tearDown() {
1872- global $db_prefix, $user, $language;
1873-
1874- // In case a fatal error occured that was not in the test process read the
1875- // log to pick up any fatal errors.
1876- $db_prefix_temp = $db_prefix;
1877- $db_prefix = $this->originalPrefix;
1878- simpletest_log_read($this->testId, $db_prefix, get_class($this), TRUE);
1879- $db_prefix = $db_prefix_temp;
1880-
1881- $emailCount = count(variable_get('drupal_test_email_collector', array()));
1882- if ($emailCount) {
1883- $message = format_plural($emailCount, t('!count e-mail was sent during this test.'), t('!count e-mails were sent during this test.'), array('!count' => $emailCount));
1884- $this->pass($message, t('E-mail'));
1885- }
1886-
1887- if (preg_match('/simpletest\d+/', $db_prefix)) {
1888- // Delete temporary files directory.
1889- simpletest_clean_temporary_directory(file_directory_path());
1890-
1891- // Remove all prefixed tables (all the tables in the schema).
1892- $schema = drupal_get_schema(NULL, TRUE);
1893- $ret = array();
1894- foreach ($schema as $name => $table) {
1895- db_drop_table($ret, $name);
1896- }
1897-
1898- // Return the database prefix to the original.
1899- $db_prefix = $this->originalPrefix;
1900-
1901- // Return the user to the original one.
1902- $user = $this->originalUser;
1903- session_save_session(TRUE);
1904-
1905- // Bring back default language. (Drupal 6)
1906- if (module_exists('locale')) {
1907- drupal_init_language();
1908- locale(NULL, NULL, TRUE);
1909- }
1910-
1911- // Ensure that internal logged in variable and cURL options are reset.
1912- $this->loggedInUser = FALSE;
1913- $this->additionalCurlOptions = array();
1914-
1915- // Reload module list and implementations to ensure that test module hooks
1916- // aren't called after tests.
1917- module_list(TRUE);
1918- module_implements('', '', TRUE);
1919-
1920- // Rebuild caches.
1921- $this->refreshVariables();
1922-
1923- // Close the CURL handler.
1924- $this->curlClose();
1925- }
1926- }
1927-
1928- /**
1929- * Initializes the cURL connection.
1930- *
1931- * If the simpletest_httpauth_credentials variable is set, this function will
1932- * add HTTP authentication headers. This is necessary for testing sites that
1933- * are protected by login credentials from public access.
1934- * See the description of $curl_options for other options.
1935- */
1936- protected function curlInitialize() {
1937- global $base_url, $db_prefix;
1938-
1939- if (!isset($this->curlHandle)) {
1940- $this->curlHandle = curl_init();
1941- $curl_options = $this->additionalCurlOptions + array(
1942- CURLOPT_COOKIEJAR => $this->cookieFile,
1943- CURLOPT_URL => $base_url,
1944- CURLOPT_FOLLOWLOCATION => TRUE,
1945- CURLOPT_MAXREDIRS => 5,
1946- CURLOPT_RETURNTRANSFER => TRUE,
1947- CURLOPT_SSL_VERIFYPEER => FALSE, // Required to make the tests run on https.
1948- CURLOPT_SSL_VERIFYHOST => FALSE, // Required to make the tests run on https.
1949- CURLOPT_HEADERFUNCTION => array(&$this, 'curlHeaderCallback'),
1950- );
1951- if (isset($this->httpauth_credentials)) {
1952- $curl_options[CURLOPT_USERPWD] = $this->httpauth_credentials;
1953- }
1954- curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options);
1955-
1956- // By default, the child session name should be the same as the parent.
1957- $this->session_name = session_name();
1958- }
1959- // We set the user agent header on each request so as to use the current
1960- // time and a new uniqid.
1961- if (preg_match('/simpletest\d+/', $db_prefix, $matches)) {
1962- curl_setopt($this->curlHandle, CURLOPT_USERAGENT, drupal_generate_test_ua($matches[0]));
1963- }
1964- }
1965-
1966- /**
1967- * Performs a cURL exec with the specified options after calling curlConnect().
1968- *
1969- * @param $curl_options
1970- * Custom cURL options.
1971- * @return
1972- * Content returned from the exec.
1973- */
1974- protected function curlExec($curl_options) {
1975- $this->curlInitialize();
1976- $url = empty($curl_options[CURLOPT_URL]) ? curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL) : $curl_options[CURLOPT_URL];
1977- if (!empty($curl_options[CURLOPT_POST])) {
1978- // This is a fix for the Curl library to prevent Expect: 100-continue
1979- // headers in POST requests, that may cause unexpected HTTP response
1980- // codes from some webservers (like lighttpd that returns a 417 error
1981- // code). It is done by setting an empty "Expect" header field that is
1982- // not overwritten by Curl.
1983- $curl_options[CURLOPT_HTTPHEADER][] = 'Expect:';
1984- }
1985- curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options);
1986-
1987- // Reset headers and the session ID.
1988- $this->session_id = NULL;
1989- $this->headers = array();
1990-
1991- $this->drupalSetContent(curl_exec($this->curlHandle), curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL));
1992- $message_vars = array(
1993- '!method' => !empty($curl_options[CURLOPT_NOBODY]) ? 'HEAD' : (empty($curl_options[CURLOPT_POSTFIELDS]) ? 'GET' : 'POST'),
1994- '@url' => $url,
1995- '@status' => curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE),
1996- '!length' => format_size(strlen($this->content))
1997- );
1998- $message = t('!method @url returned @status (!length).', $message_vars);
1999- $this->assertTrue($this->content !== FALSE, $message, t('Browser'));
2000- return $this->drupalGetContent();
2001- }
2002-
2003- /**
2004- * Reads headers and registers errors received from the tested site.
2005- *
2006- * @see _drupal_log_error().
2007- *
2008- * @param $curlHandler
2009- * The cURL handler.
2010- * @param $header
2011- * An header.
2012- */
2013- protected function curlHeaderCallback($curlHandler, $header) {
2014- $this->headers[] = $header;
2015-
2016- // Errors are being sent via X-Drupal-Assertion-* headers,
2017- // generated by _drupal_log_error() in the exact form required
2018- // by DrupalWebTestCase::error().
2019- if (preg_match('/^X-Drupal-Assertion-[0-9]+: (.*)$/', $header, $matches)) {
2020- // Call DrupalWebTestCase::error() with the parameters from the header.
2021- call_user_func_array(array(&$this, 'error'), unserialize(urldecode($matches[1])));
2022- }
2023-
2024- // Save the session cookie, if set.
2025- if (preg_match('/^Set-Cookie: ' . preg_quote($this->session_name) . '=([a-z90-9]+)/', $header, $matches)) {
2026- if ($matches[1] != 'deleted') {
2027- $this->session_id = $matches[1];
2028- }
2029- else {
2030- $this->session_id = NULL;
2031- }
2032- }
2033-
2034- // This is required by cURL.
2035- return strlen($header);
2036- }
2037-
2038- /**
2039- * Close the cURL handler and unset the handler.
2040- */
2041- protected function curlClose() {
2042- if (isset($this->curlHandle)) {
2043- curl_close($this->curlHandle);
2044- unset($this->curlHandle);
2045- }
2046- }
2047-
2048- /**
2049- * Parse content returned from curlExec using DOM and SimpleXML.
2050- *
2051- * @return
2052- * A SimpleXMLElement or FALSE on failure.
2053- */
2054- protected function parse() {
2055- if (!$this->elements) {
2056- // DOM can load HTML soup. But, HTML soup can throw warnings, suppress
2057- // them.
2058- @$htmlDom = DOMDocument::loadHTML($this->content);
2059- if ($htmlDom) {
2060- $this->pass(t('Valid HTML found on "@path"', array('@path' => $this->getUrl())), t('Browser'));
2061- // It's much easier to work with simplexml than DOM, luckily enough
2062- // we can just simply import our DOM tree.
2063- $this->elements = simplexml_import_dom($htmlDom);
2064- }
2065- }
2066- if (!$this->elements) {
2067- $this->fail(t('Parsed page successfully.'), t('Browser'));
2068- }
2069-
2070- return $this->elements;
2071- }
2072-
2073- /**
2074- * Retrieves a Drupal path or an absolute path.
2075- *
2076- * @param $path
2077- * Drupal path or URL to load into internal browser
2078- * @param $options
2079- * Options to be forwarded to url().
2080- * @param $headers
2081- * An array containing additional HTTP request headers, each formatted as
2082- * "name: value".
2083- * @return
2084- * The retrieved HTML string, also available as $this->drupalGetContent()
2085- */
2086- protected function drupalGet($path, array $options = array(), array $headers = array()) {
2087- $options['absolute'] = TRUE;
2088-
2089- // We re-using a CURL connection here. If that connection still has certain
2090- // options set, it might change the GET into a POST. Make sure we clear out
2091- // previous options.
2092- $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => $headers));
2093- $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
2094-
2095- // Replace original page output with new output from redirected page(s).
2096- if (($new = $this->checkForMetaRefresh())) {
2097- $out = $new;
2098- }
2099- $this->verbose('GET request to: ' . $path .
2100- '<hr />Ending URL: ' . $this->getUrl() .
2101- '<hr />' . $out);
2102- return $out;
2103- }
2104-
2105- /**
2106- * Execute a POST request on a Drupal page.
2107- * It will be done as usual POST request with SimpleBrowser.
2108- *
2109- * @param $path
2110- * Location of the post form. Either a Drupal path or an absolute path or
2111- * NULL to post to the current page. For multi-stage forms you can set the
2112- * path to NULL and have it post to the last received page. Example:
2113- *
2114- * // First step in form.
2115- * $edit = array(...);
2116- * $this->drupalPost('some_url', $edit, t('Save'));
2117- *
2118- * // Second step in form.
2119- * $edit = array(...);
2120- * $this->drupalPost(NULL, $edit, t('Save'));
2121- * @param $edit
2122- * Field data in an associative array. Changes the current input fields
2123- * (where possible) to the values indicated. A checkbox can be set to
2124- * TRUE to be checked and FALSE to be unchecked. Note that when a form
2125- * contains file upload fields, other fields cannot start with the '@'
2126- * character.
2127- *
2128- * Multiple select fields can be set using name[] and setting each of the
2129- * possible values. Example:
2130- * $edit = array();
2131- * $edit['name[]'] = array('value1', 'value2');
2132- * @param $submit
2133- * Value of the submit button.
2134- * @param $options
2135- * Options to be forwarded to url().
2136- * @param $headers
2137- * An array containing additional HTTP request headers, each formatted as
2138- * "name: value".
2139- */
2140- protected function drupalPost($path, $edit, $submit, array $options = array(), array $headers = array()) {
2141- $submit_matches = FALSE;
2142- if (isset($path)) {
2143- $html = $this->drupalGet($path, $options);
2144- }
2145- if ($this->parse()) {
2146- $edit_save = $edit;
2147- // Let's iterate over all the forms.
2148- $forms = $this->xpath('//form');
2149- foreach ($forms as $form) {
2150- // We try to set the fields of this form as specified in $edit.
2151- $edit = $edit_save;
2152- $post = array();
2153- $upload = array();
2154- $submit_matches = $this->handleForm($post, $edit, $upload, $submit, $form);
2155- $action = isset($form['action']) ? $this->getAbsoluteUrl($form['action']) : $this->getUrl();
2156-
2157- // We post only if we managed to handle every field in edit and the
2158- // submit button matches.
2159- if (!$edit && $submit_matches) {
2160- $post_array = $post;
2161- if ($upload) {
2162- // TODO: cURL handles file uploads for us, but the implementation
2163- // is broken. This is a less than elegant workaround. Alternatives
2164- // are being explored at #253506.
2165- foreach ($upload as $key => $file) {
2166- $file = realpath($file);
2167- if ($file && is_file($file)) {
2168- $post[$key] = '@' . $file;
2169- }
2170- }
2171- }
2172- else {
2173- foreach ($post as $key => $value) {
2174- // Encode according to application/x-www-form-urlencoded
2175- // Both names and values needs to be urlencoded, according to
2176- // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
2177- $post[$key] = urlencode($key) . '=' . urlencode($value);
2178- }
2179- $post = implode('&', $post);
2180- }
2181- $out = $this->curlExec(array(CURLOPT_URL => $action, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $post, CURLOPT_HTTPHEADER => $headers));
2182- // Ensure that any changes to variables in the other thread are picked up.
2183- $this->refreshVariables();
2184-
2185- // Replace original page output with new output from redirected page(s).
2186- if (($new = $this->checkForMetaRefresh())) {
2187- $out = $new;
2188- }
2189- $this->verbose('POST request to: ' . $path .
2190- '<hr />Ending URL: ' . $this->getUrl() .
2191- '<hr />Fields: ' . highlight_string('<?php ' . var_export($post_array, TRUE), TRUE) .
2192- '<hr />' . $out);
2193- return $out;
2194- }
2195- }
2196- // We have not found a form which contained all fields of $edit.
2197- foreach ($edit as $name => $value) {
2198- $this->fail(t('Failed to set field @name to @value', array('@name' => $name, '@value' => $value)));
2199- }
2200- $this->assertTrue($submit_matches, t('Found the @submit button', array('@submit' => $submit)));
2201- $this->fail(t('Found the requested form fields at @path', array('@path' => $path)));
2202- }
2203- }
2204-
2205- /**
2206- * Check for meta refresh tag and if found call drupalGet() recursively. This
2207- * function looks for the http-equiv attribute to be set to "Refresh"
2208- * and is case-sensitive.
2209- *
2210- * @return
2211- * Either the new page content or FALSE.
2212- */
2213- protected function checkForMetaRefresh() {
2214- if ($this->drupalGetContent() != '' && $this->parse()) {
2215- $refresh = $this->xpath('//meta[@http-equiv="Refresh"]');
2216- if (!empty($refresh)) {
2217- // Parse the content attribute of the meta tag for the format:
2218- // "[delay]: URL=[page_to_redirect_to]".
2219- if (preg_match('/\d+;\s*URL=(?P<url>.*)/i', $refresh[0]['content'], $match)) {
2220- return $this->drupalGet($this->getAbsoluteUrl(decode_entities($match['url'])));
2221- }
2222- }
2223- }
2224- return FALSE;
2225- }
2226-
2227- /**
2228- * Retrieves only the headers for a Drupal path or an absolute path.
2229- *
2230- * @param $path
2231- * Drupal path or URL to load into internal browser
2232- * @param $options
2233- * Options to be forwarded to url().
2234- * @param $headers
2235- * An array containing additional HTTP request headers, each formatted as
2236- * "name: value".
2237- * @return
2238- * The retrieved headers, also available as $this->drupalGetContent()
2239- */
2240- protected function drupalHead($path, array $options = array(), array $headers = array()) {
2241- $options['absolute'] = TRUE;
2242- $out = $this->curlExec(array(CURLOPT_NOBODY => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_HTTPHEADER => $headers));
2243- $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
2244- return $out;
2245- }
2246-
2247- /**
2248- * Handle form input related to drupalPost(). Ensure that the specified fields
2249- * exist and attempt to create POST data in the correct manner for the particular
2250- * field type.
2251- *
2252- * @param $post
2253- * Reference to array of post values.
2254- * @param $edit
2255- * Reference to array of edit values to be checked against the form.
2256- * @param $submit
2257- * Form submit button value.
2258- * @param $form
2259- * Array of form elements.
2260- * @return
2261- * Submit value matches a valid submit input in the form.
2262- */
2263- protected function handleForm(&$post, &$edit, &$upload, $submit, $form) {
2264- // Retrieve the form elements.
2265- $elements = $form->xpath('.//input|.//textarea|.//select');
2266- $submit_matches = FALSE;
2267- foreach ($elements as $element) {
2268- // SimpleXML objects need string casting all the time.
2269- $name = (string) $element['name'];
2270- // This can either be the type of <input> or the name of the tag itself
2271- // for <select> or <textarea>.
2272- $type = isset($element['type']) ? (string)$element['type'] : $element->getName();
2273- $value = isset($element['value']) ? (string)$element['value'] : '';
2274- $done = FALSE;
2275- if (isset($edit[$name])) {
2276- switch ($type) {
2277- case 'text':
2278- case 'textarea':
2279- case 'password':
2280- $post[$name] = $edit[$name];
2281- unset($edit[$name]);
2282- break;
2283- case 'radio':
2284- if ($edit[$name] == $value) {
2285- $post[$name] = $edit[$name];
2286- unset($edit[$name]);
2287- }
2288- break;
2289- case 'checkbox':
2290- // To prevent checkbox from being checked.pass in a FALSE,
2291- // otherwise the checkbox will be set to its value regardless
2292- // of $edit.
2293- if ($edit[$name] === FALSE) {
2294- unset($edit[$name]);
2295- continue 2;
2296- }
2297- else {
2298- unset($edit[$name]);
2299- $post[$name] = $value;
2300- }
2301- break;
2302- case 'select':
2303- $new_value = $edit[$name];
2304- $index = 0;
2305- $key = preg_replace('/\[\]$/', '', $name);
2306- $options = $this->getAllOptions($element);
2307- foreach ($options as $option) {
2308- if (is_array($new_value)) {
2309- $option_value= (string)$option['value'];
2310- if (in_array($option_value, $new_value)) {
2311- $post[$key . '[' . $index++ . ']'] = $option_value;
2312- $done = TRUE;
2313- unset($edit[$name]);
2314- }
2315- }
2316- elseif ($new_value == $option['value']) {
2317- $post[$name] = $new_value;
2318- unset($edit[$name]);
2319- $done = TRUE;
2320- }
2321- }
2322- break;
2323- case 'file':
2324- $upload[$name] = $edit[$name];
2325- unset($edit[$name]);
2326- break;
2327- }
2328- }
2329- if (!isset($post[$name]) && !$done) {
2330- switch ($type) {
2331- case 'textarea':
2332- $post[$name] = (string)$element;
2333- break;
2334- case 'select':
2335- $single = empty($element['multiple']);
2336- $first = TRUE;
2337- $index = 0;
2338- $key = preg_replace('/\[\]$/', '', $name);
2339- $options = $this->getAllOptions($element);
2340- foreach ($options as $option) {
2341- // For single select, we load the first option, if there is a
2342- // selected option that will overwrite it later.
2343- if ($option['selected'] || ($first && $single)) {
2344- $first = FALSE;
2345- if ($single) {
2346- $post[$name] = (string)$option['value'];
2347- }
2348- else {
2349- $post[$key . '[' . $index++ . ']'] = (string)$option['value'];
2350- }
2351- }
2352- }
2353- break;
2354- case 'file':
2355- break;
2356- case 'submit':
2357- case 'image':
2358- if ($submit == $value) {
2359- $post[$name] = $value;
2360- $submit_matches = TRUE;
2361- }
2362- break;
2363- case 'radio':
2364- case 'checkbox':
2365- if (!isset($element['checked'])) {
2366- break;
2367- }
2368- // Deliberate no break.
2369- default:
2370- $post[$name] = $value;
2371- }
2372- }
2373- }
2374- return $submit_matches;
2375- }
2376-
2377- /**
2378- * Perform an xpath search on the contents of the internal browser. The search
2379- * is relative to the root element (HTML tag normally) of the page.
2380- *
2381- * @param $xpath
2382- * The xpath string to use in the search.
2383- * @return
2384- * The return value of the xpath search. For details on the xpath string
2385- * format and return values see the SimpleXML documentation,
2386- * http://us.php.net/manual/function.simplexml-element-xpath.php.
2387- */
2388- protected function xpath($xpath) {
2389- if ($this->parse()) {
2390- return $this->elements->xpath($xpath);
2391- }
2392- return FALSE;
2393- }
2394-
2395- /**
2396- * Get all option elements, including nested options, in a select.
2397- *
2398- * @param $element
2399- * The element for which to get the options.
2400- * @return
2401- * Option elements in select.
2402- */
2403- protected function getAllOptions(SimpleXMLElement $element) {
2404- $options = array();
2405- // Add all options items.
2406- foreach ($element->option as $option) {
2407- $options[] = $option;
2408- }
2409-
2410- // Search option group children.
2411- if (isset($element->optgroup)) {
2412- foreach ($element->optgroup as $group) {
2413- $options = array_merge($options, $this->getAllOptions($group));
2414- }
2415- }
2416- return $options;
2417- }
2418-
2419- /**
2420- * Pass if a link with the specified label is found, and optional with the
2421- * specified index.
2422- *
2423- * @param $label
2424- * Text between the anchor tags.
2425- * @param $index
2426- * Link position counting from zero.
2427- * @param $message
2428- * Message to display.
2429- * @param $group
2430- * The group this message belongs to, defaults to 'Other'.
2431- * @return
2432- * TRUE if the assertion succeeded, FALSE otherwise.
2433- */
2434- protected function assertLink($label, $index = 0, $message = '', $group = 'Other') {
2435- $links = $this->xpath('//a[text()="' . $label . '"]');
2436- $message = ($message ? $message : t('Link with label "!label" found.', array('!label' => $label)));
2437- return $this->assert(isset($links[$index]), $message, $group);
2438- }
2439-
2440- /**
2441- * Pass if a link with the specified label is not found.
2442- *
2443- * @param $label
2444- * Text between the anchor tags.
2445- * @param $index
2446- * Link position counting from zero.
2447- * @param $message
2448- * Message to display.
2449- * @param $group
2450- * The group this message belongs to, defaults to 'Other'.
2451- * @return
2452- * TRUE if the assertion succeeded, FALSE otherwise.
2453- */
2454- protected function assertNoLink($label, $message = '', $group = 'Other') {
2455- $links = $this->xpath('//a[text()="' . $label . '"]');
2456- $message = ($message ? $message : t('Link with label "!label" not found.', array('!label' => $label)));
2457- return $this->assert(empty($links), $message, $group);
2458- }
2459-
2460- /**
2461- * Follows a link by name.
2462- *
2463- * Will click the first link found with this link text by default, or a
2464- * later one if an index is given. Match is case insensitive with
2465- * normalized space. The label is translated label. There is an assert
2466- * for successful click.
2467- *
2468- * @param $label
2469- * Text between the anchor tags.
2470- * @param $index
2471- * Link position counting from zero.
2472- * @return
2473- * Page on success, or FALSE on failure.
2474- */
2475- protected function clickLink($label, $index = 0) {
2476- $url_before = $this->getUrl();
2477- $urls = $this->xpath('//a[text()="' . $label . '"]');
2478-
2479- if (isset($urls[$index])) {
2480- $url_target = $this->getAbsoluteUrl($urls[$index]['href']);
2481- }
2482-
2483- $this->assertTrue(isset($urls[$index]), t('Clicked link "!label" (!url_target) from !url_before', array('!label' => $label, '!url_target' => $url_target, '!url_before' => $url_before)), t('Browser'));
2484-
2485- if (isset($urls[$index])) {
2486- return $this->drupalGet($url_target);
2487- }
2488- return FALSE;
2489- }
2490-
2491- /**
2492- * Takes a path and returns an absolute path.
2493- *
2494- * @param $path
2495- * The path, can be a Drupal path or a site-relative path. It might have a
2496- * query, too. Can even be an absolute path which is just passed through.
2497- * @return
2498- * An absolute path.
2499- */
2500- protected function getAbsoluteUrl($path) {
2501- $options = array('absolute' => TRUE);
2502- $parts = parse_url($path);
2503- // This is more crude than the menu_is_external but enough here.
2504- if (empty($parts['host'])) {
2505- $path = $parts['path'];
2506- $base_path = base_path();
2507- $n = strlen($base_path);
2508- if (substr($path, 0, $n) == $base_path) {
2509- $path = substr($path, $n);
2510- }
2511- if (isset($parts['query'])) {
2512- $options['query'] = $parts['query'];
2513- }
2514- $path = url($path, $options);
2515- }
2516- return $path;
2517- }
2518-
2519- /**
2520- * Get the current url from the cURL handler.
2521- *
2522- * @return
2523- * The current url.
2524- */
2525- protected function getUrl() {
2526- return $this->url;
2527- }
2528-
2529- /**
2530- * Gets the HTTP response headers of the requested page. Normally we are only
2531- * interested in the headers returned by the last request. However, if a page
2532- * is redirected or HTTP authentication is in use, multiple requests will be
2533- * required to retrieve the page. Headers from all requests may be requested
2534- * by passing TRUE to this function.
2535- *
2536- * @param $all_requests
2537- * Boolean value specifying whether to return headers from all requests
2538- * instead of just the last request. Defaults to FALSE.
2539- * @return
2540- * A name/value array if headers from only the last request are requested.
2541- * If headers from all requests are requested, an array of name/value
2542- * arrays, one for each request.
2543- *
2544- * The pseudonym ":status" is used for the HTTP status line.
2545- *
2546- * Values for duplicate headers are stored as a single comma-separated list.
2547- */
2548- protected function drupalGetHeaders($all_requests = FALSE) {
2549- $request = 0;
2550- $headers = array($request => array());
2551- foreach ($this->headers as $header) {
2552- $header = trim($header);
2553- if ($header === '') {
2554- $request++;
2555- }
2556- else {
2557- if (strpos($header, 'HTTP/') === 0) {
2558- $name = ':status';
2559- $value = $header;
2560- }
2561- else {
2562- list($name, $value) = explode(':', $header, 2);
2563- $name = strtolower($name);
2564- }
2565- if (isset($headers[$request][$name])) {
2566- $headers[$request][$name] .= ',' . trim($value);
2567- }
2568- else {
2569- $headers[$request][$name] = trim($value);
2570- }
2571- }
2572- }
2573- if (!$all_requests) {
2574- $headers = array_pop($headers);
2575- }
2576- return $headers;
2577- }
2578-
2579- /**
2580- * Gets the value of an HTTP response header. If multiple requests were
2581- * required to retrieve the page, only the headers from the last request will
2582- * be checked by default. However, if TRUE is passed as the second argument,
2583- * all requests will be processed from last to first until the header is
2584- * found.
2585- *
2586- * @param $name
2587- * The name of the header to retrieve. Names are case-insensitive (see RFC
2588- * 2616 section 4.2).
2589- * @param $all_requests
2590- * Boolean value specifying whether to check all requests if the header is
2591- * not found in the last request. Defaults to FALSE.
2592- * @return
2593- * The HTTP header value or FALSE if not found.
2594- */
2595- protected function drupalGetHeader($name, $all_requests = FALSE) {
2596- $name = strtolower($name);
2597- $header = FALSE;
2598- if ($all_requests) {
2599- foreach (array_reverse($this->drupalGetHeaders(TRUE)) as $headers) {
2600- if (isset($headers[$name])) {
2601- $header = $headers[$name];
2602- break;
2603- }
2604- }
2605- }
2606- else {
2607- $headers = $this->drupalGetHeaders();
2608- if (isset($headers[$name])) {
2609- $header = $headers[$name];
2610- }
2611- }
2612- return $header;
2613- }
2614-
2615- /**
2616- * Gets the current raw HTML of requested page.
2617- */
2618- protected function drupalGetContent() {
2619- return $this->content;
2620- }
2621-
2622- /**
2623- * Gets an array containing all e-mails sent during this test case.
2624- *
2625- * @param $filter
2626- * An array containing key/value pairs used to filter the e-mails that are returned.
2627- * @return
2628- * An array containing e-mail messages captured during the current test.
2629- */
2630- protected function drupalGetMails($filter = array()) {
2631- $captured_emails = variable_get('drupal_test_email_collector', array());
2632- $filtered_emails = array();
2633-
2634- foreach ($captured_emails as $message) {
2635- foreach ($filter as $key => $value) {
2636- if (!isset($message['params'][$key]) || $message['params'][$key] != $value) {
2637- continue 2;
2638- }
2639- }
2640- $filtered_emails[] = $message;
2641- }
2642-
2643- return $filtered_emails;
2644- }
2645-
2646- /**
2647- * Sets the raw HTML content. This can be useful when a page has been fetched
2648- * outside of the internal browser and assertions need to be made on the
2649- * returned page.
2650- *
2651- * A good example would be when testing drupal_http_request(). After fetching
2652- * the page the content can be set and page elements can be checked to ensure
2653- * that the function worked properly.
2654- */
2655- protected function drupalSetContent($content, $url = 'internal:') {
2656- $this->content = $content;
2657- $this->url = $url;
2658- $this->plainTextContent = FALSE;
2659- $this->elements = FALSE;
2660- }
2661-
2662- /**
2663- * Pass if the raw text IS found on the loaded page, fail otherwise. Raw text
2664- * refers to the raw HTML that the page generated.
2665- *
2666- * @param $raw
2667- * Raw (HTML) string to look for.
2668- * @param $message
2669- * Message to display.
2670- * @param $group
2671- * The group this message belongs to, defaults to 'Other'.
2672- * @return
2673- * TRUE on pass, FALSE on fail.
2674- */
2675- protected function assertRaw($raw, $message = '', $group = 'Other') {
2676- if (!$message) {
2677- $message = t('Raw "@raw" found', array('@raw' => check_plain($raw)));
2678- }
2679- return $this->assert(strpos($this->content, $raw) !== FALSE, $message, $group);
2680- }
2681-
2682- /**
2683- * Pass if the raw text is NOT found on the loaded page, fail otherwise. Raw text
2684- * refers to the raw HTML that the page generated.
2685- *
2686- * @param $raw
2687- * Raw (HTML) string to look for.
2688- * @param $message
2689- * Message to display.
2690- * @param $group
2691- * The group this message belongs to, defaults to 'Other'.
2692- * @return
2693- * TRUE on pass, FALSE on fail.
2694- */
2695- protected function assertNoRaw($raw, $message = '', $group = 'Other') {
2696- if (!$message) {
2697- $message = t('Raw "@raw" not found', array('@raw' => check_plain($raw)));
2698- }
2699- return $this->assert(strpos($this->content, $raw) === FALSE, $message, $group);
2700- }
2701-
2702- /**
2703- * Pass if the text IS found on the text version of the page. The text version
2704- * is the equivalent of what a user would see when viewing through a web browser.
2705- * In other words the HTML has been filtered out of the contents.
2706- *
2707- * @param $text
2708- * Plain text to look for.
2709- * @param $message
2710- * Message to display.
2711- * @param $group
2712- * The group this message belongs to, defaults to 'Other'.
2713- * @return
2714- * TRUE on pass, FALSE on fail.
2715- */
2716- protected function assertText($text, $message = '', $group = 'Other') {
2717- return $this->assertTextHelper($text, $message, $group, FALSE);
2718- }
2719-
2720- /**
2721- * Pass if the text is NOT found on the text version of the page. The text version
2722- * is the equivalent of what a user would see when viewing through a web browser.
2723- * In other words the HTML has been filtered out of the contents.
2724- *
2725- * @param $text
2726- * Plain text to look for.
2727- * @param $message
2728- * Message to display.
2729- * @param $group
2730- * The group this message belongs to, defaults to 'Other'.
2731- * @return
2732- * TRUE on pass, FALSE on fail.
2733- */
2734- protected function assertNoText($text, $message = '', $group = 'Other') {
2735- return $this->assertTextHelper($text, $message, $group, TRUE);
2736- }
2737-
2738- /**
2739- * Helper for assertText and assertNoText.
2740- *
2741- * It is not recommended to call this function directly.
2742- *
2743- * @param $text
2744- * Plain text to look for.
2745- * @param $message
2746- * Message to display.
2747- * @param $group
2748- * The group this message belongs to.
2749- * @param $not_exists
2750- * TRUE if this text should not exist, FALSE if it should.
2751- * @return
2752- * TRUE on pass, FALSE on fail.
2753- */
2754- protected function assertTextHelper($text, $message, $group, $not_exists) {
2755- if ($this->plainTextContent === FALSE) {
2756- $this->plainTextContent = filter_xss($this->content, array());
2757- }
2758- if (!$message) {
2759- $message = !$not_exists ? t('"@text" found', array('@text' => $text)) : t('"@text" not found', array('@text' => $text));
2760- }
2761- return $this->assert($not_exists == (strpos($this->plainTextContent, $text) === FALSE), $message, $group);
2762- }
2763-
2764- /**
2765- * Pass if the text is found ONLY ONCE on the text version of the page.
2766- *
2767- * The text version is the equivalent of what a user would see when viewing
2768- * through a web browser. In other words the HTML has been filtered out of
2769- * the contents.
2770- *
2771- * @param $text
2772- * Plain text to look for.
2773- * @param $message
2774- * Message to display.
2775- * @param $group
2776- * The group this message belongs to, defaults to 'Other'.
2777- * @return
2778- * TRUE on pass, FALSE on fail.
2779- */
2780- protected function assertUniqueText($text, $message = '', $group = 'Other') {
2781- return $this->assertUniqueTextHelper($text, $message, $group, TRUE);
2782- }
2783-
2784- /**
2785- * Pass if the text is found MORE THAN ONCE on the text version of the page.
2786- *
2787- * The text version is the equivalent of what a user would see when viewing
2788- * through a web browser. In other words the HTML has been filtered out of
2789- * the contents.
2790- *
2791- * @param $text
2792- * Plain text to look for.
2793- * @param $message
2794- * Message to display.
2795- * @param $group
2796- * The group this message belongs to, defaults to 'Other'.
2797- * @return
2798- * TRUE on pass, FALSE on fail.
2799- */
2800- protected function assertNoUniqueText($text, $message = '', $group = 'Other') {
2801- return $this->assertUniqueTextHelper($text, $message, $group, FALSE);
2802- }
2803-
2804- /**
2805- * Helper for assertUniqueText and assertNoUniqueText.
2806- *
2807- * It is not recommended to call this function directly.
2808- *
2809- * @param $text
2810- * Plain text to look for.
2811- * @param $message
2812- * Message to display.
2813- * @param $group
2814- * The group this message belongs to.
2815- * @param $be_unique
2816- * TRUE if this text should be found only once, FALSE if it should be found more than once.
2817- * @return
2818- * TRUE on pass, FALSE on fail.
2819- */
2820- protected function assertUniqueTextHelper($text, $message, $group, $be_unique) {
2821- if ($this->plainTextContent === FALSE) {
2822- $this->plainTextContent = filter_xss($this->content, array());
2823- }
2824- if (!$message) {
2825- $message = '"' . $text . '"' . ($be_unique ? ' found only once' : ' found more than once');
2826- }
2827- $first_occurance = strpos($this->plainTextContent, $text);
2828- if ($first_occurance === FALSE) {
2829- return $this->assert(FALSE, $message, $group);
2830- }
2831- $offset = $first_occurance + strlen($text);
2832- $second_occurance = strpos($this->plainTextContent, $text, $offset);
2833- return $this->assert($be_unique == ($second_occurance === FALSE), $message, $group);
2834- }
2835-
2836- /**
2837- * Will trigger a pass if the Perl regex pattern is found in the raw content.
2838- *
2839- * @param $pattern
2840- * Perl regex to look for including the regex delimiters.
2841- * @param $message
2842- * Message to display.
2843- * @param $group
2844- * The group this message belongs to.
2845- * @return
2846- * TRUE on pass, FALSE on fail.
2847- */
2848- protected function assertPattern($pattern, $message = '', $group = 'Other') {
2849- if (!$message) {
2850- $message = t('Pattern "@pattern" found', array('@pattern' => $pattern));
2851- }
2852- return $this->assert((bool) preg_match($pattern, $this->drupalGetContent()), $message, $group);
2853- }
2854-
2855- /**
2856- * Will trigger a pass if the perl regex pattern is not present in raw content.
2857- *
2858- * @param $pattern
2859- * Perl regex to look for including the regex delimiters.
2860- * @param $message
2861- * Message to display.
2862- * @param $group
2863- * The group this message belongs to.
2864- * @return
2865- * TRUE on pass, FALSE on fail.
2866- */
2867- protected function assertNoPattern($pattern, $message = '', $group = 'Other') {
2868- if (!$message) {
2869- $message = t('Pattern "@pattern" not found', array('@pattern' => $pattern));
2870- }
2871- return $this->assert(!preg_match($pattern, $this->drupalGetContent()), $message, $group);
2872- }
2873-
2874- /**
2875- * Pass if the page title is the given string.
2876- *
2877- * @param $title
2878- * The string the title should be.
2879- * @param $message
2880- * Message to display.
2881- * @param $group
2882- * The group this message belongs to.
2883- * @return
2884- * TRUE on pass, FALSE on fail.
2885- */
2886- protected function assertTitle($title, $message, $group = 'Other') {
2887- return $this->assertEqual(current($this->xpath('//title')), $title, $message, $group);
2888- }
2889-
2890- /**
2891- * Pass if the page title is not the given string.
2892- *
2893- * @param $title
2894- * The string the title should not be.
2895- * @param $message
2896- * Message to display.
2897- * @param $group
2898- * The group this message belongs to.
2899- * @return
2900- * TRUE on pass, FALSE on fail.
2901- */
2902- protected function assertNoTitle($title, $message, $group = 'Other') {
2903- return $this->assertNotEqual(current($this->xpath('//title')), $title, $message, $group);
2904- }
2905-
2906- /**
2907- * Assert that a field exists in the current page by the given XPath.
2908- *
2909- * @param $xpath
2910- * XPath used to find the field.
2911- * @param $value
2912- * Value of the field to assert.
2913- * @param $message
2914- * Message to display.
2915- * @param $group
2916- * The group this message belongs to.
2917- * @return
2918- * TRUE on pass, FALSE on fail.
2919- */
2920- protected function assertFieldByXPath($xpath, $value, $message, $group = 'Other') {
2921- $fields = $this->xpath($xpath);
2922-
2923- // If value specified then check array for match.
2924- $found = TRUE;
2925- if ($value) {
2926- $found = FALSE;
2927- if ($fields) {
2928- foreach ($fields as $field) {
2929- if (isset($field['value']) && $field['value'] == $value) {
2930- // Input element with correct value.
2931- $found = TRUE;
2932- }
2933- elseif (isset($field->option)) {
2934- // Select element found.
2935- if ($this->getSelectedItem($field) == $value) {
2936- $found = TRUE;
2937- }
2938- else {
2939- // No item selected so use first item.
2940- $items = $this->getAllOptions($field);
2941- if (!empty($items) && $items[0]['value'] == $value) {
2942- $found = TRUE;
2943- }
2944- }
2945- }
2946- elseif ((string) $field == $value) {
2947- // Text area with correct text.
2948- $found = TRUE;
2949- }
2950- }
2951- }
2952- }
2953- return $this->assertTrue($fields && $found, $message, $group);
2954- }
2955-
2956- /**
2957- * Get the selected value from a select field.
2958- *
2959- * @param $element
2960- * SimpleXMLElement select element.
2961- * @return
2962- * The selected value or FALSE.
2963- */
2964- protected function getSelectedItem(SimpleXMLElement $element) {
2965- foreach ($element->children() as $item) {
2966- if (isset($item['selected'])) {
2967- return $item['value'];
2968- }
2969- elseif ($item->getName() == 'optgroup') {
2970- if ($value = $this->getSelectedItem($item)) {
2971- return $value;
2972- }
2973- }
2974- }
2975- return FALSE;
2976- }
2977-
2978- /**
2979- * Assert that a field does not exist in the current page by the given XPath.
2980- *
2981- * @param $xpath
2982- * XPath used to find the field.
2983- * @param $value
2984- * Value of the field to assert.
2985- * @param $message
2986- * Message to display.
2987- * @param $group
2988- * The group this message belongs to.
2989- * @return
2990- * TRUE on pass, FALSE on fail.
2991- */
2992- protected function assertNoFieldByXPath($xpath, $value, $message, $group = 'Other') {
2993- $fields = $this->xpath($xpath);
2994-
2995- // If value specified then check array for match.
2996- $found = TRUE;
2997- if ($value) {
2998- $found = FALSE;
2999- if ($fields) {
3000- foreach ($fields as $field) {
3001- if ($field['value'] == $value) {
3002- $found = TRUE;
3003- }
3004- }
3005- }
3006- }
3007- return $this->assertFalse($fields && $found, $message, $group);
3008- }
3009-
3010- /**
3011- * Assert that a field exists in the current page with the given name and value.
3012- *
3013- * @param $name
3014- * Name of field to assert.
3015- * @param $value
3016- * Value of the field to assert.
3017- * @param $message
3018- * Message to display.
3019- * @param $group
3020- * The group this message belongs to.
3021- * @return
3022- * TRUE on pass, FALSE on fail.
3023- */
3024- protected function assertFieldByName($name, $value = '', $message = '') {
3025- return $this->assertFieldByXPath($this->constructFieldXpath('name', $name), $value, $message ? $message : t('Found field by name @name', array('@name' => $name)), t('Browser'));
3026- }
3027-
3028- /**
3029- * Assert that a field does not exist with the given name and value.
3030- *
3031- * @param $name
3032- * Name of field to assert.
3033- * @param $value
3034- * Value of the field to assert.
3035- * @param $message
3036- * Message to display.
3037- * @param $group
3038- * The group this message belongs to.
3039- * @return
3040- * TRUE on pass, FALSE on fail.
3041- */
3042- protected function assertNoFieldByName($name, $value = '', $message = '') {
3043- return $this->assertNoFieldByXPath($this->constructFieldXpath('name', $name), $value, $message ? $message : t('Did not find field by name @name', array('@name' => $name)), t('Browser'));
3044- }
3045-
3046- /**
3047- * Assert that a field exists in the current page with the given id and value.
3048- *
3049- * @param $id
3050- * Id of field to assert.
3051- * @param $value
3052- * Value of the field to assert.
3053- * @param $message
3054- * Message to display.
3055- * @param $group
3056- * The group this message belongs to.
3057- * @return
3058- * TRUE on pass, FALSE on fail.
3059- */
3060- protected function assertFieldById($id, $value = '', $message = '') {
3061- return $this->assertFieldByXPath($this->constructFieldXpath('id', $id), $value, $message ? $message : t('Found field by id @id', array('@id' => $id)), t('Browser'));
3062- }
3063-
3064- /**
3065- * Assert that a field does not exist with the given id and value.
3066- *
3067- * @param $id
3068- * Id of field to assert.
3069- * @param $value
3070- * Value of the field to assert.
3071- * @param $message
3072- * Message to display.
3073- * @param $group
3074- * The group this message belongs to.
3075- * @return
3076- * TRUE on pass, FALSE on fail.
3077- */
3078- protected function assertNoFieldById($id, $value = '', $message = '') {
3079- return $this->assertNoFieldByXPath($this->constructFieldXpath('id', $id), $value, $message ? $message : t('Did not find field by id @id', array('@id' => $id)), t('Browser'));
3080- }
3081-
3082- /**
3083- * Assert that a checkbox field in the current page is checked.
3084- *
3085- * @param $id
3086- * Id of field to assert.
3087- * @param $message
3088- * Message to display.
3089- * @return
3090- * TRUE on pass, FALSE on fail.
3091- */
3092- protected function assertFieldChecked($id, $message = '') {
3093- $elements = $this->xpath('//input[@id="' . $id . '"]');
3094- return $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), $message ? $message : t('Checkbox field @id is checked.', array('@id' => $id)), t('Browser'));
3095- }
3096-
3097- /**
3098- * Assert that a checkbox field in the current page is not checked.
3099- *
3100- * @param $id
3101- * Id of field to assert.
3102- * @param $message
3103- * Message to display.
3104- * @return
3105- * TRUE on pass, FALSE on fail.
3106- */
3107- protected function assertNoFieldChecked($id, $message = '') {
3108- $elements = $this->xpath('//input[@id="' . $id . '"]');
3109- return $this->assertTrue(isset($elements[0]) && empty($elements[0]['checked']), $message ? $message : t('Checkbox field @id is not checked.', array('@id' => $id)), t('Browser'));
3110- }
3111-
3112- /**
3113- * Assert that a field exists with the given name or id.
3114- *
3115- * @param $field
3116- * Name or id of field to assert.
3117- * @param $message
3118- * Message to display.
3119- * @param $group
3120- * The group this message belongs to.
3121- * @return
3122- * TRUE on pass, FALSE on fail.
3123- */
3124- protected function assertField($field, $message = '', $group = 'Other') {
3125- return $this->assertFieldByXPath($this->constructFieldXpath('name', $field) . '|' . $this->constructFieldXpath('id', $field), '', $message, $group);
3126- }
3127-
3128- /**
3129- * Assert that a field does not exist with the given name or id.
3130- *
3131- * @param $field
3132- * Name or id of field to assert.
3133- * @param $message
3134- * Message to display.
3135- * @param $group
3136- * The group this message belongs to.
3137- * @return
3138- * TRUE on pass, FALSE on fail.
3139- */
3140- protected function assertNoField($field, $message = '', $group = 'Other') {
3141- return $this->assertNoFieldByXPath($this->constructFieldXpath('name', $field) . '|' . $this->constructFieldXpath('id', $field), '', $message, $group);
3142- }
3143-
3144- /**
3145- * Helper function: construct an XPath for the given set of attributes and value.
3146- *
3147- * @param $attribute
3148- * Field attributes.
3149- * @param $value
3150- * Value of field.
3151- * @return
3152- * XPath for specified values.
3153- */
3154- protected function constructFieldXpath($attribute, $value) {
3155- return '//textarea[@' . $attribute . '="' . $value . '"]|//input[@' . $attribute . '="' . $value . '"]|//select[@' . $attribute . '="' . $value . '"]';
3156- }
3157-
3158- /**
3159- * Assert the page responds with the specified response code.
3160- *
3161- * @param $code
3162- * Response code. For example 200 is a successful page request. For a list
3163- * of all codes see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.
3164- * @param $message
3165- * Message to display.
3166- * @return
3167- * Assertion result.
3168- */
3169- protected function assertResponse($code, $message = '') {
3170- $curl_code = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);
3171- $match = is_array($code) ? in_array($curl_code, $code) : $curl_code == $code;
3172- return $this->assertTrue($match, $message ? $message : t('HTTP response expected !code, actual !curl_code', array('!code' => $code, '!curl_code' => $curl_code)), t('Browser'));
3173- }
3174-
3175- /**
3176- * Assert that the most recently sent e-mail message has a field with the given value.
3177- *
3178- * @param $name
3179- * Name of field or message property to assert. Examples: subject, body, id, ...
3180- * @param $value
3181- * Value of the field to assert.
3182- * @param $message
3183- * Message to display.
3184- * @return
3185- * TRUE on pass, FALSE on fail.
3186- */
3187- protected function assertMail($name, $value = '', $message = '') {
3188- $captured_emails = variable_get('drupal_test_email_collector', array());
3189- $email = end($captured_emails);
3190- return $this->assertTrue($email && isset($email['params'][$name]) && $email['params'][$name] == $value, $message, t('E-mail'));
3191- }
3192-
3193- /**
3194- * Log verbose message in a text file.
3195- *
3196- * The a link to the vebose message will be placed in the test results via
3197- * as a passing assertion with the text '[verbose message]'.
3198- *
3199- * @param $message
3200- * The verbose message to be stored.
3201- * @see simpletest_verbose()
3202- */
3203- protected function verbose($message) {
3204- if ($id = simpletest_verbose($message)) {
3205- $this->pass(l(t('Verbose message'), $this->originalFileDirectory . '/simpletest/verbose/' . get_class($this) . '-' . $id . '.html', array('attributes' => array('target' => '_blank'))), 'Debug');
3206- }
3207- }
3208-
3209-}
3210-
3211-/**
3212- * Log verbose message in a text file.
3213- *
3214- * If verbose mode is enabled then page requests will be dumped to a file and
3215- * presented on the test result screen. The messages will be placed in a file
3216- * located in the simpletest directory in the original file system.
3217- *
3218- * @param $message
3219- * The verbose message to be stored.
3220- * @param $original_file_directory
3221- * The original file directory, before it was changed for testing purposes.
3222- * @param $test_class
3223- * The active test case class.
3224- * @return
3225- * The ID of the message to be placed in related assertion messages.
3226- * @see DrupalTestCase->originalFileDirectory
3227- * @see DrupalWebTestCase->verbose()
3228- */
3229-function simpletest_verbose($message, $original_file_directory = NULL, $test_class = NULL) {
3230- static $file_directory = NULL, $class = NULL, $id = 1;
3231- static $verbose;
3232-
3233- // Will pass first time during setup phase, and when verbose is TRUE.
3234- if (!isset($original_file_directory) && !$verbose) {
3235- return FALSE;
3236- }
3237-
3238- if ($message && $file_directory) {
3239- $message = '<hr />ID #' . $id . ' (<a href="' . $class . '-' . ($id - 1) . '.html">Previous</a> | <a href="' . $class . '-' . ($id + 1) . '.html">Next</a>)<hr />' . $message;
3240- file_put_contents($file_directory . "/simpletest/verbose/$class-$id.html", $message, FILE_APPEND);
3241- return $id++;
3242- }
3243-
3244- if ($original_file_directory) {
3245- $file_directory = $original_file_directory;
3246- $class = $test_class;
3247- $verbose = variable_get('simpletest_verbose', FALSE);
3248- $directory = $file_directory . '/simpletest/verbose';
3249- return file_check_directory($directory, FILE_CREATE_DIRECTORY);
3250- }
3251- return FALSE;
3252-}
3253
3254=== removed directory 'modules/simpletest/files'
3255=== removed file 'modules/simpletest/files/README.txt'
3256--- modules/simpletest/files/README.txt 2009-09-15 16:10:36 +0000
3257+++ modules/simpletest/files/README.txt 1970-01-01 00:00:00 +0000
3258@@ -1,6 +0,0 @@
3259-$Id: README.txt,v 1.1.2.3 2009/09/14 23:05:19 boombatower Exp $
3260-Core: Id: README.txt,v 1.1 2008/04/20 18:23:30 dries Exp
3261-
3262-These files are use in some tests that upload files or other operations were
3263-a file is useful. These files are copied to the files directory as specified
3264-in the site settings. Other tests files are generated in order to save space.
3265\ No newline at end of file
3266
3267=== removed file 'modules/simpletest/files/html-1.txt'
3268--- modules/simpletest/files/html-1.txt 2009-04-27 17:27:02 +0000
3269+++ modules/simpletest/files/html-1.txt 1970-01-01 00:00:00 +0000
3270@@ -1,1 +0,0 @@
3271-<h1>SimpleTest HTML</h1>
3272\ No newline at end of file
3273
3274=== removed file 'modules/simpletest/files/html-2.html'
3275--- modules/simpletest/files/html-2.html 2009-04-27 17:27:02 +0000
3276+++ modules/simpletest/files/html-2.html 1970-01-01 00:00:00 +0000
3277@@ -1,1 +0,0 @@
3278-<h1>SimpleTest HTML</h1>
3279\ No newline at end of file
3280
3281=== removed file 'modules/simpletest/files/image-1.png'
3282Binary files modules/simpletest/files/image-1.png 2009-04-27 17:27:02 +0000 and modules/simpletest/files/image-1.png 1970-01-01 00:00:00 +0000 differ
3283=== removed file 'modules/simpletest/files/image-2.jpg'
3284Binary files modules/simpletest/files/image-2.jpg 2009-04-27 17:27:02 +0000 and modules/simpletest/files/image-2.jpg 1970-01-01 00:00:00 +0000 differ
3285=== removed file 'modules/simpletest/files/image-test.gif'
3286Binary files modules/simpletest/files/image-test.gif 2009-04-27 17:27:02 +0000 and modules/simpletest/files/image-test.gif 1970-01-01 00:00:00 +0000 differ
3287=== removed file 'modules/simpletest/files/image-test.jpg'
3288Binary files modules/simpletest/files/image-test.jpg 2009-04-27 17:27:02 +0000 and modules/simpletest/files/image-test.jpg 1970-01-01 00:00:00 +0000 differ
3289=== removed file 'modules/simpletest/files/image-test.png'
3290Binary files modules/simpletest/files/image-test.png 2009-04-27 17:27:02 +0000 and modules/simpletest/files/image-test.png 1970-01-01 00:00:00 +0000 differ
3291=== removed file 'modules/simpletest/files/javascript-1.txt'
3292--- modules/simpletest/files/javascript-1.txt 2009-04-27 17:27:02 +0000
3293+++ modules/simpletest/files/javascript-1.txt 1970-01-01 00:00:00 +0000
3294@@ -1,3 +0,0 @@
3295-<script>
3296-alert('SimpleTest PHP was executed!');
3297-</script>
3298\ No newline at end of file
3299
3300=== removed file 'modules/simpletest/files/javascript-2.script'
3301--- modules/simpletest/files/javascript-2.script 2009-04-27 17:27:02 +0000
3302+++ modules/simpletest/files/javascript-2.script 1970-01-01 00:00:00 +0000
3303@@ -1,3 +0,0 @@
3304-<script>
3305-alert('SimpleTest PHP was executed!');
3306-</script>
3307\ No newline at end of file
3308
3309=== removed file 'modules/simpletest/files/php-1.txt'
3310--- modules/simpletest/files/php-1.txt 2009-04-27 17:27:02 +0000
3311+++ modules/simpletest/files/php-1.txt 1970-01-01 00:00:00 +0000
3312@@ -1,3 +0,0 @@
3313-<?php
3314-print 'SimpleTest PHP was executed!';
3315-?>
3316\ No newline at end of file
3317
3318=== removed file 'modules/simpletest/files/php-2.php'
3319--- modules/simpletest/files/php-2.php 2009-09-15 16:10:36 +0000
3320+++ modules/simpletest/files/php-2.php 1970-01-01 00:00:00 +0000
3321@@ -1,2 +0,0 @@
3322-<?php
3323-print 'SimpleTest PHP was executed!';
3324
3325=== removed file 'modules/simpletest/files/sql-1.txt'
3326--- modules/simpletest/files/sql-1.txt 2009-04-27 17:27:02 +0000
3327+++ modules/simpletest/files/sql-1.txt 1970-01-01 00:00:00 +0000
3328@@ -1,1 +0,0 @@
3329-SELECT invalid_field FROM {invalid_table}
3330\ No newline at end of file
3331
3332=== removed file 'modules/simpletest/files/sql-2.sql'
3333--- modules/simpletest/files/sql-2.sql 2009-04-27 17:27:02 +0000
3334+++ modules/simpletest/files/sql-2.sql 1970-01-01 00:00:00 +0000
3335@@ -1,1 +0,0 @@
3336-SELECT invalid_field FROM {invalid_table}
3337\ No newline at end of file
3338
3339=== removed file 'modules/simpletest/run-tests.sh'
3340--- modules/simpletest/run-tests.sh 2009-09-11 00:40:07 +0000
3341+++ modules/simpletest/run-tests.sh 1970-01-01 00:00:00 +0000
3342@@ -1,590 +0,0 @@
3343-<?php
3344-// $Id: run-tests.sh,v 1.1.2.5 2009/09/05 13:34:10 boombatower Exp $
3345-// Core: Id: run-tests.sh,v 1.35 2009/08/17 19:14:41 webchick Exp
3346-
3347-/**
3348- * @file
3349- * Backport of Drupal 7 run-tests.sh with modifications, see BACKPORT.txt.
3350- * This file must be placed in the Drupal scripts folder in order for it to
3351- * work properly.
3352- *
3353- * Copyright 2008-2009 by Jimmy Berry ("boombatower", http://drupal.org/user/214218)
3354- */
3355-
3356-define('SIMPLETEST_SCRIPT_COLOR_PASS', 32); // Green.
3357-define('SIMPLETEST_SCRIPT_COLOR_FAIL', 31); // Red.
3358-define('SIMPLETEST_SCRIPT_COLOR_EXCEPTION', 33); // Brown.
3359-
3360-// Set defaults and get overrides.
3361-list($args, $count) = simpletest_script_parse_args();
3362-
3363-if ($args['help'] || $count == 0) {
3364- simpletest_script_help();
3365- exit;
3366-}
3367-
3368-if ($args['execute-batch']) {
3369- // Masquerade as Apache for running tests.
3370- simpletest_script_init("Apache");
3371- simpletest_script_execute_batch();
3372-}
3373-else {
3374- // Run administrative functions as CLI.
3375- simpletest_script_init("PHP CLI");
3376-}
3377-
3378-// Bootstrap to perform initial validation or other operations.
3379-drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
3380-if (!module_exists('simpletest')) {
3381- simpletest_script_print_error("The simpletest module must be enabled before this script can run.");
3382- exit;
3383-}
3384-
3385-if ($args['clean']) {
3386- // Clean up left-over times and directories.
3387- simpletest_clean_environment();
3388- echo "\nEnvironment cleaned.\n";
3389-
3390- // Get the status messages and print them.
3391- $messages = array_pop(drupal_get_messages('status'));
3392- foreach($messages as $text) {
3393- echo " - " . $text . "\n";
3394- }
3395- exit;
3396-}
3397-
3398-// Load SimpleTest files.
3399-$groups = simpletest_test_get_all();
3400-$all_tests = array();
3401-foreach ($groups as $group => $tests) {
3402- $all_tests = array_merge($all_tests, array_keys($tests));
3403-}
3404-$test_list = array();
3405-
3406-if ($args['list']) {
3407- // Display all available tests.
3408- echo "\nAvailable test groups & classes\n";
3409- echo "-------------------------------\n\n";
3410- foreach ($groups as $group => $tests) {
3411- echo $group . "\n";
3412- foreach ($tests as $class => $info) {
3413- echo " - " . $info['name'] . ' (' . $class . ')' . "\n";
3414- }
3415- }
3416- exit;
3417-}
3418-
3419-$test_list = simpletest_script_get_test_list();
3420-
3421-// Try to allocate unlimited time to run the tests.
3422-//drupal_set_time_limit(0);
3423-if (!ini_get('safe_mode')) {
3424- set_time_limit(0);
3425-}
3426-
3427-simpletest_script_reporter_init();
3428-
3429-// Setup database for test results.
3430-//$test_id = db_insert('simpletest_test_id')->useDefaults(array('test_id'))->execute();
3431-db_query('INSERT INTO {simpletest_test_id} VALUES (default)');
3432-$test_id = db_last_insert_id('simpletest_test_id', 'test_id');
3433-
3434-// Execute tests.
3435-simpletest_script_command($args['concurrency'], $test_id, implode(",", $test_list));
3436-
3437-// Retrieve the last database prefix used for testing and the last test class
3438-// that was run from. Use the information to read the lgo file in case any
3439-// fatal errors caused the test to crash.
3440-list($last_prefix, $last_test_class) = simpletest_last_test_get($test_id);
3441-simpletest_log_read($test_id, $last_prefix, $last_test_class);
3442-
3443-// Display results before database is cleared.
3444-simpletest_script_reporter_display_results();
3445-
3446-// Cleanup our test results.
3447-simpletest_clean_results_table($test_id);
3448-
3449-/**
3450- * Print help text.
3451- */
3452-function simpletest_script_help() {
3453- global $args;
3454-
3455- echo <<<EOF
3456-
3457-Run Drupal tests from the shell.
3458-
3459-Usage: {$args['script']} [OPTIONS] <tests>
3460-Example: {$args['script']} Profile
3461-
3462-All arguments are long options.
3463-
3464- --help Print this page.
3465-
3466- --list Display all available test groups.
3467-
3468- --clean Cleans up database tables or directories from previous, failed,
3469- tests and then exits (no tests are run).
3470-
3471- --url Immediately preceeds a URL to set the host and path. You will
3472- need this parameter if Drupal is in a subdirectory on your
3473- localhost and you have not set \$base_url in settings.php.
3474-
3475- --php The absolute path to the PHP executable. Usually not needed.
3476-
3477- --concurrency [num]
3478-
3479- Run tests in parallel, up to [num] tests at a time. This requires
3480- the Process Control Extension (PCNTL) to be compiled in PHP, not
3481- supported under Windows.
3482-
3483- --all Run all available tests.
3484-
3485- --class Run tests identified by specific class names, instead of group names.
3486-
3487- --file Run tests identified by specific file names, instead of group names.
3488- Specify the path and the extension (i.e. 'modules/user/user.test').
3489-
3490- --color Output the results with color highlighting.
3491-
3492- --verbose Output detailed assertion messages in addition to summary.
3493-
3494- <test1>[,<test2>[,<test3> ...]]
3495-
3496- One or more tests to be run. By default, these are interpreted
3497- as the names of test groups as shown at
3498- ?q=admin/build/testing.
3499- These group names typically correspond to module names like "User"
3500- or "Profile" or "System", but there is also a group "XML-RPC".
3501- If --class is specified then these are interpreted as the names of
3502- specific test classes whose test methods will be run. Tests must
3503- be separated by commas. Ignored if --all is specified.
3504-
3505-To run this script you will normally invoke it from the root directory of your
3506-Drupal installation as the webserver user (differs per configuration), or root:
3507-
3508-sudo -u [wwwrun|www-data|etc] php ./scripts/{$args['script']}
3509- --url http://example.com/ --all
3510-sudo -u [wwwrun|www-data|etc] php ./scripts/{$args['script']}
3511- --url http://example.com/ --class UploadTestCase
3512-\n
3513-EOF;
3514-}
3515-
3516-/**
3517- * Parse execution argument and ensure that all are valid.
3518- *
3519- * @return The list of arguments.
3520- */
3521-function simpletest_script_parse_args() {
3522- // Set default values.
3523- $args = array(
3524- 'script' => '',
3525- 'help' => FALSE,
3526- 'list' => FALSE,
3527- 'clean' => FALSE,
3528- 'url' => '',
3529- 'php' => '',
3530- 'concurrency' => 1,
3531- 'all' => FALSE,
3532- 'class' => FALSE,
3533- 'file' => FALSE,
3534- 'color' => FALSE,
3535- 'verbose' => FALSE,
3536- 'test_names' => array(),
3537- // Used internally.
3538- 'test-id' => NULL,
3539- 'execute-batch' => FALSE
3540- );
3541-
3542- // Override with set values.
3543- $args['script'] = basename(array_shift($_SERVER['argv']));
3544-
3545- $count = 0;
3546- while ($arg = array_shift($_SERVER['argv'])) {
3547- if (preg_match('/--(\S+)/', $arg, $matches)) {
3548- // Argument found.
3549- if (array_key_exists($matches[1], $args)) {
3550- // Argument found in list.
3551- $previous_arg = $matches[1];
3552- if (is_bool($args[$previous_arg])) {
3553- $args[$matches[1]] = TRUE;
3554- }
3555- else {
3556- $args[$matches[1]] = array_shift($_SERVER['argv']);
3557- }
3558- // Clear extraneous values.
3559- $args['test_names'] = array();
3560- $count++;
3561- }
3562- else {
3563- // Argument not found in list.
3564- simpletest_script_print_error("Unknown argument '$arg'.");
3565- exit;
3566- }
3567- }
3568- else {
3569- // Values found without an argument should be test names.
3570- $args['test_names'] += explode(',', $arg);
3571- $count++;
3572- }
3573- }
3574-
3575- // Validate the concurrency argument
3576- if (!is_numeric($args['concurrency']) || $args['concurrency'] <= 0) {
3577- simpletest_script_print_error("--concurrency must be a strictly positive integer.");
3578- exit;
3579- }
3580- elseif ($args['concurrency'] > 1 && !function_exists('pcntl_fork')) {
3581- simpletest_script_print_error("Parallel test execution requires the Process Control extension to be compiled in PHP. Please see http://php.net/manual/en/intro.pcntl.php for more information.");
3582- exit;
3583- }
3584-
3585- return array($args, $count);
3586-}
3587-
3588-/**
3589- * Initialize script variables and perform general setup requirements.
3590- */
3591-function simpletest_script_init($server_software) {
3592- global $args, $php;
3593-
3594- $host = 'localhost';
3595- $path = '';
3596- // Determine location of php command automatically, unless a command line argument is supplied.
3597- if (!empty($args['php'])) {
3598- $php = $args['php'];
3599- }
3600- elseif (!empty($_ENV['_'])) {
3601- // '_' is an environment variable set by the shell. It contains the command that was executed.
3602- $php = $_ENV['_'];
3603- }
3604- elseif (!empty($_ENV['SUDO_COMMAND'])) {
3605- // 'SUDO_COMMAND' is an environment variable set by the sudo program.
3606- // Extract only the PHP interpreter, not the rest of the command.
3607- list($php, ) = explode(' ', $_ENV['SUDO_COMMAND'], 2);
3608- }
3609- else {
3610- simpletest_script_print_error('Unable to automatically determine the path to the PHP interpreter. Please supply the --php command line argument.');
3611- simpletest_script_help();
3612- exit();
3613- }
3614-
3615- // Get url from arguments.
3616- if (!empty($args['url'])) {
3617- $parsed_url = parse_url($args['url']);
3618- $host = $parsed_url['host'] . (isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '');
3619- $path = $parsed_url['path'];
3620- }
3621-
3622- $_SERVER['HTTP_HOST'] = $host;
3623- $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
3624- $_SERVER['SERVER_ADDR'] = '127.0.0.1';
3625- $_SERVER['SERVER_SOFTWARE'] = $server_software;
3626- $_SERVER['SERVER_NAME'] = 'localhost';
3627- $_SERVER['REQUEST_URI'] = $path .'/';
3628- $_SERVER['REQUEST_METHOD'] = 'GET';
3629- $_SERVER['SCRIPT_NAME'] = $path .'/index.php';
3630- $_SERVER['PHP_SELF'] = $path .'/index.php';
3631- $_SERVER['HTTP_USER_AGENT'] = 'Drupal command line';
3632-
3633- chdir(realpath(dirname(__FILE__) . '/..'));
3634- define('DRUPAL_ROOT', getcwd());
3635- require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
3636-}
3637-
3638-/**
3639- * Execute a batch of tests.
3640- */
3641-function simpletest_script_execute_batch() {
3642- global $args;
3643-
3644- if (is_null($args['test-id'])) {
3645- simpletest_script_print_error("--execute-batch should not be called interactively.");
3646- exit;
3647- }
3648- if ($args['concurrency'] == 1) {
3649- // Fallback to mono-threaded execution.
3650- if (count($args['test_names']) > 1) {
3651- foreach ($args['test_names'] as $test_class) {
3652- // Execute each test in its separate Drupal environment.
3653- simpletest_script_command(1, $args['test-id'], $test_class);
3654- }
3655- exit;
3656- }
3657- else {
3658- // Execute an individual test.
3659- $test_class = array_shift($args['test_names']);
3660- drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
3661- simpletest_script_run_one_test($args['test-id'], $test_class);
3662- exit;
3663- }
3664- }
3665- else {
3666- // Multi-threaded execution.
3667- $children = array();
3668- while (!empty($args['test_names']) || !empty($children)) {
3669- // Fork children safely since Drupal is not bootstrapped yet.
3670- while (count($children) < $args['concurrency']) {
3671- if (empty($args['test_names'])) break;
3672-
3673- $child = array();
3674- $child['test_class'] = $test_class = array_shift($args['test_names']);
3675- $child['pid'] = pcntl_fork();
3676- if (!$child['pid']) {
3677- // This is the child process, bootstrap and execute the test.
3678- drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
3679- simpletest_script_run_one_test($args['test-id'], $test_class);
3680- exit;
3681- }
3682- else {
3683- // Register our new child.
3684- $children[] = $child;
3685- }
3686- }
3687-
3688- // Wait for children every 200ms.
3689- usleep(200000);
3690-
3691- // Check if some children finished.
3692- foreach ($children as $cid => $child) {
3693- if (pcntl_waitpid($child['pid'], $status, WUNTRACED | WNOHANG)) {
3694- // This particular child exited.
3695- unset($children[$cid]);
3696- }
3697- }
3698- }
3699- exit;
3700- }
3701-}
3702-
3703-/**
3704- * Run a single test (assume a Drupal bootstrapped environment).
3705- */
3706-function simpletest_script_run_one_test($test_id, $test_class) {
3707- // Drupal 6.
3708- require_once drupal_get_path('module', 'simpletest') . '/drupal_web_test_case.php';
3709- $classes = simpletest_test_get_all_classes();
3710- require_once $classes[$test_class]['file'];
3711-
3712- $test = new $test_class($test_id);
3713- $test->run();
3714- $info = $test->getInfo();
3715-
3716- $status = ((isset($test->results['#fail']) && $test->results['#fail'] > 0)
3717- || (isset($test->results['#exception']) && $test->results['#exception'] > 0) ? 'fail' : 'pass');
3718- simpletest_script_print($info['name'] . ' ' . _simpletest_format_summary_line($test->results) . "\n", simpletest_script_color_code($status));
3719-}
3720-
3721-/**
3722- * Execute a command to run batch of tests in separate process.
3723- */
3724-function simpletest_script_command($concurrency, $test_id, $tests) {
3725- global $args, $php;
3726-
3727- $command = "$php ./scripts/{$args['script']} --url {$args['url']}";
3728- if ($args['color']) {
3729- $command .= ' --color';
3730- }
3731- $command .= " --php " . escapeshellarg($php) . " --concurrency $concurrency --test-id $test_id --execute-batch $tests";
3732- passthru($command);
3733-}
3734-
3735-/**
3736- * Get list of tests based on arguments. If --all specified then
3737- * returns all available tests, otherwise reads list of tests.
3738- *
3739- * Will print error and exit if no valid tests were found.
3740- *
3741- * @return List of tests.
3742- */
3743-function simpletest_script_get_test_list() {
3744- global $args, $all_tests, $groups;
3745-
3746- $test_list = array();
3747- if ($args['all']) {
3748- $test_list = $all_tests;
3749- }
3750- else {
3751- if ($args['class']) {
3752- // Check for valid class names.
3753- foreach ($args['test_names'] as $class_name) {
3754- if (in_array($class_name, $all_tests)) {
3755- $test_list[] = $class_name;
3756- }
3757- }
3758- }
3759- elseif ($args['file']) {
3760- $files = array();
3761- foreach ($args['test_names'] as $file) {
3762-// $files[drupal_realpath($file)] = 1;
3763- $files[realpath($file)] = 1;
3764- }
3765-
3766- // Check for valid class names.
3767- foreach ($all_tests as $class_name) {
3768- $refclass = new ReflectionClass($class_name);
3769- $file = $refclass->getFileName();
3770- if (isset($files[$file])) {
3771- $test_list[] = $class_name;
3772- }
3773- }
3774- }
3775- else {
3776- // Check for valid group names and get all valid classes in group.
3777- foreach ($args['test_names'] as $group_name) {
3778- if (isset($groups[$group_name])) {
3779- foreach($groups[$group_name] as $class_name => $info) {
3780- $test_list[] = $class_name;
3781- }
3782- }
3783- }
3784- }
3785- }
3786-
3787- if (empty($test_list)) {
3788- simpletest_script_print_error('No valid tests were specified.');
3789- exit;
3790- }
3791- return $test_list;
3792-}
3793-
3794-/**
3795- * Initialize the reporter.
3796- */
3797-function simpletest_script_reporter_init() {
3798- global $args, $all_tests, $test_list;
3799-
3800- echo "\n";
3801- echo "Drupal test run\n";
3802- echo "---------------\n";
3803- echo "\n";
3804-
3805- // Tell the user about what tests are to be run.
3806- if ($args['all']) {
3807- echo "All tests will run.\n\n";
3808- }
3809- else {
3810- echo "Tests to be run:\n";
3811- foreach ($test_list as $class_name) {
3812- $info = call_user_func(array($class_name, 'getInfo'));
3813- echo " - " . $info['name'] . ' (' . $class_name . ')' . "\n";
3814- }
3815- echo "\n";
3816- }
3817-
3818- echo "Test run started: " . format_date($_SERVER['REQUEST_TIME'], 'long') . "\n";
3819- timer_start('run-tests');
3820- echo "\n";
3821-
3822- echo "Test summary:\n";
3823- echo "-------------\n";
3824- echo "\n";
3825-}
3826-
3827-/**
3828- * Display test results.
3829- */
3830-function simpletest_script_reporter_display_results() {
3831- global $args, $test_id, $results_map;
3832-
3833- echo "\n";
3834- $end = timer_stop('run-tests');
3835- echo "Test run duration: " . format_interval($end['time'] / 1000);
3836- echo "\n";
3837-
3838- if ($args['verbose']) {
3839- // Report results.
3840- echo "Detailed test results:\n";
3841- echo "----------------------\n";
3842- echo "\n";
3843-
3844- $results_map = array(
3845- 'pass' => 'Pass',
3846- 'fail' => 'Fail',
3847- 'exception' => 'Exception'
3848- );
3849-
3850-// $results = db_query("SELECT * FROM {simpletest} WHERE test_id = :test_id ORDER BY test_class, message_id", array(':test_id' => $test_id));
3851- $results = db_query("SELECT * FROM {simpletest} WHERE test_id = %d ORDER BY test_class, message_id", $test_id);
3852-
3853- $test_class = '';
3854-// foreach ($results as $result) {
3855- while ($result = db_fetch_object($results)) {
3856- if (isset($results_map[$result->status])) {
3857- if ($result->test_class != $test_class) {
3858- // Display test class every time results are for new test class.
3859- echo "\n\n---- $result->test_class ----\n\n\n";
3860- $test_class = $result->test_class;
3861- }
3862-
3863- simpletest_script_format_result($result);
3864- }
3865- }
3866- }
3867-}
3868-
3869-/**
3870- * Format the result so that it fits within the default 80 character
3871- * terminal size.
3872- *
3873- * @param $result The result object to format.
3874- */
3875-function simpletest_script_format_result($result) {
3876- global $results_map, $color;
3877-
3878- $summary = sprintf("%-10.10s %-10.10s %-30.30s %-5.5s %-20.20s\n",
3879- $results_map[$result->status], $result->message_group, basename($result->file), $result->line, $result->caller);
3880-
3881- simpletest_script_print($summary, simpletest_script_color_code($result->status));
3882-
3883- $lines = explode("\n", wordwrap(trim(strip_tags($result->message)), 76));
3884- foreach ($lines as $line) {
3885- echo " $line\n";
3886- }
3887-}
3888-
3889-/**
3890- * Print error message prefixed with " ERROR: " and displayed in fail color
3891- * if color output is enabled.
3892- *
3893- * @param $message The message to print.
3894- */
3895-function simpletest_script_print_error($message) {
3896- simpletest_script_print(" ERROR: $message\n", SIMPLETEST_SCRIPT_COLOR_FAIL);
3897-}
3898-
3899-/**
3900- * Print a message to the console, if color is enabled then the specified
3901- * color code will be used.
3902- *
3903- * @param $message The message to print.
3904- * @param $color_code The color code to use for coloring.
3905- */
3906-function simpletest_script_print($message, $color_code) {
3907- global $args;
3908- if ($args['color']) {
3909- echo "\033[" . $color_code . "m" . $message . "\033[0m";
3910- }
3911- else {
3912- echo $message;
3913- }
3914-}
3915-
3916-/**
3917- * Get the color code associated with the specified status.
3918- *
3919- * @param $status The status string to get code for.
3920- * @return Color code.
3921- */
3922-function simpletest_script_color_code($status) {
3923- switch ($status) {
3924- case 'pass':
3925- return SIMPLETEST_SCRIPT_COLOR_PASS;
3926- case 'fail':
3927- return SIMPLETEST_SCRIPT_COLOR_FAIL;
3928- case 'exception':
3929- return SIMPLETEST_SCRIPT_COLOR_EXCEPTION;
3930- }
3931- return 0; // Default formatting.
3932-}
3933
3934=== removed file 'modules/simpletest/simpletest.css'
3935--- modules/simpletest/simpletest.css 2009-09-11 00:40:07 +0000
3936+++ modules/simpletest/simpletest.css 1970-01-01 00:00:00 +0000
3937@@ -1,74 +0,0 @@
3938-/* $Id: simpletest.css,v 1.1.6.4 2009/09/05 13:34:10 boombatower Exp $
3939-/* Core: Id: simpletest.css,v 1.6 2009/08/04 06:47:00 webchick Exp */
3940-
3941-/* Addon for the simpletest module */
3942-#simpletest {
3943-}
3944-
3945-/* Test Table */
3946-#simpletest-form-table th.select-all {
3947- width: 25px;
3948-}
3949-
3950-th.simpletest_test {
3951- width: 160px;
3952-}
3953-
3954-table#simpletest-form-table tr td {
3955- background-color: white;
3956- color: #494949;
3957-}
3958-
3959-table#simpletest-form-table tr.simpletest-group td {
3960- background-color: #EDF5FA;
3961- color: #494949;
3962-}
3963-
3964-div.message > div.item-list {
3965- font-weight: normal;
3966-}
3967-
3968-div.simpletest-pass {
3969- color: #33a333;
3970-}
3971-
3972-.simpletest-fail {
3973- color: #981010;
3974-}
3975-
3976-tr.simpletest-pass.odd {
3977- background: #b6ffb6;
3978-}
3979-
3980-tr.simpletest-pass.even {
3981- background: #9bff9b;
3982-}
3983-
3984-tr.simpletest-fail.odd {
3985- background: #ffc9c9;
3986-}
3987-
3988-tr.simpletest-fail.even {
3989- background: #ffacac;
3990-}
3991-
3992-tr.simpletest-exception.odd {
3993- background: #f4ea71;
3994-}
3995-
3996-tr.simpletest-exception.even {
3997- background: #f5e742;
3998-}
3999-
4000-tr.simpletest-debug.odd {
4001- background: #eeeeee;
4002-}
4003-
4004-tr.simpletest-debug.even {
4005- background: #ffffff;
4006-}
4007-
4008-div.simpletest-image {
4009- display: inline;
4010- cursor: pointer;
4011-}
4012
4013=== removed file 'modules/simpletest/simpletest.info'
4014--- modules/simpletest/simpletest.info 2009-09-15 16:10:36 +0000
4015+++ modules/simpletest/simpletest.info 1970-01-01 00:00:00 +0000
4016@@ -1,50 +0,0 @@
4017-; $Id: simpletest.info,v 1.4.2.2.2.7 2009/09/05 13:34:10 boombatower Exp $
4018-; Core: Id: simpletest.info,v 1.10 2009/08/31 18:30:26 webchick Exp
4019-name = "SimpleTest"
4020-description = "Provides a framework for unit and functional testing."
4021-; package = Core
4022-package = Development
4023-; version = VERSION
4024-; core = 7.x
4025-core = 6.x
4026-php = 5 ; Drupal 6
4027-files[] = simpletest.module
4028-files[] = simpletest.pages.inc
4029-files[] = simpletest.install
4030-files[] = simpletest.test
4031-files[] = drupal_web_test_case.php
4032-
4033-; Drupal 6
4034-files[] = tests/block.test
4035-
4036-; Tests in tests directory.
4037-; files[] = tests/actions.test
4038-; files[] = tests/batch.test
4039-; files[] = tests/bootstrap.test
4040-; files[] = tests/browser.test
4041-; files[] = tests/cache.test
4042-; files[] = tests/common.test
4043-; files[] = tests/database_test.test
4044-; files[] = tests/error.test
4045-; files[] = tests/file.test
4046-; files[] = tests/filetransfer.test
4047-; files[] = tests/form.test
4048-; files[] = tests/graph.test
4049-; files[] = tests/image.test
4050-; files[] = tests/lock.test
4051-; files[] = tests/mail.test
4052-; files[] = tests/menu.test
4053-; files[] = tests/module.test
4054-; files[] = tests/registry.test
4055-; files[] = tests/schema.test
4056-; files[] = tests/session.test
4057-; files[] = tests/theme.test
4058-; files[] = tests/unicode.test
4059-; files[] = tests/xmlrpc.test
4060-
4061-; Information added by drupal.org packaging script on 2009-09-14
4062-version = "6.x-2.9"
4063-core = "6.x"
4064-project = "simpletest"
4065-datestamp = "1252971974"
4066-
4067
4068=== removed file 'modules/simpletest/simpletest.install'
4069--- modules/simpletest/simpletest.install 2009-09-16 00:11:48 +0000
4070+++ modules/simpletest/simpletest.install 1970-01-01 00:00:00 +0000
4071@@ -1,301 +0,0 @@
4072-<?php
4073-// $Id: simpletest.install,v 1.4.2.3.2.19 2009/09/14 22:32:11 boombatower Exp $
4074-// Core: Id: simpletest.install,v 1.26 2009/08/17 19:14:41 webchick Exp
4075-
4076-/**
4077- * @file
4078- * Backport of Drupal 7 simpletest.install with modifications, see BACKPORT.txt.
4079- *
4080- * Copyright 2008-2009 by Jimmy Berry ("boombatower", http://drupal.org/user/214218)
4081- */
4082-
4083-/**
4084- * Implementation of hook_install().
4085- */
4086-function simpletest_install() {
4087- drupal_install_schema('simpletest');
4088- // Check for files directory.
4089- $path = file_directory_path() . '/simpletest';
4090- if (file_check_directory($path, FILE_CREATE_DIRECTORY)) {
4091- // Generate binary and text test files.
4092- $generated = FALSE;
4093- if (simpletest_get_file_count($path, 'binary') == 0) {
4094- $lines = array(64, 1024);
4095- foreach ($lines as $line) {
4096- simpletest_generate_file('binary', 64, $line, 'binary');
4097- }
4098- $generated = TRUE;
4099- }
4100-
4101- if (simpletest_get_file_count($path, 'text') == 0) {
4102- $lines = array(16, 256, 1024, 2048, 20480);
4103- foreach ($lines as $line) {
4104- simpletest_generate_file('text', 64, $line);
4105- }
4106- $generated = TRUE;
4107- }
4108-
4109- // Copy other test files for consistency.
4110- $original = drupal_get_path('module', 'simpletest') . '/files';
4111- $files = file_scan_directory($original, '(html|image|javascript|php|sql)-.*');
4112-
4113- // If there are more files in SimpleTest's files directory than the site's
4114- // files directory, restore all the files. This situation might occur when
4115- // an errant test deletes one or more files from the site's files
4116- // directory. It serves a convenience to developers so that they can get
4117- // the test files back easily.
4118- if (count($files) > count(file_scan_directory($path, '(html|image|javascript|php|sql)-.*'))) {
4119- foreach ($files as $file) {
4120- copy($file->filename, $path . '/' . $file->basename);
4121- }
4122- $generated = TRUE;
4123- }
4124-
4125- if ($generated) {
4126- drupal_set_message('Extra test files generated/copied.');
4127- }
4128- }
4129-}
4130-
4131-/**
4132- * Generate test file.
4133- */
4134-function simpletest_generate_file($filename, $width, $lines, $type = 'binary-text') {
4135- $size = $width * $lines - $lines;
4136-
4137- // Generate random text
4138- $text = '';
4139- for ($i = 0; $i < $size; $i++) {
4140- switch ($type) {
4141- case 'text':
4142- $text .= chr(rand(32, 126));
4143- break;
4144- case 'binary':
4145- $text .= chr(rand(0, 31));
4146- break;
4147- case 'binary-text':
4148- default:
4149- $text .= rand(0, 1);
4150- break;
4151- }
4152- }
4153- $text = wordwrap($text, $width - 1, "\n", TRUE) . "\n"; // Add \n for symetrical file.
4154-
4155- // Create filename.
4156- $path = file_directory_path() . '/simpletest/';
4157- $count = simpletest_get_file_count($path, $filename);
4158- file_put_contents($path . $filename . '-' . ($count + 1) . '.txt', $text);
4159-}
4160-
4161-/**
4162- * Get the number of files that have the specified filename base.
4163- */
4164-function simpletest_get_file_count($directory, $filename) {
4165- $files = scandir($directory);
4166- $count = 0;
4167- foreach ($files as $file) {
4168- if (preg_match('/' . $filename . '.*?/', $file)) {
4169- $count++;
4170- }
4171- }
4172- return $count;
4173-}
4174-
4175-/**
4176- * Implementation of hook_uninstall().
4177- */
4178-function simpletest_uninstall() {
4179- simpletest_clean_environment();
4180-
4181- // Remove settings variables.
4182- variable_del('simpletest_username');
4183- variable_del('simpletest_password');
4184- variable_del('simpletest_clear_results');
4185- variable_del('simpletest_verbose');
4186-
4187- // Uninstall schema.
4188- drupal_uninstall_schema('simpletest');
4189-
4190- // Remove generated files.
4191- $path = file_directory_path() . '/simpletest';
4192- $files = file_scan_directory($path, '.*');
4193- foreach ($files as $file) {
4194- unlink($file->filename);
4195- }
4196- rmdir($path);
4197-}
4198-
4199-/**
4200- * Check that the cURL extension exists for PHP.
4201- */
4202-function simpletest_requirements($phase) {
4203- $requirements = array();
4204- $t = get_t();
4205-
4206- $has_curl = function_exists('curl_init');
4207- $has_hash = function_exists('hash_hmac');
4208- $has_domdocument = class_exists('DOMDocument');
4209-
4210- $requirements['curl'] = array(
4211- 'title' => $t('cURL'),
4212- 'value' => $has_curl ? $t('Enabled') : $t('Not found'),
4213- );
4214- if (!$has_curl) {
4215- $requirements['curl']['severity'] = REQUIREMENT_ERROR;
4216- $requirements['curl']['description'] = $t('Simpletest could not be installed because the PHP <a href="@curl_url">cURL</a> library is not available.', array('@curl_url' => 'http://php.net/manual/en/curl.setup.php'));
4217- }
4218- $requirements['hash'] = array(
4219- 'title' => $t('hash'),
4220- 'value' => $has_hash ? $t('Enabled') : $t('Not found'),
4221- );
4222- if (!$has_hash) {
4223- $requirements['hash']['severity'] = REQUIREMENT_ERROR;
4224- $requirements['hash']['description'] = $t('Simpletest could not be installed because the PHP <a href="@hash_url">hash</a> extension is disabled.', array('@hash_url' => 'http://php.net/manual/en/book.hash.php'));
4225- }
4226-
4227- $requirements['php_domdocument'] = array(
4228- 'title' => $t('PHP DOMDocument class'),
4229- 'value' => $has_domdocument ? $t('Enabled') : $t('Not found'),
4230- );
4231- if (!$has_domdocument) {
4232- $requirements['php_domdocument']['severity'] = REQUIREMENT_ERROR;
4233- $requirements['php_domdocument']['description'] =t('SimpleTest requires the DOMDocument class to be available. Please check the configure command at the <a href="@link-phpinfo">PHP info page</a>.', array('@link-phpinfo' => url('admin/reports/status/php')));
4234- }
4235-
4236- // Drupal 6.
4237- // Check that the global variable is defined signifying that the code was inserted correctly.
4238- if (isset($GLOBALS['simpletest_installed'])) {
4239- $requirements['simpletest_settings'] = array(
4240- 'title' => $t('SimpleTest code addition'),
4241- 'value' => t('Found'),
4242- 'severity' => REQUIREMENT_OK
4243- );
4244- }
4245- else {
4246- $requirements['simpletest_settings'] = array(
4247- 'title' => $t('SimpleTest code addition'),
4248- 'value' => t('Not-found'),
4249- 'severity' => REQUIREMENT_ERROR,
4250- 'description' => $t('SimpleTest could not be installed. Must apply core patch, please see
4251- <a href="@install">INSTALL.txt</a>.',
4252- array('%settings' => realpath(conf_path() . '/settings.php'),
4253- '@install' => drupal_get_path('module', 'simpletest') . '/INSTALL.txt')),
4254- );
4255- }
4256-
4257- return $requirements;
4258-}
4259-
4260-function simpletest_schema() {
4261- $schema['simpletest'] = array(
4262- 'description' => 'Stores simpletest messages',
4263- 'fields' => array(
4264- 'message_id' => array(
4265- 'type' => 'serial',
4266- 'not null' => TRUE,
4267- 'description' => 'Primary Key: Unique simpletest message ID.',
4268- ),
4269- 'test_id' => array(
4270- 'type' => 'int',
4271- 'not null' => TRUE,
4272- 'default' => 0,
4273- 'description' => 'Test ID, messages belonging to the same ID are reported together',
4274- ),
4275- 'test_class' => array(
4276- 'type' => 'varchar',
4277- 'length' => 255,
4278- 'not null' => TRUE,
4279- 'default' => '',
4280- 'description' => 'The name of the class that created this message.',
4281- ),
4282- 'status' => array(
4283- 'type' => 'varchar',
4284- 'length' => 9,
4285- 'not null' => TRUE,
4286- 'default' => '',
4287- 'description' => 'Message status. Core understands pass, fail, exception.',
4288- ),
4289- 'message' => array(
4290- 'type' => 'text',
4291- 'not null' => TRUE,
4292- 'description' => 'The message itself.',
4293- ),
4294- 'message_group' => array(
4295- 'type' => 'varchar',
4296- 'length' => 255,
4297- 'not null' => TRUE,
4298- 'default' => '',
4299- 'description' => 'The message group this message belongs to. For example: warning, browser, user.',
4300- ),
4301- 'function' => array(
4302- 'type' => 'varchar',
4303- 'length' => 255,
4304- 'not null' => TRUE,
4305- 'default' => '',
4306- 'description' => 'Name of the assertion function or method that created this message.',
4307- ),
4308- 'line' => array(
4309- 'type' => 'int',
4310- 'not null' => TRUE,
4311- 'default' => 0,
4312- 'description' => 'Line number on which the function is called.',
4313- ),
4314- 'file' => array(
4315- 'type' => 'varchar',
4316- 'length' => 255,
4317- 'not null' => TRUE,
4318- 'default' => '',
4319- 'description' => 'Name of the file where the function is called.',
4320- ),
4321- ),
4322- 'primary key' => array('message_id'),
4323- 'indexes' => array(
4324- 'reporter' => array('test_class', 'message_id'),
4325- ),
4326- );
4327- $schema['simpletest_test_id'] = array(
4328- 'description' => 'Stores simpletest test IDs, used to auto-incrament the test ID so that a fresh test ID is used.',
4329- 'fields' => array(
4330- 'test_id' => array(
4331- 'type' => 'serial',
4332- 'not null' => TRUE,
4333- 'description' => 'Primary Key: Unique simpletest ID used to group test results together. Each time a set of tests
4334- are run a new test ID is used.',
4335- ),
4336- 'last_prefix' => array(
4337- 'type' => 'varchar',
4338- 'length' => 60,
4339- 'not null' => FALSE,
4340- 'default' => '',
4341- 'description' => 'The last database prefix used during testing.',
4342- ),
4343- ),
4344- 'primary key' => array('test_id'),
4345- );
4346- return $schema;
4347-}
4348-
4349-/**
4350- * Upgrade simpletest 5.x-1.x and 6.x-1.x to 6.x-2.1 release.
4351- *
4352- * Provides a basic upgrade path for initial switch to 2.x branch. The update
4353- * path will not be continued as there is no data that needs to be updated and
4354- * any further releases should simply un-install and install just like Drupal
4355- * HEAD development.
4356- */
4357-function simpletest_update_6200() {
4358- $ret = array();
4359-
4360- // Drop any existing SimpleTest tables.
4361- if (db_table_exists('simpletest')) {
4362- db_drop_table($ret, 'simpletest');
4363- }
4364- if (db_table_exists('simpletest_test_id')) {
4365- db_drop_table($ret, 'simpletest_test_id');
4366- }
4367-
4368- // Install most recent schema and files.
4369- simpletest_install();
4370-
4371- return $ret;
4372-}
4373
4374=== removed file 'modules/simpletest/simpletest.js'
4375--- modules/simpletest/simpletest.js 2009-09-11 00:40:07 +0000
4376+++ modules/simpletest/simpletest.js 1970-01-01 00:00:00 +0000
4377@@ -1,114 +0,0 @@
4378-// $Id: simpletest.js,v 1.2.4.5 2009/09/05 13:34:10 boombatower Exp $
4379-// Core: Id: simpletest.js,v 1.11 2009/04/27 20:19:37 webchick Exp
4380-//(function ($) {
4381-
4382-/**
4383- * Add the cool table collapsing on the testing overview page.
4384- */
4385-//Drupal.behaviors.simpleTestMenuCollapse = {
4386-// attach: function (context, settings) {
4387-Drupal.behaviors.simpleTestMenuCollapse = function() {
4388- var timeout = null;
4389- // Adds expand-collapse functionality.
4390- $('div.simpletest-image').each(function () {
4391-// direction = settings.simpleTest[$(this).attr('id')].imageDirection;
4392-// $(this).html(settings.simpleTest.images[direction]);
4393- direction = Drupal.settings.simpleTest[$(this).attr('id')].imageDirection;
4394- $(this).html(Drupal.settings.simpleTest.images[direction]);
4395- });
4396-
4397- // Adds group toggling functionality to arrow images.
4398- $('div.simpletest-image').click(function () {
4399-// var trs = $(this).parents('tbody').children('.' + settings.simpleTest[this.id].testClass);
4400-// var direction = settings.simpleTest[this.id].imageDirection;
4401- var trs = $(this).parents('tbody').children('.' + Drupal.settings.simpleTest[this.id].testClass);
4402- var direction = Drupal.settings.simpleTest[this.id].imageDirection;
4403- var row = direction ? trs.size() - 1 : 0;
4404-
4405- // If clicked in the middle of expanding a group, stop so we can switch directions.
4406- if (timeout) {
4407- clearTimeout(timeout);
4408- }
4409-
4410- // Function to toggle an individual row according to the current direction.
4411- // We set a timeout of 20 ms until the next row will be shown/hidden to
4412- // create a sliding effect.
4413- function rowToggle() {
4414- if (direction) {
4415- if (row >= 0) {
4416- $(trs[row]).hide();
4417- row--;
4418- timeout = setTimeout(rowToggle, 20);
4419- }
4420- }
4421- else {
4422- if (row < trs.size()) {
4423- $(trs[row]).removeClass('js-hide').show();
4424- row++;
4425- timeout = setTimeout(rowToggle, 20);
4426- }
4427- }
4428- }
4429-
4430- // Kick-off the toggling upon a new click.
4431- rowToggle();
4432-
4433- // Toggle the arrow image next to the test group title.
4434-// $(this).html(settings.simpleTest.images[(direction ? 0 : 1)]);
4435-// settings.simpleTest[this.id].imageDirection = !direction;
4436- $(this).html(Drupal.settings.simpleTest.images[(direction ? 0 : 1)]);
4437- Drupal.settings.simpleTest[this.id].imageDirection = !direction;
4438-
4439- });
4440-// }
4441-};
4442-
4443-/**
4444- * Select/deselect all the inner checkboxes when the outer checkboxes are
4445- * selected/deselected.
4446- */
4447-//Drupal.behaviors.simpleTestSelectAll = {
4448-// attach: function (context, settings) {
4449-Drupal.behaviors.simpleTestSelectAll = function() {
4450- $('td.simpletest-select-all').each(function () {
4451-// var testCheckboxes = settings.simpleTest['simpletest-test-group-' + $(this).attr('id')].testNames;
4452- var testCheckboxes = Drupal.settings.simpleTest['simpletest-test-group-' + $(this).attr('id')].testNames;
4453- var groupCheckbox = $('<input type="checkbox" class="form-checkbox" id="' + $(this).attr('id') + '-select-all" />');
4454-
4455- // Each time a single-test checkbox is checked or unchecked, make sure
4456- // that the associated group checkbox gets the right state too.
4457- var updateGroupCheckbox = function () {
4458- var checkedTests = 0;
4459- for (var i = 0; i < testCheckboxes.length; i++) {
4460- $('#' + testCheckboxes[i]).each(function () {
4461- if (($(this).attr('checked'))) {
4462- checkedTests++;
4463- }
4464- });
4465- }
4466- $(groupCheckbox).attr('checked', (checkedTests == testCheckboxes.length));
4467- };
4468-
4469- // Have the single-test checkboxes follow the group checkbox.
4470- groupCheckbox.change(function () {
4471- var checked = !!($(this).attr('checked'));
4472- for (var i = 0; i < testCheckboxes.length; i++) {
4473- $('#' + testCheckboxes[i]).attr('checked', checked);
4474- }
4475- });
4476-
4477- // Have the group checkbox follow the single-test checkboxes.
4478- for (var i = 0; i < testCheckboxes.length; i++) {
4479- $('#' + testCheckboxes[i]).change(function () {
4480- updateGroupCheckbox();
4481- });
4482- }
4483-
4484- // Initialize status for the group checkbox correctly.
4485- updateGroupCheckbox();
4486- $(this).append(groupCheckbox);
4487- });
4488-// }
4489-};
4490-
4491-//})(jQuery);
4492
4493=== removed file 'modules/simpletest/simpletest.module'
4494--- modules/simpletest/simpletest.module 2009-09-16 00:11:48 +0000
4495+++ modules/simpletest/simpletest.module 1970-01-01 00:00:00 +0000
4496@@ -1,533 +0,0 @@
4497-<?php
4498-// $Id: simpletest.module,v 1.33.2.4.2.20 2009/09/14 20:34:30 boombatower Exp $
4499-// Core: Id: simpletest.module,v 1.71 2009/08/24 00:14:21 webchick Exp
4500-
4501-/**
4502- * @file
4503- * Backport of Drupal 7 simpletest.module with modifications, see BACKPORT.txt.
4504- *
4505- * Copyright 2008-2009 by Jimmy Berry ("boombatower", http://drupal.org/user/214218)
4506- */
4507-
4508-/**
4509- * Implementation of hook_help().
4510- */
4511-function simpletest_help($path, $arg) {
4512- switch ($path) {
4513- case 'admin/help#simpletest':
4514- $output = '<p>' . t('The SimpleTest module is a framework for running automated unit tests in Drupal. It can be used to verify a working state of Drupal before and after any code changes, or as a means for developers to write and execute tests for their modules.') . '</p>';
4515- $output .= '<p>' . t('Visit <a href="@admin-simpletest">Administer >> Structure >> SimpleTest</a> to display a list of available tests. For comprehensive testing, select <em>all</em> tests, or individually select tests for more targeted testing. Note that it might take several minutes for all tests to complete.)', array('@admin-simpletest' => url('admin/build/testing'))) . '</p>';
4516- $output .= '<p>' . t('After the tests have run, a message will be displayed next to each test group indicating whether tests within it passed, failed, or had exceptions. A pass means that a test returned the expected results, while fail means that it did not. An exception normally indicates an error outside of the test, such as a PHP warning or notice. If there were fails or exceptions, the results are expanded, and the tests that had issues will be indicated in red or pink rows. Use these results to refine your code and tests until all tests return a pass.') . '</p>';
4517- $output .= '<p>' . t('For more information on creating and modifying your own tests, see the <a href="@simpletest-api">SimpleTest API Documentation</a> in the Drupal handbook.', array('@simpletest-api' => 'http://drupal.org/simpletest')) . '</p>';
4518- $output .= '<p>' . t('For more information, see the online handbook entry for <a href="@simpletest">SimpleTest module</a>.', array('@simpletest' => 'http://drupal.org/handbook/modules/simpletest')) . '</p>';
4519- return $output;
4520- }
4521-}
4522-
4523-/**
4524- * Implementation of hook_menu().
4525- */
4526-function simpletest_menu() {
4527- $items['admin/build/testing'] = array(
4528- 'title' => 'Testing',
4529- 'page callback' => 'drupal_get_form',
4530- 'page arguments' => array('simpletest_test_form'),
4531- 'description' => 'Run tests against Drupal core and your active modules. These tests help assure that your site code is working as designed.',
4532- 'access arguments' => array('administer unit tests'),
4533- 'file' => 'simpletest.pages.inc',
4534- );
4535- $items['admin/build/testing/list'] = array(
4536- 'title' => 'List',
4537- 'type' => MENU_DEFAULT_LOCAL_TASK,
4538- );
4539- $items['admin/build/testing/settings'] = array(
4540- 'title' => 'Settings',
4541- 'page callback' => 'drupal_get_form',
4542- 'page arguments' => array('simpletest_settings_form'),
4543- 'access arguments' => array('administer unit tests'),
4544- 'type' => MENU_LOCAL_TASK,
4545- 'file' => 'simpletest.pages.inc',
4546- );
4547- $items['admin/build/testing/results/%'] = array(
4548- 'title' => 'Test result',
4549- 'page callback' => 'drupal_get_form',
4550- 'page arguments' => array('simpletest_result_form', 4),
4551- 'description' => 'View result of tests.',
4552- 'access arguments' => array('administer unit tests'),
4553- 'type' => MENU_CALLBACK,
4554- 'file' => 'simpletest.pages.inc',
4555- );
4556- return $items;
4557-}
4558-
4559-/**
4560- * Implementation of hook_perm().
4561- */
4562-function simpletest_perm() {
4563- return array('administer unit tests');
4564-}
4565-
4566-/**
4567- * Implementation of hook_theme().
4568- */
4569-function simpletest_theme() {
4570- return array(
4571- 'simpletest_test_table' => array(
4572- 'arguments' => array('table' => NULL),
4573- 'file' => 'simpletest.pages.inc',
4574- ),
4575- 'simpletest_result_summary' => array(
4576- 'arguments' => array('form' => NULL),
4577- 'file' => 'simpletest.pages.inc',
4578- ),
4579- );
4580-}
4581-
4582-function _simpletest_format_summary_line($summary) {
4583- $args = array(
4584- '@pass' => format_plural(isset($summary['#pass']) ? $summary['#pass'] : 0, '1 pass', '@count passes'),
4585- '@fail' => format_plural(isset($summary['#fail']) ? $summary['#fail'] : 0, '1 fail', '@count fails'),
4586- '@exception' => format_plural(isset($summary['#exception']) ? $summary['#exception'] : 0, '1 exception', '@count exceptions'),
4587- );
4588- if (!$summary['#debug']) {
4589- return t('@pass, @fail, and @exception', $args);
4590- }
4591- $args['@debug'] = format_plural(isset($summary['#debug']) ? $summary['#debug'] : 0, '1 debug message', '@count debug messages');
4592- return t('@pass, @fail, @exception, and @debug', $args);
4593-}
4594-
4595-/**
4596- * Actually runs tests.
4597- *
4598- * @param $test_list
4599- * List of tests to run.
4600- * @param $reporter
4601- * Which reporter to use. Allowed values are: text, xml, html and drupal,
4602- * drupal being the default.
4603- */
4604-function simpletest_run_tests($test_list, $reporter = 'drupal') {
4605- cache_clear_all();
4606- db_query('INSERT INTO {simpletest_test_id} (test_id) VALUES (default)');
4607- $test_id = db_last_insert_id('simpletest_test_id', 'test_id');
4608-
4609- // Clear out the previous verbose files.
4610- simpletest_clean_temporary_directory(file_directory_path() . '/simpletest/verbose');
4611-
4612- // Get the info for the first test being run.
4613- $first_test = array_shift($test_list);
4614- $first_instance = new $first_test();
4615- array_unshift($test_list, $first_test);
4616- $info = $first_instance->getInfo();
4617-
4618- $batch = array(
4619- 'title' => t('Running SimpleTests'),
4620- 'operations' => array(
4621- array('_simpletest_batch_operation', array($test_list, $test_id)),
4622- ),
4623- 'finished' => '_simpletest_batch_finished',
4624- 'progress_message' => '',
4625- 'css' => array(drupal_get_path('module', 'simpletest') . '/simpletest.css'),
4626- 'init_message' => t('Processing test @num of @max - %test.', array('%test' => $info['name'], '@num' => '1', '@max' => count($test_list))),
4627- );
4628- batch_set($batch);
4629-
4630- module_invoke_all('test_group_started');
4631-
4632- // Normally, the forms portion of the batch API takes care of calling
4633- // batch_process(), but in the process it saves the whole $form into the
4634- // database (which is huge for the test selection form).
4635- // By calling batch_process() directly, we skip that behavior and ensure
4636- // that we don't exceed the size of data that can be sent to the database
4637- // (max_allowed_packet on MySQL).
4638- batch_process('admin/build/testing/results/' . $test_id);
4639-}
4640-
4641-/**
4642- * Batch operation callback.
4643- */
4644-function _simpletest_batch_operation($test_list_init, $test_id, &$context) {
4645- // Get working values.
4646- if (!isset($context['sandbox']['max'])) {
4647- // First iteration: initialize working values.
4648- $test_list = $test_list_init;
4649- $context['sandbox']['max'] = count($test_list);
4650- $test_results = array('#pass' => 0, '#fail' => 0, '#exception' => 0, '#debug' => 0);
4651- }
4652- else {
4653- // Nth iteration: get the current values where we last stored them.
4654- $test_list = $context['sandbox']['tests'];
4655- $test_results = $context['sandbox']['test_results'];
4656- }
4657- $max = $context['sandbox']['max'];
4658-
4659- // Perform the next test.
4660- $test_class = array_shift($test_list);
4661-
4662- // Drupal 6.
4663- require_once drupal_get_path('module', 'simpletest') . '/drupal_web_test_case.php';
4664- $classes = simpletest_test_get_all_classes();
4665- require_once $classes[$test_class]['file'];
4666-
4667- $test = new $test_class($test_id);
4668- $test->run();
4669- $size = count($test_list);
4670- $info = $test->getInfo();
4671-
4672- module_invoke_all('test_finished', $test->results);
4673-
4674- // Gather results and compose the report.
4675- $test_results[$test_class] = $test->results;
4676- foreach ($test_results[$test_class] as $key => $value) {
4677- $test_results[$key] += $value;
4678- }
4679- $test_results[$test_class]['#name'] = $info['name'];
4680- $items = array();
4681- foreach (element_children($test_results) as $class) {
4682- array_unshift($items, '<div class="simpletest-' . ($test_results[$class]['#fail'] + $test_results[$class]['#exception'] ? 'fail' : 'pass') . '">' . t('@name: @summary', array('@name' => $test_results[$class]['#name'], '@summary' => _simpletest_format_summary_line($test_results[$class]))) . '</div>');
4683- }
4684- $context['message'] = t('Processed test @num of @max - %test.', array('%test' => $info['name'], '@num' => $max - $size, '@max' => $max));
4685- $context['message'] .= '<div class="simpletest-' . ($test_results['#fail'] + $test_results['#exception'] ? 'fail' : 'pass') . '">Overall results: ' . _simpletest_format_summary_line($test_results) . '</div>';
4686- $context['message'] .= theme('item_list', $items);
4687-
4688- // Save working values for the next iteration.
4689- $context['sandbox']['tests'] = $test_list;
4690- $context['sandbox']['test_results'] = $test_results;
4691- // The test_id is the only thing we need to save for the report page.
4692- $context['results']['test_id'] = $test_id;
4693-
4694- // Multistep processing: report progress.
4695- $context['finished'] = 1 - $size / $max;
4696-}
4697-
4698-//function _simpletest_batch_finished($success, $results, $operations, $elapsed) {
4699-function _simpletest_batch_finished($success, $results, $operations) {
4700- if ($success) {
4701- drupal_set_message(t('The test run finished.'));
4702- }
4703- else {
4704- // Use the test_id passed as a parameter to _simpletest_batch_operation().
4705- $test_id = $operations[0][1][1];
4706-
4707- // Retrieve the last database prefix used for testing and the last test
4708- // class that was run from. Use the information to read the lgo file
4709- // in case any fatal errors caused the test to crash.
4710- list($last_prefix, $last_test_class) = simpletest_last_test_get($test_id);
4711- simpletest_log_read($test_id, $last_prefix, $last_test_class);
4712-
4713- drupal_set_message(t('The test run did not successfully finish.'), 'error');
4714- drupal_set_message(t('Please use the <em>Clean environment</em> button to clean-up temporary files and tables.'), 'warning');
4715- }
4716- module_invoke_all('test_group_finished');
4717-}
4718-
4719-/*
4720- * Get information about the last test that ran given a test ID.
4721- *
4722- * @param $test_id
4723- * The test ID to get the last test from.
4724- * @return
4725- * Array containing the last database prefix used and the last test class
4726- * that ran.
4727- */
4728-function simpletest_last_test_get($test_id) {
4729-// $last_prefix = db_result(db_query_range('SELECT last_prefix FROM {simpletest_test_id} WHERE test_id = :test_id', array(':test_id' => $test_id), 0, 1));
4730- $last_prefix = db_result(db_query_range('SELECT last_prefix FROM {simpletest_test_id} WHERE test_id = ' . $test_id, 0, 1));
4731-// $last_test_class = db_result(db_query_range('SELECT test_class FROM {simpletest} WHERE test_id = :test_id ORDER BY message_id DESC', array(':test_id' => $test_id), 0, 1));
4732- $last_test_class = db_result(db_query_range('SELECT test_class FROM {simpletest} WHERE test_id = ' . $test_id . ' ORDER BY message_id DESC', 0, 1));
4733- return array($last_prefix, $last_test_class);
4734-}
4735-
4736-/**
4737- * Read the error log and report any errors as assertion failures.
4738- *
4739- * The errors in the log should only be fatal errors since any other errors
4740- * will have been recorded by the error handler.
4741- *
4742- * @param $test_id
4743- * The test ID to which the log relates.
4744- * @param $prefix
4745- * The database prefix to which the log relates.
4746- * @param $test_class
4747- * The test class to which the log relates.
4748- * @param $during_test
4749- * Indicates that the current file directory path is a temporary file
4750- * file directory used during testing.
4751- * @return
4752- * Found any entries in log.
4753- */
4754-function simpletest_log_read($test_id, $prefix, $test_class, $during_test = FALSE) {
4755- require_once drupal_get_path('module', 'simpletest') . '/drupal_web_test_case.php';
4756- $log = file_directory_path() . ($during_test ? '' : '/simpletest/' . substr($prefix, 10)) . '/error.log';
4757- $found = FALSE;
4758- if (file_exists($log)) {
4759- foreach (file($log) as $line) {
4760- if (preg_match('/\[.*?\] (.*?): (.*?) in (.*) on line (\d+)/', $line, $match)) {
4761- // Parse PHP fatal errors for example: PHP Fatal error: Call to
4762- // undefined function break_me() in /path/to/file.php on line 17
4763- $caller = array(
4764- 'line' => $match[4],
4765- 'file' => $match[3],
4766- );
4767- DrupalTestCase::insertAssert($test_id, $test_class, FALSE, $match[2], $match[1], $caller);
4768- }
4769- else {
4770- // Unkown format, place the entire message in the log.
4771- DrupalTestCase::insertAssert($test_id, $test_class, FALSE, $line, 'Fatal error');
4772- }
4773- $found = TRUE;
4774- }
4775- }
4776- return $found;
4777-}
4778-
4779-/**
4780- * Get a list of all of the tests provided by the system.
4781- *
4782- * The list of test classes is loaded from the registry where it looks for
4783- * files ending in ".test". Once loaded the test list is cached and stored in
4784- * a static variable. In order to list tests provided by disabled modules
4785- * hook_registry_files_alter() is used to forcefully add them to the registry.
4786- *
4787- * @return
4788- * An array of tests keyed with the groups specified in each of the tests
4789- * getInfo() method and then keyed by the test class. An example of the array
4790- * structure is provided below.
4791- *
4792- * @code
4793- * $groups['Blog'] => array(
4794- * 'BlogTestCase' => array(
4795- * 'name' => 'Blog functionality',
4796- * 'description' => 'Create, view, edit, delete, ...',
4797- * 'group' => 'Blog',
4798- * ),
4799- * );
4800- * @endcode
4801- * @see simpletest_registry_files_alter()
4802- */
4803-function simpletest_test_get_all() {
4804- static $groups;
4805-
4806- if (!$groups) {
4807- // Load test information from cache if available, otherwise retrieve the
4808- // information from each tests getInfo() method.
4809- if ($cache = cache_get('simpletest', 'cache')) {
4810- $groups = $cache->data;
4811- }
4812- else {
4813- // Select all clases in files ending with .test.
4814- $classes = simpletest_test_get_all_classes();
4815-
4816- $groups = array();
4817-
4818- // Check that each class has a getInfo() method and store the information
4819- // in an array keyed with the group specified in the test information.
4820- foreach ($classes as $class) {
4821- $class = $class['class'];
4822-
4823- if (class_exists($class) && method_exists($class, 'getInfo')) {
4824- // Valid test class, retrieve test information.
4825- $info = call_user_func(array($class, 'getInfo'));
4826-
4827- // Initialize test groups.
4828- if (!isset($groups[$info['group']])) {
4829- $groups[$info['group']] = array();
4830- }
4831- $groups[$info['group']][$class] = $info;
4832- }
4833- }
4834- // Sort the groups and tests within the groups by name.
4835- uksort($groups, 'strnatcasecmp');
4836- foreach ($groups as $group => &$tests) {
4837- uksort($tests, 'strnatcasecmp');
4838- }
4839-
4840- cache_set('simpletest', $groups);
4841- }
4842- }
4843- return $groups;
4844-}
4845-
4846-function simpletest_test_get_all_classes() {
4847- // Must load DrupalWebTestCase before loading any other test classes which
4848- // will extend it.
4849- require_once 'drupal_web_test_case.php';
4850-
4851- $classes = array();
4852- $files = module_rebuild_cache();
4853- foreach ($files as $file) {
4854- $directory = dirname($file->filename);
4855- $test_files = file_scan_directory($directory, '\.test$', array('.', '..', 'CVS', '.svn'), FALSE, FALSE);
4856- $test_files += file_scan_directory($directory . '/tests', '\.test$');
4857-
4858- foreach ($test_files as $test_file) {
4859- $pre = get_declared_classes();
4860- require_once $test_file->filename;
4861- $post = get_declared_classes();
4862-
4863- $classes_new = array_values(array_diff($post, $pre));
4864- foreach ($classes_new as $class) {
4865- $classes[$class] = array('file' => $test_file->filename, 'class' => $class);
4866- }
4867- }
4868- }
4869-
4870- return $classes;
4871-}
4872-
4873-
4874-/**
4875- * Remove all temporary database tables and directories.
4876- */
4877-function simpletest_clean_environment() {
4878- simpletest_clean_database();
4879- simpletest_clean_temporary_directories();
4880- if (variable_get('simpletest_clear_results', TRUE)) {
4881- $count = simpletest_clean_results_table();
4882- drupal_set_message(format_plural($count, 'Removed 1 test result.', 'Removed @count test results.'));
4883- }
4884- else {
4885- drupal_set_message(t('Clear results is disabled and the test results table will not be cleared.'), 'warning');
4886- }
4887-}
4888-
4889-/**
4890- * Removed prefixed tables from the database that are left over from crashed tests.
4891- */
4892-function simpletest_clean_database() {
4893- $tables = simpletest_get_like_tables();
4894- $schema = drupal_get_schema_unprocessed('simpletest');
4895- $ret = array();
4896- foreach (array_diff_key($tables, $schema) as $table) {
4897- // Strip the prefix and skip tables without digits following "simpletest",
4898- // e.g. {simpletest_test_id}.
4899- if (preg_match('/simpletest\d+.*/', $table, $matches)) {
4900- db_drop_table($ret, $matches[0]);
4901- }
4902- }
4903-
4904- if (count($ret) > 0) {
4905- drupal_set_message(format_plural(count($ret), 'Removed 1 leftover table.', 'Removed @count leftover tables.'));
4906- }
4907- else {
4908- drupal_set_message(t('No leftover tables to remove.'));
4909- }
4910-}
4911-
4912-/**
4913- * Find all tables that are like the specified base table name. (Drupal 6)
4914- *
4915- * @param string $base_table Base table name.
4916- * @param boolean $count Return the table count instead of list of tables.
4917- * @return mixed Array of matching tables or count of tables.
4918- */
4919-function simpletest_get_like_tables($base_table = 'simpletest', $count = FALSE) {
4920- global $db_url, $db_prefix;
4921- $url = parse_url(is_array($db_url) ? $db_url['default'] : $db_url);
4922- $database = substr($url['path'], 1);
4923- $result = db_query("SELECT table_name FROM information_schema.tables WHERE (table_schema = '$database' OR table_catalog = '$database') AND table_name LIKE '$db_prefix$base_table%'");
4924- $schema = drupal_get_schema_unprocessed('simpletest');
4925-
4926- $tables = array();
4927- while ($table = db_result($result)) {
4928- if (!isset($schema[$table])) {
4929- $tables[] = $table;
4930- }
4931- }
4932- return ($count) ? count($tables) : $tables;
4933-}
4934-
4935-/**
4936- * Find all leftover temporary directories and remove them.
4937- */
4938-function simpletest_clean_temporary_directories() {
4939- $files = scandir(file_directory_path());
4940- $count = 0;
4941- foreach ($files as $file) {
4942- $path = file_directory_path() . $file;
4943- if (is_dir($path) && preg_match('/^simpletest\d+/', $file)) {
4944- simpletest_clean_temporary_directory($path);
4945- $count++;
4946- }
4947- }
4948-
4949- if ($count > 0) {
4950- drupal_set_message(format_plural($count, 'Removed 1 temporary directory.', 'Removed @count temporary directories.'));
4951- }
4952- else {
4953- drupal_set_message(t('No temporary directories to remove.'));
4954- }
4955-}
4956-
4957-/**
4958- * Remove all files from specified directory and then remove directory. (Drupal 6)
4959- *
4960- * @param string $path Directory path.
4961- */
4962-function simpletest_clean_temporary_directory($path) {
4963- // Drupal 6.
4964- if (!is_dir($path)) {
4965- return;
4966- }
4967-
4968- $files = scandir($path);
4969- foreach ($files as $file) {
4970- if ($file != '.' && $file != '..') {
4971- $file_path = "$path/$file";
4972- if (is_dir($file_path)) {
4973- simpletest_clean_temporary_directory($file_path);
4974- }
4975- else {
4976-// file_unmanaged_delete($file_path);
4977- unlink($file_path);
4978- }
4979- }
4980- }
4981- rmdir($path);
4982-}
4983-
4984-/**
4985- * Clear the test result tables.
4986- *
4987- * @param $test_id
4988- * Test ID to remove results for, or NULL to remove all results.
4989- * @return
4990- * The number of results removed.
4991- */
4992-function simpletest_clean_results_table($test_id = NULL) {
4993- if (variable_get('simpletest_clear_results', TRUE)) {
4994- if ($test_id) {
4995- $count = db_result(db_query('SELECT COUNT(test_id) FROM {simpletest_test_id} WHERE test_id = %d', $test_id));
4996-
4997- db_query("DELETE FROM {simpletest} WHERE test_id = %d", $test_id);
4998- db_query("DELETE FROM {simpletest_test_id} WHERE test_id = %d", $test_id);
4999- }
5000- else {
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to status/vote changes: