followup r91869: validate id chars for incoming prefs tabs in hash ([\w-]+ is suffici...
[mediawiki.git] / maintenance / fuzz-tester.php
blob18af4de45d32f57692619182afcaa20e93f8ed99
1 <?php
2 /**
3 * Performs fuzz-style testing of MediaWiki's parser and forms.
5 * Copyright © 2006 Nick Jenkins
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * http://www.gnu.org/copyleft/gpl.html
22 * @file
23 * @ingroup Maintenance
24 * @author Nick Jenkins ( http://nickj.org/ ).
27 Started: 18 May 2006.
29 Description:
30 Performs fuzz-style testing of MediaWiki's parser and forms.
32 How:
33 - Generate lots of nasty wiki text.
34 - Ask the Parser to render that wiki text to HTML, or ask MediaWiki's forms
35 to deal with that wiki text.
36 - Check MediaWiki's output for problems.
37 - Repeat.
39 Why:
40 - To help find bugs.
41 - To help find security issues, or potential security issues.
43 What type of problems are being checked for:
44 - Unclosed tags.
45 - Errors or interesting warnings from Tidy.
46 - PHP errors / warnings / notices.
47 - MediaWiki internal errors.
48 - Very slow responses.
49 - No response from apache.
50 - Optionally checking for malformed HTML using the W3C validator.
52 Background:
53 Many of the wikiFuzz class methods are a modified PHP port,
54 of a "shameless" Python port, of LCAMTUF'S MANGELME:
55 - http://www.securiteam.com/tools/6Z00N1PBFK.html
56 - http://www.securityfocus.com/archive/1/378632/2004-10-15/2004-10-21/0
58 Video:
59 There's an XviD video discussing this fuzz tester. You can get it from:
60 http://files.nickj.org/MediaWiki/Fuzz-Testing-MediaWiki-xvid.avi
62 Requirements:
63 To run this, you will need:
64 - Command-line PHP5, with PHP-curl enabled (not all installations have this
65 enabled - try "apt-get install php5-curl" if you're on Debian to install).
66 - the Tidy standalone executable. ("apt-get install tidy").
68 Optional:
69 - If you want to run the curl scripts, you'll need standalone curl installed
70 ("apt-get install curl")
71 - For viewing the W3C validator output on a command line, the "html2text"
72 program may be useful ("apt-get install html2text")
74 Saving tests and test results:
75 Any of the fuzz tests which find problems are saved for later review.
76 In order to help track down problems, tests are saved in a number of
77 different formats. The default filename extensions and their meanings are:
78 - ".test.php" : PHP script that reproduces just that one problem using PHP-Curl.
79 - ".curl.sh" : Shell script that reproduces that problem using standalone curl.
80 - ".data.bin" : The serialized PHP data so that this script can re-run the test.
81 - ".info.txt" : A human-readable text file with details of the field contents.
83 Wiki configuration for testing:
84 You should make some additions to LocalSettings.php in order to catch the most
85 errors. Note this configuration is for **TESTING PURPOSES ONLY**, and is IN NO
86 WAY, SHAPE, OR FORM suitable for deployment on a hostile network. That said,
87 personally I find these additions to be the most helpful for testing purposes:
89 // --------- Start ---------
90 // Everyone can do everything. Very useful for testing, yet useless for deployment.
91 $wgGroupPermissions['*']['autoconfirmed'] = true;
92 $wgGroupPermissions['*']['block'] = true;
93 $wgGroupPermissions['*']['bot'] = true;
94 $wgGroupPermissions['*']['delete'] = true;
95 $wgGroupPermissions['*']['deletedhistory'] = true;
96 $wgGroupPermissions['*']['deleterevision'] = true;
97 $wgGroupPermissions['*']['editinterface'] = true;
98 $wgGroupPermissions['*']['hiderevision'] = true;
99 $wgGroupPermissions['*']['import'] = true;
100 $wgGroupPermissions['*']['importupload'] = true;
101 $wgGroupPermissions['*']['minoredit'] = true;
102 $wgGroupPermissions['*']['move'] = true;
103 $wgGroupPermissions['*']['patrol'] = true;
104 $wgGroupPermissions['*']['protect'] = true;
105 $wgGroupPermissions['*']['proxyunbannable'] = true;
106 $wgGroupPermissions['*']['renameuser'] = true;
107 $wgGroupPermissions['*']['reupload'] = true;
108 $wgGroupPermissions['*']['reupload-shared'] = true;
109 $wgGroupPermissions['*']['rollback'] = true;
110 $wgGroupPermissions['*']['siteadmin'] = true;
111 $wgGroupPermissions['*']['trackback'] = true;
112 $wgGroupPermissions['*']['unwatchedpages'] = true;
113 $wgGroupPermissions['*']['upload'] = true;
114 $wgGroupPermissions['*']['userrights'] = true;
115 $wgGroupPermissions['*']['renameuser'] = true;
116 $wgGroupPermissions['*']['makebot'] = true;
117 $wgGroupPermissions['*']['makesysop'] = true;
119 // Enable weird and wonderful options:
120 // Increase default error reporting level.
121 error_reporting (E_ALL); // At a later date could be increased to E_ALL | E_STRICT
122 $wgBlockOpenProxies = true; // Some block pages require this to be true in order to test.
123 $wgEnableUploads = true; // enable uploads.
124 //$wgUseTrackbacks = true; // enable trackbacks; However this breaks the viewPageTest, so currently disabled.
125 $wgDBerrorLog = "/root/mediawiki-db-error-log.txt"; // log DB errors, replace with suitable path.
126 $wgShowSQLErrors = true; // Show SQL errors (instead of saying the query was hidden).
127 $wgShowExceptionDetails = true; // want backtraces.
128 $wgEnableAPI = true; // enable API.
129 $wgEnableWriteAPI = true; // enable API.
131 // Install & enable Parser Hook extensions to increase code coverage. E.g.:
132 require_once("extensions/ParserFunctions/ParserFunctions.php");
133 require_once("extensions/Cite/Cite.php");
134 require_once("extensions/inputbox/inputbox.php");
135 require_once("extensions/Sort/Sort.php");
136 require_once("extensions/wikihiero/wikihiero.php");
137 require_once("extensions/CharInsert/CharInsert.php");
138 require_once("extensions/FixedImage/FixedImage.php");
140 // Install & enable Special Page extensions to increase code coverage. E.g.:
141 require_once("extensions/Cite/SpecialCite.php");
142 require_once("extensions/Filepath/SpecialFilepath.php");
143 require_once("extensions/Makebot/Makebot.php");
144 require_once("extensions/Makesysop/SpecialMakesysop.php");
145 require_once("extensions/Renameuser/SpecialRenameuser.php");
146 require_once("extensions/LinkSearch/LinkSearch.php");
147 // --------- End ---------
149 If you want to try E_STRICT error logging, add this to the above:
150 // --------- Start ---------
151 error_reporting (E_ALL | E_STRICT);
152 set_error_handler( 'error_handler' );
153 function error_handler ($type, $message, $file=__FILE__, $line=__LINE__) {
154 if ($message == "var: Deprecated. Please use the public/private/protected modifiers") return;
155 print "<br />\n<b>Strict Standards:</b> Type: <b>$type</b>: $message in <b>$file</b> on line <b>$line</b><br />\n";
157 // --------- End ---------
159 Also add/change this in LocalSettings.php:
160 // --------- Start ---------
161 $wgEnableProfileInfo = true;
162 $wgDBserver = "localhost"; // replace with DB server hostname
163 // --------- End ---------
165 Usage:
166 Run with "php fuzz-tester.php".
167 To see the various command-line options, run "php fuzz-tester.php --help".
168 To stop the script, press Ctrl-C.
170 Console output:
171 - If requested, first any previously failed tests will be rerun.
172 - Then new tests will be generated and run. Any tests that fail will be saved,
173 and a brief message about why they failed will be printed on the console.
174 - The console will show the number of tests run, time run, number of tests
175 failed, number of tests being done per minute, and the name of the current test.
177 TODO:
178 Some known things that could improve this script:
179 - Logging in with cookie jar storage needed for some tests (as there are some
180 pages that cannot be tested without being logged in, and which are currently
181 untested - e.g. Special:Emailuser, Special:Preferences, adding to Watchist).
182 - Testing of Timeline extension (I cannot test as ploticus has/had issues on
183 my architecture).
187 // ///////////////////////// COMMAND LINE HELP ////////////////////////////////////
189 // This is a command line script, load MediaWiki env (gives command line options);
190 require_once( dirname( __FILE__ ) . '/commandLine.inc' );
192 // if the user asked for an explanation of command line options.
193 if ( isset( $options["help"] ) ) {
194 print <<<ENDS
195 MediaWiki $wgVersion fuzz tester
196 Usage: php {$_SERVER["SCRIPT_NAME"]} [--quiet] [--base-url=<url-to-test-wiki>]
197 [--directory=<failed-test-path>] [--include-binary]
198 [--w3c-validate] [--delete-passed-retests] [--help]
199 [--user=<username>] [--password=<password>]
200 [--rerun-failed-tests] [--max-errors=<int>]
201 [--max-runtime=<num-minutes>]
202 [--specific-test=<test-name>]
204 Options:
205 --quiet : Hides passed tests, shows only failed tests.
206 --base-url : URL to a wiki on which to run the tests.
207 The "http://" is optional and can be omitted.
208 --directory : Full path to directory for storing failed tests.
209 Will be created if it does not exist.
210 --include-binary : Includes non-alphanumeric characters in the tests.
211 --w3c-validate : Validates pages using the W3C's web validator.
212 Slow. Currently many pages fail validation.
213 --user : Login name of a valid user on your test wiki.
214 --password : Password for the valid user on your test wiki.
215 --delete-passed-retests : Will delete retests that now pass.
216 Requires --rerun-failed-tests to be meaningful.
217 --rerun-failed-tests : Whether to rerun any previously failed tests.
218 --max-errors : Maximum number of errors to report before exiting.
219 Does not include errors from --rerun-failed-tests
220 --max-runtime : Maximum runtime, in minutes, to run before exiting.
221 Only applies to new tests, not --rerun-failed-tests
222 --specific-test : Runs only the specified fuzz test.
223 Only applies to new tests, not --rerun-failed-tests
224 --keep-passed-tests : Saves all test files, even those that pass.
225 --help : Show this help message.
227 Example:
228 If you wanted to fuzz test a nightly MediaWiki checkout using cron for 1 hour,
229 and only wanted to be informed of errors, and did not want to redo previously
230 failed tests, and wanted a maximum of 100 errors, then you could do:
231 php {$_SERVER["SCRIPT_NAME"]} --quiet --max-errors=100 --max-runtime=60
234 ENDS;
236 exit( 0 );
240 // if we got command line options, check they look valid.
241 $validOptions = array ( "quiet", "base-url", "directory", "include-binary",
242 "w3c-validate", "user", "password", "delete-passed-retests",
243 "rerun-failed-tests", "max-errors",
244 "max-runtime", "specific-test", "keep-passed-tests", "help" );
245 if ( !empty( $options ) ) {
246 $unknownArgs = array_diff ( array_keys( $options ), $validOptions );
247 foreach ( $unknownArgs as $invalidArg ) {
248 print "Ignoring invalid command-line option: --$invalidArg\n";
253 // /////////////////////////// CONFIGURATION ////////////////////////////////////
255 // URL to some wiki on which we can run our tests.
256 if ( !empty( $options["base-url"] ) ) {
257 define( "WIKI_BASE_URL", $options["base-url"] );
258 } else {
259 define( "WIKI_BASE_URL", $wgServer . $wgScriptPath . '/' );
262 // The directory name where we store the output.
263 // Example for Windows: "c:\\temp\\wiki-fuzz"
264 if ( !empty( $options["directory"] ) ) {
265 define( "DIRECTORY", $options["directory"] );
266 } else {
267 define( "DIRECTORY", "{$wgUploadDirectory}/fuzz-tests" );
270 // Should our test fuzz data include binary strings?
271 define( "INCLUDE_BINARY", isset( $options["include-binary"] ) );
273 // Whether we want to validate HTML output on the web.
274 // At the moment very few generated pages will validate, so not recommended.
275 define( "VALIDATE_ON_WEB", isset( $options["w3c-validate"] ) );
276 // URL to use to validate our output:
277 define( "VALIDATOR_URL", "http://validator.w3.org/check" );
279 // Location of Tidy standalone executable.
280 define( "PATH_TO_TIDY", "/usr/bin/tidy" );
282 // The name of a user who has edited on your wiki. Used
283 // when testing the Special:Contributions and Special:Userlogin page.
284 if ( !empty( $options["user"] ) ) {
285 define( "USER_ON_WIKI", $options["user"] );
286 } else {
287 define( "USER_ON_WIKI", "nickj" );
290 // The password of the above user. Used when testing the login page,
291 // and to do this we sometimes need to login successfully.
292 if ( !empty( $options["password"] ) ) {
293 define( "USER_PASSWORD", $options["password"] );
294 } else {
295 // And no, this is not a valid password on any public wiki.
296 define( "USER_PASSWORD", "nickj" );
299 // If we have a test that failed, and then we run it again, and it passes,
300 // do you want to delete it or keep it?
301 define( "DELETE_PASSED_RETESTS", isset( $options["delete-passed-retests"] ) );
303 // Do we want to rerun old saved tests at script startup?
304 // Set to true to help catch regressions, or false if you only want new stuff.
305 define( "RERUN_OLD_TESTS", isset( $options["rerun-failed-tests"] ) );
307 // File where the database errors are logged. Should be defined in LocalSettings.php.
308 define( "DB_ERROR_LOG_FILE", $wgDBerrorLog );
310 // Run in chatty mode (all output, default), or run in quiet mode (only prints out details of failed tests)?
311 define( "QUIET", isset( $options["quiet"] ) );
313 // Keep all test files, even those that pass. Potentially useful to tracking input that causes something
314 // unusual to happen, if you don't know what "unusual" is until later.
315 define( "KEEP_PASSED_TESTS", isset( $options["keep-passed-tests"] ) );
317 // The maximum runtime, if specified.
318 if ( !empty( $options["max-runtime"] ) && intval( $options["max-runtime"] ) > 0 ) {
319 define( "MAX_RUNTIME", intval( $options["max-runtime"] ) );
322 // The maximum number of problems to find, if specified. Excludes retest errors.
323 if ( !empty( $options["max-errors"] ) && intval( $options["max-errors"] ) > 0 ) {
324 define( "MAX_ERRORS", intval( $options["max-errors"] ) );
327 // if the user has requested a specific test (instead of all tests), and the test they asked for looks valid.
328 if ( !empty( $options["specific-test"] ) ) {
329 if ( class_exists( $options["specific-test"] ) && get_parent_class( $options["specific-test"] ) == "pageTest" ) {
330 define( "SPECIFIC_TEST", $options["specific-test"] );
332 else {
333 print "Ignoring invalid --specific-test\n";
337 // Define the file extensions we'll use:
338 define( "PHP_TEST" , ".test.php" );
339 define( "CURL_TEST", ".curl.sh" );
340 define( "DATA_FILE", ".data.bin" );
341 define( "INFO_FILE", ".info.txt" );
342 define( "HTML_FILE", ".wiki_preview.html" );
344 // If it goes wrong, we want to know about it.
345 error_reporting( E_ALL | E_STRICT );
347 // ////////////// A CLASS THAT GENERATES RANDOM NASTY WIKI & HTML STRINGS //////////////////////
349 class wikiFuzz {
351 // Only some HTML tags are understood with params by MediaWiki, the rest are ignored.
352 // List the tags that accept params below, as well as what those params are.
353 public static $data = array(
354 "B" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
355 "CAPTION" => array( "CLASS", "ID", "STYLE", "align", "lang", "dir", "title" ),
356 "CENTER" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title" ),
357 "DIV" => array( "CLASS", "STYLE", "ID", "align", "lang", "dir", "title" ),
358 "FONT" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title", "face", "size", "color" ),
359 "H1" => array( "STYLE", "CLASS", "ID", "align", "lang", "dir", "title" ),
360 "H2" => array( "STYLE", "CLASS", "ID", "align", "lang", "dir", "title" ),
361 "HR" => array( "STYLE", "CLASS", "ID", "WIDTH", "lang", "dir", "title", "size", "noshade" ),
362 "LI" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "type", "value" ),
363 "TABLE" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "BORDER", "CELLPADDING",
364 "CELLSPACING", "lang", "dir", "title", "summary", "frame", "rules" ),
365 "TD" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "COLSPAN", "ROWSPAN",
366 "VALIGN", "abbr", "axis", "headers", "scope", "nowrap", "height", "lang",
367 "dir", "title", "char", "charoff" ),
368 "TH" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "COLSPAN", "ROWSPAN",
369 "VALIGN", "abbr", "axis", "headers", "scope", "nowrap", "height", "lang",
370 "dir", "title", "char", "charoff" ),
371 "TR" => array( "CLASS", "STYLE", "ID", "BGCOLOR", "ALIGN", "VALIGN", "lang", "dir", "title", "char", "charoff" ),
372 "UL" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title", "type" ),
373 "P" => array( "style", "class", "id", "align", "lang", "dir", "title" ),
374 "blockquote" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "cite" ),
375 "span" => array( "CLASS", "ID", "STYLE", "align", "lang", "dir", "title" ),
376 "code" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
377 "tt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
378 "small" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
379 "big" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
380 "s" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
381 "u" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
382 "del" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "datetime", "cite" ),
383 "ins" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "datetime", "cite" ),
384 "sub" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
385 "sup" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
386 "ol" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "type", "start" ),
387 "br" => array( "CLASS", "ID", "STYLE", "title", "clear" ),
388 "cite" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
389 "var" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
390 "dl" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
391 "ruby" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
392 "rt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
393 "rp" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
394 "dt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
395 "dl" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
396 "em" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
397 "strong" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
398 "i" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
399 "thead" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ),
400 "tfoot" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ),
401 "tbody" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ),
402 "colgroup" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign', 'span', 'width' ),
403 "col" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign', 'span', 'width' ),
404 "pre" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "width" ),
406 // extension tags that accept parameters:
407 "sort" => array( "order", "class" ),
408 "ref" => array( "name" ),
409 "categorytree" => array( "hideroot", "mode", "style" ),
410 "chemform" => array( "link", "wikilink", "query" ),
411 "section" => array( "begin", "new" ),
413 // older MW transclusion.
414 "transclude" => array( "page" ),
417 // The types of the HTML that we will be testing were defined above
418 // Note: this needs to be initialized later to be equal to: array_keys(wikiFuzz::$data);
419 // as such, it also needs to also be publicly modifiable.
420 public static $types;
423 // Some attribute values.
424 static private $other = array( "&", "=", ":", "?", "\"", "\n", "%n%n%n%n%n%n%n%n%n%n%n%n", "\\" );
425 static private $ints = array(
426 // various numbers
427 "0", "-1", "127", "-7897", "89000", "808080", "90928345",
428 "0xfffffff", "ffff",
430 // Different ways of saying: '
431 "&#0000039;", // Long UTF-8 Unicode encoding
432 "&#39;", // dec version.
433 "&#x27;", // hex version.
434 "&#xA7;", // malformed hex variant, MSB not zero.
436 // Different ways of saying: "
437 "&#0000034;", // Long UTF-8 Unicode encoding
438 "&#34;",
439 "&#x22;", // hex version.
440 "&#xA2;", // malformed hex variant, MSB not zero.
442 // Different ways of saying: <
443 "<",
444 "&#0000060", // Long UTF-8 Unicode encoding without semicolon (Mediawiki wants the colon)
445 "&#0000060;", // Long UTF-8 Unicode encoding with semicolon
446 "&#60;",
447 "&#x3C;", // hex version.
448 "&#xBC;", // malformed hex variant, MSB not zero.
449 "&#x0003C;", // mid-length hex version
450 "&#X00003C;", // slightly longer hex version, with capital "X"
452 // Different ways of saying: >
453 ">",
454 "&#0000062;", // Long UTF-8 Unicode encoding
455 "&#62;",
456 "&#x3E;", // hex version.
457 "&#xBE;", // malformed variant, MSB not zero.
459 // Different ways of saying: [
460 "&#0000091;", // Long UTF-8 Unicode encoding
461 "&#91;",
462 "&#x5B;", // hex version.
464 // Different ways of saying: {{
465 "&#0000123;&#0000123;", // Long UTF-8 Unicode encoding
466 "&#123;&#123;",
467 "&#x7B;&#x7B;", // hex version.
469 // Different ways of saying: |
470 "&#0000124;", // Long UTF-8 Unicode encoding
471 "&#124;",
472 "&#x7C;", // hex version.
473 "&#xFC;", // malformed hex variant, MSB not zero.
475 // a "lignature" - http://www.robinlionheart.com/stds/html4/spchars#ligature
476 // &#8204; == &zwnj;
477 "&#8204;"
480 // Defines various wiki-related bits of syntax, that can potentially cause
481 // MediaWiki to do something other than just print that literal text.
482 static private $ext = array(
483 // links, templates, parameters.
484 "[[", "]]", "{{", "}}", "|", "[", "]", "{{{", "}}}", "|]]",
486 // wiki tables.
487 "\n{|", "\n|}",
488 "!",
489 "\n!",
490 "!!",
491 "||",
492 "\n|-", "| ", "\n|",
494 // section headings.
495 "=", "==", "===", "====", "=====", "======",
497 // lists (ordered and unordered) and indentation.
498 "\n*", "*", "\n:", ":",
499 "\n#", "#",
501 // definition lists (dl, dt, dd), newline, and newline with pre, and a tab.
502 "\n;", ";", "\n ",
504 // Whitespace: newline, tab, space.
505 "\n", "\t", " ",
507 // Some XSS attack vectors from http://ha.ckers.org/xss.html
508 "&#x09;", // tab
509 "&#x0A;", // newline
510 "&#x0D;", // carriage return
511 "\0", // null character
512 " &#14; ", // spaces and meta characters
513 "'';!--\"<XSS>=&{()}", // compact injection of XSS & SQL tester
515 // various NULL fields
516 "%00",
517 "&#00;",
518 "\0",
520 // horizontal rule.
521 "-----", "\n-----",
523 // signature, redirect, bold, italics.
524 "~~~~", "#REDIRECT [[", "'''", "''",
526 // comments.
527 "<!--", "-->",
529 // quotes.
530 "\"", "'",
532 // tag start and tag end.
533 "<", ">",
535 // implicit link creation on URIs.
536 "http://",
537 "https://",
538 "ftp://",
539 "irc://",
540 "news:",
541 'gopher://',
542 'telnet://',
543 'nntp://',
544 'worldwind://',
545 'mailto:',
547 // images.
548 "[[image:",
549 ".gif",
550 ".png",
551 ".jpg",
552 ".jpeg",
553 'thumbnail=',
554 'thumbnail',
555 'thumb=',
556 'thumb',
557 'right',
558 'none',
559 'left',
560 'framed',
561 'frame',
562 'enframed',
563 'centre',
564 'center',
565 "Image:",
566 "[[:Image",
567 'px',
568 'upright=',
569 'border',
571 // misc stuff to throw at the Parser.
572 '%08X',
573 '/',
574 ":x{|",
575 "\n|+",
576 "<noinclude>",
577 "</noinclude>",
578 " \302\273",
579 " :",
580 " !",
581 " ;",
582 "\302\253",
583 "[[category:",
584 "?=",
585 "(",
586 ")",
587 "]]]",
588 "../",
589 "{{{{",
590 "}}}}",
591 "[[Special:",
592 "<includeonly>",
593 "</includeonly>",
594 "<!--MWTEMPLATESECTION=",
595 '<!--MWTOC-->',
597 // implicit link creation on booknum, RFC, and PubMed ID usage (both with and without IDs)
598 "ISBN 2",
599 "RFC 000",
600 "PMID 000",
601 "ISBN ",
602 "RFC ",
603 "PMID ",
605 // magic words:
606 '__NOTOC__',
607 '__FORCETOC__',
608 '__NOEDITSECTION__',
609 '__START__',
610 '__NOTITLECONVERT__',
611 '__NOCONTENTCONVERT__',
612 '__END__',
613 '__TOC__',
614 '__NOTC__',
615 '__NOCC__',
616 "__FORCETOC__",
617 "__NEWSECTIONLINK__",
618 "__NOGALLERY__",
620 // more magic words / internal templates.
621 '{{PAGENAME}}',
622 '{{PAGENAMEE}}',
623 '{{NAMESPACE}}',
624 "{{MSG:",
625 "}}",
626 "{{MSGNW:",
627 "}}",
628 "{{INT:",
629 "}}",
630 '{{SITENAME}}',
631 "{{NS:",
632 "}}",
633 "{{LOCALURL:",
634 "}}",
635 "{{LOCALURLE:",
636 "}}",
637 "{{SCRIPTPATH}}",
638 "{{GRAMMAR:gentiv|",
639 "}}",
640 "{{REVISIONID}}",
641 "{{SUBPAGENAME}}",
642 "{{SUBPAGENAMEE}}",
643 "{{ns:0}}",
644 "{{fullurle:",
645 "}}",
646 "{{subst::",
647 "}}",
648 "{{UCFIRST:",
649 "}}",
650 "{{UC:",
651 '{{SERVERNAME}}',
652 '{{SERVER}}',
653 "{{RAW:",
654 "}}",
655 "{{PLURAL:",
656 "}}",
657 "{{LCFIRST:",
658 "}}",
659 "{{LC:",
660 "}}",
661 '{{CURRENTWEEK}}',
662 '{{CURRENTDOW}}',
663 "{{INT:{{LC:contribs-showhideminor}}|",
664 "}}",
665 "{{INT:googlesearch|",
666 "}}",
667 "{{BASEPAGENAME}}",
668 "{{CONTENTLANGUAGE}}",
669 "{{PAGESINNAMESPACE:}}",
670 "{{#language:",
671 "}}",
672 "{{#special:",
673 "}}",
674 "{{#special:emailuser",
675 "}}",
677 // Some raw link for magic words.
678 "{{NUMBEROFPAGES:R",
679 "}}",
680 "{{NUMBEROFUSERS:R",
681 "}}",
682 "{{NUMBEROFARTICLES:R",
683 "}}",
684 "{{NUMBEROFFILES:R",
685 "}}",
686 "{{NUMBEROFADMINS:R",
687 "}}",
688 "{{padleft:",
689 "}}",
690 "{{padright:",
691 "}}",
692 "{{DEFAULTSORT:",
693 "}}",
695 // internal Math "extension":
696 "<math>",
697 "</math>",
699 // Parser extension functions:
700 "{{#expr:",
701 "{{#if:",
702 "{{#ifeq:",
703 "{{#ifexist:",
704 "{{#ifexpr:",
705 "{{#switch:",
706 "{{#time:",
707 "}}",
709 // references table for the Cite extension.
710 "<references/>",
712 // Internal Parser tokens - try inserting some of these.
713 "UNIQ25f46b0524f13e67NOPARSE",
714 "UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002",
715 "\x07UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002-QINU",
717 // Inputbox extension:
718 "<inputbox>\ntype=search\nsearchbuttonlabel=\n",
719 "</inputbox>",
721 // charInsert extension:
722 "<charInsert>",
723 "</charInsert>",
725 // wikiHiero extension:
726 "<hiero>",
727 "</hiero>",
729 // Image gallery:
730 "<gallery>",
731 "</gallery>",
733 // FixedImage extension.
734 "<fundraising/>",
736 // Timeline extension: currently untested.
738 // Nowiki:
739 "<nOwIkI>",
740 "</nowiki>",
742 // an external image to test the external image displaying code
743 "http://debian.org/Pics/debian.png",
745 // LabeledSectionTransclusion extension.
746 "{{#lstx:",
747 "}}",
748 "{{#lst:",
749 "}}",
750 "{{#lst:Main Page|",
751 "}}"
755 ** Randomly returns one element of the input array.
757 static public function chooseInput( array $input ) {
758 $randindex = wikiFuzz::randnum( count( $input ) - 1 );
759 return $input[$randindex];
762 // Max number of parameters for HTML attributes.
763 static private $maxparams = 10;
766 ** Returns random number between finish and start.
768 static public function randnum( $finish, $start = 0 ) {
769 return mt_rand( $start, $finish );
773 ** Returns a mix of random text and random wiki syntax.
775 static private function randstring() {
776 $thestring = "";
778 for ( $i = 0; $i < 40; $i++ ) {
779 $what = wikiFuzz::randnum( 1 );
781 if ( $what == 0 ) { // include some random wiki syntax
782 $which = wikiFuzz::randnum( count( wikiFuzz::$ext ) - 1 );
783 $thestring .= wikiFuzz::$ext[$which];
785 else { // include some random text
786 $char = INCLUDE_BINARY
787 // Decimal version:
788 // "&#" . wikiFuzz::randnum(255) . ";"
789 // Hex version:
790 ? "&#x" . str_pad( dechex( wikiFuzz::randnum( 255 ) ), wikiFuzz::randnum( 2, 7 ), "0", STR_PAD_LEFT ) . ";"
791 // A truly binary version:
792 // ? chr(wikiFuzz::randnum(0,255))
793 : chr( wikiFuzz::randnum( 126, 32 ) );
795 $length = wikiFuzz::randnum( 8 );
796 $thestring .= str_repeat ( $char, $length );
799 return $thestring;
803 ** Returns either random text, or random wiki syntax, or random data from "ints",
804 ** or random data from "other".
806 static private function makestring() {
807 $what = wikiFuzz::randnum( 2 );
808 if ( $what == 0 ) {
809 return wikiFuzz::randstring();
811 elseif ( $what == 1 ) {
812 return wikiFuzz::$ints[wikiFuzz::randnum( count( wikiFuzz::$ints ) - 1 )];
814 else {
815 return wikiFuzz::$other[wikiFuzz::randnum( count( wikiFuzz::$other ) - 1 )];
820 * Returns the matched character slash-escaped as in a C string
821 * Helper for makeTitleSafe callback
823 static private function stringEscape( $matches ) {
824 return sprintf( "\\x%02x", ord( $matches[1] ) );
828 ** Strips out the stuff that Mediawiki balks at in a page's title.
829 ** Implementation copied/pasted from cleanupTable.inc & cleanupImages.php
831 static public function makeTitleSafe( $str ) {
832 $legalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF";
833 return preg_replace_callback(
834 "/([^$legalTitleChars])/", 'wikiFuzz::stringEscape',
835 $str );
839 ** Returns a string of fuzz text.
841 static private function loop() {
842 switch ( wikiFuzz::randnum( 3 ) ) {
843 case 1: // an opening tag, with parameters.
844 $string = "";
845 $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 );
846 $t = wikiFuzz::$types[$i];
847 $arr = wikiFuzz::$data[$t];
848 $string .= "<" . $t . " ";
849 $num_params = min( wikiFuzz::$maxparams, count( $arr ) );
850 for ( $z = 0; $z < $num_params; $z++ ) {
851 $badparam = $arr[wikiFuzz::randnum( count( $arr ) - 1 )];
852 $badstring = wikiFuzz::makestring();
853 $string .= $badparam . "=" . wikiFuzz::getRandQuote() . $badstring . wikiFuzz::getRandQuote() . " ";
855 $string .= ">\n";
856 return $string;
857 case 2: // a closing tag.
858 $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 );
859 return "</" . wikiFuzz::$types[$i] . ">";
860 case 3: // a random string, between tags.
861 return wikiFuzz::makeString();
863 return ""; // catch-all, should never be called.
867 ** Returns one of the three styles of random quote: ', ", and nothing.
869 static private function getRandQuote() {
870 switch ( wikiFuzz::randnum( 3 ) ) {
871 case 1 : return "'";
872 case 2 : return "\"";
873 default: return "";
878 ** Returns fuzz text, with the parameter indicating approximately how many lines of text you want.
880 static public function makeFuzz( $maxtypes = 2 ) {
881 $page = "";
882 for ( $k = 0; $k < $maxtypes; $k++ ) {
883 $page .= wikiFuzz::loop();
885 return $page;
890 // ////// MEDIAWIKI PAGES TO TEST, AND HOW TO TEST THEM ///////
893 ** A page test has just these things:
894 ** 1) Form parameters.
895 ** 2) the URL we are going to test those parameters on.
896 ** 3) Any cookies required for the test.
897 ** 4) Whether Tidy should validate the page. Defaults to true, but can be turned off.
898 ** Declared abstract because it should be extended by a class
899 ** that supplies these parameters.
901 abstract class pageTest {
902 protected $params;
903 protected $pagePath;
904 protected $cookie = "";
905 protected $tidyValidate = true;
907 public function getParams() {
908 return $this->params;
911 public function getPagePath() {
912 return $this->pagePath;
915 public function getCookie() {
916 return $this->cookie;
919 public function tidyValidate() {
920 return $this->tidyValidate;
926 ** a page test for the "Edit" page. Tests Parser.php and Sanitizer.php.
928 class editPageTest extends pageTest {
929 function __construct() {
930 $this->pagePath = "index.php?title=WIKIFUZZ";
932 $this->params = array (
933 "action" => "submit",
934 "wpMinoredit" => wikiFuzz::makeFuzz( 2 ),
935 "wpPreview" => wikiFuzz::makeFuzz( 2 ),
936 "wpSection" => wikiFuzz::makeFuzz( 2 ),
937 "wpEdittime" => wikiFuzz::makeFuzz( 2 ),
938 "wpSummary" => wikiFuzz::makeFuzz( 2 ),
939 "wpScrolltop" => wikiFuzz::makeFuzz( 2 ),
940 "wpStarttime" => wikiFuzz::makeFuzz( 2 ),
941 "wpAutoSummary" => wikiFuzz::makeFuzz( 2 ),
942 "wpTextbox1" => wikiFuzz::makeFuzz( 40 ) // the main wiki text, need lots of this.
945 // sometimes we don't want to specify certain parameters.
946 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSection"] );
947 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEdittime"] );
948 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSummary"] );
949 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpScrolltop"] );
950 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpStarttime"] );
951 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpAutoSummary"] );
952 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpTextbox1"] );
958 ** a page test for "Special:Listusers".
960 class listusersTest extends pageTest {
961 function __construct() {
962 $this->pagePath = "index.php?title=Special:Listusers";
964 $this->params = array (
965 "title" => wikiFuzz::makeFuzz( 2 ),
966 "group" => wikiFuzz::makeFuzz( 2 ),
967 "username" => wikiFuzz::makeFuzz( 2 ),
968 "Go" => wikiFuzz::makeFuzz( 2 ),
969 "limit" => wikiFuzz::chooseInput( array( "0", "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
970 "offset" => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) )
977 ** a page test for "Special:Search".
979 class searchTest extends pageTest {
980 function __construct() {
981 $this->pagePath = "index.php?title=Special:Search";
983 $this->params = array (
984 "action" => "index.php?title=Special:Search",
985 "ns0" => wikiFuzz::makeFuzz( 2 ),
986 "ns1" => wikiFuzz::makeFuzz( 2 ),
987 "ns2" => wikiFuzz::makeFuzz( 2 ),
988 "ns3" => wikiFuzz::makeFuzz( 2 ),
989 "ns4" => wikiFuzz::makeFuzz( 2 ),
990 "ns5" => wikiFuzz::makeFuzz( 2 ),
991 "ns6" => wikiFuzz::makeFuzz( 2 ),
992 "ns7" => wikiFuzz::makeFuzz( 2 ),
993 "ns8" => wikiFuzz::makeFuzz( 2 ),
994 "ns9" => wikiFuzz::makeFuzz( 2 ),
995 "ns10" => wikiFuzz::makeFuzz( 2 ),
996 "ns11" => wikiFuzz::makeFuzz( 2 ),
997 "ns12" => wikiFuzz::makeFuzz( 2 ),
998 "ns13" => wikiFuzz::makeFuzz( 2 ),
999 "ns14" => wikiFuzz::makeFuzz( 2 ),
1000 "ns15" => wikiFuzz::makeFuzz( 2 ),
1001 "redirs" => wikiFuzz::makeFuzz( 2 ),
1002 "search" => wikiFuzz::makeFuzz( 2 ),
1003 "offset" => wikiFuzz::chooseInput( array( "", "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) ),
1004 "fulltext" => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) ),
1005 "searchx" => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) )
1012 ** a page test for "Special:Recentchanges".
1014 class recentchangesTest extends pageTest {
1015 function __construct() {
1016 $this->pagePath = "index.php?title=Special:Recentchanges";
1018 $this->params = array (
1019 "action" => wikiFuzz::makeFuzz( 2 ),
1020 "title" => wikiFuzz::makeFuzz( 2 ),
1021 "namespace" => wikiFuzz::chooseInput( range( -1, 15 ) ),
1022 "Go" => wikiFuzz::makeFuzz( 2 ),
1023 "invert" => wikiFuzz::chooseInput( array( "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1024 "hideanons" => wikiFuzz::chooseInput( array( "-1", "------'-------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1025 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "---------'----0", "+1", "81340909772349234", wikiFuzz::makeFuzz( 2 ) ) ),
1026 "days" => wikiFuzz::chooseInput( array( "-1", "----------'---0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1027 "hideminor" => wikiFuzz::chooseInput( array( "-1", "-----------'--0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1028 "hidebots" => wikiFuzz::chooseInput( array( "-1", "---------'----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1029 "hideliu" => wikiFuzz::chooseInput( array( "-1", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1030 "hidepatrolled" => wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1031 "hidemyself" => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1032 'categories_any' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1033 'categories' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1034 'feed' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) )
1041 ** a page test for "Special:Prefixindex".
1043 class prefixindexTest extends pageTest {
1044 function __construct() {
1045 $this->pagePath = "index.php?title=Special:Prefixindex";
1047 $this->params = array (
1048 "title" => "Special:Prefixindex",
1049 "namespace" => wikiFuzz::randnum( 101, -10 ),
1050 "Go" => wikiFuzz::makeFuzz( 2 )
1053 // sometimes we want 'prefix', sometimes we want 'from', and sometimes we want nothing.
1054 if ( wikiFuzz::randnum( 3 ) == 0 ) {
1055 $this->params["prefix"] = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1",
1056 wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) );
1058 if ( wikiFuzz::randnum( 3 ) == 0 ) {
1059 $this->params["from"] = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1",
1060 wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) );
1067 ** a page test for "Special:MIMEsearch".
1069 class mimeSearchTest extends pageTest {
1070 function __construct() {
1071 $this->pagePath = "index.php?title=Special:MIMEsearch";
1073 $this->params = array (
1074 "action" => "index.php?title=Special:MIMEsearch",
1075 "mime" => wikiFuzz::makeFuzz( 3 ),
1076 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "-------'------0", "+1", "81342321351235325", wikiFuzz::makeFuzz( 2 ) ) ),
1077 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "-----'--------0", "+1", "81341231235365252234324", wikiFuzz::makeFuzz( 2 ) ) )
1084 ** a page test for "Special:Log".
1086 class specialLogTest extends pageTest {
1087 function __construct() {
1088 $this->pagePath = "index.php?title=Special:Log";
1090 $this->params = array (
1091 "type" => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
1092 "par" => wikiFuzz::makeFuzz( 2 ),
1093 "user" => wikiFuzz::makeFuzz( 2 ),
1094 "page" => wikiFuzz::makeFuzz( 2 ),
1095 "from" => wikiFuzz::makeFuzz( 2 ),
1096 "until" => wikiFuzz::makeFuzz( 2 ),
1097 "title" => wikiFuzz::makeFuzz( 2 )
1104 ** a page test for "Special:Userlogin", with a successful login.
1106 class successfulUserLoginTest extends pageTest {
1107 function __construct() {
1108 $this->pagePath = "index.php?title=Special:Userlogin&action=submitlogin&type=login&returnto=" . wikiFuzz::makeFuzz( 2 );
1110 $this->params = array (
1111 "wpName" => USER_ON_WIKI,
1112 // sometimes real password, sometimes not:
1113 'wpPassword' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), USER_PASSWORD ) ),
1114 'wpRemember' => wikiFuzz::makeFuzz( 2 )
1117 $this->cookie = "wikidb_session=" . wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) );
1123 ** a page test for "Special:Userlogin".
1125 class userLoginTest extends pageTest {
1126 function __construct() {
1128 $this->pagePath = "index.php?title=Special:Userlogin";
1130 $this->params = array (
1131 'wpRetype' => wikiFuzz::makeFuzz( 2 ),
1132 'wpRemember' => wikiFuzz::makeFuzz( 2 ),
1133 'wpRealName' => wikiFuzz::makeFuzz( 2 ),
1134 'wpPassword' => wikiFuzz::makeFuzz( 2 ),
1135 'wpName' => wikiFuzz::makeFuzz( 2 ),
1136 'wpMailmypassword' => wikiFuzz::makeFuzz( 2 ),
1137 'wpLoginattempt' => wikiFuzz::makeFuzz( 2 ),
1138 'wpEmail' => wikiFuzz::makeFuzz( 2 ),
1139 'wpDomain' => wikiFuzz::chooseInput( array( "", "local", wikiFuzz::makeFuzz( 2 ) ) ),
1140 'wpCreateaccountMail' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
1141 'wpCreateaccount' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
1142 'wpCookieCheck' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
1143 'type' => wikiFuzz::chooseInput( array( "signup", "login", "", wikiFuzz::makeFuzz( 2 ) ) ),
1144 'returnto' => wikiFuzz::makeFuzz( 2 ),
1145 'action' => wikiFuzz::chooseInput( array( "", "submitlogin", wikiFuzz::makeFuzz( 2 ) ) )
1148 $this->cookie = "wikidb_session=" . wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) );
1154 ** a page test for "Special:Ipblocklist" (also includes unblocking)
1156 class ipblocklistTest extends pageTest {
1157 function __construct() {
1158 $this->pagePath = "index.php?title=Special:Ipblocklist";
1160 $this->params = array (
1161 'wpUnblockAddress' => wikiFuzz::makeFuzz( 2 ),
1162 'ip' => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
1163 // something like an IP address, sometimes invalid:
1164 ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
1165 . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
1166 'id' => wikiFuzz::makeFuzz( 2 ),
1167 'wpUnblockReason' => wikiFuzz::makeFuzz( 2 ),
1168 'action' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "success", "submit", "unblock" ) ),
1169 'wpEditToken' => wikiFuzz::makeFuzz( 2 ),
1170 'wpBlock' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "" ) ),
1171 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1",
1172 "09700982312351132098234", wikiFuzz::makeFuzz( 2 ) ) ),
1173 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1",
1174 "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) )
1177 // sometimes we don't want to specify certain parameters.
1178 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
1179 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["ip"] );
1180 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["id"] );
1181 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpUnblockAddress"] );
1187 ** a page test for "Special:Newimages".
1189 class newImagesTest extends pageTest {
1190 function __construct() {
1191 $this->pagePath = "index.php?title=Special:Newimages";
1193 $this->params = array (
1194 'hidebots' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "1", "", "-1" ) ),
1195 'wpIlMatch' => wikiFuzz::makeFuzz( 2 ),
1196 'until' => wikiFuzz::makeFuzz( 2 ),
1197 'from' => wikiFuzz::makeFuzz( 2 )
1200 // sometimes we don't want to specify certain parameters.
1201 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["until"] );
1202 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["from"] );
1208 ** a page test for the "Special:Imagelist" page.
1210 class imagelistTest extends pageTest {
1211 function __construct() {
1212 $this->pagePath = "index.php?title=Special:Imagelist";
1214 $this->params = array (
1215 'sort' => wikiFuzz::chooseInput( array( "bysize", "byname" , "bydate", wikiFuzz::makeFuzz( 2 ) ) ),
1216 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "09700982312351132098234", wikiFuzz::makeFuzz( 2 ) ) ),
1217 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ),
1218 'wpIlMatch' => wikiFuzz::makeFuzz( 2 )
1225 ** a page test for "Special:Export".
1227 class specialExportTest extends pageTest {
1228 function __construct() {
1229 $this->pagePath = "index.php?title=Special:Export";
1231 $this->params = array (
1232 'action' => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
1233 'pages' => wikiFuzz::makeFuzz( 2 ),
1234 'curonly' => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ),
1235 'listauthors' => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ),
1236 'history' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ),
1240 // For the time being, need to disable "submit" action as Tidy barfs on MediaWiki's XML export.
1241 if ( $this->params['action'] == 'submit' ) $this->params['action'] = '';
1243 // Sometimes remove the history field.
1244 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["history"] );
1246 // page does not produce HTML.
1247 $this->tidyValidate = false;
1253 ** a page test for "Special:Booksources".
1255 class specialBooksourcesTest extends pageTest {
1256 function __construct() {
1257 $this->pagePath = "index.php?title=Special:Booksources";
1259 $this->params = array (
1260 'go' => wikiFuzz::makeFuzz( 2 ),
1261 // ISBN codes have to contain some semi-numeric stuff or will be ignored:
1262 'isbn' => "0X0" . wikiFuzz::makeFuzz( 2 )
1269 ** a page test for "Special:Allpages".
1271 class specialAllpagesTest extends pageTest {
1272 function __construct() {
1273 $this->pagePath = "index.php?title=Special%3AAllpages";
1275 $this->params = array (
1276 'from' => wikiFuzz::makeFuzz( 2 ),
1277 'namespace' => wikiFuzz::chooseInput( range( -1, 15 ) ),
1278 'go' => wikiFuzz::makeFuzz( 2 )
1285 ** a page test for the page History.
1287 class pageHistoryTest extends pageTest {
1288 function __construct() {
1289 $this->pagePath = "index.php?title=Main_Page&action=history";
1291 $this->params = array (
1292 'limit' => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1293 'offset' => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ),
1294 "go" => wikiFuzz::chooseInput( array( "first", "last", wikiFuzz::makeFuzz( 2 ) ) ),
1295 "dir" => wikiFuzz::chooseInput( array( "prev", "next", wikiFuzz::makeFuzz( 2 ) ) ),
1296 "diff" => wikiFuzz::chooseInput( array( "-1", "--------'-----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1297 "oldid" => wikiFuzz::chooseInput( array( "prev", "-1", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1298 "feed" => wikiFuzz::makeFuzz( 2 )
1305 ** a page test for the Special:Contributions".
1307 class contributionsTest extends pageTest {
1308 function __construct() {
1309 $this->pagePath = "index.php?title=Special:Contributions/" . USER_ON_WIKI;
1311 $this->params = array (
1312 'target' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "newbies", USER_ON_WIKI ) ),
1313 'namespace' => wikiFuzz::chooseInput( array( -1, 15, 1, wikiFuzz::makeFuzz( 2 ) ) ),
1314 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "982342131232131231241", wikiFuzz::makeFuzz( 2 ) ) ),
1315 'bot' => wikiFuzz::chooseInput( array( "", "-1", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1316 'go' => wikiFuzz::chooseInput( array( "-1", 'prev', 'next', wikiFuzz::makeFuzz( 2 ) ) )
1323 ** a page test for viewing a normal page, whilst posting various params.
1325 class viewPageTest extends pageTest {
1326 function __construct() {
1327 $this->pagePath = "index.php?title=Main_Page";
1329 $this->params = array (
1330 "useskin" => wikiFuzz::chooseInput( array( "chick", "cologneblue", "myskin",
1331 "nostalgia", "simple", "standard", wikiFuzz::makeFuzz( 2 ) ) ),
1332 "uselang" => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ),
1333 "ab", "af", "an", "ar", "arc", "as", "ast", "av", "ay", "az", "ba",
1334 "bat-smg", "be", "bg", "bm", "bn", "bo", "bpy", "br", "bs", "ca",
1335 "ce", "cs", "csb", "cv", "cy", "da", "de", "dv", "dz", "el", "en",
1336 "eo", "es", "et", "eu", "fa", "fi", "fo", "fr", "fur", "fy", "ga",
1337 "gn", "gsw", "gu", "he", "hi", "hr", "hu", "ia", "id", "ii", "is",
1338 "it", "ja", "jv", "ka", "km", "kn", "ko", "ks", "ku", "kv", "la",
1339 "li", "lo", "lt", "lv", "mk", "ml", "ms", "nah", "nap", "nds",
1340 "nds-nl", "nl", "nn", "no", "non", "nv", "oc", "or", "os", "pa",
1341 "pl", "pms", "ps", "pt", "pt-br", "qu", "rmy", "ro", "ru", "sc",
1342 "sd", "sk", "sl", "sq", "sr", "sr-ec", "sr-el",
1343 "su", "sv", "ta", "te", "th", "tr", "tt", "ty", "tyv", "udm",
1344 "ug", "uk", "ur", "utf8", "vec", "vi", "wa", "xal", "yi", "za",
1345 "zh", "zh-cn", "zh-hk", "zh-sg", "zh-tw", "zh-tw" ) ),
1346 "returnto" => wikiFuzz::makeFuzz( 2 ),
1347 "feed" => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ),
1348 "rcid" => wikiFuzz::makeFuzz( 2 ),
1349 "action" => wikiFuzz::chooseInput( array( "view", "raw", "render", wikiFuzz::makeFuzz( 2 ), "markpatrolled" ) ),
1350 "printable" => wikiFuzz::makeFuzz( 2 ),
1351 "oldid" => wikiFuzz::makeFuzz( 2 ),
1352 "redirect" => wikiFuzz::makeFuzz( 2 ),
1353 "diff" => wikiFuzz::makeFuzz( 2 ),
1354 "search" => wikiFuzz::makeFuzz( 2 ),
1355 "rdfrom" => wikiFuzz::makeFuzz( 2 ), // things from Article.php from here on:
1356 "token" => wikiFuzz::makeFuzz( 2 ),
1357 "tbid" => wikiFuzz::makeFuzz( 2 ),
1358 "action" => wikiFuzz::chooseInput( array( "purge", wikiFuzz::makeFuzz( 2 ) ) ),
1359 "wpReason" => wikiFuzz::makeFuzz( 2 ),
1360 "wpEditToken" => wikiFuzz::makeFuzz( 2 ),
1361 "from" => wikiFuzz::makeFuzz( 2 ),
1362 "bot" => wikiFuzz::makeFuzz( 2 ),
1363 "summary" => wikiFuzz::makeFuzz( 2 ),
1364 "direction" => wikiFuzz::chooseInput( array( "next", "prev", wikiFuzz::makeFuzz( 2 ) ) ),
1365 "section" => wikiFuzz::makeFuzz( 2 ),
1366 "preload" => wikiFuzz::makeFuzz( 2 ),
1370 // Tidy does not know how to valid atom or rss, so exclude from testing for the time being.
1371 if ( $this->params["feed"] == "atom" ) { unset( $this->params["feed"] ); }
1372 elseif ( $this->params["feed"] == "rss" ) { unset( $this->params["feed"] ); }
1374 // Raw pages cannot really be validated
1375 if ( $this->params["action"] == "raw" ) unset( $this->params["action"] );
1377 // sometimes we don't want to specify certain parameters.
1378 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["rcid"] );
1379 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["diff"] );
1380 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["rdfrom"] );
1381 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["oldid"] );
1383 // usually don't want action == purge.
1384 if ( wikiFuzz::randnum( 6 ) > 1 ) unset( $this->params["action"] );
1390 ** a page test for "Special:Allmessages".
1392 class specialAllmessagesTest extends pageTest {
1393 function __construct() {
1394 $this->pagePath = "index.php?title=Special:Allmessages";
1396 // only really has one parameter
1397 $this->params = array (
1398 "ot" => wikiFuzz::chooseInput( array( "php", "html", wikiFuzz::makeFuzz( 2 ) ) )
1404 ** a page test for "Special:Newpages".
1406 class specialNewpagesPageTest extends pageTest {
1407 function __construct() {
1408 $this->pagePath = "index.php?title=Special:Newpages";
1410 $this->params = array (
1411 "namespace" => wikiFuzz::chooseInput( range( -1, 15 ) ),
1412 "feed" => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ),
1413 'limit' => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1414 'offset' => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) )
1417 // Tidy does not know how to valid atom or rss, so exclude from testing for the time being.
1418 if ( $this->params["feed"] == "atom" ) { unset( $this->params["feed"] ); }
1419 elseif ( $this->params["feed"] == "rss" ) { unset( $this->params["feed"] ); }
1424 ** a page test for "redirect.php"
1426 class redirectTest extends pageTest {
1427 function __construct() {
1428 $this->pagePath = "redirect.php";
1430 $this->params = array (
1431 "wpDropdown" => wikiFuzz::makeFuzz( 2 )
1434 // sometimes we don't want to specify certain parameters.
1435 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpDropdown"] );
1441 ** a page test for "Special:Confirmemail"
1443 class confirmEmail extends pageTest {
1444 function __construct() {
1445 // sometimes we send a bogus confirmation code, and sometimes we don't.
1446 $this->pagePath = "index.php?title=Special:Confirmemail" . wikiFuzz::chooseInput( array( "", "/" . wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 1 ) ) ) );
1448 $this->params = array (
1449 "token" => wikiFuzz::makeFuzz( 2 )
1456 ** a page test for "Special:Watchlist"
1457 ** Note: this test would be better if we were logged in.
1459 class watchlistTest extends pageTest {
1460 function __construct() {
1461 $this->pagePath = "index.php?title=Special:Watchlist";
1463 $this->params = array (
1464 "remove" => wikiFuzz::chooseInput( array( "Remove checked items from watchlist", wikiFuzz::makeFuzz( 2 ) ) ),
1465 'days' => wikiFuzz::chooseInput( array( 0, -1, -230, "--", 3, 9, wikiFuzz::makeFuzz( 2 ) ) ),
1466 'hideOwn' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1467 'hideBots' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1468 'namespace' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1469 'action' => wikiFuzz::chooseInput( array( "submit", "clear", wikiFuzz::makeFuzz( 2 ) ) ),
1470 'id[]' => wikiFuzz::makeFuzz( 2 ),
1471 'edit' => wikiFuzz::makeFuzz( 2 ),
1472 'token' => wikiFuzz::chooseInput( array( "", "1243213", wikiFuzz::makeFuzz( 2 ) ) )
1475 // sometimes we specifiy "reset", and sometimes we don't.
1476 if ( wikiFuzz::randnum( 3 ) == 0 ) $this->params["reset"] = wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) );
1482 ** a page test for "Special:Blockme"
1484 class specialBlockmeTest extends pageTest {
1485 function __construct() {
1486 $this->pagePath = "index.php?title=Special:Blockme";
1488 $this->params = array ( );
1490 // sometimes we specify "ip", and sometimes we don't.
1491 if ( wikiFuzz::randnum( 1 ) == 0 ) {
1492 $this->params["ip"] = wikiFuzz::chooseInput( array( "10.12.41.213", wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) );
1499 ** a page test for "Special:Movepage"
1501 class specialMovePage extends pageTest {
1502 function __construct() {
1503 $this->pagePath = "index.php?title=Special:Movepage";
1505 $this->params = array (
1506 "action" => wikiFuzz::chooseInput( array( "success", "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
1507 'wpEditToken' => wikiFuzz::chooseInput( array( '', 0, 34987987, wikiFuzz::makeFuzz( 2 ) ) ),
1508 'target' => wikiFuzz::chooseInput( array( "x", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ) ) ),
1509 'wpOldTitle' => wikiFuzz::chooseInput( array( "z", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ), wikiFuzz::makeFuzz( 2 ) ) ),
1510 'wpNewTitle' => wikiFuzz::chooseInput( array( "y", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ), wikiFuzz::makeFuzz( 2 ) ) ),
1511 'wpReason' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ) ) ),
1512 'wpMovetalk' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1513 'wpDeleteAndMove' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1514 'wpConfirm' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1515 'talkmoved' => wikiFuzz::chooseInput( array( "1", wikiFuzz::makeFuzz( 2 ), "articleexists", 'notalkpage' ) ),
1516 'oldtitle' => wikiFuzz::makeFuzz( 2 ),
1517 'newtitle' => wikiFuzz::makeFuzz( 2 ),
1518 'wpMovetalk' => wikiFuzz::chooseInput( array( "1", "0", wikiFuzz::makeFuzz( 2 ) ) )
1521 // sometimes we don't want to specify certain parameters.
1522 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["wpEditToken"] );
1523 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["target"] );
1524 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpNewTitle"] );
1525 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpReason"] );
1526 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpOldTitle"] );
1532 ** a page test for "Special:Undelete"
1534 class specialUndeletePageTest extends pageTest {
1535 function __construct() {
1536 $this->pagePath = "index.php?title=Special:Undelete";
1538 $this->params = array (
1539 "action" => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
1540 'wpEditToken' => wikiFuzz::chooseInput( array( '', 0, 34987987, wikiFuzz::makeFuzz( 2 ) ) ),
1541 'target' => wikiFuzz::chooseInput( array( "x", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ) ) ),
1542 'timestamp' => wikiFuzz::chooseInput( array( "125223", wikiFuzz::makeFuzz( 2 ) ) ),
1543 'file' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1544 'restore' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1545 'preview' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1546 'wpComment' => wikiFuzz::makeFuzz( 2 )
1549 // sometimes we don't want to specify certain parameters.
1550 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["wpEditToken"] );
1551 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["target"] );
1552 if ( wikiFuzz::randnum( 1 ) == 0 ) unset( $this->params["restore"] );
1553 if ( wikiFuzz::randnum( 1 ) == 0 ) unset( $this->params["preview"] );
1559 ** a page test for "Special:Unlockdb"
1561 class specialUnlockdbPageTest extends pageTest {
1562 function __construct() {
1563 $this->pagePath = "index.php?title=Special:Unlockdb";
1565 $this->params = array (
1566 "action" => wikiFuzz::chooseInput( array( "submit", "success", "", wikiFuzz::makeFuzz( 2 ) ) ),
1567 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1568 'wpLockConfirm' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) )
1571 // sometimes we don't want to specify certain parameters.
1572 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpEditToken"] );
1573 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
1574 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpLockConfirm"] );
1580 ** a page test for "Special:Lockdb"
1582 class specialLockdbPageTest extends pageTest {
1583 function __construct() {
1584 $this->pagePath = "index.php?title=Special:Lockdb";
1586 $this->params = array (
1587 "action" => wikiFuzz::chooseInput( array( "submit", "success", "", wikiFuzz::makeFuzz( 2 ) ) ),
1588 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1589 'wpLockReason' => wikiFuzz::makeFuzz( 2 ),
1590 'wpLockConfirm' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
1593 // sometimes we don't want to specify certain parameters.
1594 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpEditToken"] );
1595 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
1596 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpLockConfirm"] );
1602 ** a page test for "Special:Userrights"
1604 class specialUserrights extends pageTest {
1605 function __construct() {
1606 $this->pagePath = "index.php?title=Special:Userrights";
1608 $this->params = array (
1609 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1610 'user-editname' => wikiFuzz::chooseInput( array( "Nickj2", "Nickj2\n<xyz>", wikiFuzz::makeFuzz( 2 ) ) ),
1611 'ssearchuser' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1612 'saveusergroups' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ), "Save User Groups" ),
1613 'member[]' => wikiFuzz::chooseInput( array( "0", "bot", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1614 "available[]" => wikiFuzz::chooseInput( array( "0", "sysop", "bureaucrat", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
1617 // sometimes we don't want to specify certain parameters.
1618 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['ssearchuser'] );
1619 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['saveusergroups'] );
1625 ** a test for page protection and unprotection.
1627 class pageProtectionForm extends pageTest {
1628 function __construct() {
1629 $this->pagePath = "index.php?title=Main_Page";
1631 $this->params = array (
1632 "action" => "protect",
1633 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1634 "mwProtect-level-edit" => wikiFuzz::chooseInput( array( '', 'autoconfirmed', 'sysop', wikiFuzz::makeFuzz( 2 ) ) ),
1635 "mwProtect-level-move" => wikiFuzz::chooseInput( array( '', 'autoconfirmed', 'sysop', wikiFuzz::makeFuzz( 2 ) ) ),
1636 "mwProtectUnchained" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1637 'mwProtect-reason' => wikiFuzz::chooseInput( array( "because it was there", wikiFuzz::makeFuzz( 2 ) ) )
1641 // sometimes we don't want to specify certain parameters.
1642 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["mwProtectUnchained"] );
1643 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['mwProtect-reason'] );
1649 ** a page test for "Special:Blockip".
1651 class specialBlockip extends pageTest {
1652 function __construct() {
1653 $this->pagePath = "index.php?title=Special:Blockip";
1655 $this->params = array (
1656 "action" => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
1657 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1658 "wpBlockAddress" => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
1659 // something like an IP address, sometimes invalid:
1660 ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
1661 . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
1662 "ip" => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
1663 // something like an IP address, sometimes invalid:
1664 ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
1665 . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
1666 "wpBlockOther" => wikiFuzz::chooseInput( array( '', 'Nickj2', wikiFuzz::makeFuzz( 2 ) ) ),
1667 "wpBlockExpiry" => wikiFuzz::chooseInput( array( "other", "2 hours", "1 day", "3 days", "1 week", "2 weeks",
1668 "1 month", "3 months", "6 months", "1 year", "infinite", wikiFuzz::makeFuzz( 2 ) ) ),
1669 "wpBlockReason" => wikiFuzz::chooseInput( array( "because it was there", wikiFuzz::makeFuzz( 2 ) ) ),
1670 "wpAnonOnly" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1671 "wpCreateAccount" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1672 "wpBlock" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
1675 // sometimes we don't want to specify certain parameters.
1676 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockOther"] );
1677 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockExpiry"] );
1678 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockReason"] );
1679 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpAnonOnly"] );
1680 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpCreateAccount"] );
1681 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockAddress"] );
1682 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["ip"] );
1688 ** a test for the imagepage.
1690 class imagepageTest extends pageTest {
1691 function __construct() {
1692 $this->pagePath = "index.php?title=Image:Small-email.png";
1694 $this->params = array (
1695 "image" => wikiFuzz::chooseInput( array( "Small-email.png", wikiFuzz::makeFuzz( 2 ) ) ),
1696 "wpReason" => wikiFuzz::makeFuzz( 2 ),
1697 "oldimage" => wikiFuzz::chooseInput( array( "Small-email.png", wikiFuzz::makeFuzz( 2 ) ) ),
1698 "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1701 // sometimes we don't want to specify certain parameters.
1702 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["image"] );
1703 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpReason"] );
1704 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldimage"] );
1705 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEditToken"] );
1711 ** a test for page deletion form.
1713 class pageDeletion extends pageTest {
1714 function __construct() {
1715 $this->pagePath = "index.php?title=Main_Page&action=delete";
1717 $this->params = array (
1718 "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1719 "wpReason" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1720 "wpConfirm" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1723 // sometimes we don't want to specify certain parameters.
1724 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpReason"] );
1725 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpEditToken"] );
1726 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpConfirm"] );
1733 ** a test for Revision Deletion.
1735 class specialRevisionDeletePageTest extends pageTest {
1736 function __construct() {
1737 $this->pagePath = "index.php?title=Special:Revisiondelete";
1739 $this->params = array (
1740 "target" => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
1741 "oldid" => wikiFuzz::makeFuzz( 2 ),
1742 "oldid[]" => wikiFuzz::makeFuzz( 2 ),
1743 "wpReason" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1744 "revdelete-hide-text" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1745 "revdelete-hide-comment" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1746 "revdelete-hide-user" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1747 "revdelete-hide-restricted" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1750 // sometimes we don't want to specify certain parameters.
1751 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["target"] );
1752 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldid"] );
1753 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldid[]"] );
1754 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpReason"] );
1755 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-text"] );
1756 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-comment"] );
1757 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-user"] );
1758 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-restricted"] );
1764 ** a test for Special:Import.
1766 class specialImportPageTest extends pageTest {
1767 function __construct() {
1768 $this->pagePath = "index.php?title=Special:Import";
1770 $this->params = array (
1771 "action" => "submit",
1772 "source" => wikiFuzz::chooseInput( array( "upload", "interwiki", wikiFuzz::makeFuzz( 2 ) ) ),
1773 "MAX_FILE_SIZE" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1774 "xmlimport" => wikiFuzz::chooseInput( array( "/var/www/hosts/mediawiki/wiki/AdminSettings.php", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1775 "namespace" => wikiFuzz::chooseInput( array( wikiFuzz::randnum( 30, -6 ), wikiFuzz::makeFuzz( 2 ) ) ),
1776 "interwiki" => wikiFuzz::makeFuzz( 2 ),
1777 "interwikiHistory" => wikiFuzz::makeFuzz( 2 ),
1778 "frompage" => wikiFuzz::makeFuzz( 2 ),
1781 // sometimes we don't want to specify certain parameters.
1782 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["action"] );
1783 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["source"] );
1784 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["MAX_FILE_SIZE"] );
1785 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["xmlimport"] );
1786 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["interwiki"] );
1787 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["interwikiHistory"] );
1788 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["frompage"] );
1790 // Note: Need to do a file upload to fully test this Special page.
1796 ** a test for thumb.php
1798 class thumbTest extends pageTest {
1799 function __construct() {
1800 $this->pagePath = "thumb.php";
1802 $this->params = array (
1803 "f" => wikiFuzz::chooseInput( array( "..", "\\", "small-email.png", wikiFuzz::makeFuzz( 2 ) ) ),
1804 "w" => wikiFuzz::chooseInput( array( "80", wikiFuzz::randnum( 6000, -200 ), wikiFuzz::makeFuzz( 2 ) ) ),
1805 "r" => wikiFuzz::chooseInput( array( "0", wikiFuzz::makeFuzz( 2 ) ) ),
1808 // sometimes we don't want to specify certain parameters.
1809 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["f"] );
1810 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["w"] );
1811 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["r"] );
1817 ** a test for trackback.php
1819 class trackbackTest extends pageTest {
1820 function __construct() {
1821 $this->pagePath = "trackback.php";
1823 $this->params = array (
1824 "url" => wikiFuzz::makeFuzz( 2 ),
1825 "blog_name" => wikiFuzz::chooseInput( array( "80", wikiFuzz::randnum( 6000, -200 ), wikiFuzz::makeFuzz( 2 ) ) ),
1826 "article" => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
1827 "title" => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
1828 "excerpt" => wikiFuzz::makeFuzz( 2 ),
1831 // sometimes we don't want to specify certain parameters.
1832 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["title"] );
1833 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["excerpt"] );
1835 // page does not produce HTML.
1836 $this->tidyValidate = false;
1842 ** a test for profileinfo.php
1844 class profileInfo extends pageTest {
1845 function __construct() {
1846 $this->pagePath = "profileinfo.php";
1848 $this->params = array (
1849 "expand" => wikiFuzz::makeFuzz( 2 ),
1850 "sort" => wikiFuzz::chooseInput( array( "time", "count", "name", wikiFuzz::makeFuzz( 2 ) ) ),
1851 "filter" => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
1854 // sometimes we don't want to specify certain parameters.
1855 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["sort"] );
1856 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["filter"] );
1862 ** a test for Special:Cite (extension Special page).
1864 class specialCitePageTest extends pageTest {
1865 function __construct() {
1866 $this->pagePath = "index.php?title=Special:Cite";
1868 $this->params = array (
1869 "page" => wikiFuzz::chooseInput( array( "\" onmouseover=\"alert(1);\"", "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
1870 "id" => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "-9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ),
1873 // sometimes we don't want to specify certain parameters.
1874 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["page"] );
1875 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["id"] );
1881 ** a test for Special:Filepath (extension Special page).
1883 class specialFilepathPageTest extends pageTest {
1884 function __construct() {
1885 $this->pagePath = "index.php?title=Special:Filepath";
1887 $this->params = array (
1888 "file" => wikiFuzz::chooseInput( array( "Small-email.png", "Small-email.png" . wikiFuzz::makeFuzz( 1 ), wikiFuzz::makeFuzz( 2 ) ) ),
1895 ** a test for Special:Makebot (extension Special page).
1897 class specialMakebot extends pageTest {
1898 function __construct() {
1899 $this->pagePath = "index.php?title=Special:Makebot";
1901 $this->params = array (
1902 "username" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ),
1903 "dosearch" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1904 "grant" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1905 "comment" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1906 "token" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1909 // sometimes we don't want to specify certain parameters.
1910 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["dosearch"] );
1911 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["grant"] );
1912 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["token"] );
1918 ** a test for Special:Makesysop (extension Special page).
1920 class specialMakesysop extends pageTest {
1921 function __construct() {
1922 $this->pagePath = "index.php?title=Special:Makesysop";
1924 $this->params = array (
1925 "wpMakesysopUser" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ),
1926 "action" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1927 "wpMakesysopSubmit" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1928 "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1929 "wpSetBureaucrat" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1932 // sometimes we don't want to specify certain parameters.
1933 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpMakesysopSubmit"] );
1934 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpEditToken"] );
1935 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpSetBureaucrat"] );
1941 ** a test for Special:Renameuser (extension Special page).
1943 class specialRenameuserPageTest extends pageTest {
1944 function __construct() {
1945 $this->pagePath = "index.php?title=Special:Renameuser";
1947 $this->params = array (
1948 "oldusername" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ),
1949 "newusername" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ),
1950 "token" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1957 ** a test for Special:Linksearch (extension Special page).
1959 class specialLinksearch extends pageTest {
1960 function __construct() {
1961 $this->pagePath = "index.php?title=Special%3ALinksearch";
1963 $this->params = array (
1964 "target" => wikiFuzz::makeFuzz( 2 ),
1967 // sometimes we don't want to specify certain parameters.
1968 if ( wikiFuzz::randnum( 10 ) == 0 ) unset( $this->params["target"] );
1974 ** a test for Special:CategoryTree (extension Special page).
1976 class specialCategoryTree extends pageTest {
1977 function __construct() {
1978 $this->pagePath = "index.php?title=Special:CategoryTree";
1980 $this->params = array (
1981 "target" => wikiFuzz::makeFuzz( 2 ),
1982 "from" => wikiFuzz::makeFuzz( 2 ),
1983 "until" => wikiFuzz::makeFuzz( 2 ),
1984 "showas" => wikiFuzz::makeFuzz( 2 ),
1985 "mode" => wikiFuzz::chooseInput( array( "pages", "categories", "all", wikiFuzz::makeFuzz( 2 ) ) ),
1988 // sometimes we do want to specify certain parameters.
1989 if ( wikiFuzz::randnum( 5 ) == 0 ) $this->params["notree"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
1995 ** a test for "Special:Chemicalsources" (extension Special page).
1997 class specialChemicalsourcesTest extends pageTest {
1998 function __construct() {
1999 $this->pagePath = "index.php?title=Special:Chemicalsources";
2001 // choose an input format to use.
2002 $format = wikiFuzz::chooseInput(
2003 array( 'go',
2004 'CAS',
2005 'EINECS',
2006 'CHEBI',
2007 'PubChem',
2008 'SMILES',
2009 'InChI',
2010 'ATCCode',
2011 'KEGG',
2012 'RTECS',
2013 'ECNumber',
2014 'DrugBank',
2015 'Formula',
2016 'Name'
2020 // values for different formats usually start with either letters or numbers.
2021 switch ( $format ) {
2022 case 'Name' : $value = "A"; break;
2023 case 'InChI' :
2024 case 'SMILES' :
2025 case 'Formula': $value = "C"; break;
2026 default : $value = "0"; break;
2029 // and then we append the fuzz input.
2030 $this->params = array ( $format => $value . wikiFuzz::makeFuzz( 2 ) );
2036 ** A test for api.php (programmatic interface to MediaWiki in XML/JSON/RSS/etc formats).
2037 ** Quite involved to test because there are lots of options/parameters, and because
2038 ** for a lot of the functionality if all the parameters don't make sense then it just
2039 ** returns the help screen - so currently a lot of the tests aren't actually doing much
2040 ** because something wasn't right in the query.
2042 ** @todo: Incomplete / unfinished; Runs too fast (suggests not much testing going on).
2044 class api extends pageTest {
2046 // API login mode.
2047 private static function loginMode() {
2048 $arr = array ( "lgname" => wikiFuzz::makeFuzz( 2 ),
2049 "lgpassword" => wikiFuzz::makeFuzz( 2 ),
2051 // sometimes we want to specify the extra "lgdomain" parameter.
2052 if ( wikiFuzz::randnum( 3 ) == 0 ) {
2053 $arr["lgdomain"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
2056 return $arr;
2059 // API OpenSearch mode.
2060 private static function opensearchMode() {
2061 return array ( "search" => wikiFuzz::makeFuzz( 2 ) );
2064 // API watchlist feed mode.
2065 private static function feedwatchlistMode() {
2066 // @todo FIXME: Add "wikiFuzz::makeFuzz(2)" as possible value below?
2067 return array ( "feedformat" => wikiFuzz::chooseInput( array( "rss", "atom" ) ) );
2070 // API query mode.
2071 private static function queryMode() {
2072 // @todo FIXME: Add "wikiFuzz::makeFuzz(2)" as possible params for the elements below?
2073 // Suspect this will stuff up the tests more, but need to check.
2074 $params = array (
2075 // @todo FIXME: More titles.
2076 "titles" => wikiFuzz::chooseInput( array( "Main Page" ) ),
2077 // @todo FIXME: More pageids.
2078 "pageids" => 1,
2079 "prop" => wikiFuzz::chooseInput( array( "info", "revisions", "watchlist" ) ),
2080 "list" => wikiFuzz::chooseInput( array( "allpages", "logevents", "watchlist", "usercontribs", "recentchanges", "backlinks", "embeddedin", "imagelinks" ) ),
2081 "meta" => wikiFuzz::chooseInput( array( "siteinfo" ) ),
2082 "generator" => wikiFuzz::chooseInput( array( "allpages", "logevents", "watchlist", "info", "revisions" ) ),
2083 "siprop" => wikiFuzz::chooseInput( array( "general", "namespaces", "general|namespaces" ) ),
2086 // Add extra parameters based on what list choice we got.
2087 switch ( $params["list"] ) {
2088 case "usercontribs" : self::addListParams ( $params, "uc", array( "limit", "start", "end", "user", "dir" ) ); break;
2089 case "allpages" : self::addListParams ( $params, "ap", array( "from", "prefix", "namespace", "filterredir", "limit" ) ); break;
2090 case "watchlist" : self::addListParams ( $params, "wl", array( "allrev", "start", "end", "namespace", "dir", "limit", "prop" ) ); break;
2091 case "logevents" : self::addListParams ( $params, "le", array( "limit", "type", "start", "end", "user", "dir" ) ); break;
2092 case "recentchanges": self::addListParams ( $params, "rc", array( "limit", "prop", "show", "namespace", "start", "end", "dir" ) ); break;
2093 case "backlinks" : self::addListParams ( $params, "bl", array( "continue", "namespace", "redirect", "limit" ) ); break;
2094 case "embeddedin" : self::addListParams ( $params, "ei", array( "continue", "namespace", "redirect", "limit" ) ); break;
2095 case "imagelinks" : self::addListParams ( $params, "il", array( "continue", "namespace", "redirect", "limit" ) ); break;
2098 if ( $params["prop"] == "revisions" ) {
2099 self::addListParams ( $params, "rv", array( "prop", "limit", "startid", "endid", "end", "dir" ) );
2102 // Sometimes we want redirects, sometimes we don't.
2103 if ( wikiFuzz::randnum( 3 ) == 0 ) {
2104 $params["redirects"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
2107 return $params;
2110 // Adds all the elements to the array, using the specified prefix.
2111 private static function addListParams( &$array, $prefix, $elements ) {
2112 foreach ( $elements as $element ) {
2113 $array[$prefix . $element] = self::getParamDetails( $element );
2117 // For a given element name, returns the data for that element.
2118 private static function getParamDetails( $element ) {
2119 switch ( $element ) {
2120 case 'startid' :
2121 case 'endid' :
2122 case 'start' :
2123 case 'end' :
2124 case 'limit' : return wikiFuzz::chooseInput( array( "0", "-1", "---'----------0", "+1", "8134", "320742734234235", "20060230121212", wikiFuzz::randnum( 9000, -100 ), wikiFuzz::makeFuzz( 2 ) ) );
2125 case 'dir' : return wikiFuzz::chooseInput( array( "newer", "older", wikiFuzz::makeFuzz( 2 ) ) );
2126 case 'user' : return wikiFuzz::chooseInput( array( USER_ON_WIKI, wikiFuzz::makeFuzz( 2 ) ) );
2127 case 'namespace' : return wikiFuzz::chooseInput( array( -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 200000, wikiFuzz::makeFuzz( 2 ) ) );
2128 case 'filterredir': return wikiFuzz::chooseInput( array( "all", "redirects", "nonredirectsallpages", wikiFuzz::makeFuzz( 2 ) ) );
2129 case 'allrev' : return wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
2130 case 'prop' : return wikiFuzz::chooseInput( array( "user", "comment", "timestamp", "patrol", "flags", "user|user|comment|flags", wikiFuzz::makeFuzz( 2 ) ) );
2131 case 'type' : return wikiFuzz::chooseInput( array( "block", "protect", "rights", "delete", "upload", "move", "import", "renameuser", "newusers", "makebot", wikiFuzz::makeFuzz( 2 ) ) );
2132 case 'hide' : return wikiFuzz::chooseInput( array( "minor", "bots", "anons", "liu", "liu|bots|", wikiFuzz::makeFuzz( 2 ) ) );
2133 case 'show' : return wikiFuzz::chooseInput( array( 'minor', '!minor', 'bot', '!bot', 'anon', '!anon', wikiFuzz::makeFuzz( 2 ) ) );
2134 default : return wikiFuzz::makeFuzz( 2 );
2138 // Entry point.
2139 function __construct() {
2140 $this->pagePath = "api.php";
2142 $modes = array ( "help",
2143 "login",
2144 "opensearch",
2145 "feedwatchlist",
2146 "query" );
2147 $action = wikiFuzz::chooseInput( array_merge ( $modes, array( wikiFuzz::makeFuzz( 2 ) ) ) );
2149 switch ( $action ) {
2150 case "login" : $this->params = self::loginMode();
2151 break;
2152 case "opensearch" : $this->params = self::opensearchMode();
2153 break;
2154 case "feedwatchlist" : $this->params = self::feedwatchlistMode();
2155 break;
2156 case "query" : $this->params = self::queryMode();
2157 break;
2158 case "help" :
2159 default : // Do something random - "Crazy Ivan" mode.
2160 $random_mode = wikiFuzz::chooseInput( $modes ) . "Mode";
2161 // There is no "helpMode".
2162 if ( $random_mode == "helpMode" ) $random_mode = "queryMode";
2163 $this->params = self::$random_mode();
2164 break;
2167 // Save the selected action.
2168 $this->params["action"] = $action;
2170 // Set the cookie:
2171 // @todo FIXME: Need to get this cookie dynamically set, rather than hard-coded.
2172 $this->cookie = "wikidbUserID=10001; wikidbUserName=Test; wikidb_session=178df0fe68c75834643af65dec9ec98a; wikidbToken=1adc6753d62c44aec950c024d7ae0540";
2174 // Output format
2175 $this->params["format"] = wikiFuzz::chooseInput( array( "json", "jsonfm", "php", "phpfm",
2176 "wddx", "wddxfm", "xml", "xmlfm",
2177 "yaml", "yamlfm", "raw", "rawfm",
2178 wikiFuzz::makeFuzz( 2 ) ) );
2180 // Page does not produce HTML (sometimes).
2181 $this->tidyValidate = false;
2187 ** a page test for the GeSHi extension.
2189 class GeSHi_Test extends pageTest {
2191 private function getGeSHiContent() {
2192 return "<source lang=\"" . $this->getLang() . "\" "
2193 . ( wikiFuzz::randnum( 2 ) == 0 ? "line " : "" )
2194 . ( wikiFuzz::randnum( 2 ) == 0 ? "strict " : "" )
2195 . "start=" . wikiFuzz::chooseInput( array( wikiFuzz::randnum( 6000, -6000 ), wikiFuzz::makeFuzz( 2 ) ) )
2196 . ">"
2197 . wikiFuzz::makeFuzz( 2 )
2198 . "</source>";
2201 private function getLang() {
2202 return wikiFuzz::chooseInput( array( "actionscript", "ada", "apache", "applescript", "asm", "asp", "autoit", "bash", "blitzbasic", "bnf", "c", "c_mac", "caddcl", "cadlisp",
2203 "cfdg", "cfm", "cpp", "cpp-qt", "csharp", "css", "d", "delphi", "diff", "div", "dos", "eiffel", "fortran", "freebasic", "gml", "groovy", "html4strict", "idl",
2204 "ini", "inno", "io", "java", "java5", "javascript", "latex", "lisp", "lua", "matlab", "mirc", "mpasm", "mysql", "nsis", "objc", "ocaml", "ocaml-brief", "oobas",
2205 "oracle8", "pascal", "perl", "php", "php-brief", "plsql", "python", "qbasic", "rails", "reg", "robots", "ruby", "sas", "scheme", "sdlbasic", "smalltalk", "smarty",
2206 "sql", "tcl", "text", "thinbasic", "tsql", "vb", "vbnet", "vhdl", "visualfoxpro", "winbatch", "xml", "xpp", "z80", wikiFuzz::makeFuzz( 1 ) ) );
2209 function __construct() {
2210 $this->pagePath = "index.php?title=WIKIFUZZ";
2212 $this->params = array (
2213 "action" => "submit",
2214 "wpMinoredit" => "test",
2215 "wpPreview" => "test",
2216 "wpSection" => "test",
2217 "wpEdittime" => "test",
2218 "wpSummary" => "test",
2219 "wpScrolltop" => "test",
2220 "wpStarttime" => "test",
2221 "wpAutoSummary" => "test",
2222 "wpTextbox1" => $this->getGeSHiContent() // the main wiki text, contains fake GeSHi content.
2229 ** selects a page test to run.
2231 function selectPageTest( $count ) {
2233 // if the user only wants a specific test, then only ever give them that.
2234 if ( defined( "SPECIFIC_TEST" ) ) {
2235 $testType = SPECIFIC_TEST;
2236 return new $testType ();
2239 // Some of the time we test Special pages, the remaining
2240 // time we test using the standard edit page.
2241 switch ( $count % 100 ) {
2242 case 0 : return new successfulUserLoginTest();
2243 case 1 : return new listusersTest();
2244 case 2 : return new searchTest();
2245 case 3 : return new recentchangesTest();
2246 case 4 : return new prefixindexTest();
2247 case 5 : return new mimeSearchTest();
2248 case 6 : return new specialLogTest();
2249 case 7 : return new userLoginTest();
2250 case 8 : return new ipblocklistTest();
2251 case 9 : return new newImagesTest();
2252 case 10: return new imagelistTest();
2253 case 11: return new specialExportTest();
2254 case 12: return new specialBooksourcesTest();
2255 case 13: return new specialAllpagesTest();
2256 case 14: return new pageHistoryTest();
2257 case 15: return new contributionsTest();
2258 case 16: return new viewPageTest();
2259 case 17: return new specialAllmessagesTest();
2260 case 18: return new specialNewpagesPageTest();
2261 case 19: return new searchTest();
2262 case 20: return new redirectTest();
2263 case 21: return new confirmEmail();
2264 case 22: return new watchlistTest();
2265 case 23: return new specialBlockmeTest();
2266 case 24: return new specialUndeletePageTest();
2267 case 25: return new specialMovePage();
2268 case 26: return new specialUnlockdbPageTest();
2269 case 27: return new specialLockdbPageTest();
2270 case 28: return new specialUserrights();
2271 case 29: return new pageProtectionForm();
2272 case 30: return new specialBlockip();
2273 case 31: return new imagepageTest();
2274 case 32: return new pageDeletion();
2275 case 33: return new specialRevisionDeletePageTest();
2276 case 34: return new specialImportPageTest();
2277 case 35: return new thumbTest();
2278 case 36: return new trackbackTest();
2279 case 37: return new profileInfo();
2280 case 38: return new specialCitePageTest();
2281 case 39: return new specialFilepathPageTest();
2282 case 40: return new specialMakebot();
2283 case 41: return new specialMakesysop();
2284 case 42: return new specialRenameuserPageTest();
2285 case 43: return new specialLinksearch();
2286 case 44: return new specialCategoryTree();
2287 case 45: return new api();
2288 case 45: return new specialChemicalsourcesTest();
2289 default: return new editPageTest();
2294 // ///////////////////// SAVING OUTPUT /////////////////////////
2297 ** Utility function for saving a file. Currently has no error checking.
2299 function saveFile( $data, $name ) {
2300 file_put_contents( $name, $data );
2305 ** Returns a test as an experimental GET-to-POST URL.
2306 ** This doesn't seem to always work though, and sometimes the output is too long
2307 ** to be a valid GET URL, so we also save in other formats.
2309 function getAsURL( pageTest $test ) {
2310 $used_question_mark = ( strpos( $test->getPagePath(), "?" ) !== false );
2311 $retval = "http://get-to-post.nickj.org/?" . WIKI_BASE_URL . $test->getPagePath();
2312 foreach ( $test->getParams() as $param => $value ) {
2313 if ( !$used_question_mark ) {
2314 $retval .= "?";
2315 $used_question_mark = true;
2317 else {
2318 $retval .= "&";
2320 $retval .= $param . "=" . urlencode( $value );
2322 return $retval;
2327 ** Saves a plain-text human-readable version of a test.
2329 function saveTestAsText( pageTest $test, $filename ) {
2330 $str = "Test: " . $test->getPagePath();
2331 foreach ( $test->getParams() as $param => $value ) {
2332 $str .= "\n$param: $value";
2334 $str .= "\nGet-to-post URL: " . getAsURL( $test ) . "\n";
2335 saveFile( $str, $filename );
2340 ** Saves a test as a standalone basic PHP script that shows this one problem.
2341 ** Resulting script requires PHP-Curl be installed in order to work.
2343 function saveTestAsPHP( pageTest $test, $filename ) {
2344 $str = "<?php\n"
2345 . "\$params = " . var_export( escapeForCurl( $test->getParams() ), true ) . ";\n"
2346 . "\$ch = curl_init();\n"
2347 . "curl_setopt(\$ch, CURLOPT_POST, 1);\n"
2348 . "curl_setopt(\$ch, CURLOPT_POSTFIELDS, \$params );\n"
2349 . "curl_setopt(\$ch, CURLOPT_URL, " . var_export( WIKI_BASE_URL . $test->getPagePath(), true ) . ");\n"
2350 . "curl_setopt(\$ch, CURLOPT_RETURNTRANSFER,1);\n"
2351 . ( $test->getCookie() ? "curl_setopt(\$ch, CURLOPT_COOKIE, " . var_export( $test->getCookie(), true ) . ");\n" : "" )
2352 . "\$result=curl_exec(\$ch);\n"
2353 . "curl_close (\$ch);\n"
2354 . "print \$result;\n"
2355 . "\n";
2356 saveFile( $str, $filename );
2361 ** Escapes a value so that it can be used on the command line by Curl.
2362 ** Specifically, "<" and "@" need to be escaped if they are the first character,
2363 ** otherwise curl interprets these as meaning that we want to insert a file.
2365 function escapeForCurl( array $input_params ) {
2366 $output_params = array();
2367 foreach ( $input_params as $param => $value ) {
2368 if ( strlen( $value ) > 0 && ( $value[0] == "@" || $value[0] == "<" ) ) {
2369 $value = "\\" . $value;
2371 $output_params[$param] = $value;
2373 return $output_params;
2378 ** Saves a test as a standalone CURL shell script that shows this one problem.
2379 ** Resulting script requires standalone Curl be installed in order to work.
2381 function saveTestAsCurl( pageTest $test, $filename ) {
2382 $str = "#!/bin/bash\n"
2383 . "curl --silent --include --globoff \\\n"
2384 . ( $test->getCookie() ? " --cookie " . escapeshellarg( $test->getCookie() ) . " \\\n" : "" );
2385 foreach ( escapeForCurl( $test->getParams() ) as $param => $value ) {
2386 $str .= " -F " . escapeshellarg( $param ) . "=" . escapeshellarg( $value ) . " \\\n";
2388 $str .= " " . escapeshellarg( WIKI_BASE_URL . $test->getPagePath() ); // beginning space matters.
2389 $str .= "\n";
2390 saveFile( $str, $filename );
2391 chmod( $filename, 0755 ); // make executable
2396 ** Saves the internal data structure to file.
2398 function saveTestData ( pageTest $test, $filename ) {
2399 saveFile( serialize( $test ), $filename );
2404 ** saves a test in the various formats.
2406 function saveTest( pageTest $test, $testname ) {
2407 $base_name = DIRECTORY . "/" . $testname;
2408 saveTestAsText( $test, $base_name . INFO_FILE );
2409 saveTestAsPHP ( $test, $base_name . PHP_TEST );
2410 saveTestAsCurl( $test, $base_name . CURL_TEST );
2411 saveTestData ( $test, $base_name . DATA_FILE );
2415 // ////////////////// MEDIAWIKI OUTPUT /////////////////////////
2418 ** Asks MediaWiki for the HTML output of a test.
2420 function wikiTestOutput( pageTest $test ) {
2422 $ch = curl_init();
2424 // specify the cookie, if required.
2425 if ( $test->getCookie() ) curl_setopt( $ch, CURLOPT_COOKIE, $test->getCookie() );
2426 curl_setopt( $ch, CURLOPT_POST, 1 ); // save form using a POST
2428 $params = escapeForCurl( $test->getParams() );
2429 curl_setopt( $ch, CURLOPT_POSTFIELDS, $params ); // load the POST variables
2431 curl_setopt( $ch, CURLOPT_URL, WIKI_BASE_URL . $test->getPagePath() ); // set url to post to
2432 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); // return into a variable
2434 $result = curl_exec ( $ch );
2436 // if we encountered an error, then say so, and return an empty string.
2437 if ( curl_error( $ch ) ) {
2438 print "\nCurl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch );
2439 $result = "";
2442 curl_close ( $ch );
2444 return $result;
2448 // ////////////////// HTML VALIDATION /////////////////////////
2451 ** Asks the validator whether this is valid HTML, or not.
2453 function validateHTML( $text ) {
2455 $params = array ( "fragment" => $text );
2457 $ch = curl_init();
2459 curl_setopt( $ch, CURLOPT_POST, 1 ); // save form using a POST
2460 curl_setopt( $ch, CURLOPT_POSTFIELDS, $params ); // load the POST variables
2461 curl_setopt( $ch, CURLOPT_URL, VALIDATOR_URL ); // set url to post to
2462 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); // return into a variable
2464 $result = curl_exec ( $ch );
2466 // if we encountered an error, then log it, and exit.
2467 if ( curl_error( $ch ) ) {
2468 trigger_error( "Curl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ) );
2469 print "Curl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ) . " - exiting.\n";
2470 exit( 1 );
2473 curl_close ( $ch );
2475 $valid = ( strpos( $result, "Failed validation" ) === false );
2477 return array( $valid, $result );
2482 ** Get tidy to check for no HTML errors in the output file (e.g. unescaped strings).
2484 function tidyCheckFile( $name ) {
2485 $file = DIRECTORY . "/" . $name;
2486 $command = PATH_TO_TIDY . " -output /tmp/out.html -quiet $file 2>&1";
2487 $x = `$command`;
2489 // Look for the most interesting Tidy errors and warnings.
2490 if ( strpos( $x, "end of file while parsing attributes" ) !== false
2491 || strpos( $x, "attribute with missing trailing quote mark" ) !== false
2492 || strpos( $x, "missing '>' for end of tag" ) !== false
2493 || strpos( $x, "Error:" ) !== false ) {
2494 print "\nTidy found something - view details with: $command";
2495 return false;
2496 } else {
2497 return true;
2503 ** Returns whether or not an database error log file has changed in size since
2504 ** the last time this was run. This is used to tell if a test caused a DB error.
2506 function dbErrorLogged() {
2507 static $filesize;
2509 // first time running this function
2510 if ( !isset( $filesize ) ) {
2511 // create log if it does not exist
2512 if ( DB_ERROR_LOG_FILE && !file_exists( DB_ERROR_LOG_FILE ) ) {
2513 saveFile( '', DB_ERROR_LOG_FILE );
2515 $filesize = filesize( DB_ERROR_LOG_FILE );
2516 return false;
2519 $newsize = filesize( DB_ERROR_LOG_FILE );
2520 // if the log has grown, then assume the current test caused it.
2521 if ( $newsize != $filesize ) {
2522 $filesize = $newsize;
2523 return true;
2526 return false;
2529 // //////////////// TOP-LEVEL PROBLEM-FINDING FUNCTION ////////////////////////
2532 ** takes a page test, and runs it and tests it for problems in the output.
2533 ** Returns: False on finding a problem, or True on no problems being found.
2535 function runWikiTest( pageTest $test, &$testname, $can_overwrite = false ) {
2537 // by default don't overwrite a previous test of the same name.
2538 while ( ! $can_overwrite && file_exists( DIRECTORY . "/" . $testname . DATA_FILE ) ) {
2539 $testname .= "-" . mt_rand( 0, 9 );
2542 $filename = DIRECTORY . "/" . $testname . DATA_FILE;
2544 // Store the time before and after, to find slow pages.
2545 $before = microtime( true );
2547 // Get MediaWiki to give us the output of this test.
2548 $wiki_preview = wikiTestOutput( $test );
2550 $after = microtime( true );
2552 // if we received no response, then that's interesting.
2553 if ( $wiki_preview == "" ) {
2554 print "\nNo response received for: $filename";
2555 return false;
2558 // save output HTML to file.
2559 $html_file = DIRECTORY . "/" . $testname . HTML_FILE;
2560 saveFile( $wiki_preview, $html_file );
2562 // if there were PHP errors in the output, then that's interesting too.
2563 if ( strpos( $wiki_preview, "<b>Warning</b>: " ) !== false
2564 || strpos( $wiki_preview, "<b>Fatal error</b>: " ) !== false
2565 || strpos( $wiki_preview, "<b>Notice</b>: " ) !== false
2566 || strpos( $wiki_preview, "<b>Error</b>: " ) !== false
2567 || strpos( $wiki_preview, "<b>Strict Standards:</b>" ) !== false
2569 $error = substr( $wiki_preview, strpos( $wiki_preview, "</b>:" ) + 7, 50 );
2570 // Avoid probable PHP bug with bad session ids; http://bugs.php.net/bug.php?id=38224
2571 if ( $error != "Unknown: The session id contains illegal character" ) {
2572 print "\nPHP error/warning/notice in HTML output: $html_file ; $error";
2573 return false;
2577 // if there was a MediaWiki Backtrace message in the output, then that's also interesting.
2578 if ( strpos( $wiki_preview, "Backtrace:" ) !== false ) {
2579 print "\nInternal MediaWiki error in HTML output: $html_file";
2580 return false;
2583 // if there was a Parser error comment in the output, then that's potentially interesting.
2584 if ( strpos( $wiki_preview, "!-- ERR" ) !== false ) {
2585 print "\nParser Error comment in HTML output: $html_file";
2586 return false;
2589 // if a database error was logged, then that's definitely interesting.
2590 if ( dbErrorLogged() ) {
2591 print "\nDatabase Error logged for: $filename";
2592 return false;
2595 // validate result
2596 $valid = true;
2597 if ( VALIDATE_ON_WEB ) {
2598 list ( $valid, $validator_output ) = validateHTML( $wiki_preview );
2599 if ( !$valid ) print "\nW3C web validation failed - view details with: html2text " . DIRECTORY . "/" . $testname . ".validator_output.html";
2602 // Get tidy to check the page, unless we already know it produces non-XHTML output.
2603 if ( $test->tidyValidate() ) {
2604 $valid = tidyCheckFile( $testname . HTML_FILE ) && $valid;
2607 // if it took more than 2 seconds to render, then it may be interesting too. (Possible DoS attack?)
2608 if ( ( $after - $before ) >= 2 ) {
2609 print "\nParticularly slow to render (" . round( $after - $before, 2 ) . " seconds): $filename";
2610 return false;
2613 if ( $valid ) {
2614 // Remove temp HTML file if test was valid:
2615 unlink( $html_file );
2616 } elseif ( VALIDATE_ON_WEB ) {
2617 saveFile( $validator_output, DIRECTORY . "/" . $testname . ".validator_output.html" );
2620 return $valid;
2624 // ///////////////// RERUNNING OLD TESTS ///////////////////
2627 ** We keep our failed tests so that they can be rerun.
2628 ** This function does that retesting.
2630 function rerunPreviousTests() {
2631 print "Retesting previously found problems.\n";
2633 $dir_contents = scandir ( DIRECTORY );
2635 // sort file into the order a normal person would use.
2636 natsort ( $dir_contents );
2638 foreach ( $dir_contents as $file ) {
2640 // if file is not a test, then skip it.
2641 // Note we need to escape any periods or will be treated as "any character".
2642 $matches = array();
2643 if ( !preg_match( "/(.*)" . str_replace( ".", "\.", DATA_FILE ) . "$/", $file, $matches ) ) continue;
2645 // reload the test.
2646 $full_path = DIRECTORY . "/" . $file;
2647 $test = unserialize( file_get_contents( $full_path ) );
2649 // if this is not a valid test, then skip it.
2650 if ( ! $test instanceof pageTest ) {
2651 print "\nSkipping invalid test - $full_path";
2652 continue;
2655 // The date format is in Apache log format, which makes it easier to locate
2656 // which retest caused which error in the Apache logs (only happens usually if
2657 // apache segfaults).
2658 if ( !QUIET ) print "[" . date ( "D M d H:i:s Y" ) . "] Retesting $file (" . get_class( $test ) . ")";
2660 // run test
2661 $testname = $matches[1];
2662 $valid = runWikiTest( $test, $testname, true );
2664 if ( !$valid ) {
2665 saveTest( $test, $testname );
2666 if ( QUIET ) {
2667 print "\nTest: " . get_class( $test ) . " ; Testname: $testname\n------";
2668 } else {
2669 print "\n";
2672 else {
2673 if ( !QUIET ) print "\r";
2674 if ( DELETE_PASSED_RETESTS ) {
2675 $prefix = DIRECTORY . "/" . $testname;
2676 if ( is_file( $prefix . DATA_FILE ) ) unlink( $prefix . DATA_FILE );
2677 if ( is_file( $prefix . PHP_TEST ) ) unlink( $prefix . PHP_TEST );
2678 if ( is_file( $prefix . CURL_TEST ) ) unlink( $prefix . CURL_TEST );
2679 if ( is_file( $prefix . INFO_FILE ) ) unlink( $prefix . INFO_FILE );
2684 print "\nDone retesting.\n";
2688 // //////////////////// MAIN LOOP ////////////////////////
2691 // first check whether CURL is installed, because sometimes it's not.
2692 if ( ! function_exists( 'curl_init' ) ) {
2693 die( "Could not find 'curl_init' function. Is the curl extension compiled into PHP?\n" );
2696 // Initialization of types. wikiFuzz doesn't have a constructor because we want to
2697 // access it staticly and not have any globals.
2698 wikiFuzz::$types = array_keys( wikiFuzz::$data );
2700 // Make directory if doesn't exist
2701 if ( !is_dir( DIRECTORY ) ) {
2702 mkdir ( DIRECTORY, 0700 );
2704 // otherwise, we first retest the things that we have found in previous runs
2705 elseif ( RERUN_OLD_TESTS ) {
2706 rerunPreviousTests();
2709 // main loop.
2710 $start_time = date( "U" );
2711 $num_errors = 0;
2712 if ( !QUIET ) {
2713 print "Beginning main loop. Results are stored in the " . DIRECTORY . " directory.\n";
2714 print "Press CTRL+C to stop testing.\n";
2717 for ( $count = 0; true; $count++ ) {
2718 if ( !QUIET ) {
2719 // spinning progress indicator.
2720 switch( $count % 4 ) {
2721 case '0': print "\r/"; break;
2722 case '1': print "\r-"; break;
2723 case '2': print "\r\\"; break;
2724 case '3': print "\r|"; break;
2726 print " $count";
2729 // generate a page test to run.
2730 $test = selectPageTest( $count );
2732 $mins = ( date( "U" ) - $start_time ) / 60;
2733 if ( !QUIET && $mins > 0 ) {
2734 print ". $num_errors poss errors. "
2735 . floor( $mins ) . " mins. "
2736 . round ( $count / $mins, 0 ) . " tests/min. "
2737 . get_class( $test ); // includes the current test name.
2740 // run this test against MediaWiki, and see if the output was valid.
2741 $testname = $count;
2742 $valid = runWikiTest( $test, $testname, false );
2744 // save the failed test
2745 if ( ! $valid ) {
2746 if ( QUIET ) {
2747 print "\nTest: " . get_class( $test ) . " ; Testname: $testname\n------";
2748 } else {
2749 print "\n";
2751 saveTest( $test, $testname );
2752 $num_errors += 1;
2753 } elseif ( KEEP_PASSED_TESTS ) {
2754 // print current time, with microseconds (matches "strace" format), and the test name.
2755 print " " . date( "H:i:s." ) . substr( current( explode( " ", microtime() ) ), 2 ) . " " . $testname;
2756 saveTest( $test, $testname );
2759 // stop if we have reached max number of errors.
2760 if ( defined( "MAX_ERRORS" ) && $num_errors >= MAX_ERRORS ) {
2761 break;
2764 // stop if we have reached max number of mins runtime.
2765 if ( defined( "MAX_RUNTIME" ) && $mins >= MAX_RUNTIME ) {
2766 break;