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