Line ending fixes for r67320.
[mediawiki.git] / maintenance / fuzz-tester.php
blob6af8a1570ce4f77e6a78aced59d20863e62aae9e
1 <?php
2 /**
3 * @file
4 * @ingroup Maintenance
5 * @author Nick Jenkins ( http://nickj.org/ ).
6 * @copyright 2006 Nick Jenkins
7 * @licence GNU General Public Licence 2.0
9 Started: 18 May 2006.
11 Description:
12 Performs fuzz-style testing of MediaWiki's parser and forms.
14 How:
15 - Generate lots of nasty wiki text.
16 - Ask the Parser to render that wiki text to HTML, or ask MediaWiki's forms
17 to deal with that wiki text.
18 - Check MediaWiki's output for problems.
19 - Repeat.
21 Why:
22 - To help find bugs.
23 - To help find security issues, or potential security issues.
25 What type of problems are being checked for:
26 - Unclosed tags.
27 - Errors or interesting warnings from Tidy.
28 - PHP errors / warnings / notices.
29 - MediaWiki internal errors.
30 - Very slow responses.
31 - No response from apache.
32 - Optionally checking for malformed HTML using the W3C validator.
34 Background:
35 Many of the wikiFuzz class methods are a modified PHP port,
36 of a "shameless" Python port, of LCAMTUF'S MANGELME:
37 - http://www.securiteam.com/tools/6Z00N1PBFK.html
38 - http://www.securityfocus.com/archive/1/378632/2004-10-15/2004-10-21/0
40 Video:
41 There's an XviD video discussing this fuzz tester. You can get it from:
42 http://files.nickj.org/MediaWiki/Fuzz-Testing-MediaWiki-xvid.avi
44 Requirements:
45 To run this, you will need:
46 - Command-line PHP5, with PHP-curl enabled (not all installations have this
47 enabled - try "apt-get install php5-curl" if you're on Debian to install).
48 - the Tidy standalone executable. ("apt-get install tidy").
50 Optional:
51 - If you want to run the curl scripts, you'll need standalone curl installed
52 ("apt-get install curl")
53 - For viewing the W3C validator output on a command line, the "html2text"
54 program may be useful ("apt-get install html2text")
56 Saving tests and test results:
57 Any of the fuzz tests which find problems are saved for later review.
58 In order to help track down problems, tests are saved in a number of
59 different formats. The default filename extensions and their meanings are:
60 - ".test.php" : PHP script that reproduces just that one problem using PHP-Curl.
61 - ".curl.sh" : Shell script that reproduces that problem using standalone curl.
62 - ".data.bin" : The serialized PHP data so that this script can re-run the test.
63 - ".info.txt" : A human-readable text file with details of the field contents.
65 Wiki configuration for testing:
66 You should make some additions to LocalSettings.php in order to catch the most
67 errors. Note this configuration is for **TESTING PURPOSES ONLY**, and is IN NO
68 WAY, SHAPE, OR FORM suitable for deployment on a hostile network. That said,
69 personally I find these additions to be the most helpful for testing purposes:
71 // --------- Start ---------
72 // Everyone can do everything. Very useful for testing, yet useless for deployment.
73 $wgGroupPermissions['*']['autoconfirmed'] = true;
74 $wgGroupPermissions['*']['block'] = true;
75 $wgGroupPermissions['*']['bot'] = true;
76 $wgGroupPermissions['*']['delete'] = true;
77 $wgGroupPermissions['*']['deletedhistory'] = true;
78 $wgGroupPermissions['*']['deleterevision'] = true;
79 $wgGroupPermissions['*']['editinterface'] = true;
80 $wgGroupPermissions['*']['hiderevision'] = true;
81 $wgGroupPermissions['*']['import'] = true;
82 $wgGroupPermissions['*']['importupload'] = true;
83 $wgGroupPermissions['*']['minoredit'] = true;
84 $wgGroupPermissions['*']['move'] = true;
85 $wgGroupPermissions['*']['patrol'] = true;
86 $wgGroupPermissions['*']['protect'] = true;
87 $wgGroupPermissions['*']['proxyunbannable'] = true;
88 $wgGroupPermissions['*']['renameuser'] = true;
89 $wgGroupPermissions['*']['reupload'] = true;
90 $wgGroupPermissions['*']['reupload-shared'] = true;
91 $wgGroupPermissions['*']['rollback'] = true;
92 $wgGroupPermissions['*']['siteadmin'] = true;
93 $wgGroupPermissions['*']['trackback'] = true;
94 $wgGroupPermissions['*']['unwatchedpages'] = true;
95 $wgGroupPermissions['*']['upload'] = true;
96 $wgGroupPermissions['*']['userrights'] = true;
97 $wgGroupPermissions['*']['renameuser'] = true;
98 $wgGroupPermissions['*']['makebot'] = true;
99 $wgGroupPermissions['*']['makesysop'] = true;
101 // Enable weird and wonderful options:
102 // Increase default error reporting level.
103 error_reporting (E_ALL); // At a later date could be increased to E_ALL | E_STRICT
104 $wgBlockOpenProxies = true; // Some block pages require this to be true in order to test.
105 $wgEnableUploads = true; // enable uploads.
106 //$wgUseTrackbacks = true; // enable trackbacks; However this breaks the viewPageTest, so currently disabled.
107 $wgDBerrorLog = "/root/mediawiki-db-error-log.txt"; // log DB errors, replace with suitable path.
108 $wgShowSQLErrors = true; // Show SQL errors (instead of saying the query was hidden).
109 $wgShowExceptionDetails = true; // want backtraces.
110 $wgEnableAPI = true; // enable API.
111 $wgEnableWriteAPI = true; // enable API.
113 // Install & enable Parser Hook extensions to increase code coverage. E.g.:
114 require_once("extensions/ParserFunctions/ParserFunctions.php");
115 require_once("extensions/Cite/Cite.php");
116 require_once("extensions/inputbox/inputbox.php");
117 require_once("extensions/Sort/Sort.php");
118 require_once("extensions/wikihiero/wikihiero.php");
119 require_once("extensions/CharInsert/CharInsert.php");
120 require_once("extensions/FixedImage/FixedImage.php");
122 // Install & enable Special Page extensions to increase code coverage. E.g.:
123 require_once("extensions/Cite/SpecialCite.php");
124 require_once("extensions/Filepath/SpecialFilepath.php");
125 require_once("extensions/Makebot/Makebot.php");
126 require_once("extensions/Makesysop/SpecialMakesysop.php");
127 require_once("extensions/Renameuser/SpecialRenameuser.php");
128 require_once("extensions/LinkSearch/LinkSearch.php");
129 // --------- End ---------
131 If you want to try E_STRICT error logging, add this to the above:
132 // --------- Start ---------
133 error_reporting (E_ALL | E_STRICT);
134 set_error_handler( 'error_handler' );
135 function error_handler ($type, $message, $file=__FILE__, $line=__LINE__) {
136 if ($message == "var: Deprecated. Please use the public/private/protected modifiers") return;
137 print "<br />\n<b>Strict Standards:</b> Type: <b>$type</b>: $message in <b>$file</b> on line <b>$line</b><br />\n";
139 // --------- End ---------
141 Also add/change this in LocalSettings.php:
142 // --------- Start ---------
143 $wgEnableProfileInfo = true;
144 $wgDBserver = "localhost"; // replace with DB server hostname
145 // --------- End ---------
147 Usage:
148 Run with "php fuzz-tester.php".
149 To see the various command-line options, run "php fuzz-tester.php --help".
150 To stop the script, press Ctrl-C.
152 Console output:
153 - If requested, first any previously failed tests will be rerun.
154 - Then new tests will be generated and run. Any tests that fail will be saved,
155 and a brief message about why they failed will be printed on the console.
156 - The console will show the number of tests run, time run, number of tests
157 failed, number of tests being done per minute, and the name of the current test.
159 TODO:
160 Some known things that could improve this script:
161 - Logging in with cookie jar storage needed for some tests (as there are some
162 pages that cannot be tested without being logged in, and which are currently
163 untested - e.g. Special:Emailuser, Special:Preferences, adding to Watchist).
164 - Testing of Timeline extension (I cannot test as ploticus has/had issues on
165 my architecture).
169 // ///////////////////////// COMMAND LINE HELP ////////////////////////////////////
171 // This is a command line script, load MediaWiki env (gives command line options);
172 require_once( dirname( __FILE__ ) . '/commandLine.inc' );
174 // if the user asked for an explanation of command line options.
175 if ( isset( $options["help"] ) ) {
176 print <<<ENDS
177 MediaWiki $wgVersion fuzz tester
178 Usage: php {$_SERVER["SCRIPT_NAME"]} [--quiet] [--base-url=<url-to-test-wiki>]
179 [--directory=<failed-test-path>] [--include-binary]
180 [--w3c-validate] [--delete-passed-retests] [--help]
181 [--user=<username>] [--password=<password>]
182 [--rerun-failed-tests] [--max-errors=<int>]
183 [--max-runtime=<num-minutes>]
184 [--specific-test=<test-name>]
186 Options:
187 --quiet : Hides passed tests, shows only failed tests.
188 --base-url : URL to a wiki on which to run the tests.
189 The "http://" is optional and can be omitted.
190 --directory : Full path to directory for storing failed tests.
191 Will be created if it does not exist.
192 --include-binary : Includes non-alphanumeric characters in the tests.
193 --w3c-validate : Validates pages using the W3C's web validator.
194 Slow. Currently many pages fail validation.
195 --user : Login name of a valid user on your test wiki.
196 --password : Password for the valid user on your test wiki.
197 --delete-passed-retests : Will delete retests that now pass.
198 Requires --rerun-failed-tests to be meaningful.
199 --rerun-failed-tests : Whether to rerun any previously failed tests.
200 --max-errors : Maximum number of errors to report before exiting.
201 Does not include errors from --rerun-failed-tests
202 --max-runtime : Maximum runtime, in minutes, to run before exiting.
203 Only applies to new tests, not --rerun-failed-tests
204 --specific-test : Runs only the specified fuzz test.
205 Only applies to new tests, not --rerun-failed-tests
206 --keep-passed-tests : Saves all test files, even those that pass.
207 --help : Show this help message.
209 Example:
210 If you wanted to fuzz test a nightly MediaWiki checkout using cron for 1 hour,
211 and only wanted to be informed of errors, and did not want to redo previously
212 failed tests, and wanted a maximum of 100 errors, then you could do:
213 php {$_SERVER["SCRIPT_NAME"]} --quiet --max-errors=100 --max-runtime=60
216 ENDS;
218 exit( 0 );
222 // if we got command line options, check they look valid.
223 $validOptions = array ( "quiet", "base-url", "directory", "include-binary",
224 "w3c-validate", "user", "password", "delete-passed-retests",
225 "rerun-failed-tests", "max-errors",
226 "max-runtime", "specific-test", "keep-passed-tests", "help" );
227 if ( !empty( $options ) ) {
228 $unknownArgs = array_diff ( array_keys( $options ), $validOptions );
229 foreach ( $unknownArgs as $invalidArg ) {
230 print "Ignoring invalid command-line option: --$invalidArg\n";
235 // /////////////////////////// CONFIGURATION ////////////////////////////////////
237 // URL to some wiki on which we can run our tests.
238 if ( !empty( $options["base-url"] ) ) {
239 define( "WIKI_BASE_URL", $options["base-url"] );
240 } else {
241 define( "WIKI_BASE_URL", $wgServer . $wgScriptPath . '/' );
244 // The directory name where we store the output.
245 // Example for Windows: "c:\\temp\\wiki-fuzz"
246 if ( !empty( $options["directory"] ) ) {
247 define( "DIRECTORY", $options["directory"] );
248 } else {
249 define( "DIRECTORY", "{$wgUploadDirectory}/fuzz-tests" );
252 // Should our test fuzz data include binary strings?
253 define( "INCLUDE_BINARY", isset( $options["include-binary"] ) );
255 // Whether we want to validate HTML output on the web.
256 // At the moment very few generated pages will validate, so not recommended.
257 define( "VALIDATE_ON_WEB", isset( $options["w3c-validate"] ) );
258 // URL to use to validate our output:
259 define( "VALIDATOR_URL", "http://validator.w3.org/check" );
261 // Location of Tidy standalone executable.
262 define( "PATH_TO_TIDY", "/usr/bin/tidy" );
264 // The name of a user who has edited on your wiki. Used
265 // when testing the Special:Contributions and Special:Userlogin page.
266 if ( !empty( $options["user"] ) ) {
267 define( "USER_ON_WIKI", $options["user"] );
268 } else {
269 define( "USER_ON_WIKI", "nickj" );
272 // The password of the above user. Used when testing the login page,
273 // and to do this we sometimes need to login successfully.
274 if ( !empty( $options["password"] ) ) {
275 define( "USER_PASSWORD", $options["password"] );
276 } else {
277 // And no, this is not a valid password on any public wiki.
278 define( "USER_PASSWORD", "nickj" );
281 // If we have a test that failed, and then we run it again, and it passes,
282 // do you want to delete it or keep it?
283 define( "DELETE_PASSED_RETESTS", isset( $options["delete-passed-retests"] ) );
285 // Do we want to rerun old saved tests at script startup?
286 // Set to true to help catch regressions, or false if you only want new stuff.
287 define( "RERUN_OLD_TESTS", isset( $options["rerun-failed-tests"] ) );
289 // File where the database errors are logged. Should be defined in LocalSettings.php.
290 define( "DB_ERROR_LOG_FILE", $wgDBerrorLog );
292 // Run in chatty mode (all output, default), or run in quiet mode (only prints out details of failed tests)?
293 define( "QUIET", isset( $options["quiet"] ) );
295 // Keep all test files, even those that pass. Potentially useful to tracking input that causes something
296 // unusual to happen, if you don't know what "unusual" is until later.
297 define( "KEEP_PASSED_TESTS", isset( $options["keep-passed-tests"] ) );
299 // The maximum runtime, if specified.
300 if ( !empty( $options["max-runtime"] ) && intval( $options["max-runtime"] ) > 0 ) {
301 define( "MAX_RUNTIME", intval( $options["max-runtime"] ) );
304 // The maximum number of problems to find, if specified. Excludes retest errors.
305 if ( !empty( $options["max-errors"] ) && intval( $options["max-errors"] ) > 0 ) {
306 define( "MAX_ERRORS", intval( $options["max-errors"] ) );
309 // if the user has requested a specific test (instead of all tests), and the test they asked for looks valid.
310 if ( !empty( $options["specific-test"] ) ) {
311 if ( class_exists( $options["specific-test"] ) && get_parent_class( $options["specific-test"] ) == "pageTest" ) {
312 define( "SPECIFIC_TEST", $options["specific-test"] );
314 else {
315 print "Ignoring invalid --specific-test\n";
319 // Define the file extensions we'll use:
320 define( "PHP_TEST" , ".test.php" );
321 define( "CURL_TEST", ".curl.sh" );
322 define( "DATA_FILE", ".data.bin" );
323 define( "INFO_FILE", ".info.txt" );
324 define( "HTML_FILE", ".wiki_preview.html" );
326 // If it goes wrong, we want to know about it.
327 error_reporting( E_ALL | E_STRICT );
329 // ////////////// A CLASS THAT GENERATES RANDOM NASTY WIKI & HTML STRINGS //////////////////////
331 class wikiFuzz {
333 // Only some HTML tags are understood with params by MediaWiki, the rest are ignored.
334 // List the tags that accept params below, as well as what those params are.
335 public static $data = array(
336 "B" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
337 "CAPTION" => array( "CLASS", "ID", "STYLE", "align", "lang", "dir", "title" ),
338 "CENTER" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title" ),
339 "DIV" => array( "CLASS", "STYLE", "ID", "align", "lang", "dir", "title" ),
340 "FONT" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title", "face", "size", "color" ),
341 "H1" => array( "STYLE", "CLASS", "ID", "align", "lang", "dir", "title" ),
342 "H2" => array( "STYLE", "CLASS", "ID", "align", "lang", "dir", "title" ),
343 "HR" => array( "STYLE", "CLASS", "ID", "WIDTH", "lang", "dir", "title", "size", "noshade" ),
344 "LI" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "type", "value" ),
345 "TABLE" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "BORDER", "CELLPADDING",
346 "CELLSPACING", "lang", "dir", "title", "summary", "frame", "rules" ),
347 "TD" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "COLSPAN", "ROWSPAN",
348 "VALIGN", "abbr", "axis", "headers", "scope", "nowrap", "height", "lang",
349 "dir", "title", "char", "charoff" ),
350 "TH" => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "COLSPAN", "ROWSPAN",
351 "VALIGN", "abbr", "axis", "headers", "scope", "nowrap", "height", "lang",
352 "dir", "title", "char", "charoff" ),
353 "TR" => array( "CLASS", "STYLE", "ID", "BGCOLOR", "ALIGN", "VALIGN", "lang", "dir", "title", "char", "charoff" ),
354 "UL" => array( "CLASS", "STYLE", "ID", "lang", "dir", "title", "type" ),
355 "P" => array( "style", "class", "id", "align", "lang", "dir", "title" ),
356 "blockquote" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "cite" ),
357 "span" => array( "CLASS", "ID", "STYLE", "align", "lang", "dir", "title" ),
358 "code" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
359 "tt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
360 "small" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
361 "big" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
362 "s" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
363 "u" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
364 "del" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "datetime", "cite" ),
365 "ins" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "datetime", "cite" ),
366 "sub" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
367 "sup" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
368 "ol" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "type", "start" ),
369 "br" => array( "CLASS", "ID", "STYLE", "title", "clear" ),
370 "cite" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
371 "var" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
372 "dl" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
373 "ruby" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
374 "rt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
375 "rp" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
376 "dt" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
377 "dl" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
378 "em" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
379 "strong" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
380 "i" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
381 "thead" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ),
382 "tfoot" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ),
383 "tbody" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign' ),
384 "colgroup" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign', 'span', 'width' ),
385 "col" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", 'align', 'char', 'charoff', 'valign', 'span', 'width' ),
386 "pre" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "width" ),
388 // extension tags that accept parameters:
389 "sort" => array( "order", "class" ),
390 "ref" => array( "name" ),
391 "categorytree" => array( "hideroot", "mode", "style" ),
392 "chemform" => array( "link", "wikilink", "query" ),
393 "section" => array( "begin", "new" ),
395 // older MW transclusion.
396 "transclude" => array( "page" ),
399 // The types of the HTML that we will be testing were defined above
400 // Note: this needs to be initialized later to be equal to: array_keys(wikiFuzz::$data);
401 // as such, it also needs to also be publicly modifiable.
402 public static $types;
405 // Some attribute values.
406 static private $other = array( "&", "=", ":", "?", "\"", "\n", "%n%n%n%n%n%n%n%n%n%n%n%n", "\\" );
407 static private $ints = array(
408 // various numbers
409 "0", "-1", "127", "-7897", "89000", "808080", "90928345",
410 "0xfffffff", "ffff",
412 // Different ways of saying: '
413 "&#0000039;", // Long UTF-8 Unicode encoding
414 "&#39;", // dec version.
415 "&#x27;", // hex version.
416 "&#xA7;", // malformed hex variant, MSB not zero.
418 // Different ways of saying: "
419 "&#0000034;", // Long UTF-8 Unicode encoding
420 "&#34;",
421 "&#x22;", // hex version.
422 "&#xA2;", // malformed hex variant, MSB not zero.
424 // Different ways of saying: <
425 "<",
426 "&#0000060", // Long UTF-8 Unicode encoding without semicolon (Mediawiki wants the colon)
427 "&#0000060;", // Long UTF-8 Unicode encoding with semicolon
428 "&#60;",
429 "&#x3C;", // hex version.
430 "&#xBC;", // malformed hex variant, MSB not zero.
431 "&#x0003C;", // mid-length hex version
432 "&#X00003C;", // slightly longer hex version, with capital "X"
434 // Different ways of saying: >
435 ">",
436 "&#0000062;", // Long UTF-8 Unicode encoding
437 "&#62;",
438 "&#x3E;", // hex version.
439 "&#xBE;", // malformed variant, MSB not zero.
441 // Different ways of saying: [
442 "&#0000091;", // Long UTF-8 Unicode encoding
443 "&#91;",
444 "&#x5B;", // hex version.
446 // Different ways of saying: {{
447 "&#0000123;&#0000123;", // Long UTF-8 Unicode encoding
448 "&#123;&#123;",
449 "&#x7B;&#x7B;", // hex version.
451 // Different ways of saying: |
452 "&#0000124;", // Long UTF-8 Unicode encoding
453 "&#124;",
454 "&#x7C;", // hex version.
455 "&#xFC;", // malformed hex variant, MSB not zero.
457 // a "lignature" - http://www.robinlionheart.com/stds/html4/spchars#ligature
458 // &#8204; == &zwnj;
459 "&#8204;"
462 // Defines various wiki-related bits of syntax, that can potentially cause
463 // MediaWiki to do something other than just print that literal text.
464 static private $ext = array(
465 // links, templates, parameters.
466 "[[", "]]", "{{", "}}", "|", "[", "]", "{{{", "}}}", "|]]",
468 // wiki tables.
469 "\n{|", "\n|}",
470 "!",
471 "\n!",
472 "!!",
473 "||",
474 "\n|-", "| ", "\n|",
476 // section headings.
477 "=", "==", "===", "====", "=====", "======",
479 // lists (ordered and unordered) and indentation.
480 "\n*", "*", "\n:", ":",
481 "\n#", "#",
483 // definition lists (dl, dt, dd), newline, and newline with pre, and a tab.
484 "\n;", ";", "\n ",
486 // Whitespace: newline, tab, space.
487 "\n", "\t", " ",
489 // Some XSS attack vectors from http://ha.ckers.org/xss.html
490 "&#x09;", // tab
491 "&#x0A;", // newline
492 "&#x0D;", // carriage return
493 "\0", // null character
494 " &#14; ", // spaces and meta characters
495 "'';!--\"<XSS>=&{()}", // compact injection of XSS & SQL tester
497 // various NULL fields
498 "%00",
499 "&#00;",
500 "\0",
502 // horizontal rule.
503 "-----", "\n-----",
505 // signature, redirect, bold, italics.
506 "~~~~", "#REDIRECT [[", "'''", "''",
508 // comments.
509 "<!--", "-->",
511 // quotes.
512 "\"", "'",
514 // tag start and tag end.
515 "<", ">",
517 // implicit link creation on URIs.
518 "http://",
519 "https://",
520 "ftp://",
521 "irc://",
522 "news:",
523 'gopher://',
524 'telnet://',
525 'nntp://',
526 'worldwind://',
527 'mailto:',
529 // images.
530 "[[image:",
531 ".gif",
532 ".png",
533 ".jpg",
534 ".jpeg",
535 'thumbnail=',
536 'thumbnail',
537 'thumb=',
538 'thumb',
539 'right',
540 'none',
541 'left',
542 'framed',
543 'frame',
544 'enframed',
545 'centre',
546 'center',
547 "Image:",
548 "[[:Image",
549 'px',
550 'upright=',
551 'border',
553 // misc stuff to throw at the Parser.
554 '%08X',
555 '/',
556 ":x{|",
557 "\n|+",
558 "<noinclude>",
559 "</noinclude>",
560 " \302\273",
561 " :",
562 " !",
563 " ;",
564 "\302\253",
565 "[[category:",
566 "?=",
567 "(",
568 ")",
569 "]]]",
570 "../",
571 "{{{{",
572 "}}}}",
573 "[[Special:",
574 "<includeonly>",
575 "</includeonly>",
576 "<!--MWTEMPLATESECTION=",
577 '<!--MWTOC-->',
579 // implicit link creation on booknum, RFC, and PubMed ID usage (both with and without IDs)
580 "ISBN 2",
581 "RFC 000",
582 "PMID 000",
583 "ISBN ",
584 "RFC ",
585 "PMID ",
587 // magic words:
588 '__NOTOC__',
589 '__FORCETOC__',
590 '__NOEDITSECTION__',
591 '__START__',
592 '__NOTITLECONVERT__',
593 '__NOCONTENTCONVERT__',
594 '__END__',
595 '__TOC__',
596 '__NOTC__',
597 '__NOCC__',
598 "__FORCETOC__",
599 "__NEWSECTIONLINK__",
600 "__NOGALLERY__",
602 // more magic words / internal templates.
603 '{{PAGENAME}}',
604 '{{PAGENAMEE}}',
605 '{{NAMESPACE}}',
606 "{{MSG:",
607 "}}",
608 "{{MSGNW:",
609 "}}",
610 "{{INT:",
611 "}}",
612 '{{SITENAME}}',
613 "{{NS:",
614 "}}",
615 "{{LOCALURL:",
616 "}}",
617 "{{LOCALURLE:",
618 "}}",
619 "{{SCRIPTPATH}}",
620 "{{GRAMMAR:gentiv|",
621 "}}",
622 "{{REVISIONID}}",
623 "{{SUBPAGENAME}}",
624 "{{SUBPAGENAMEE}}",
625 "{{ns:0}}",
626 "{{fullurle:",
627 "}}",
628 "{{subst::",
629 "}}",
630 "{{UCFIRST:",
631 "}}",
632 "{{UC:",
633 '{{SERVERNAME}}',
634 '{{SERVER}}',
635 "{{RAW:",
636 "}}",
637 "{{PLURAL:",
638 "}}",
639 "{{LCFIRST:",
640 "}}",
641 "{{LC:",
642 "}}",
643 '{{CURRENTWEEK}}',
644 '{{CURRENTDOW}}',
645 "{{INT:{{LC:contribs-showhideminor}}|",
646 "}}",
647 "{{INT:googlesearch|",
648 "}}",
649 "{{BASEPAGENAME}}",
650 "{{CONTENTLANGUAGE}}",
651 "{{PAGESINNAMESPACE:}}",
652 "{{#language:",
653 "}}",
654 "{{#special:",
655 "}}",
656 "{{#special:emailuser",
657 "}}",
659 // Some raw link for magic words.
660 "{{NUMBEROFPAGES:R",
661 "}}",
662 "{{NUMBEROFUSERS:R",
663 "}}",
664 "{{NUMBEROFARTICLES:R",
665 "}}",
666 "{{NUMBEROFFILES:R",
667 "}}",
668 "{{NUMBEROFADMINS:R",
669 "}}",
670 "{{padleft:",
671 "}}",
672 "{{padright:",
673 "}}",
674 "{{DEFAULTSORT:",
675 "}}",
677 // internal Math "extension":
678 "<math>",
679 "</math>",
681 // Parser extension functions:
682 "{{#expr:",
683 "{{#if:",
684 "{{#ifeq:",
685 "{{#ifexist:",
686 "{{#ifexpr:",
687 "{{#switch:",
688 "{{#time:",
689 "}}",
691 // references table for the Cite extension.
692 "<references/>",
694 // Internal Parser tokens - try inserting some of these.
695 "UNIQ25f46b0524f13e67NOPARSE",
696 "UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002",
697 "\x07UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002-QINU",
699 // Inputbox extension:
700 "<inputbox>\ntype=search\nsearchbuttonlabel=\n",
701 "</inputbox>",
703 // charInsert extension:
704 "<charInsert>",
705 "</charInsert>",
707 // wikiHiero extension:
708 "<hiero>",
709 "</hiero>",
711 // Image gallery:
712 "<gallery>",
713 "</gallery>",
715 // FixedImage extension.
716 "<fundraising/>",
718 // Timeline extension: currently untested.
720 // Nowiki:
721 "<nOwIkI>",
722 "</nowiki>",
724 // an external image to test the external image displaying code
725 "http://debian.org/Pics/debian.png",
727 // LabeledSectionTransclusion extension.
728 "{{#lstx:",
729 "}}",
730 "{{#lst:",
731 "}}",
732 "{{#lst:Main Page|",
733 "}}"
737 ** Randomly returns one element of the input array.
739 static public function chooseInput( array $input ) {
740 $randindex = wikiFuzz::randnum( count( $input ) - 1 );
741 return $input[$randindex];
744 // Max number of parameters for HTML attributes.
745 static private $maxparams = 10;
747 /**
748 ** Returns random number between finish and start.
750 static public function randnum( $finish, $start = 0 ) {
751 return mt_rand( $start, $finish );
755 ** Returns a mix of random text and random wiki syntax.
757 static private function randstring() {
758 $thestring = "";
760 for ( $i = 0; $i < 40; $i++ ) {
761 $what = wikiFuzz::randnum( 1 );
763 if ( $what == 0 ) { // include some random wiki syntax
764 $which = wikiFuzz::randnum( count( wikiFuzz::$ext ) - 1 );
765 $thestring .= wikiFuzz::$ext[$which];
767 else { // include some random text
768 $char = INCLUDE_BINARY
769 // Decimal version:
770 // "&#" . wikiFuzz::randnum(255) . ";"
771 // Hex version:
772 ? "&#x" . str_pad( dechex( wikiFuzz::randnum( 255 ) ), wikiFuzz::randnum( 2, 7 ), "0", STR_PAD_LEFT ) . ";"
773 // A truly binary version:
774 // ? chr(wikiFuzz::randnum(0,255))
775 : chr( wikiFuzz::randnum( 126, 32 ) );
777 $length = wikiFuzz::randnum( 8 );
778 $thestring .= str_repeat ( $char, $length );
781 return $thestring;
785 ** Returns either random text, or random wiki syntax, or random data from "ints",
786 ** or random data from "other".
788 static private function makestring() {
789 $what = wikiFuzz::randnum( 2 );
790 if ( $what == 0 ) {
791 return wikiFuzz::randstring();
793 elseif ( $what == 1 ) {
794 return wikiFuzz::$ints[wikiFuzz::randnum( count( wikiFuzz::$ints ) - 1 )];
796 else {
797 return wikiFuzz::$other[wikiFuzz::randnum( count( wikiFuzz::$other ) - 1 )];
803 ** Strips out the stuff that Mediawiki balks at in a page's title.
804 ** Implementation copied/pasted from cleanupTable.inc & cleanupImages.php
806 static public function makeTitleSafe( $str ) {
807 $legalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF";
808 return preg_replace_callback(
809 "/([^$legalTitleChars])/",
810 create_function(
811 // single quotes are essential here,
812 // or alternative escape all $ as \$
813 '$matches',
814 'return sprintf( "\\x%02x", ord( $matches[1] ) );'
816 $str );
820 ** Returns a string of fuzz text.
822 static private function loop() {
823 switch ( wikiFuzz::randnum( 3 ) ) {
824 case 1: // an opening tag, with parameters.
825 $string = "";
826 $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 );
827 $t = wikiFuzz::$types[$i];
828 $arr = wikiFuzz::$data[$t];
829 $string .= "<" . $t . " ";
830 $num_params = min( wikiFuzz::$maxparams, count( $arr ) );
831 for ( $z = 0; $z < $num_params; $z++ ) {
832 $badparam = $arr[wikiFuzz::randnum( count( $arr ) - 1 )];
833 $badstring = wikiFuzz::makestring();
834 $string .= $badparam . "=" . wikiFuzz::getRandQuote() . $badstring . wikiFuzz::getRandQuote() . " ";
836 $string .= ">\n";
837 return $string;
838 case 2: // a closing tag.
839 $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 );
840 return "</" . wikiFuzz::$types[$i] . ">";
841 case 3: // a random string, between tags.
842 return wikiFuzz::makeString();
844 return ""; // catch-all, should never be called.
848 ** Returns one of the three styles of random quote: ', ", and nothing.
850 static private function getRandQuote() {
851 switch ( wikiFuzz::randnum( 3 ) ) {
852 case 1 : return "'";
853 case 2 : return "\"";
854 default: return "";
859 ** Returns fuzz text, with the parameter indicating approximately how many lines of text you want.
861 static public function makeFuzz( $maxtypes = 2 ) {
862 $page = "";
863 for ( $k = 0; $k < $maxtypes; $k++ ) {
864 $page .= wikiFuzz::loop();
866 return $page;
871 // ////// MEDIAWIKI PAGES TO TEST, AND HOW TO TEST THEM ///////
874 ** A page test has just these things:
875 ** 1) Form parameters.
876 ** 2) the URL we are going to test those parameters on.
877 ** 3) Any cookies required for the test.
878 ** 4) Whether Tidy should validate the page. Defaults to true, but can be turned off.
879 ** Declared abstract because it should be extended by a class
880 ** that supplies these parameters.
882 abstract class pageTest {
883 protected $params;
884 protected $pagePath;
885 protected $cookie = "";
886 protected $tidyValidate = true;
888 public function getParams() {
889 return $this->params;
892 public function getPagePath() {
893 return $this->pagePath;
896 public function getCookie() {
897 return $this->cookie;
900 public function tidyValidate() {
901 return $this->tidyValidate;
907 ** a page test for the "Edit" page. Tests Parser.php and Sanitizer.php.
909 class editPageTest extends pageTest {
910 function __construct() {
911 $this->pagePath = "index.php?title=WIKIFUZZ";
913 $this->params = array (
914 "action" => "submit",
915 "wpMinoredit" => wikiFuzz::makeFuzz( 2 ),
916 "wpPreview" => wikiFuzz::makeFuzz( 2 ),
917 "wpSection" => wikiFuzz::makeFuzz( 2 ),
918 "wpEdittime" => wikiFuzz::makeFuzz( 2 ),
919 "wpSummary" => wikiFuzz::makeFuzz( 2 ),
920 "wpScrolltop" => wikiFuzz::makeFuzz( 2 ),
921 "wpStarttime" => wikiFuzz::makeFuzz( 2 ),
922 "wpAutoSummary" => wikiFuzz::makeFuzz( 2 ),
923 "wpTextbox1" => wikiFuzz::makeFuzz( 40 ) // the main wiki text, need lots of this.
926 // sometimes we don't want to specify certain parameters.
927 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSection"] );
928 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEdittime"] );
929 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSummary"] );
930 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpScrolltop"] );
931 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpStarttime"] );
932 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpAutoSummary"] );
933 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpTextbox1"] );
939 ** a page test for "Special:Listusers".
941 class listusersTest extends pageTest {
942 function __construct() {
943 $this->pagePath = "index.php?title=Special:Listusers";
945 $this->params = array (
946 "title" => wikiFuzz::makeFuzz( 2 ),
947 "group" => wikiFuzz::makeFuzz( 2 ),
948 "username" => wikiFuzz::makeFuzz( 2 ),
949 "Go" => wikiFuzz::makeFuzz( 2 ),
950 "limit" => wikiFuzz::chooseInput( array( "0", "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
951 "offset" => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) )
958 ** a page test for "Special:Search".
960 class searchTest extends pageTest {
961 function __construct() {
962 $this->pagePath = "index.php?title=Special:Search";
964 $this->params = array (
965 "action" => "index.php?title=Special:Search",
966 "ns0" => wikiFuzz::makeFuzz( 2 ),
967 "ns1" => wikiFuzz::makeFuzz( 2 ),
968 "ns2" => wikiFuzz::makeFuzz( 2 ),
969 "ns3" => wikiFuzz::makeFuzz( 2 ),
970 "ns4" => wikiFuzz::makeFuzz( 2 ),
971 "ns5" => wikiFuzz::makeFuzz( 2 ),
972 "ns6" => wikiFuzz::makeFuzz( 2 ),
973 "ns7" => wikiFuzz::makeFuzz( 2 ),
974 "ns8" => wikiFuzz::makeFuzz( 2 ),
975 "ns9" => wikiFuzz::makeFuzz( 2 ),
976 "ns10" => wikiFuzz::makeFuzz( 2 ),
977 "ns11" => wikiFuzz::makeFuzz( 2 ),
978 "ns12" => wikiFuzz::makeFuzz( 2 ),
979 "ns13" => wikiFuzz::makeFuzz( 2 ),
980 "ns14" => wikiFuzz::makeFuzz( 2 ),
981 "ns15" => wikiFuzz::makeFuzz( 2 ),
982 "redirs" => wikiFuzz::makeFuzz( 2 ),
983 "search" => wikiFuzz::makeFuzz( 2 ),
984 "offset" => wikiFuzz::chooseInput( array( "", "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) ),
985 "fulltext" => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) ),
986 "searchx" => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) )
993 ** a page test for "Special:Recentchanges".
995 class recentchangesTest extends pageTest {
996 function __construct() {
997 $this->pagePath = "index.php?title=Special:Recentchanges";
999 $this->params = array (
1000 "action" => wikiFuzz::makeFuzz( 2 ),
1001 "title" => wikiFuzz::makeFuzz( 2 ),
1002 "namespace" => wikiFuzz::chooseInput( range( -1, 15 ) ),
1003 "Go" => wikiFuzz::makeFuzz( 2 ),
1004 "invert" => wikiFuzz::chooseInput( array( "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1005 "hideanons" => wikiFuzz::chooseInput( array( "-1", "------'-------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1006 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "---------'----0", "+1", "81340909772349234", wikiFuzz::makeFuzz( 2 ) ) ),
1007 "days" => wikiFuzz::chooseInput( array( "-1", "----------'---0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1008 "hideminor" => wikiFuzz::chooseInput( array( "-1", "-----------'--0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1009 "hidebots" => wikiFuzz::chooseInput( array( "-1", "---------'----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1010 "hideliu" => wikiFuzz::chooseInput( array( "-1", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1011 "hidepatrolled" => wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1012 "hidemyself" => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1013 'categories_any' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1014 'categories' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1015 'feed' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) )
1022 ** a page test for "Special:Prefixindex".
1024 class prefixindexTest extends pageTest {
1025 function __construct() {
1026 $this->pagePath = "index.php?title=Special:Prefixindex";
1028 $this->params = array (
1029 "title" => "Special:Prefixindex",
1030 "namespace" => wikiFuzz::randnum( -10, 101 ),
1031 "Go" => wikiFuzz::makeFuzz( 2 )
1034 // sometimes we want 'prefix', sometimes we want 'from', and sometimes we want nothing.
1035 if ( wikiFuzz::randnum( 3 ) == 0 ) {
1036 $this->params["prefix"] = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1",
1037 wikiFuzz::randnum( -10, 8134 ), wikiFuzz::makeFuzz( 2 ) ) );
1039 if ( wikiFuzz::randnum( 3 ) == 0 ) {
1040 $this->params["from"] = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1",
1041 wikiFuzz::randnum( -10, 8134 ), wikiFuzz::makeFuzz( 2 ) ) );
1048 ** a page test for "Special:MIMEsearch".
1050 class mimeSearchTest extends pageTest {
1051 function __construct() {
1052 $this->pagePath = "index.php?title=Special:MIMEsearch";
1054 $this->params = array (
1055 "action" => "index.php?title=Special:MIMEsearch",
1056 "mime" => wikiFuzz::makeFuzz( 3 ),
1057 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "-------'------0", "+1", "81342321351235325", wikiFuzz::makeFuzz( 2 ) ) ),
1058 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "-----'--------0", "+1", "81341231235365252234324", wikiFuzz::makeFuzz( 2 ) ) )
1065 ** a page test for "Special:Log".
1067 class specialLogTest extends pageTest {
1068 function __construct() {
1069 $this->pagePath = "index.php?title=Special:Log";
1071 $this->params = array (
1072 "type" => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
1073 "par" => wikiFuzz::makeFuzz( 2 ),
1074 "user" => wikiFuzz::makeFuzz( 2 ),
1075 "page" => wikiFuzz::makeFuzz( 2 ),
1076 "from" => wikiFuzz::makeFuzz( 2 ),
1077 "until" => wikiFuzz::makeFuzz( 2 ),
1078 "title" => wikiFuzz::makeFuzz( 2 )
1085 ** a page test for "Special:Userlogin", with a successful login.
1087 class successfulUserLoginTest extends pageTest {
1088 function __construct() {
1089 $this->pagePath = "index.php?title=Special:Userlogin&action=submitlogin&type=login&returnto=" . wikiFuzz::makeFuzz( 2 );
1091 $this->params = array (
1092 "wpName" => USER_ON_WIKI,
1093 // sometimes real password, sometimes not:
1094 'wpPassword' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), USER_PASSWORD ) ),
1095 'wpRemember' => wikiFuzz::makeFuzz( 2 )
1098 $this->cookie = "wikidb_session=" . wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) );
1104 ** a page test for "Special:Userlogin".
1106 class userLoginTest extends pageTest {
1107 function __construct() {
1109 $this->pagePath = "index.php?title=Special:Userlogin";
1111 $this->params = array (
1112 'wpRetype' => wikiFuzz::makeFuzz( 2 ),
1113 'wpRemember' => wikiFuzz::makeFuzz( 2 ),
1114 'wpRealName' => wikiFuzz::makeFuzz( 2 ),
1115 'wpPassword' => wikiFuzz::makeFuzz( 2 ),
1116 'wpName' => wikiFuzz::makeFuzz( 2 ),
1117 'wpMailmypassword' => wikiFuzz::makeFuzz( 2 ),
1118 'wpLoginattempt' => wikiFuzz::makeFuzz( 2 ),
1119 'wpEmail' => wikiFuzz::makeFuzz( 2 ),
1120 'wpDomain' => wikiFuzz::chooseInput( array( "", "local", wikiFuzz::makeFuzz( 2 ) ) ),
1121 'wpCreateaccountMail' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
1122 'wpCreateaccount' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
1123 'wpCookieCheck' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
1124 'type' => wikiFuzz::chooseInput( array( "signup", "login", "", wikiFuzz::makeFuzz( 2 ) ) ),
1125 'returnto' => wikiFuzz::makeFuzz( 2 ),
1126 'action' => wikiFuzz::chooseInput( array( "", "submitlogin", wikiFuzz::makeFuzz( 2 ) ) )
1129 $this->cookie = "wikidb_session=" . wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) );
1135 ** a page test for "Special:Ipblocklist" (also includes unblocking)
1137 class ipblocklistTest extends pageTest {
1138 function __construct() {
1139 $this->pagePath = "index.php?title=Special:Ipblocklist";
1141 $this->params = array (
1142 'wpUnblockAddress' => wikiFuzz::makeFuzz( 2 ),
1143 'ip' => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
1144 // something like an IP address, sometimes invalid:
1145 ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
1146 . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
1147 'id' => wikiFuzz::makeFuzz( 2 ),
1148 'wpUnblockReason' => wikiFuzz::makeFuzz( 2 ),
1149 'action' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "success", "submit", "unblock" ) ),
1150 'wpEditToken' => wikiFuzz::makeFuzz( 2 ),
1151 'wpBlock' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "" ) ),
1152 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1",
1153 "09700982312351132098234", wikiFuzz::makeFuzz( 2 ) ) ),
1154 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1",
1155 "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) )
1158 // sometimes we don't want to specify certain parameters.
1159 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
1160 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["ip"] );
1161 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["id"] );
1162 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpUnblockAddress"] );
1168 ** a page test for "Special:Newimages".
1170 class newImagesTest extends pageTest {
1171 function __construct() {
1172 $this->pagePath = "index.php?title=Special:Newimages";
1174 $this->params = array (
1175 'hidebots' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "1", "", "-1" ) ),
1176 'wpIlMatch' => wikiFuzz::makeFuzz( 2 ),
1177 'until' => wikiFuzz::makeFuzz( 2 ),
1178 'from' => wikiFuzz::makeFuzz( 2 )
1181 // sometimes we don't want to specify certain parameters.
1182 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["until"] );
1183 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["from"] );
1189 ** a page test for the "Special:Imagelist" page.
1191 class imagelistTest extends pageTest {
1192 function __construct() {
1193 $this->pagePath = "index.php?title=Special:Imagelist";
1195 $this->params = array (
1196 'sort' => wikiFuzz::chooseInput( array( "bysize", "byname" , "bydate", wikiFuzz::makeFuzz( 2 ) ) ),
1197 'limit' => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "09700982312351132098234", wikiFuzz::makeFuzz( 2 ) ) ),
1198 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ),
1199 'wpIlMatch' => wikiFuzz::makeFuzz( 2 )
1206 ** a page test for "Special:Export".
1208 class specialExportTest extends pageTest {
1209 function __construct() {
1210 $this->pagePath = "index.php?title=Special:Export";
1212 $this->params = array (
1213 'action' => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
1214 'pages' => wikiFuzz::makeFuzz( 2 ),
1215 'curonly' => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ),
1216 'listauthors' => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ),
1217 'history' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ),
1221 // For the time being, need to disable "submit" action as Tidy barfs on MediaWiki's XML export.
1222 if ( $this->params['action'] == 'submit' ) $this->params['action'] = '';
1224 // Sometimes remove the history field.
1225 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["history"] );
1227 // page does not produce HTML.
1228 $this->tidyValidate = false;
1234 ** a page test for "Special:Booksources".
1236 class specialBooksourcesTest extends pageTest {
1237 function __construct() {
1238 $this->pagePath = "index.php?title=Special:Booksources";
1240 $this->params = array (
1241 'go' => wikiFuzz::makeFuzz( 2 ),
1242 // ISBN codes have to contain some semi-numeric stuff or will be ignored:
1243 'isbn' => "0X0" . wikiFuzz::makeFuzz( 2 )
1250 ** a page test for "Special:Allpages".
1252 class specialAllpagesTest extends pageTest {
1253 function __construct() {
1254 $this->pagePath = "index.php?title=Special%3AAllpages";
1256 $this->params = array (
1257 'from' => wikiFuzz::makeFuzz( 2 ),
1258 'namespace' => wikiFuzz::chooseInput( range( -1, 15 ) ),
1259 'go' => wikiFuzz::makeFuzz( 2 )
1266 ** a page test for the page History.
1268 class pageHistoryTest extends pageTest {
1269 function __construct() {
1270 $this->pagePath = "index.php?title=Main_Page&action=history";
1272 $this->params = array (
1273 'limit' => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1274 'offset' => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ),
1275 "go" => wikiFuzz::chooseInput( array( "first", "last", wikiFuzz::makeFuzz( 2 ) ) ),
1276 "dir" => wikiFuzz::chooseInput( array( "prev", "next", wikiFuzz::makeFuzz( 2 ) ) ),
1277 "diff" => wikiFuzz::chooseInput( array( "-1", "--------'-----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1278 "oldid" => wikiFuzz::chooseInput( array( "prev", "-1", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1279 "feed" => wikiFuzz::makeFuzz( 2 )
1286 ** a page test for the Special:Contributions".
1288 class contributionsTest extends pageTest {
1289 function __construct() {
1290 $this->pagePath = "index.php?title=Special:Contributions/" . USER_ON_WIKI;
1292 $this->params = array (
1293 'target' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "newbies", USER_ON_WIKI ) ),
1294 'namespace' => wikiFuzz::chooseInput( array( -1, 15, 1, wikiFuzz::makeFuzz( 2 ) ) ),
1295 'offset' => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "982342131232131231241", wikiFuzz::makeFuzz( 2 ) ) ),
1296 'bot' => wikiFuzz::chooseInput( array( "", "-1", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1297 'go' => wikiFuzz::chooseInput( array( "-1", 'prev', 'next', wikiFuzz::makeFuzz( 2 ) ) )
1304 ** a page test for viewing a normal page, whilst posting various params.
1306 class viewPageTest extends pageTest {
1307 function __construct() {
1308 $this->pagePath = "index.php?title=Main_Page";
1310 $this->params = array (
1311 "useskin" => wikiFuzz::chooseInput( array( "chick", "cologneblue", "myskin",
1312 "nostalgia", "simple", "standard", wikiFuzz::makeFuzz( 2 ) ) ),
1313 "uselang" => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ),
1314 "ab", "af", "an", "ar", "arc", "as", "ast", "av", "ay", "az", "ba",
1315 "bat-smg", "be", "bg", "bm", "bn", "bo", "bpy", "br", "bs", "ca",
1316 "ce", "cs", "csb", "cv", "cy", "da", "de", "dv", "dz", "el", "en",
1317 "eo", "es", "et", "eu", "fa", "fi", "fo", "fr", "fur", "fy", "ga",
1318 "gn", "gsw", "gu", "he", "hi", "hr", "hu", "ia", "id", "ii", "is",
1319 "it", "ja", "jv", "ka", "km", "kn", "ko", "ks", "ku", "kv", "la",
1320 "li", "lo", "lt", "lv", "mk", "ml", "ms", "nah", "nap", "nds",
1321 "nds-nl", "nl", "nn", "no", "non", "nv", "oc", "or", "os", "pa",
1322 "pl", "pms", "ps", "pt", "pt-br", "qu", "rmy", "ro", "ru", "sc",
1323 "sd", "sk", "sl", "sq", "sr", "sr-ec", "sr-el",
1324 "su", "sv", "ta", "te", "th", "tr", "tt", "ty", "tyv", "udm",
1325 "ug", "uk", "ur", "utf8", "vec", "vi", "wa", "xal", "yi", "za",
1326 "zh", "zh-cn", "zh-hk", "zh-sg", "zh-tw", "zh-tw" ) ),
1327 "returnto" => wikiFuzz::makeFuzz( 2 ),
1328 "feed" => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ),
1329 "rcid" => wikiFuzz::makeFuzz( 2 ),
1330 "action" => wikiFuzz::chooseInput( array( "view", "raw", "render", wikiFuzz::makeFuzz( 2 ), "markpatrolled" ) ),
1331 "printable" => wikiFuzz::makeFuzz( 2 ),
1332 "oldid" => wikiFuzz::makeFuzz( 2 ),
1333 "redirect" => wikiFuzz::makeFuzz( 2 ),
1334 "diff" => wikiFuzz::makeFuzz( 2 ),
1335 "search" => wikiFuzz::makeFuzz( 2 ),
1336 "rdfrom" => wikiFuzz::makeFuzz( 2 ), // things from Article.php from here on:
1337 "token" => wikiFuzz::makeFuzz( 2 ),
1338 "tbid" => wikiFuzz::makeFuzz( 2 ),
1339 "action" => wikiFuzz::chooseInput( array( "purge", wikiFuzz::makeFuzz( 2 ) ) ),
1340 "wpReason" => wikiFuzz::makeFuzz( 2 ),
1341 "wpEditToken" => wikiFuzz::makeFuzz( 2 ),
1342 "from" => wikiFuzz::makeFuzz( 2 ),
1343 "bot" => wikiFuzz::makeFuzz( 2 ),
1344 "summary" => wikiFuzz::makeFuzz( 2 ),
1345 "direction" => wikiFuzz::chooseInput( array( "next", "prev", wikiFuzz::makeFuzz( 2 ) ) ),
1346 "section" => wikiFuzz::makeFuzz( 2 ),
1347 "preload" => wikiFuzz::makeFuzz( 2 ),
1351 // Tidy does not know how to valid atom or rss, so exclude from testing for the time being.
1352 if ( $this->params["feed"] == "atom" ) { unset( $this->params["feed"] ); }
1353 else if ( $this->params["feed"] == "rss" ) { unset( $this->params["feed"] ); }
1355 // Raw pages cannot really be validated
1356 if ( $this->params["action"] == "raw" ) unset( $this->params["action"] );
1358 // sometimes we don't want to specify certain parameters.
1359 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["rcid"] );
1360 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["diff"] );
1361 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["rdfrom"] );
1362 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["oldid"] );
1364 // usually don't want action == purge.
1365 if ( wikiFuzz::randnum( 6 ) > 1 ) unset( $this->params["action"] );
1371 ** a page test for "Special:Allmessages".
1373 class specialAllmessagesTest extends pageTest {
1374 function __construct() {
1375 $this->pagePath = "index.php?title=Special:Allmessages";
1377 // only really has one parameter
1378 $this->params = array (
1379 "ot" => wikiFuzz::chooseInput( array( "php", "html", wikiFuzz::makeFuzz( 2 ) ) )
1385 ** a page test for "Special:Newpages".
1387 class specialNewpages extends pageTest {
1388 function __construct() {
1389 $this->pagePath = "index.php?title=Special:Newpages";
1391 $this->params = array (
1392 "namespace" => wikiFuzz::chooseInput( range( -1, 15 ) ),
1393 "feed" => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ),
1394 'limit' => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
1395 'offset' => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) )
1398 // Tidy does not know how to valid atom or rss, so exclude from testing for the time being.
1399 if ( $this->params["feed"] == "atom" ) { unset( $this->params["feed"] ); }
1400 else if ( $this->params["feed"] == "rss" ) { unset( $this->params["feed"] ); }
1405 ** a page test for "redirect.php"
1407 class redirectTest extends pageTest {
1408 function __construct() {
1409 $this->pagePath = "redirect.php";
1411 $this->params = array (
1412 "wpDropdown" => wikiFuzz::makeFuzz( 2 )
1415 // sometimes we don't want to specify certain parameters.
1416 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpDropdown"] );
1422 ** a page test for "Special:Confirmemail"
1424 class confirmEmail extends pageTest {
1425 function __construct() {
1426 // sometimes we send a bogus confirmation code, and sometimes we don't.
1427 $this->pagePath = "index.php?title=Special:Confirmemail" . wikiFuzz::chooseInput( array( "", "/" . wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 1 ) ) ) );
1429 $this->params = array (
1430 "token" => wikiFuzz::makeFuzz( 2 )
1437 ** a page test for "Special:Watchlist"
1438 ** Note: this test would be better if we were logged in.
1440 class watchlistTest extends pageTest {
1441 function __construct() {
1442 $this->pagePath = "index.php?title=Special:Watchlist";
1444 $this->params = array (
1445 "remove" => wikiFuzz::chooseInput( array( "Remove checked items from watchlist", wikiFuzz::makeFuzz( 2 ) ) ),
1446 'days' => wikiFuzz::chooseInput( array( 0, -1, -230, "--", 3, 9, wikiFuzz::makeFuzz( 2 ) ) ),
1447 'hideOwn' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1448 'hideBots' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1449 'namespace' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1450 'action' => wikiFuzz::chooseInput( array( "submit", "clear", wikiFuzz::makeFuzz( 2 ) ) ),
1451 'id[]' => wikiFuzz::makeFuzz( 2 ),
1452 'edit' => wikiFuzz::makeFuzz( 2 ),
1453 'token' => wikiFuzz::chooseInput( array( "", "1243213", wikiFuzz::makeFuzz( 2 ) ) )
1456 // sometimes we specifiy "reset", and sometimes we don't.
1457 if ( wikiFuzz::randnum( 3 ) == 0 ) $this->params["reset"] = wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) );
1463 ** a page test for "Special:Blockme"
1465 class specialBlockmeTest extends pageTest {
1466 function __construct() {
1467 $this->pagePath = "index.php?title=Special:Blockme";
1469 $this->params = array ( );
1471 // sometimes we specify "ip", and sometimes we don't.
1472 if ( wikiFuzz::randnum( 1 ) == 0 ) {
1473 $this->params["ip"] = wikiFuzz::chooseInput( array( "10.12.41.213", wikiFuzz::randnum( -10, 8134 ), wikiFuzz::makeFuzz( 2 ) ) );
1480 ** a page test for "Special:Movepage"
1482 class specialMovePage extends pageTest {
1483 function __construct() {
1484 $this->pagePath = "index.php?title=Special:Movepage";
1486 $this->params = array (
1487 "action" => wikiFuzz::chooseInput( array( "success", "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
1488 'wpEditToken' => wikiFuzz::chooseInput( array( '', 0, 34987987, wikiFuzz::makeFuzz( 2 ) ) ),
1489 'target' => wikiFuzz::chooseInput( array( "x", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ) ) ),
1490 'wpOldTitle' => wikiFuzz::chooseInput( array( "z", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ), wikiFuzz::makeFuzz( 2 ) ) ),
1491 'wpNewTitle' => wikiFuzz::chooseInput( array( "y", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ), wikiFuzz::makeFuzz( 2 ) ) ),
1492 'wpReason' => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ) ) ),
1493 'wpMovetalk' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1494 'wpDeleteAndMove' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1495 'wpConfirm' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1496 'talkmoved' => wikiFuzz::chooseInput( array( "1", wikiFuzz::makeFuzz( 2 ), "articleexists", 'notalkpage' ) ),
1497 'oldtitle' => wikiFuzz::makeFuzz( 2 ),
1498 'newtitle' => wikiFuzz::makeFuzz( 2 ),
1499 'wpMovetalk' => wikiFuzz::chooseInput( array( "1", "0", wikiFuzz::makeFuzz( 2 ) ) )
1502 // sometimes we don't want to specify certain parameters.
1503 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["wpEditToken"] );
1504 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["target"] );
1505 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpNewTitle"] );
1506 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpReason"] );
1507 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpOldTitle"] );
1513 ** a page test for "Special:Undelete"
1515 class specialUndelete extends pageTest {
1516 function __construct() {
1517 $this->pagePath = "index.php?title=Special:Undelete";
1519 $this->params = array (
1520 "action" => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
1521 'wpEditToken' => wikiFuzz::chooseInput( array( '', 0, 34987987, wikiFuzz::makeFuzz( 2 ) ) ),
1522 'target' => wikiFuzz::chooseInput( array( "x", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ) ) ),
1523 'timestamp' => wikiFuzz::chooseInput( array( "125223", wikiFuzz::makeFuzz( 2 ) ) ),
1524 'file' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1525 'restore' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1526 'preview' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
1527 'wpComment' => wikiFuzz::makeFuzz( 2 )
1530 // sometimes we don't want to specify certain parameters.
1531 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["wpEditToken"] );
1532 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["target"] );
1533 if ( wikiFuzz::randnum( 1 ) == 0 ) unset( $this->params["restore"] );
1534 if ( wikiFuzz::randnum( 1 ) == 0 ) unset( $this->params["preview"] );
1540 ** a page test for "Special:Unlockdb"
1542 class specialUnlockdb extends pageTest {
1543 function __construct() {
1544 $this->pagePath = "index.php?title=Special:Unlockdb";
1546 $this->params = array (
1547 "action" => wikiFuzz::chooseInput( array( "submit", "success", "", wikiFuzz::makeFuzz( 2 ) ) ),
1548 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1549 'wpLockConfirm' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) )
1552 // sometimes we don't want to specify certain parameters.
1553 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpEditToken"] );
1554 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
1555 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpLockConfirm"] );
1561 ** a page test for "Special:Lockdb"
1563 class specialLockdb extends pageTest {
1564 function __construct() {
1565 $this->pagePath = "index.php?title=Special:Lockdb";
1567 $this->params = array (
1568 "action" => wikiFuzz::chooseInput( array( "submit", "success", "", wikiFuzz::makeFuzz( 2 ) ) ),
1569 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1570 'wpLockReason' => wikiFuzz::makeFuzz( 2 ),
1571 'wpLockConfirm' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
1574 // sometimes we don't want to specify certain parameters.
1575 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpEditToken"] );
1576 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
1577 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpLockConfirm"] );
1583 ** a page test for "Special:Userrights"
1585 class specialUserrights extends pageTest {
1586 function __construct() {
1587 $this->pagePath = "index.php?title=Special:Userrights";
1589 $this->params = array (
1590 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1591 'user-editname' => wikiFuzz::chooseInput( array( "Nickj2", "Nickj2\n<xyz>", wikiFuzz::makeFuzz( 2 ) ) ),
1592 'ssearchuser' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1593 'saveusergroups' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ), "Save User Groups" ),
1594 'member[]' => wikiFuzz::chooseInput( array( "0", "bot", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1595 "available[]" => wikiFuzz::chooseInput( array( "0", "sysop", "bureaucrat", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
1598 // sometimes we don't want to specify certain parameters.
1599 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['ssearchuser'] );
1600 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['saveusergroups'] );
1606 ** a test for page protection and unprotection.
1608 class pageProtectionForm extends pageTest {
1609 function __construct() {
1610 $this->pagePath = "index.php?title=Main_Page";
1612 $this->params = array (
1613 "action" => "protect",
1614 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1615 "mwProtect-level-edit" => wikiFuzz::chooseInput( array( '', 'autoconfirmed', 'sysop', wikifuzz::makeFuzz( 2 ) ) ),
1616 "mwProtect-level-move" => wikiFuzz::chooseInput( array( '', 'autoconfirmed', 'sysop', wikifuzz::makeFuzz( 2 ) ) ),
1617 "mwProtectUnchained" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1618 'mwProtect-reason' => wikiFuzz::chooseInput( array( "because it was there", wikifuzz::makeFuzz( 2 ) ) )
1622 // sometimes we don't want to specify certain parameters.
1623 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["mwProtectUnchained"] );
1624 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['mwProtect-reason'] );
1630 ** a page test for "Special:Blockip".
1632 class specialBlockip extends pageTest {
1633 function __construct() {
1634 $this->pagePath = "index.php?title=Special:Blockip";
1636 $this->params = array (
1637 "action" => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
1638 'wpEditToken' => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1639 "wpBlockAddress" => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
1640 // something like an IP address, sometimes invalid:
1641 ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
1642 . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
1643 "ip" => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
1644 // something like an IP address, sometimes invalid:
1645 ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
1646 . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
1647 "wpBlockOther" => wikiFuzz::chooseInput( array( '', 'Nickj2', wikifuzz::makeFuzz( 2 ) ) ),
1648 "wpBlockExpiry" => wikiFuzz::chooseInput( array( "other", "2 hours", "1 day", "3 days", "1 week", "2 weeks",
1649 "1 month", "3 months", "6 months", "1 year", "infinite", wikiFuzz::makeFuzz( 2 ) ) ),
1650 "wpBlockReason" => wikiFuzz::chooseInput( array( "because it was there", wikifuzz::makeFuzz( 2 ) ) ),
1651 "wpAnonOnly" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1652 "wpCreateAccount" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1653 "wpBlock" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
1656 // sometimes we don't want to specify certain parameters.
1657 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockOther"] );
1658 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockExpiry"] );
1659 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockReason"] );
1660 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpAnonOnly"] );
1661 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpCreateAccount"] );
1662 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockAddress"] );
1663 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["ip"] );
1669 ** a test for the imagepage.
1671 class imagepageTest extends pageTest {
1672 function __construct() {
1673 $this->pagePath = "index.php?title=Image:Small-email.png";
1675 $this->params = array (
1676 "image" => wikiFuzz::chooseInput( array( "Small-email.png", wikifuzz::makeFuzz( 2 ) ) ),
1677 "wpReason" => wikifuzz::makeFuzz( 2 ),
1678 "oldimage" => wikiFuzz::chooseInput( array( "Small-email.png", wikifuzz::makeFuzz( 2 ) ) ),
1679 "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1682 // sometimes we don't want to specify certain parameters.
1683 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["image"] );
1684 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpReason"] );
1685 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldimage"] );
1686 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEditToken"] );
1692 ** a test for page deletion form.
1694 class pageDeletion extends pageTest {
1695 function __construct() {
1696 $this->pagePath = "index.php?title=Main_Page&action=delete";
1698 $this->params = array (
1699 "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1700 "wpReason" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1701 "wpConfirm" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1704 // sometimes we don't want to specify certain parameters.
1705 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpReason"] );
1706 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpEditToken"] );
1707 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpConfirm"] );
1714 ** a test for Revision Deletion.
1716 class specialRevisionDelete extends pageTest {
1717 function __construct() {
1718 $this->pagePath = "index.php?title=Special:Revisiondelete";
1720 $this->params = array (
1721 "target" => wikiFuzz::chooseInput( array( "Main Page", wikifuzz::makeFuzz( 2 ) ) ),
1722 "oldid" => wikifuzz::makeFuzz( 2 ),
1723 "oldid[]" => wikifuzz::makeFuzz( 2 ),
1724 "wpReason" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1725 "revdelete-hide-text" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1726 "revdelete-hide-comment" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1727 "revdelete-hide-user" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1728 "revdelete-hide-restricted" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1731 // sometimes we don't want to specify certain parameters.
1732 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["target"] );
1733 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldid"] );
1734 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldid[]"] );
1735 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpReason"] );
1736 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-text"] );
1737 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-comment"] );
1738 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-user"] );
1739 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-restricted"] );
1745 ** a test for Special:Import.
1747 class specialImport extends pageTest {
1748 function __construct() {
1749 $this->pagePath = "index.php?title=Special:Import";
1751 $this->params = array (
1752 "action" => "submit",
1753 "source" => wikiFuzz::chooseInput( array( "upload", "interwiki", wikifuzz::makeFuzz( 2 ) ) ),
1754 "MAX_FILE_SIZE" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikifuzz::makeFuzz( 2 ) ) ),
1755 "xmlimport" => wikiFuzz::chooseInput( array( "/var/www/hosts/mediawiki/wiki/AdminSettings.php", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
1756 "namespace" => wikiFuzz::chooseInput( array( wikiFuzz::randnum( 30, -6 ), wikiFuzz::makeFuzz( 2 ) ) ),
1757 "interwiki" => wikiFuzz::makeFuzz( 2 ),
1758 "interwikiHistory" => wikiFuzz::makeFuzz( 2 ),
1759 "frompage" => wikiFuzz::makeFuzz( 2 ),
1762 // sometimes we don't want to specify certain parameters.
1763 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["action"] );
1764 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["source"] );
1765 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["MAX_FILE_SIZE"] );
1766 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["xmlimport"] );
1767 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["interwiki"] );
1768 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["interwikiHistory"] );
1769 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["frompage"] );
1771 // Note: Need to do a file upload to fully test this Special page.
1777 ** a test for thumb.php
1779 class thumbTest extends pageTest {
1780 function __construct() {
1781 $this->pagePath = "thumb.php";
1783 $this->params = array (
1784 "f" => wikiFuzz::chooseInput( array( "..", "\\", "small-email.png", wikifuzz::makeFuzz( 2 ) ) ),
1785 "w" => wikiFuzz::chooseInput( array( "80", wikiFuzz::randnum( 6000, -200 ), wikifuzz::makeFuzz( 2 ) ) ),
1786 "r" => wikiFuzz::chooseInput( array( "0", wikifuzz::makeFuzz( 2 ) ) ),
1789 // sometimes we don't want to specify certain parameters.
1790 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["f"] );
1791 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["w"] );
1792 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["r"] );
1798 ** a test for trackback.php
1800 class trackbackTest extends pageTest {
1801 function __construct() {
1802 $this->pagePath = "trackback.php";
1804 $this->params = array (
1805 "url" => wikifuzz::makeFuzz( 2 ),
1806 "blog_name" => wikiFuzz::chooseInput( array( "80", wikiFuzz::randnum( 6000, -200 ), wikifuzz::makeFuzz( 2 ) ) ),
1807 "article" => wikiFuzz::chooseInput( array( "Main Page", wikifuzz::makeFuzz( 2 ) ) ),
1808 "title" => wikiFuzz::chooseInput( array( "Main Page", wikifuzz::makeFuzz( 2 ) ) ),
1809 "excerpt" => wikifuzz::makeFuzz( 2 ),
1812 // sometimes we don't want to specify certain parameters.
1813 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["title"] );
1814 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["excerpt"] );
1816 // page does not produce HTML.
1817 $this->tidyValidate = false;
1823 ** a test for profileinfo.php
1825 class profileInfo extends pageTest {
1826 function __construct() {
1827 $this->pagePath = "profileinfo.php";
1829 $this->params = array (
1830 "expand" => wikifuzz::makeFuzz( 2 ),
1831 "sort" => wikiFuzz::chooseInput( array( "time", "count", "name", wikifuzz::makeFuzz( 2 ) ) ),
1832 "filter" => wikiFuzz::chooseInput( array( "Main Page", wikifuzz::makeFuzz( 2 ) ) ),
1835 // sometimes we don't want to specify certain parameters.
1836 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["sort"] );
1837 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["filter"] );
1843 ** a test for Special:Cite (extension Special page).
1845 class specialCite extends pageTest {
1846 function __construct() {
1847 $this->pagePath = "index.php?title=Special:Cite";
1849 $this->params = array (
1850 "page" => wikiFuzz::chooseInput( array( "\" onmouseover=\"alert(1);\"", "Main Page", wikifuzz::makeFuzz( 2 ) ) ),
1851 "id" => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "-9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ),
1854 // sometimes we don't want to specify certain parameters.
1855 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["page"] );
1856 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["id"] );
1862 ** a test for Special:Filepath (extension Special page).
1864 class specialFilepath extends pageTest {
1865 function __construct() {
1866 $this->pagePath = "index.php?title=Special:Filepath";
1868 $this->params = array (
1869 "file" => wikiFuzz::chooseInput( array( "Small-email.png", "Small-email.png" . wikifuzz::makeFuzz( 1 ), wikiFuzz::makeFuzz( 2 ) ) ),
1876 ** a test for Special:Makebot (extension Special page).
1878 class specialMakebot extends pageTest {
1879 function __construct() {
1880 $this->pagePath = "index.php?title=Special:Makebot";
1882 $this->params = array (
1883 "username" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikifuzz::makeFuzz( 1 ) ) ),
1884 "dosearch" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikifuzz::makeFuzz( 2 ) ) ),
1885 "grant" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikifuzz::makeFuzz( 2 ) ) ),
1886 "comment" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1887 "token" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1890 // sometimes we don't want to specify certain parameters.
1891 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["dosearch"] );
1892 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["grant"] );
1893 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["token"] );
1899 ** a test for Special:Makesysop (extension Special page).
1901 class specialMakesysop extends pageTest {
1902 function __construct() {
1903 $this->pagePath = "index.php?title=Special:Makesysop";
1905 $this->params = array (
1906 "wpMakesysopUser" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikifuzz::makeFuzz( 1 ) ) ),
1907 "action" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikifuzz::makeFuzz( 2 ) ) ),
1908 "wpMakesysopSubmit" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikifuzz::makeFuzz( 2 ) ) ),
1909 "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1910 "wpSetBureaucrat" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1913 // sometimes we don't want to specify certain parameters.
1914 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpMakesysopSubmit"] );
1915 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpEditToken"] );
1916 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpSetBureaucrat"] );
1922 ** a test for Special:Renameuser (extension Special page).
1924 class specialRenameuser extends pageTest {
1925 function __construct() {
1926 $this->pagePath = "index.php?title=Special:Renameuser";
1928 $this->params = array (
1929 "oldusername" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikifuzz::makeFuzz( 1 ) ) ),
1930 "newusername" => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikifuzz::makeFuzz( 1 ) ) ),
1931 "token" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
1938 ** a test for Special:Linksearch (extension Special page).
1940 class specialLinksearch extends pageTest {
1941 function __construct() {
1942 $this->pagePath = "index.php?title=Special%3ALinksearch";
1944 $this->params = array (
1945 "target" => wikifuzz::makeFuzz( 2 ),
1948 // sometimes we don't want to specify certain parameters.
1949 if ( wikiFuzz::randnum( 10 ) == 0 ) unset( $this->params["target"] );
1955 ** a test for Special:CategoryTree (extension Special page).
1957 class specialCategoryTree extends pageTest {
1958 function __construct() {
1959 $this->pagePath = "index.php?title=Special:CategoryTree";
1961 $this->params = array (
1962 "target" => wikifuzz::makeFuzz( 2 ),
1963 "from" => wikifuzz::makeFuzz( 2 ),
1964 "until" => wikifuzz::makeFuzz( 2 ),
1965 "showas" => wikifuzz::makeFuzz( 2 ),
1966 "mode" => wikiFuzz::chooseInput( array( "pages", "categories", "all", wikifuzz::makeFuzz( 2 ) ) ),
1969 // sometimes we do want to specify certain parameters.
1970 if ( wikiFuzz::randnum( 5 ) == 0 ) $this->params["notree"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
1976 ** a test for "Special:Chemicalsources" (extension Special page).
1978 class specialChemicalsourcesTest extends pageTest {
1979 function __construct() {
1980 $this->pagePath = "index.php?title=Special:Chemicalsources";
1982 // choose an input format to use.
1983 $format = wikiFuzz::chooseInput(
1984 array( 'go',
1985 'CAS',
1986 'EINECS',
1987 'CHEBI',
1988 'PubChem',
1989 'SMILES',
1990 'InChI',
1991 'ATCCode',
1992 'KEGG',
1993 'RTECS',
1994 'ECNumber',
1995 'DrugBank',
1996 'Formula',
1997 'Name'
2001 // values for different formats usually start with either letters or numbers.
2002 switch ( $format ) {
2003 case 'Name' : $value = "A"; break;
2004 case 'InChI' :
2005 case 'SMILES' :
2006 case 'Formula': $value = "C"; break;
2007 default : $value = "0"; break;
2010 // and then we append the fuzz input.
2011 $this->params = array ( $format => $value . wikifuzz::makeFuzz( 2 ) );
2017 ** A test for api.php (programmatic interface to MediaWiki in XML/JSON/RSS/etc formats).
2018 ** Quite involved to test because there are lots of options/parameters, and because
2019 ** for a lot of the functionality if all the parameters don't make sense then it just
2020 ** returns the help screen - so currently a lot of the tests aren't actually doing much
2021 ** because something wasn't right in the query.
2023 ** @todo: Incomplete / unfinished; Runs too fast (suggests not much testing going on).
2025 class api extends pageTest {
2027 // API login mode.
2028 private static function loginMode() {
2029 $arr = array ( "lgname" => wikifuzz::makeFuzz( 2 ),
2030 "lgpassword" => wikifuzz::makeFuzz( 2 ),
2032 // sometimes we want to specify the extra "lgdomain" parameter.
2033 if ( wikiFuzz::randnum( 3 ) == 0 ) {
2034 $arr["lgdomain"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
2037 return $arr;
2040 // API OpenSearch mode.
2041 private static function opensearchMode() {
2042 return array ( "search" => wikifuzz::makeFuzz( 2 ) );
2045 // API watchlist feed mode.
2046 private static function feedwatchlistMode() {
2047 // FIXME: add "wikifuzz::makeFuzz(2)" as possible value below?
2048 return array ( "feedformat" => wikiFuzz::chooseInput( array( "rss", "atom" ) ) );
2051 // API query mode.
2052 private static function queryMode() {
2053 // FIXME: add "wikifuzz::makeFuzz(2)" as possible params for the elements below?
2054 // Suspect this will stuff up the tests more, but need to check.
2055 $params = array (
2056 // FIXME: More titles.
2057 "titles" => wikiFuzz::chooseInput( array( "Main Page" ) ),
2058 // FIXME: More pageids.
2059 "pageids" => 1,
2060 "prop" => wikiFuzz::chooseInput( array( "info", "revisions", "watchlist" ) ),
2061 "list" => wikiFuzz::chooseInput( array( "allpages", "logevents", "watchlist", "usercontribs", "recentchanges", "backlinks", "embeddedin", "imagelinks" ) ),
2062 "meta" => wikiFuzz::chooseInput( array( "siteinfo" ) ),
2063 "generator" => wikiFuzz::chooseInput( array( "allpages", "logevents", "watchlist", "info", "revisions" ) ),
2064 "siprop" => wikiFuzz::chooseInput( array( "general", "namespaces", "general|namespaces" ) ),
2067 // Add extra parameters based on what list choice we got.
2068 switch ( $params["list"] ) {
2069 case "usercontribs" : self::addListParams ( $params, "uc", array( "limit", "start", "end", "user", "dir" ) ); break;
2070 case "allpages" : self::addListParams ( $params, "ap", array( "from", "prefix", "namespace", "filterredir", "limit" ) ); break;
2071 case "watchlist" : self::addListParams ( $params, "wl", array( "allrev", "start", "end", "namespace", "dir", "limit", "prop" ) ); break;
2072 case "logevents" : self::addListParams ( $params, "le", array( "limit", "type", "start", "end", "user", "dir" ) ); break;
2073 case "recentchanges": self::addListParams ( $params, "rc", array( "limit", "prop", "show", "namespace", "start", "end", "dir" ) ); break;
2074 case "backlinks" : self::addListParams ( $params, "bl", array( "continue", "namespace", "redirect", "limit" ) ); break;
2075 case "embeddedin" : self::addListParams ( $params, "ei", array( "continue", "namespace", "redirect", "limit" ) ); break;
2076 case "imagelinks" : self::addListParams ( $params, "il", array( "continue", "namespace", "redirect", "limit" ) ); break;
2079 if ( $params["prop"] == "revisions" ) {
2080 self::addListParams ( $params, "rv", array( "prop", "limit", "startid", "endid", "end", "dir" ) );
2083 // Sometimes we want redirects, sometimes we don't.
2084 if ( wikiFuzz::randnum( 3 ) == 0 ) {
2085 $params["redirects"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
2088 return $params;
2091 // Adds all the elements to the array, using the specified prefix.
2092 private static function addListParams( &$array, $prefix, $elements ) {
2093 foreach ( $elements as $element ) {
2094 $array[$prefix . $element] = self::getParamDetails( $element );
2098 // For a given element name, returns the data for that element.
2099 private static function getParamDetails( $element ) {
2100 switch ( $element ) {
2101 case 'startid' :
2102 case 'endid' :
2103 case 'start' :
2104 case 'end' :
2105 case 'limit' : return wikiFuzz::chooseInput( array( "0", "-1", "---'----------0", "+1", "8134", "320742734234235", "20060230121212", wikiFuzz::randnum( 9000, -100 ), wikiFuzz::makeFuzz( 2 ) ) );
2106 case 'dir' : return wikiFuzz::chooseInput( array( "newer", "older", wikifuzz::makeFuzz( 2 ) ) );
2107 case 'user' : return wikiFuzz::chooseInput( array( USER_ON_WIKI, wikifuzz::makeFuzz( 2 ) ) );
2108 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 ) ) );
2109 case 'filterredir': return wikiFuzz::chooseInput( array( "all", "redirects", "nonredirectsallpages", wikifuzz::makeFuzz( 2 ) ) );
2110 case 'allrev' : return wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
2111 case 'prop' : return wikiFuzz::chooseInput( array( "user", "comment", "timestamp", "patrol", "flags", "user|user|comment|flags", wikifuzz::makeFuzz( 2 ) ) );
2112 case 'type' : return wikiFuzz::chooseInput( array( "block", "protect", "rights", "delete", "upload", "move", "import", "renameuser", "newusers", "makebot", wikifuzz::makeFuzz( 2 ) ) );
2113 case 'hide' : return wikiFuzz::chooseInput( array( "minor", "bots", "anons", "liu", "liu|bots|", wikifuzz::makeFuzz( 2 ) ) );
2114 case 'show' : return wikiFuzz::chooseInput( array( 'minor', '!minor', 'bot', '!bot', 'anon', '!anon', wikifuzz::makeFuzz( 2 ) ) );
2115 default : return wikifuzz::makeFuzz( 2 );
2119 // Entry point.
2120 function __construct() {
2121 $this->pagePath = "api.php";
2123 $modes = array ( "help",
2124 "login",
2125 "opensearch",
2126 "feedwatchlist",
2127 "query" );
2128 $action = wikiFuzz::chooseInput( array_merge ( $modes, array( wikifuzz::makeFuzz( 2 ) ) ) );
2130 switch ( $action ) {
2131 case "login" : $this->params = self::loginMode();
2132 break;
2133 case "opensearch" : $this->params = self::opensearchMode();
2134 break;
2135 case "feedwatchlist" : $this->params = self::feedwatchlistMode();
2136 break;
2137 case "query" : $this->params = self::queryMode();
2138 break;
2139 case "help" :
2140 default : // Do something random - "Crazy Ivan" mode.
2141 $random_mode = wikiFuzz::chooseInput( $modes ) . "Mode";
2142 // There is no "helpMode".
2143 if ( $random_mode == "helpMode" ) $random_mode = "queryMode";
2144 $this->params = self::$random_mode();
2145 break;
2148 // Save the selected action.
2149 $this->params["action"] = $action;
2151 // Set the cookie:
2152 // FIXME: need to get this cookie dynamically set, rather than hard-coded.
2153 $this->cookie = "wikidbUserID=10001; wikidbUserName=Test; wikidb_session=178df0fe68c75834643af65dec9ec98a; wikidbToken=1adc6753d62c44aec950c024d7ae0540";
2155 // Output format
2156 $this->params["format"] = wikiFuzz::chooseInput( array( "json", "jsonfm", "php", "phpfm",
2157 "wddx", "wddxfm", "xml", "xmlfm",
2158 "yaml", "yamlfm", "raw", "rawfm",
2159 wikifuzz::makeFuzz( 2 ) ) );
2161 // Page does not produce HTML (sometimes).
2162 $this->tidyValidate = false;
2168 ** a page test for the GeSHi extension.
2170 class GeSHi_Test extends pageTest {
2172 private function getGeSHiContent() {
2173 return "<source lang=\"" . $this->getLang() . "\" "
2174 . ( wikiFuzz::randnum( 2 ) == 0 ? "line " : "" )
2175 . ( wikiFuzz::randnum( 2 ) == 0 ? "strict " : "" )
2176 . "start=" . wikiFuzz::chooseInput( array( wikiFuzz::randnum( -6000, 6000 ), wikifuzz::makeFuzz( 2 ) ) )
2177 . ">"
2178 . wikiFuzz::makeFuzz( 2 )
2179 . "</source>";
2182 private function getLang() {
2183 return wikiFuzz::chooseInput( array( "actionscript", "ada", "apache", "applescript", "asm", "asp", "autoit", "bash", "blitzbasic", "bnf", "c", "c_mac", "caddcl", "cadlisp",
2184 "cfdg", "cfm", "cpp", "cpp-qt", "csharp", "css", "d", "delphi", "diff", "div", "dos", "eiffel", "fortran", "freebasic", "gml", "groovy", "html4strict", "idl",
2185 "ini", "inno", "io", "java", "java5", "javascript", "latex", "lisp", "lua", "matlab", "mirc", "mpasm", "mysql", "nsis", "objc", "ocaml", "ocaml-brief", "oobas",
2186 "oracle8", "pascal", "perl", "php", "php-brief", "plsql", "python", "qbasic", "rails", "reg", "robots", "ruby", "sas", "scheme", "sdlbasic", "smalltalk", "smarty",
2187 "sql", "tcl", "text", "thinbasic", "tsql", "vb", "vbnet", "vhdl", "visualfoxpro", "winbatch", "xml", "xpp", "z80", wikifuzz::makeFuzz( 1 ) ) );
2190 function __construct() {
2191 $this->pagePath = "index.php?title=WIKIFUZZ";
2193 $this->params = array (
2194 "action" => "submit",
2195 "wpMinoredit" => "test",
2196 "wpPreview" => "test",
2197 "wpSection" => "test",
2198 "wpEdittime" => "test",
2199 "wpSummary" => "test",
2200 "wpScrolltop" => "test",
2201 "wpStarttime" => "test",
2202 "wpAutoSummary" => "test",
2203 "wpTextbox1" => $this->getGeSHiContent() // the main wiki text, contains fake GeSHi content.
2210 ** selects a page test to run.
2212 function selectPageTest( $count ) {
2214 // if the user only wants a specific test, then only ever give them that.
2215 if ( defined( "SPECIFIC_TEST" ) ) {
2216 $testType = SPECIFIC_TEST;
2217 return new $testType ();
2220 // Some of the time we test Special pages, the remaining
2221 // time we test using the standard edit page.
2222 switch ( $count % 100 ) {
2223 case 0 : return new successfulUserLoginTest();
2224 case 1 : return new listusersTest();
2225 case 2 : return new searchTest();
2226 case 3 : return new recentchangesTest();
2227 case 4 : return new prefixindexTest();
2228 case 5 : return new mimeSearchTest();
2229 case 6 : return new specialLogTest();
2230 case 7 : return new userLoginTest();
2231 case 8 : return new ipblocklistTest();
2232 case 9 : return new newImagesTest();
2233 case 10: return new imagelistTest();
2234 case 11: return new specialExportTest();
2235 case 12: return new specialBooksourcesTest();
2236 case 13: return new specialAllpagesTest();
2237 case 14: return new pageHistoryTest();
2238 case 15: return new contributionsTest();
2239 case 16: return new viewPageTest();
2240 case 17: return new specialAllmessagesTest();
2241 case 18: return new specialNewpages();
2242 case 19: return new searchTest();
2243 case 20: return new redirectTest();
2244 case 21: return new confirmEmail();
2245 case 22: return new watchlistTest();
2246 case 23: return new specialBlockmeTest();
2247 case 24: return new specialUndelete();
2248 case 25: return new specialMovePage();
2249 case 26: return new specialUnlockdb();
2250 case 27: return new specialLockdb();
2251 case 28: return new specialUserrights();
2252 case 29: return new pageProtectionForm();
2253 case 30: return new specialBlockip();
2254 case 31: return new imagepageTest();
2255 case 32: return new pageDeletion();
2256 case 33: return new specialRevisionDelete();
2257 case 34: return new specialImport();
2258 case 35: return new thumbTest();
2259 case 36: return new trackbackTest();
2260 case 37: return new profileInfo();
2261 case 38: return new specialCite();
2262 case 39: return new specialFilepath();
2263 case 40: return new specialMakebot();
2264 case 41: return new specialMakesysop();
2265 case 42: return new specialRenameuser();
2266 case 43: return new specialLinksearch();
2267 case 44: return new specialCategoryTree();
2268 case 45: return new api();
2269 case 45: return new specialChemicalsourcesTest();
2270 default: return new editPageTest();
2275 // ///////////////////// SAVING OUTPUT /////////////////////////
2278 ** Utility function for saving a file. Currently has no error checking.
2280 function saveFile( $data, $name ) {
2281 file_put_contents( $name, $data );
2286 ** Returns a test as an experimental GET-to-POST URL.
2287 ** This doesn't seem to always work though, and sometimes the output is too long
2288 ** to be a valid GET URL, so we also save in other formats.
2290 function getAsURL( pageTest $test ) {
2291 $used_question_mark = ( strpos( $test->getPagePath(), "?" ) !== false );
2292 $retval = "http://get-to-post.nickj.org/?" . WIKI_BASE_URL . $test->getPagePath();
2293 foreach ( $test->getParams() as $param => $value ) {
2294 if ( !$used_question_mark ) {
2295 $retval .= "?";
2296 $used_question_mark = true;
2298 else {
2299 $retval .= "&";
2301 $retval .= $param . "=" . urlencode( $value );
2303 return $retval;
2308 ** Saves a plain-text human-readable version of a test.
2310 function saveTestAsText( pageTest $test, $filename ) {
2311 $str = "Test: " . $test->getPagePath();
2312 foreach ( $test->getParams() as $param => $value ) {
2313 $str .= "\n$param: $value";
2315 $str .= "\nGet-to-post URL: " . getAsURL( $test ) . "\n";
2316 saveFile( $str, $filename );
2321 ** Saves a test as a standalone basic PHP script that shows this one problem.
2322 ** Resulting script requires PHP-Curl be installed in order to work.
2324 function saveTestAsPHP( pageTest $test, $filename ) {
2325 $str = "<?php\n"
2326 . "\$params = " . var_export( escapeForCurl( $test->getParams() ), true ) . ";\n"
2327 . "\$ch = curl_init();\n"
2328 . "curl_setopt(\$ch, CURLOPT_POST, 1);\n"
2329 . "curl_setopt(\$ch, CURLOPT_POSTFIELDS, \$params );\n"
2330 . "curl_setopt(\$ch, CURLOPT_URL, " . var_export( WIKI_BASE_URL . $test->getPagePath(), true ) . ");\n"
2331 . "curl_setopt(\$ch, CURLOPT_RETURNTRANSFER,1);\n"
2332 . ( $test->getCookie() ? "curl_setopt(\$ch, CURLOPT_COOKIE, " . var_export( $test->getCookie(), true ) . ");\n" : "" )
2333 . "\$result=curl_exec(\$ch);\n"
2334 . "curl_close (\$ch);\n"
2335 . "print \$result;\n"
2336 . "?>\n";
2337 saveFile( $str, $filename );
2342 ** Escapes a value so that it can be used on the command line by Curl.
2343 ** Specifically, "<" and "@" need to be escaped if they are the first character,
2344 ** otherwise curl interprets these as meaning that we want to insert a file.
2346 function escapeForCurl( array $input_params ) {
2347 $output_params = array();
2348 foreach ( $input_params as $param => $value ) {
2349 if ( strlen( $value ) > 0 && ( $value[0] == "@" || $value[0] == "<" ) ) {
2350 $value = "\\" . $value;
2352 $output_params[$param] = $value;
2354 return $output_params;
2359 ** Saves a test as a standalone CURL shell script that shows this one problem.
2360 ** Resulting script requires standalone Curl be installed in order to work.
2362 function saveTestAsCurl( pageTest $test, $filename ) {
2363 $str = "#!/bin/bash\n"
2364 . "curl --silent --include --globoff \\\n"
2365 . ( $test->getCookie() ? " --cookie " . escapeshellarg( $test->getCookie() ) . " \\\n" : "" );
2366 foreach ( escapeForCurl( $test->getParams() ) as $param => $value ) {
2367 $str .= " -F " . escapeshellarg( $param ) . "=" . escapeshellarg( $value ) . " \\\n";
2369 $str .= " " . escapeshellarg( WIKI_BASE_URL . $test->getPagePath() ); // beginning space matters.
2370 $str .= "\n";
2371 saveFile( $str, $filename );
2372 chmod( $filename, 0755 ); // make executable
2377 ** Saves the internal data structure to file.
2379 function saveTestData ( pageTest $test, $filename ) {
2380 saveFile( serialize( $test ), $filename );
2385 ** saves a test in the various formats.
2387 function saveTest( pageTest $test, $testname ) {
2388 $base_name = DIRECTORY . "/" . $testname;
2389 saveTestAsText( $test, $base_name . INFO_FILE );
2390 saveTestAsPHP ( $test, $base_name . PHP_TEST );
2391 saveTestAsCurl( $test, $base_name . CURL_TEST );
2392 saveTestData ( $test, $base_name . DATA_FILE );
2396 // ////////////////// MEDIAWIKI OUTPUT /////////////////////////
2399 ** Asks MediaWiki for the HTML output of a test.
2401 function wikiTestOutput( pageTest $test ) {
2403 $ch = curl_init();
2405 // specify the cookie, if required.
2406 if ( $test->getCookie() ) curl_setopt( $ch, CURLOPT_COOKIE, $test->getCookie() );
2407 curl_setopt( $ch, CURLOPT_POST, 1 ); // save form using a POST
2409 $params = escapeForCurl( $test->getParams() );
2410 curl_setopt( $ch, CURLOPT_POSTFIELDS, $params ); // load the POST variables
2412 curl_setopt( $ch, CURLOPT_URL, WIKI_BASE_URL . $test->getPagePath() ); // set url to post to
2413 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); // return into a variable
2415 $result = curl_exec ( $ch );
2417 // if we encountered an error, then say so, and return an empty string.
2418 if ( curl_error( $ch ) ) {
2419 print "\nCurl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch );
2420 $result = "";
2423 curl_close ( $ch );
2425 return $result;
2429 // ////////////////// HTML VALIDATION /////////////////////////
2432 ** Asks the validator whether this is valid HTML, or not.
2434 function validateHTML( $text ) {
2436 $params = array ( "fragment" => $text );
2438 $ch = curl_init();
2440 curl_setopt( $ch, CURLOPT_POST, 1 ); // save form using a POST
2441 curl_setopt( $ch, CURLOPT_POSTFIELDS, $params ); // load the POST variables
2442 curl_setopt( $ch, CURLOPT_URL, VALIDATOR_URL ); // set url to post to
2443 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 ); // return into a variable
2445 $result = curl_exec ( $ch );
2447 // if we encountered an error, then log it, and exit.
2448 if ( curl_error( $ch ) ) {
2449 trigger_error( "Curl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ) );
2450 print "Curl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ) . " - exiting.\n";
2451 exit( 1 );
2454 curl_close ( $ch );
2456 $valid = ( strpos( $result, "Failed validation" ) === false ? true : false );
2458 return array( $valid, $result );
2463 ** Get tidy to check for no HTML errors in the output file (e.g. unescaped strings).
2465 function tidyCheckFile( $name ) {
2466 $file = DIRECTORY . "/" . $name;
2467 $command = PATH_TO_TIDY . " -output /tmp/out.html -quiet $file 2>&1";
2468 $x = `$command`;
2470 // Look for the most interesting Tidy errors and warnings.
2471 if ( strpos( $x, "end of file while parsing attributes" ) !== false
2472 || strpos( $x, "attribute with missing trailing quote mark" ) !== false
2473 || strpos( $x, "missing '>' for end of tag" ) !== false
2474 || strpos( $x, "Error:" ) !== false ) {
2475 print "\nTidy found something - view details with: $command";
2476 return false;
2477 } else {
2478 return true;
2484 ** Returns whether or not an database error log file has changed in size since
2485 ** the last time this was run. This is used to tell if a test caused a DB error.
2487 function dbErrorLogged() {
2488 static $filesize;
2490 // first time running this function
2491 if ( !isset( $filesize ) ) {
2492 // create log if it does not exist
2493 if ( !file_exists( DB_ERROR_LOG_FILE ) ) {
2494 saveFile( "", DB_ERROR_LOG_FILE );
2496 $filesize = filesize( DB_ERROR_LOG_FILE );
2497 return false;
2500 $newsize = filesize( DB_ERROR_LOG_FILE );
2501 // if the log has grown, then assume the current test caused it.
2502 if ( $newsize != $filesize ) {
2503 $filesize = $newsize;
2504 return true;
2507 return false;
2510 // //////////////// TOP-LEVEL PROBLEM-FINDING FUNCTION ////////////////////////
2513 ** takes a page test, and runs it and tests it for problems in the output.
2514 ** Returns: False on finding a problem, or True on no problems being found.
2516 function runWikiTest( pageTest $test, &$testname, $can_overwrite = false ) {
2518 // by default don't overwrite a previous test of the same name.
2519 while ( ! $can_overwrite && file_exists( DIRECTORY . "/" . $testname . DATA_FILE ) ) {
2520 $testname .= "-" . mt_rand( 0, 9 );
2523 $filename = DIRECTORY . "/" . $testname . DATA_FILE;
2525 // Store the time before and after, to find slow pages.
2526 $before = microtime( true );
2528 // Get MediaWiki to give us the output of this test.
2529 $wiki_preview = wikiTestOutput( $test );
2531 $after = microtime( true );
2533 // if we received no response, then that's interesting.
2534 if ( $wiki_preview == "" ) {
2535 print "\nNo response received for: $filename";
2536 return false;
2539 // save output HTML to file.
2540 $html_file = DIRECTORY . "/" . $testname . HTML_FILE;
2541 saveFile( $wiki_preview, $html_file );
2543 // if there were PHP errors in the output, then that's interesting too.
2544 if ( strpos( $wiki_preview, "<b>Warning</b>: " ) !== false
2545 || strpos( $wiki_preview, "<b>Fatal error</b>: " ) !== false
2546 || strpos( $wiki_preview, "<b>Notice</b>: " ) !== false
2547 || strpos( $wiki_preview, "<b>Error</b>: " ) !== false
2548 || strpos( $wiki_preview, "<b>Strict Standards:</b>" ) !== false
2550 $error = substr( $wiki_preview, strpos( $wiki_preview, "</b>:" ) + 7, 50 );
2551 // Avoid probable PHP bug with bad session ids; http://bugs.php.net/bug.php?id=38224
2552 if ( $error != "Unknown: The session id contains illegal character" ) {
2553 print "\nPHP error/warning/notice in HTML output: $html_file ; $error";
2554 return false;
2558 // if there was a MediaWiki Backtrace message in the output, then that's also interesting.
2559 if ( strpos( $wiki_preview, "Backtrace:" ) !== false ) {
2560 print "\nInternal MediaWiki error in HTML output: $html_file";
2561 return false;
2564 // if there was a Parser error comment in the output, then that's potentially interesting.
2565 if ( strpos( $wiki_preview, "!-- ERR" ) !== false ) {
2566 print "\nParser Error comment in HTML output: $html_file";
2567 return false;
2570 // if a database error was logged, then that's definitely interesting.
2571 if ( dbErrorLogged() ) {
2572 print "\nDatabase Error logged for: $filename";
2573 return false;
2576 // validate result
2577 $valid = true;
2578 if ( VALIDATE_ON_WEB ) {
2579 list ( $valid, $validator_output ) = validateHTML( $wiki_preview );
2580 if ( !$valid ) print "\nW3C web validation failed - view details with: html2text " . DIRECTORY . "/" . $testname . ".validator_output.html";
2583 // Get tidy to check the page, unless we already know it produces non-XHTML output.
2584 if ( $test->tidyValidate() ) {
2585 $valid = tidyCheckFile( $testname . HTML_FILE ) && $valid;
2588 // if it took more than 2 seconds to render, then it may be interesting too. (Possible DoS attack?)
2589 if ( ( $after - $before ) >= 2 ) {
2590 print "\nParticularly slow to render (" . round( $after - $before, 2 ) . " seconds): $filename";
2591 return false;
2594 if ( $valid ) {
2595 // Remove temp HTML file if test was valid:
2596 unlink( $html_file );
2597 } elseif ( VALIDATE_ON_WEB ) {
2598 saveFile( $validator_output, DIRECTORY . "/" . $testname . ".validator_output.html" );
2601 return $valid;
2605 // ///////////////// RERUNNING OLD TESTS ///////////////////
2608 ** We keep our failed tests so that they can be rerun.
2609 ** This function does that retesting.
2611 function rerunPreviousTests() {
2612 print "Retesting previously found problems.\n";
2614 $dir_contents = scandir ( DIRECTORY );
2616 // sort file into the order a normal person would use.
2617 natsort ( $dir_contents );
2619 foreach ( $dir_contents as $file ) {
2621 // if file is not a test, then skip it.
2622 // Note we need to escape any periods or will be treated as "any character".
2623 $matches = array();
2624 if ( !ereg( "(.*)" . str_replace( ".", "\.", DATA_FILE ) . "$", $file, $matches ) ) continue;
2626 // reload the test.
2627 $full_path = DIRECTORY . "/" . $file;
2628 $test = unserialize( file_get_contents( $full_path ) );
2630 // if this is not a valid test, then skip it.
2631 if ( ! $test instanceof pageTest ) {
2632 print "\nSkipping invalid test - $full_path";
2633 continue;
2636 // The date format is in Apache log format, which makes it easier to locate
2637 // which retest caused which error in the Apache logs (only happens usually if
2638 // apache segfaults).
2639 if ( !QUIET ) print "[" . date ( "D M d H:i:s Y" ) . "] Retesting $file (" . get_class( $test ) . ")";
2641 // run test
2642 $testname = $matches[1];
2643 $valid = runWikiTest( $test, $testname, true );
2645 if ( !$valid ) {
2646 saveTest( $test, $testname );
2647 if ( QUIET ) {
2648 print "\nTest: " . get_class( $test ) . " ; Testname: $testname\n------";
2649 } else {
2650 print "\n";
2653 else {
2654 if ( !QUIET ) print "\r";
2655 if ( DELETE_PASSED_RETESTS ) {
2656 $prefix = DIRECTORY . "/" . $testname;
2657 if ( is_file( $prefix . DATA_FILE ) ) unlink( $prefix . DATA_FILE );
2658 if ( is_file( $prefix . PHP_TEST ) ) unlink( $prefix . PHP_TEST );
2659 if ( is_file( $prefix . CURL_TEST ) ) unlink( $prefix . CURL_TEST );
2660 if ( is_file( $prefix . INFO_FILE ) ) unlink( $prefix . INFO_FILE );
2665 print "\nDone retesting.\n";
2669 // //////////////////// MAIN LOOP ////////////////////////
2672 // first check whether CURL is installed, because sometimes it's not.
2673 if ( ! function_exists( 'curl_init' ) ) {
2674 die( "Could not find 'curl_init' function. Is the curl extension compiled into PHP?\n" );
2677 // Initialization of types. wikiFuzz doesn't have a constructor because we want to
2678 // access it staticly and not have any globals.
2679 wikiFuzz::$types = array_keys( wikiFuzz::$data );
2681 // Make directory if doesn't exist
2682 if ( !is_dir( DIRECTORY ) ) {
2683 mkdir ( DIRECTORY, 0700 );
2685 // otherwise, we first retest the things that we have found in previous runs
2686 else if ( RERUN_OLD_TESTS ) {
2687 rerunPreviousTests();
2690 // main loop.
2691 $start_time = date( "U" );
2692 $num_errors = 0;
2693 if ( !QUIET ) {
2694 print "Beginning main loop. Results are stored in the " . DIRECTORY . " directory.\n";
2695 print "Press CTRL+C to stop testing.\n";
2698 for ( $count = 0; true; $count++ ) {
2699 if ( !QUIET ) {
2700 // spinning progress indicator.
2701 switch( $count % 4 ) {
2702 case '0': print "\r/"; break;
2703 case '1': print "\r-"; break;
2704 case '2': print "\r\\"; break;
2705 case '3': print "\r|"; break;
2707 print " $count";
2710 // generate a page test to run.
2711 $test = selectPageTest( $count );
2713 $mins = ( date( "U" ) - $start_time ) / 60;
2714 if ( !QUIET && $mins > 0 ) {
2715 print ". $num_errors poss errors. "
2716 . floor( $mins ) . " mins. "
2717 . round ( $count / $mins, 0 ) . " tests/min. "
2718 . get_class( $test ); // includes the current test name.
2721 // run this test against MediaWiki, and see if the output was valid.
2722 $testname = $count;
2723 $valid = runWikiTest( $test, $testname, false );
2725 // save the failed test
2726 if ( ! $valid ) {
2727 if ( QUIET ) {
2728 print "\nTest: " . get_class( $test ) . " ; Testname: $testname\n------";
2729 } else {
2730 print "\n";
2732 saveTest( $test, $testname );
2733 $num_errors += 1;
2734 } else if ( KEEP_PASSED_TESTS ) {
2735 // print current time, with microseconds (matches "strace" format), and the test name.
2736 print " " . date( "H:i:s." ) . substr( current( explode( " ", microtime() ) ), 2 ) . " " . $testname;
2737 saveTest( $test, $testname );
2740 // stop if we have reached max number of errors.
2741 if ( defined( "MAX_ERRORS" ) && $num_errors >= MAX_ERRORS ) {
2742 break;
2745 // stop if we have reached max number of mins runtime.
2746 if ( defined( "MAX_RUNTIME" ) && $mins >= MAX_RUNTIME ) {
2747 break;