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