MediaWiki  REL1_20
fuzz-tester.php
Go to the documentation of this file.
00001 <?php
00181 // ///////////////////////// COMMAND LINE HELP ////////////////////////////////////
00182 
00183 // This is a command line script, load MediaWiki env (gives command line options);
00184 require_once( __DIR__ . '/commandLine.inc' );
00185 
00186 // if the user asked for an explanation of command line options.
00187 if ( isset( $options["help"] ) ) {
00188         print <<<ENDS
00189 MediaWiki $wgVersion fuzz tester
00190 Usage: php {$_SERVER["SCRIPT_NAME"]} [--quiet] [--base-url=<url-to-test-wiki>]
00191                                                    [--directory=<failed-test-path>] [--include-binary]
00192                                                    [--w3c-validate] [--delete-passed-retests] [--help]
00193                                                    [--user=<username>] [--password=<password>]
00194                                                    [--rerun-failed-tests] [--max-errors=<int>]
00195                                                    [--max-runtime=<num-minutes>]
00196                                                    [--specific-test=<test-name>]
00197 
00198 Options:
00199   --quiet                 : Hides passed tests, shows only failed tests.
00200   --base-url              : URL to a wiki on which to run the tests.
00201                                                         The "http://" is optional and can be omitted.
00202   --directory             : Full path to directory for storing failed tests.
00203                                                         Will be created if it does not exist.
00204   --include-binary        : Includes non-alphanumeric characters in the tests.
00205   --w3c-validate          : Validates pages using the W3C's web validator.
00206                                                         Slow. Currently many pages fail validation.
00207   --user                  : Login name of a valid user on your test wiki.
00208   --password              : Password for the valid user on your test wiki.
00209   --delete-passed-retests : Will delete retests that now pass.
00210                                                         Requires --rerun-failed-tests to be meaningful.
00211   --rerun-failed-tests    : Whether to rerun any previously failed tests.
00212   --max-errors            : Maximum number of errors to report before exiting.
00213                                                         Does not include errors from --rerun-failed-tests
00214   --max-runtime           : Maximum runtime, in minutes, to run before exiting.
00215                                                         Only applies to new tests, not --rerun-failed-tests
00216   --specific-test         : Runs only the specified fuzz test.
00217                                                         Only applies to new tests, not --rerun-failed-tests
00218   --keep-passed-tests     : Saves all test files, even those that pass.
00219   --help                  : Show this help message.
00220 
00221 Example:
00222   If you wanted to fuzz test a nightly MediaWiki checkout using cron for 1 hour,
00223   and only wanted to be informed of errors, and did not want to redo previously
00224   failed tests, and wanted a maximum of 100 errors, then you could do:
00225   php {$_SERVER["SCRIPT_NAME"]} --quiet --max-errors=100 --max-runtime=60
00226 
00227 
00228 ENDS;
00229 
00230         exit( 0 );
00231 }
00232 
00233 
00234 // if we got command line options, check they look valid.
00235 $validOptions = array ( "quiet", "base-url", "directory", "include-binary",
00236                 "w3c-validate", "user", "password", "delete-passed-retests",
00237                 "rerun-failed-tests", "max-errors",
00238                 "max-runtime", "specific-test", "keep-passed-tests", "help" );
00239 if ( !empty( $options ) ) {
00240         $unknownArgs = array_diff ( array_keys( $options ), $validOptions );
00241         foreach ( $unknownArgs as $invalidArg ) {
00242                 print "Ignoring invalid command-line option: --$invalidArg\n";
00243         }
00244 }
00245 
00246 
00247 // /////////////////////////// CONFIGURATION ////////////////////////////////////
00248 
00249 // URL to some wiki on which we can run our tests.
00250 if ( !empty( $options["base-url"] ) ) {
00251         define( "WIKI_BASE_URL", $options["base-url"] );
00252 } else {
00253         define( "WIKI_BASE_URL", $wgServer . $wgScriptPath . '/' );
00254 }
00255 
00256 // The directory name where we store the output.
00257 // Example for Windows: "c:\\temp\\wiki-fuzz"
00258 if ( !empty( $options["directory"] ) ) {
00259         define( "DIRECTORY", $options["directory"] );
00260 } else {
00261         define( "DIRECTORY", "{$wgUploadDirectory}/fuzz-tests" );
00262 }
00263 
00264 // Should our test fuzz data include binary strings?
00265 define( "INCLUDE_BINARY",  isset( $options["include-binary"] ) );
00266 
00267 // Whether we want to validate HTML output on the web.
00268 // At the moment very few generated pages will validate, so not recommended.
00269 define( "VALIDATE_ON_WEB", isset( $options["w3c-validate"] ) );
00270 // URL to use to validate our output:
00271 define( "VALIDATOR_URL",  "http://validator.w3.org/check" );
00272 
00273 // Location of Tidy standalone executable.
00274 define( "PATH_TO_TIDY",  "/usr/bin/tidy" );
00275 
00276 // The name of a user who has edited on your wiki. Used
00277 // when testing the Special:Contributions and Special:Userlogin page.
00278 if ( !empty( $options["user"] ) ) {
00279         define( "USER_ON_WIKI", $options["user"] );
00280 } else {
00281         define( "USER_ON_WIKI", "nickj" );
00282 }
00283 
00284 // The password of the above user. Used when testing the login page,
00285 // and to do this we sometimes need to login successfully.
00286 if ( !empty( $options["password"] ) ) {
00287         define( "USER_PASSWORD", $options["password"] );
00288 } else {
00289         // And no, this is not a valid password on any public wiki.
00290         define( "USER_PASSWORD", "nickj" );
00291 }
00292 
00293 // If we have a test that failed, and then we run it again, and it passes,
00294 // do you want to delete it or keep it?
00295 define( "DELETE_PASSED_RETESTS", isset( $options["delete-passed-retests"] ) );
00296 
00297 // Do we want to rerun old saved tests at script startup?
00298 // Set to true to help catch regressions, or false if you only want new stuff.
00299 define( "RERUN_OLD_TESTS", isset( $options["rerun-failed-tests"] ) );
00300 
00301 // File where the database errors are logged. Should be defined in LocalSettings.php.
00302 define( "DB_ERROR_LOG_FILE", $wgDBerrorLog );
00303 
00304 // Run in chatty mode (all output, default), or run in quiet mode (only prints out details of failed tests)?
00305 define( "QUIET", isset( $options["quiet"] ) );
00306 
00307 // Keep all test files, even those that pass. Potentially useful to tracking input that causes something
00308 // unusual to happen, if you don't know what "unusual" is until later.
00309 define( "KEEP_PASSED_TESTS", isset( $options["keep-passed-tests"] ) );
00310 
00311 // The maximum runtime, if specified.
00312 if ( !empty( $options["max-runtime"] ) && intval( $options["max-runtime"] ) > 0 ) {
00313         define( "MAX_RUNTIME", intval( $options["max-runtime"] ) );
00314 }
00315 
00316 // The maximum number of problems to find, if specified. Excludes retest errors.
00317 if ( !empty( $options["max-errors"] ) && intval( $options["max-errors"] ) > 0 ) {
00318         define( "MAX_ERRORS", intval( $options["max-errors"] ) );
00319 }
00320 
00321 // if the user has requested a specific test (instead of all tests), and the test they asked for looks valid.
00322 if ( !empty( $options["specific-test"] ) ) {
00323         if ( class_exists( $options["specific-test"] ) && get_parent_class( $options["specific-test"] ) == "pageTest" ) {
00324                 define( "SPECIFIC_TEST", $options["specific-test"] );
00325         }
00326         else {
00327                 print "Ignoring invalid --specific-test\n";
00328         }
00329 }
00330 
00331 // Define the file extensions we'll use:
00332 define( "PHP_TEST" , ".test.php" );
00333 define( "CURL_TEST", ".curl.sh" );
00334 define( "DATA_FILE", ".data.bin" );
00335 define( "INFO_FILE", ".info.txt" );
00336 define( "HTML_FILE", ".wiki_preview.html" );
00337 
00338 // If it goes wrong, we want to know about it.
00339 error_reporting( E_ALL | E_STRICT );
00340 
00341 // //////////////  A CLASS THAT GENERATES RANDOM NASTY WIKI & HTML STRINGS  //////////////////////
00342 
00343 class wikiFuzz {
00344 
00345         // Only some HTML tags are understood with params by MediaWiki, the rest are ignored.
00346         // List the tags that accept params below, as well as what those params are.
00347         public static $data = array(
00348                         "B"          => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00349                         "CAPTION"    => array( "CLASS", "ID", "STYLE", "align", "lang", "dir", "title" ),
00350                         "CENTER"     => array( "CLASS", "STYLE", "ID", "lang", "dir", "title" ),
00351                         "DIV"        => array( "CLASS", "STYLE", "ID", "align", "lang", "dir", "title" ),
00352                         "FONT"       => array( "CLASS", "STYLE", "ID", "lang", "dir", "title", "face", "size", "color" ),
00353                         "H1"         => array( "STYLE", "CLASS", "ID", "align", "lang", "dir", "title" ),
00354                         "H2"         => array( "STYLE", "CLASS", "ID", "align", "lang", "dir", "title" ),
00355                         "HR"         => array( "STYLE", "CLASS", "ID", "WIDTH", "lang", "dir", "title", "size", "noshade" ),
00356                         "LI"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "type", "value" ),
00357                         "TABLE"      => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "BORDER", "CELLPADDING",
00358                                                                    "CELLSPACING", "lang", "dir", "title", "summary", "frame", "rules" ),
00359                         "TD"         => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "COLSPAN", "ROWSPAN",
00360                                                                   "VALIGN", "abbr", "axis", "headers", "scope", "nowrap", "height", "lang",
00361                                                                   "dir", "title", "char", "charoff" ),
00362                         "TH"         => array( "STYLE", "CLASS", "ID", "BGCOLOR", "WIDTH", "ALIGN", "COLSPAN", "ROWSPAN",
00363                                                                   "VALIGN", "abbr", "axis", "headers", "scope", "nowrap", "height", "lang",
00364                                                                   "dir", "title", "char", "charoff" ),
00365                         "TR"         => array( "CLASS", "STYLE", "ID", "BGCOLOR", "ALIGN", "VALIGN", "lang", "dir", "title", "char", "charoff" ),
00366                         "UL"         => array( "CLASS", "STYLE", "ID", "lang", "dir", "title", "type" ),
00367                         "P"          => array( "style", "class", "id", "align", "lang", "dir", "title" ),
00368                         "blockquote" => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "cite" ),
00369                         "span"       => array( "CLASS", "ID", "STYLE", "align", "lang", "dir", "title" ),
00370                         "code"       => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00371                         "tt"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00372                         "small"      => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00373                         "big"        => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00374                         "s"          => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00375                         "u"          => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00376                         "del"        => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "datetime", "cite" ),
00377                         "ins"        => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "datetime", "cite" ),
00378                         "sub"        => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00379                         "sup"        => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00380                         "ol"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "type", "start" ),
00381                         "br"         => array( "CLASS", "ID", "STYLE", "title", "clear" ),
00382                         "cite"       => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00383                         "var"        => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00384                         "ruby"       => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00385                         "rt"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00386                         "rp"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00387                         "dt"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00388                         "dl"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00389                         "em"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00390                         "strong"     => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00391                         "i"          => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00392                         "thead"      => array( "CLASS", "ID", "STYLE", "lang", "dir", "title",  'align', 'char', 'charoff', 'valign' ),
00393                         "tfoot"      => array( "CLASS", "ID", "STYLE", "lang", "dir", "title",  'align', 'char', 'charoff', 'valign' ),
00394                         "tbody"      => array( "CLASS", "ID", "STYLE", "lang", "dir", "title",  'align', 'char', 'charoff', 'valign' ),
00395                         "colgroup"   => array( "CLASS", "ID", "STYLE", "lang", "dir", "title",  'align', 'char', 'charoff', 'valign', 'span', 'width' ),
00396                         "col"        => array( "CLASS", "ID", "STYLE", "lang", "dir", "title",  'align', 'char', 'charoff', 'valign', 'span', 'width' ),
00397                         "pre"        => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "width" ),
00398 
00399                         // extension tags that accept parameters:
00400                         "sort"         => array( "order", "class" ),
00401                         "ref"          => array( "name" ),
00402                         "categorytree" => array( "hideroot", "mode", "style" ),
00403                         "chemform"     => array( "link", "wikilink", "query" ),
00404                         "section"      => array( "begin", "new" ),
00405 
00406                         // older MW transclusion.
00407                         "transclude"   => array( "page" ),
00408                                 );
00409 
00410         // The types of the HTML that we will be testing were defined above
00411         // Note: this needs to be initialized later to be equal to: array_keys(wikiFuzz::$data);
00412         // as such, it also needs to also be publicly modifiable.
00413         public static $types;
00414 
00415 
00416         // Some attribute values.
00417         static private $other = array( "&", "=", ":", "?", "\"", "\n", "%n%n%n%n%n%n%n%n%n%n%n%n", "\\" );
00418         static private $ints  = array(
00419                         // various numbers
00420                         "0", "-1", "127", "-7897", "89000", "808080", "90928345",
00421                         "0xfffffff", "ffff",
00422 
00423                         // Different ways of saying: '
00424                         "&#0000039;", // Long UTF-8 Unicode encoding
00425                         "&#39;",  // dec version.
00426                         "&#x27;", // hex version.
00427                         "&#xA7;", // malformed hex variant, MSB not zero.
00428 
00429                         // Different ways of saying: "
00430                         "&#0000034;", // Long UTF-8 Unicode encoding
00431                         "&#34;",
00432                         "&#x22;", // hex version.
00433                         "&#xA2;", // malformed hex variant, MSB not zero.
00434 
00435                         // Different ways of saying: <
00436                         "<",
00437                         "&#0000060",  // Long UTF-8 Unicode encoding without semicolon (Mediawiki wants the colon)
00438                         "&#0000060;", // Long UTF-8 Unicode encoding with semicolon
00439                         "&#60;",
00440                         "&#x3C;",     // hex version.
00441                         "&#xBC;",     // malformed hex variant, MSB not zero.
00442                         "&#x0003C;",  // mid-length hex version
00443                         "&#X00003C;", // slightly longer hex version, with capital "X"
00444 
00445                         // Different ways of saying: >
00446                         ">",
00447                         "&#0000062;", // Long UTF-8 Unicode encoding
00448                         "&#62;",
00449                         "&#x3E;",     // hex version.
00450                         "&#xBE;",     // malformed variant, MSB not zero.
00451 
00452                         // Different ways of saying: [
00453                         "&#0000091;", // Long UTF-8 Unicode encoding
00454                         "&#91;",
00455                         "&#x5B;",     // hex version.
00456 
00457                         // Different ways of saying: {{
00458                         "&#0000123;&#0000123;", // Long UTF-8 Unicode encoding
00459                         "&#123;&#123;",
00460                         "&#x7B;&#x7B;",         // hex version.
00461 
00462                         // Different ways of saying: |
00463                         "&#0000124;", // Long UTF-8 Unicode encoding
00464                         "&#124;",
00465                         "&#x7C;",     // hex version.
00466                         "&#xFC;",     // malformed hex variant, MSB not zero.
00467 
00468                         // a "lignature" - http://www.robinlionheart.com/stds/html4/spchars#ligature
00469                         // &#8204; == &zwnj;
00470                         "&#8204;"
00471                                 );
00472 
00473         // Defines various wiki-related bits of syntax, that can potentially cause
00474         // MediaWiki to do something other than just print that literal text.
00475         static private $ext = array(
00476                         // links, templates, parameters.
00477                         "[[", "]]", "{{", "}}", "|", "[", "]", "{{{", "}}}", "|]]",
00478 
00479                         // wiki tables.
00480                         "\n{|", "\n|}",
00481                         "!",
00482                         "\n!",
00483                         "!!",
00484                         "||",
00485                         "\n|-", "| ", "\n|",
00486 
00487                         // section headings.
00488                         "=", "==", "===", "====", "=====", "======",
00489 
00490                         // lists (ordered and unordered) and indentation.
00491                         "\n*", "*", "\n:", ":",
00492                         "\n#", "#",
00493 
00494                         // definition lists (dl, dt, dd), newline, and newline with pre, and a tab.
00495                         "\n;", ";", "\n ",
00496 
00497                         // Whitespace: newline, tab, space.
00498                         "\n", "\t", " ",
00499 
00500                         // Some XSS attack vectors from http://ha.ckers.org/xss.html
00501                         "&#x09;", // tab
00502                         "&#x0A;", // newline
00503                         "&#x0D;", // carriage return
00504                         "\0",     // null character
00505                         " &#14; ", // spaces and meta characters
00506                         "'';!--\"<XSS>=&{()}", // compact injection of XSS & SQL tester
00507 
00508                         // various NULL fields
00509                         "%00",
00510                         "&#00;",
00511                         "\0",
00512 
00513                         // horizontal rule.
00514                         "-----", "\n-----",
00515 
00516                         // signature, redirect, bold, italics.
00517                         "~~~~", "#REDIRECT [[", "'''", "''",
00518 
00519                         // comments.
00520                         "<!--", "-->",
00521 
00522                         // quotes.
00523                         "\"", "'",
00524 
00525                         // tag start and tag end.
00526                         "<", ">",
00527 
00528                         // implicit link creation on URIs.
00529                         "http://",
00530                         "https://",
00531                         "ftp://",
00532                         "irc://",
00533                         "news:",
00534                         'gopher://',
00535                         'telnet://',
00536                         'nntp://',
00537                         'worldwind://',
00538                         'mailto:',
00539 
00540                         // images.
00541                         "[[image:",
00542                         ".gif",
00543                         ".png",
00544                         ".jpg",
00545                         ".jpeg",
00546                         'thumbnail=',
00547                         'thumbnail',
00548                         'thumb=',
00549                         'thumb',
00550                         'right',
00551                         'none',
00552                         'left',
00553                         'framed',
00554                         'frame',
00555                         'enframed',
00556                         'centre',
00557                         'center',
00558                         "Image:",
00559                         "[[:Image",
00560                         'px',
00561                         'upright=',
00562                         'border',
00563 
00564                         // misc stuff to throw at the Parser.
00565                         '%08X',
00566                         '/',
00567                         ":x{|",
00568                         "\n|+",
00569                         "<noinclude>",
00570                         "</noinclude>",
00571                         " \302\273",
00572                         " :",
00573                         " !",
00574                         " ;",
00575                         "\302\253",
00576                         "[[category:",
00577                         "?=",
00578                         "(",
00579                         ")",
00580                         "]]]",
00581                         "../",
00582                         "{{{{",
00583                         "}}}}",
00584                         "[[Special:",
00585                         "<includeonly>",
00586                         "</includeonly>",
00587                         "<!--MWTEMPLATESECTION=",
00588                         '<!--MWTOC-->',
00589 
00590                         // implicit link creation on booknum, RFC, and PubMed ID usage (both with and without IDs)
00591                         "ISBN 2",
00592                         "RFC 000",
00593                         "PMID 000",
00594                         "ISBN ",
00595                         "RFC ",
00596                         "PMID ",
00597 
00598                         // magic words:
00599                         '__NOTOC__',
00600                         '__FORCETOC__',
00601                         '__NOEDITSECTION__',
00602                         '__START__',
00603                         '__NOTITLECONVERT__',
00604                         '__NOCONTENTCONVERT__',
00605                         '__END__',
00606                         '__TOC__',
00607                         '__NOTC__',
00608                         '__NOCC__',
00609                         "__FORCETOC__",
00610                         "__NEWSECTIONLINK__",
00611                         "__NOGALLERY__",
00612 
00613                         // more magic words / internal templates.
00614                         '{{PAGENAME}}',
00615                         '{{PAGENAMEE}}',
00616                         '{{NAMESPACE}}',
00617                         "{{MSG:",
00618                         "}}",
00619                         "{{MSGNW:",
00620                         "}}",
00621                         "{{INT:",
00622                         "}}",
00623                         '{{SITENAME}}',
00624                         "{{NS:",
00625                         "}}",
00626                         "{{LOCALURL:",
00627                         "}}",
00628                         "{{LOCALURLE:",
00629                         "}}",
00630                         "{{SCRIPTPATH}}",
00631                         "{{GRAMMAR:gentiv|",
00632                         "}}",
00633                         "{{REVISIONID}}",
00634                         "{{SUBPAGENAME}}",
00635                         "{{SUBPAGENAMEE}}",
00636                         "{{ns:0}}",
00637                         "{{fullurle:",
00638                         "}}",
00639                         "{{subst::",
00640                         "}}",
00641                         "{{UCFIRST:",
00642                         "}}",
00643                         "{{UC:",
00644                         '{{SERVERNAME}}',
00645                         '{{SERVER}}',
00646                         "{{RAW:",
00647                         "}}",
00648                         "{{PLURAL:",
00649                         "}}",
00650                         "{{LCFIRST:",
00651                         "}}",
00652                         "{{LC:",
00653                         "}}",
00654                         '{{CURRENTWEEK}}',
00655                         '{{CURRENTDOW}}',
00656                         "{{INT:{{LC:contribs-showhideminor}}|",
00657                         "}}",
00658                         "{{INT:googlesearch|",
00659                         "}}",
00660                         "{{BASEPAGENAME}}",
00661                         "{{CONTENTLANGUAGE}}",
00662                         "{{PAGESINNAMESPACE:}}",
00663                         "{{#language:",
00664                         "}}",
00665                         "{{#special:",
00666                         "}}",
00667                         "{{#special:emailuser",
00668                         "}}",
00669 
00670                         // Some raw link for magic words.
00671                         "{{NUMBEROFPAGES:R",
00672                         "}}",
00673                         "{{NUMBEROFUSERS:R",
00674                         "}}",
00675                         "{{NUMBEROFARTICLES:R",
00676                         "}}",
00677                         "{{NUMBEROFFILES:R",
00678                         "}}",
00679                         "{{NUMBEROFADMINS:R",
00680                         "}}",
00681                         "{{padleft:",
00682                         "}}",
00683                         "{{padright:",
00684                         "}}",
00685                         "{{DEFAULTSORT:",
00686                         "}}",
00687 
00688                         // internal Math "extension":
00689                         "<math>",
00690                         "</math>",
00691 
00692                         // Parser extension functions:
00693                         "{{#expr:",
00694                         "{{#if:",
00695                         "{{#ifeq:",
00696                         "{{#ifexist:",
00697                         "{{#ifexpr:",
00698                         "{{#switch:",
00699                         "{{#time:",
00700                         "}}",
00701 
00702                         // references table for the Cite extension.
00703                         "<references/>",
00704 
00705                         // Internal Parser tokens - try inserting some of these.
00706                         "UNIQ25f46b0524f13e67NOPARSE",
00707                         "UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002",
00708                         "\x07UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002-QINU",
00709 
00710                         // Inputbox extension:
00711                         "<inputbox>\ntype=search\nsearchbuttonlabel=\n",
00712                         "</inputbox>",
00713 
00714                         // charInsert extension:
00715                         "<charInsert>",
00716                         "</charInsert>",
00717 
00718                         // wikiHiero extension:
00719                         "<hiero>",
00720                         "</hiero>",
00721 
00722                         // Image gallery:
00723                         "<gallery>",
00724                         "</gallery>",
00725 
00726                         // FixedImage extension.
00727                         "<fundraising/>",
00728 
00729                         // Timeline extension: currently untested.
00730 
00731                         // Nowiki:
00732                         "<nOwIkI>",
00733                         "</nowiki>",
00734 
00735                         // an external image to test the external image displaying code
00736                         "http://debian.org/Pics/debian.png",
00737 
00738                         // LabeledSectionTransclusion extension.
00739                         "{{#lstx:",
00740                         "}}",
00741                         "{{#lst:",
00742                         "}}",
00743                         "{{#lst:Main Page|",
00744                         "}}"
00745                         );
00746 
00750         static public function chooseInput( array $input ) {
00751                 $randindex = wikiFuzz::randnum( count( $input ) - 1 );
00752                 return $input[$randindex];
00753         }
00754 
00755         // Max number of parameters for HTML attributes.
00756         static private $maxparams = 10;
00757 
00764         static public function randnum( $finish, $start = 0 ) {
00765                 return mt_rand( $start, $finish );
00766         }
00767 
00772         static private function randstring() {
00773                 $thestring = "";
00774 
00775                 for ( $i = 0; $i < 40; $i++ ) {
00776                         $what = wikiFuzz::randnum( 1 );
00777 
00778                         if ( $what == 0 ) { // include some random wiki syntax
00779                                 $which = wikiFuzz::randnum( count( wikiFuzz::$ext ) - 1 );
00780                                 $thestring .= wikiFuzz::$ext[$which];
00781                         }
00782                         else { // include some random text
00783                                 $char = INCLUDE_BINARY
00784                                         // Decimal version:
00785                                         // "&#" . wikiFuzz::randnum(255) . ";"
00786                                         // Hex version:
00787                                         ? "&#x" . str_pad( dechex( wikiFuzz::randnum( 255 ) ), wikiFuzz::randnum( 2, 7 ), "0", STR_PAD_LEFT ) . ";"
00788                                         // A truly binary version:
00789                                         // ? chr(wikiFuzz::randnum(0,255))
00790                                         : chr( wikiFuzz::randnum( 126, 32 ) );
00791 
00792                                 $length = wikiFuzz::randnum( 8 );
00793                                 $thestring .= str_repeat ( $char, $length );
00794                         }
00795                 }
00796                 return $thestring;
00797         }
00798 
00804         static private function makestring() {
00805                 $what = wikiFuzz::randnum( 2 );
00806                 if ( $what == 0 ) {
00807                         return wikiFuzz::randstring();
00808                 } elseif ( $what == 1 ) {
00809                         return wikiFuzz::$ints[wikiFuzz::randnum( count( wikiFuzz::$ints ) - 1 )];
00810                 } else {
00811                         return wikiFuzz::$other[wikiFuzz::randnum( count( wikiFuzz::$other ) - 1 )];
00812                 }
00813         }
00814 
00821         static private function stringEscape( $matches ) {
00822                 return sprintf( "\\x%02x", ord( $matches[1] ) );
00823         }
00824 
00831         static public function makeTitleSafe( $str ) {
00832                 $legalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF";
00833                 return preg_replace_callback(
00834                                 "/([^$legalTitleChars])/", 'wikiFuzz::stringEscape',
00835                                 $str );
00836         }
00837 
00842         static private function loop() {
00843                 switch ( wikiFuzz::randnum( 3 ) ) {
00844                         case 1: // an opening tag, with parameters.
00845                                 $string = "";
00846                                 $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 );
00847                                 $t = wikiFuzz::$types[$i];
00848                                 $arr = wikiFuzz::$data[$t];
00849                                 $string .= "<" . $t . " ";
00850                                 $num_params = min( wikiFuzz::$maxparams, count( $arr ) );
00851                                 for ( $z = 0; $z < $num_params; $z++ ) {
00852                                         $badparam = $arr[wikiFuzz::randnum( count( $arr ) - 1 )];
00853                                         $badstring = wikiFuzz::makestring();
00854                                         $string .= $badparam . "=" . wikiFuzz::getRandQuote() . $badstring . wikiFuzz::getRandQuote() . " ";
00855                                 }
00856                                 $string .= ">\n";
00857                                 return $string;
00858                         case 2: // a closing tag.
00859                                 $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 );
00860                                 return "</" . wikiFuzz::$types[$i] . ">";
00861                         case 3: // a random string, between tags.
00862                                 return wikiFuzz::makeString();
00863                 }
00864                 return "";    // catch-all, should never be called.
00865         }
00866 
00871         static private function getRandQuote() {
00872                 switch ( wikiFuzz::randnum( 3 ) ) {
00873                         case 1 : return "'";
00874                         case 2 : return "\"";
00875                         default: return "";
00876                 }
00877         }
00878 
00884         static public function makeFuzz( $maxtypes = 2 ) {
00885                 $page = "";
00886                 for ( $k = 0; $k < $maxtypes; $k++ ) {
00887                         $page .= wikiFuzz::loop();
00888                 }
00889                 return $page;
00890         }
00891 }
00892 
00893 
00894 // //////   MEDIAWIKI PAGES TO TEST, AND HOW TO TEST THEM  ///////
00895 
00905 abstract class pageTest {
00906         protected $params;
00907         protected $pagePath;
00908         protected $cookie = "";
00909         protected $tidyValidate = true;
00910 
00911         public function getParams() {
00912                 return $this->params;
00913         }
00914 
00915         public function getPagePath() {
00916                 return $this->pagePath;
00917         }
00918 
00919         public function getCookie() {
00920                 return $this->cookie;
00921         }
00922 
00923         public function tidyValidate() {
00924                 return $this->tidyValidate;
00925         }
00926 }
00927 
00928 
00932 class editPageTest extends pageTest {
00933         function __construct() {
00934                 $this->pagePath = "index.php?title=WIKIFUZZ";
00935 
00936                 $this->params = array (
00937                                 "action"        => "submit",
00938                                 "wpMinoredit"   => wikiFuzz::makeFuzz( 2 ),
00939                                 "wpPreview"     => wikiFuzz::makeFuzz( 2 ),
00940                                 "wpSection"     => wikiFuzz::makeFuzz( 2 ),
00941                                 "wpEdittime"    => wikiFuzz::makeFuzz( 2 ),
00942                                 "wpSummary"     => wikiFuzz::makeFuzz( 2 ),
00943                                 "wpScrolltop"   => wikiFuzz::makeFuzz( 2 ),
00944                                 "wpStarttime"   => wikiFuzz::makeFuzz( 2 ),
00945                                 "wpAutoSummary" => wikiFuzz::makeFuzz( 2 ),
00946                                 "wpTextbox1"    => wikiFuzz::makeFuzz( 40 )  // the main wiki text, need lots of this.
00947                                 );
00948 
00949                 // sometimes we don't want to specify certain parameters.
00950                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSection"] );
00951                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEdittime"] );
00952                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSummary"] );
00953                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpScrolltop"] );
00954                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpStarttime"] );
00955                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpAutoSummary"] );
00956                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpTextbox1"] );
00957         }
00958 }
00959 
00960 
00964 class listusersTest extends pageTest {
00965         function __construct() {
00966                 $this->pagePath = "index.php?title=Special:Listusers";
00967 
00968                 $this->params = array (
00969                                 "title"        => wikiFuzz::makeFuzz( 2 ),
00970                                 "group"        => wikiFuzz::makeFuzz( 2 ),
00971                                 "username"     => wikiFuzz::makeFuzz( 2 ),
00972                                 "Go"           => wikiFuzz::makeFuzz( 2 ),
00973                                 "limit"        => wikiFuzz::chooseInput( array( "0", "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
00974                                 "offset"       => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) )
00975                                 );
00976         }
00977 }
00978 
00979 
00983 class searchTest extends pageTest {
00984         function __construct() {
00985                 $this->pagePath = "index.php?title=Special:Search";
00986 
00987                 $this->params = array (
00988                                 "action"        => "index.php?title=Special:Search",
00989                                 "ns0"           => wikiFuzz::makeFuzz( 2 ),
00990                                 "ns1"           => wikiFuzz::makeFuzz( 2 ),
00991                                 "ns2"           => wikiFuzz::makeFuzz( 2 ),
00992                                 "ns3"           => wikiFuzz::makeFuzz( 2 ),
00993                                 "ns4"           => wikiFuzz::makeFuzz( 2 ),
00994                                 "ns5"           => wikiFuzz::makeFuzz( 2 ),
00995                                 "ns6"           => wikiFuzz::makeFuzz( 2 ),
00996                                 "ns7"           => wikiFuzz::makeFuzz( 2 ),
00997                                 "ns8"           => wikiFuzz::makeFuzz( 2 ),
00998                                 "ns9"           => wikiFuzz::makeFuzz( 2 ),
00999                                 "ns10"          => wikiFuzz::makeFuzz( 2 ),
01000                                 "ns11"          => wikiFuzz::makeFuzz( 2 ),
01001                                 "ns12"          => wikiFuzz::makeFuzz( 2 ),
01002                                 "ns13"          => wikiFuzz::makeFuzz( 2 ),
01003                                 "ns14"          => wikiFuzz::makeFuzz( 2 ),
01004                                 "ns15"          => wikiFuzz::makeFuzz( 2 ),
01005                                 "redirs"        => wikiFuzz::makeFuzz( 2 ),
01006                                 "search"        => wikiFuzz::makeFuzz( 2 ),
01007                                 "offset"        => wikiFuzz::chooseInput( array( "", "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) ),
01008                                 "fulltext"      => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) ),
01009                                 "searchx"       => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) )
01010                                         );
01011         }
01012 }
01013 
01014 
01018 class recentchangesTest extends pageTest {
01019         function __construct() {
01020                 $this->pagePath = "index.php?title=Special:Recentchanges";
01021 
01022                 $this->params = array (
01023                                 "action"        => wikiFuzz::makeFuzz( 2 ),
01024                                 "title"         => wikiFuzz::makeFuzz( 2 ),
01025                                 "namespace"     => wikiFuzz::chooseInput( range( -1, 15 ) ),
01026                                 "Go"            => wikiFuzz::makeFuzz( 2 ),
01027                                 "invert"        => wikiFuzz::chooseInput( array( "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01028                                 "hideanons"     => wikiFuzz::chooseInput( array( "-1", "------'-------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01029                                 'limit'         => wikiFuzz::chooseInput( array( "0", "-1", "---------'----0", "+1", "81340909772349234",  wikiFuzz::makeFuzz( 2 ) ) ),
01030                                 "days"          => wikiFuzz::chooseInput( array( "-1", "----------'---0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01031                                 "hideminor"     => wikiFuzz::chooseInput( array( "-1", "-----------'--0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01032                                 "hidebots"      => wikiFuzz::chooseInput( array( "-1", "---------'----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01033                                 "hideliu"       => wikiFuzz::chooseInput( array( "-1", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01034                                 "hidepatrolled" => wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01035                                 "hidemyself"    => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01036                                 'categories_any' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01037                                 'categories'    => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01038                                 'feed'          => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) )
01039                                 );
01040         }
01041 }
01042 
01043 
01047 class prefixindexTest extends pageTest {
01048         function __construct() {
01049                 $this->pagePath = "index.php?title=Special:Prefixindex";
01050 
01051                 $this->params = array (
01052                                 "title"         => "Special:Prefixindex",
01053                                 "namespace"     => wikiFuzz::randnum( 101, -10 ),
01054                                 "Go"            => wikiFuzz::makeFuzz( 2 )
01055                                 );
01056 
01057                 // sometimes we want 'prefix', sometimes we want 'from', and sometimes we want nothing.
01058                 if ( wikiFuzz::randnum( 3 ) == 0 ) {
01059                         $this->params["prefix"] = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1",
01060                                                                                                  wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) );
01061                 }
01062                 if ( wikiFuzz::randnum( 3 ) == 0 ) {
01063                         $this->params["from"]   = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1",
01064                                                                                                 wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) );
01065                 }
01066         }
01067 }
01068 
01069 
01073 class mimeSearchTest extends pageTest {
01074         function __construct() {
01075                 $this->pagePath = "index.php?title=Special:MIMEsearch";
01076 
01077                 $this->params = array (
01078                                 "action"        => "index.php?title=Special:MIMEsearch",
01079                                 "mime"          => wikiFuzz::makeFuzz( 3 ),
01080                                 'limit'         => wikiFuzz::chooseInput( array( "0", "-1", "-------'------0", "+1", "81342321351235325",  wikiFuzz::makeFuzz( 2 ) ) ),
01081                                 'offset'        => wikiFuzz::chooseInput( array( "0", "-1", "-----'--------0", "+1", "81341231235365252234324",  wikiFuzz::makeFuzz( 2 ) ) )
01082                                 );
01083         }
01084 }
01085 
01086 
01090 class specialLogTest extends pageTest {
01091         function __construct() {
01092                 $this->pagePath = "index.php?title=Special:Log";
01093 
01094                 $this->params = array (
01095                                 "type"        => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
01096                                 "par"         => wikiFuzz::makeFuzz( 2 ),
01097                                 "user"        => wikiFuzz::makeFuzz( 2 ),
01098                                 "page"        => wikiFuzz::makeFuzz( 2 ),
01099                                 "from"        => wikiFuzz::makeFuzz( 2 ),
01100                                 "until"       => wikiFuzz::makeFuzz( 2 ),
01101                                 "title"       => wikiFuzz::makeFuzz( 2 )
01102                                 );
01103         }
01104 }
01105 
01106 
01110 class successfulUserLoginTest extends pageTest {
01111         function __construct() {
01112                 $this->pagePath = "index.php?title=Special:Userlogin&action=submitlogin&type=login&returnto=" . wikiFuzz::makeFuzz( 2 );
01113 
01114                 $this->params = array (
01115                                 "wpName"          => USER_ON_WIKI,
01116                                 // sometimes real password, sometimes not:
01117                                 'wpPassword'      => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), USER_PASSWORD ) ),
01118                                 'wpRemember'      => wikiFuzz::makeFuzz( 2 )
01119                                 );
01120 
01121                 $this->cookie = "wikidb_session=" .  wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) );
01122         }
01123 }
01124 
01125 
01129 class userLoginTest extends pageTest {
01130         function __construct() {
01131 
01132                 $this->pagePath = "index.php?title=Special:Userlogin";
01133 
01134                 $this->params = array (
01135                                 'wpRetype'        => wikiFuzz::makeFuzz( 2 ),
01136                                 'wpRemember'      => wikiFuzz::makeFuzz( 2 ),
01137                                 'wpRealName'      => wikiFuzz::makeFuzz( 2 ),
01138                                 'wpPassword'      => wikiFuzz::makeFuzz( 2 ),
01139                                 'wpName'          => wikiFuzz::makeFuzz( 2 ),
01140                                 'wpMailmypassword' => wikiFuzz::makeFuzz( 2 ),
01141                                 'wpLoginattempt'  => wikiFuzz::makeFuzz( 2 ),
01142                                 'wpEmail'         => wikiFuzz::makeFuzz( 2 ),
01143                                 'wpDomain'        => wikiFuzz::chooseInput( array( "", "local", wikiFuzz::makeFuzz( 2 ) ) ),
01144                                 'wpCreateaccountMail' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
01145                                 'wpCreateaccount' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
01146                                 'wpCookieCheck'   => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
01147                                 'type'            => wikiFuzz::chooseInput( array( "signup", "login", "", wikiFuzz::makeFuzz( 2 ) ) ),
01148                                 'returnto'        => wikiFuzz::makeFuzz( 2 ),
01149                                 'action'          => wikiFuzz::chooseInput( array( "", "submitlogin", wikiFuzz::makeFuzz( 2 ) ) )
01150                                 );
01151 
01152                 $this->cookie = "wikidb_session=" . wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) );
01153         }
01154 }
01155 
01156 
01160 class ipblocklistTest extends pageTest {
01161         function __construct() {
01162                 $this->pagePath = "index.php?title=Special:Ipblocklist";
01163 
01164                 $this->params = array (
01165                                 'wpUnblockAddress' => wikiFuzz::makeFuzz( 2 ),
01166                                 'ip'              => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
01167                                                                          // something like an IP address, sometimes invalid:
01168                                                                          ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
01169                                                                            . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
01170                                 'id'              => wikiFuzz::makeFuzz( 2 ),
01171                                 'wpUnblockReason' => wikiFuzz::makeFuzz( 2 ),
01172                                 'action'          => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "success", "submit", "unblock" ) ),
01173                                 'wpEditToken'     => wikiFuzz::makeFuzz( 2 ),
01174                                 'wpBlock'         => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "" ) ),
01175                                 'limit'           => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1",
01176                                                                                                  "09700982312351132098234",  wikiFuzz::makeFuzz( 2 ) ) ),
01177                                 'offset'          => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1",
01178                                                                                                  "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) )
01179                                 );
01180 
01181                 // sometimes we don't want to specify certain parameters.
01182                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
01183                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["ip"] );
01184                 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["id"] );
01185                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpUnblockAddress"] );
01186         }
01187 }
01188 
01189 
01193 class newImagesTest extends  pageTest {
01194         function __construct() {
01195                 $this->pagePath = "index.php?title=Special:Newimages";
01196 
01197                 $this->params = array (
01198                                 'hidebots'  => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "1", "", "-1" ) ),
01199                                 'wpIlMatch' => wikiFuzz::makeFuzz( 2 ),
01200                                 'until'     => wikiFuzz::makeFuzz( 2 ),
01201                                 'from'      => wikiFuzz::makeFuzz( 2 )
01202                                 );
01203 
01204                 // sometimes we don't want to specify certain parameters.
01205                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["until"] );
01206                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["from"] );
01207         }
01208 }
01209 
01210 
01214 class imagelistTest extends pageTest {
01215         function __construct() {
01216                 $this->pagePath = "index.php?title=Special:Imagelist";
01217 
01218                 $this->params = array (
01219                                 'sort'      => wikiFuzz::chooseInput( array( "bysize", "byname" , "bydate", wikiFuzz::makeFuzz( 2 ) ) ),
01220                                 'limit'     => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "09700982312351132098234",  wikiFuzz::makeFuzz( 2 ) ) ),
01221                                 'offset'    => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ),
01222                                 'wpIlMatch' => wikiFuzz::makeFuzz( 2 )
01223                                 );
01224         }
01225 }
01226 
01227 
01231 class specialExportTest extends pageTest {
01232         function __construct() {
01233                 $this->pagePath = "index.php?title=Special:Export";
01234 
01235                 $this->params = array (
01236                                 'action'      => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
01237                                 'pages'       => wikiFuzz::makeFuzz( 2 ),
01238                                 'curonly'     => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ),
01239                                 'listauthors' => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ),
01240                                 'history'     => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ),
01241 
01242                                 );
01243 
01244                 // For the time being, need to disable "submit" action as Tidy barfs on MediaWiki's XML export.
01245                 if ( $this->params['action'] == 'submit' ) $this->params['action'] = '';
01246 
01247                 // Sometimes remove the history field.
01248                 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["history"] );
01249 
01250                 // page does not produce HTML.
01251                 $this->tidyValidate = false;
01252         }
01253 }
01254 
01255 
01259 class specialBooksourcesTest extends pageTest {
01260         function __construct() {
01261                 $this->pagePath = "index.php?title=Special:Booksources";
01262 
01263                 $this->params = array (
01264                                 'go'    => wikiFuzz::makeFuzz( 2 ),
01265                                 // ISBN codes have to contain some semi-numeric stuff or will be ignored:
01266                                 'isbn'  => "0X0" . wikiFuzz::makeFuzz( 2 )
01267                                 );
01268         }
01269 }
01270 
01271 
01275 class specialAllpagesTest extends pageTest {
01276         function __construct() {
01277                 $this->pagePath = "index.php?title=Special%3AAllpages";
01278 
01279                 $this->params = array (
01280                                 'from'      => wikiFuzz::makeFuzz( 2 ),
01281                                 'namespace' => wikiFuzz::chooseInput( range( -1, 15 ) ),
01282                                 'go'        => wikiFuzz::makeFuzz( 2 )
01283                                 );
01284         }
01285 }
01286 
01287 
01291 class pageHistoryTest extends pageTest {
01292         function __construct() {
01293                 $this->pagePath = "index.php?title=Main_Page&action=history";
01294 
01295                 $this->params = array (
01296                                 'limit'     => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134",  wikiFuzz::makeFuzz( 2 ) ) ),
01297                                 'offset'    => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ),
01298                                 "go"        => wikiFuzz::chooseInput( array( "first", "last", wikiFuzz::makeFuzz( 2 ) ) ),
01299                                 "dir"       => wikiFuzz::chooseInput( array( "prev", "next", wikiFuzz::makeFuzz( 2 ) ) ),
01300                                 "diff"      => wikiFuzz::chooseInput( array( "-1", "--------'-----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01301                                 "oldid"     => wikiFuzz::chooseInput( array( "prev", "-1", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01302                                 "feed"      => wikiFuzz::makeFuzz( 2 )
01303                                 );
01304         }
01305 }
01306 
01307 
01311 class contributionsTest extends pageTest {
01312         function __construct() {
01313                 $this->pagePath = "index.php?title=Special:Contributions/" . USER_ON_WIKI;
01314 
01315                 $this->params = array (
01316                                 'target'    => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "newbies", USER_ON_WIKI ) ),
01317                                 'namespace' => wikiFuzz::chooseInput( array( -1, 15, 1, wikiFuzz::makeFuzz( 2 ) ) ),
01318                                 'offset'    => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "982342131232131231241", wikiFuzz::makeFuzz( 2 ) ) ),
01319                                 'bot'       => wikiFuzz::chooseInput( array( "", "-1", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
01320                                 'go'        => wikiFuzz::chooseInput( array( "-1", 'prev', 'next', wikiFuzz::makeFuzz( 2 ) ) )
01321                                 );
01322         }
01323 }
01324 
01325 
01329 class viewPageTest extends pageTest {
01330         function __construct() {
01331                 $this->pagePath = "index.php?title=Main_Page";
01332 
01333                 $this->params = array (
01334                                 "useskin"        => wikiFuzz::chooseInput( array( "chick", "cologneblue", "myskin",
01335                                                                                 "nostalgia", "simple", "standard", wikiFuzz::makeFuzz( 2 ) ) ),
01336                                 "uselang"        => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ),
01337                                                 "ab", "af", "an", "ar", "arc", "as", "ast", "av", "ay", "az", "ba",
01338                                                 "bat-smg", "be", "bg", "bm", "bn", "bo", "bpy", "br", "bs", "ca",
01339                                                 "ce", "cs", "csb", "cv", "cy", "da", "de", "dv", "dz", "el", "en",
01340                                                 "eo", "es", "et", "eu", "fa", "fi", "fo", "fr", "fur", "fy", "ga",
01341                                                 "gn", "gsw", "gu", "he", "hi", "hr", "hu", "ia", "id", "ii", "is",
01342                                                 "it", "ja", "jv", "ka", "km", "kn", "ko", "ks", "ku", "kv", "la",
01343                                                 "li", "lo", "lt", "lv", "mk", "ml", "ms", "nah", "nap", "nds",
01344                                                 "nds-nl", "nl", "nn", "no", "non", "nv", "oc", "or", "os", "pa",
01345                                                 "pl", "pms", "ps", "pt", "pt-br", "qu", "rmy", "ro", "ru", "sc",
01346                                                 "sd", "sk", "sl", "sq", "sr", "sr-ec", "sr-el",
01347                                                 "su", "sv", "ta", "te", "th", "tr", "tt", "ty", "tyv", "udm",
01348                                                 "ug", "uk", "ur", "utf8", "vec", "vi", "wa", "xal", "yi", "za",
01349                                                 "zh", "zh-cn", "zh-hk", "zh-sg", "zh-tw", "zh-tw" ) ),
01350                                 "returnto"       => wikiFuzz::makeFuzz( 2 ),
01351                                 "feed"           => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ),
01352                                 "rcid"           => wikiFuzz::makeFuzz( 2 ),
01353                                 "action"         => wikiFuzz::chooseInput( array( "view", "raw", "render", wikiFuzz::makeFuzz( 2 ), "markpatrolled" ) ),
01354                                 "printable"      => wikiFuzz::makeFuzz( 2 ),
01355                                 "oldid"          => wikiFuzz::makeFuzz( 2 ),
01356                                 "redirect"       => wikiFuzz::makeFuzz( 2 ),
01357                                 "diff"           => wikiFuzz::makeFuzz( 2 ),
01358                                 "search"         => wikiFuzz::makeFuzz( 2 ),
01359                                 "rdfrom"         => wikiFuzz::makeFuzz( 2 ),  // things from Article.php from here on:
01360                                 "token"          => wikiFuzz::makeFuzz( 2 ),
01361                                 "tbid"           => wikiFuzz::makeFuzz( 2 ),
01362                                 // @todo FIXME: Duplicate array key.
01363                                 "action"         => wikiFuzz::chooseInput( array( "purge", wikiFuzz::makeFuzz( 2 ) ) ),
01364                                 "wpReason"       => wikiFuzz::makeFuzz( 2 ),
01365                                 "wpEditToken"    => wikiFuzz::makeFuzz( 2 ),
01366                                 "from"           => wikiFuzz::makeFuzz( 2 ),
01367                                 "bot"            => wikiFuzz::makeFuzz( 2 ),
01368                                 "summary"        => wikiFuzz::makeFuzz( 2 ),
01369                                 "direction"      => wikiFuzz::chooseInput( array( "next", "prev", wikiFuzz::makeFuzz( 2 ) ) ),
01370                                 "section"        => wikiFuzz::makeFuzz( 2 ),
01371                                 "preload"        => wikiFuzz::makeFuzz( 2 ),
01372 
01373                                 );
01374 
01375                 // Tidy does not know how to valid atom or rss, so exclude from testing for the time being.
01376                 if ( $this->params["feed"] == "atom" )     { unset( $this->params["feed"] ); }
01377                 elseif ( $this->params["feed"] == "rss" ) { unset( $this->params["feed"] ); }
01378 
01379                 // Raw pages cannot really be validated
01380                 if ( $this->params["action"] == "raw" ) unset( $this->params["action"] );
01381 
01382                 // sometimes we don't want to specify certain parameters.
01383                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["rcid"] );
01384                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["diff"] );
01385                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["rdfrom"] );
01386                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["oldid"] );
01387 
01388                 // usually don't want action == purge.
01389                 if ( wikiFuzz::randnum( 6 ) > 1 ) unset( $this->params["action"] );
01390         }
01391 }
01392 
01393 
01397 class specialAllmessagesTest extends pageTest {
01398         function __construct() {
01399                 $this->pagePath = "index.php?title=Special:Allmessages";
01400 
01401                 // only really has one parameter
01402                 $this->params = array (
01403                                 "ot"     => wikiFuzz::chooseInput( array( "php", "html", wikiFuzz::makeFuzz( 2 ) ) )
01404                                 );
01405         }
01406 }
01407 
01411 class specialNewpagesPageTest extends pageTest {
01412         function __construct() {
01413                 $this->pagePath = "index.php?title=Special:Newpages";
01414 
01415                 $this->params = array (
01416                                 "namespace" => wikiFuzz::chooseInput( range( -1, 15 ) ),
01417                                 "feed"      => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ),
01418                                 'limit'     => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134",  wikiFuzz::makeFuzz( 2 ) ) ),
01419                                 'offset'    => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) )
01420                                 );
01421 
01422                 // Tidy does not know how to valid atom or rss, so exclude from testing for the time being.
01423                 if ( $this->params["feed"] == "atom" )     { unset( $this->params["feed"] ); }
01424                 elseif ( $this->params["feed"] == "rss" ) { unset( $this->params["feed"] ); }
01425         }
01426 }
01427 
01431 class redirectTest extends pageTest {
01432         function __construct() {
01433                 $this->pagePath = "redirect.php";
01434 
01435                 $this->params = array (
01436                                 "wpDropdown" => wikiFuzz::makeFuzz( 2 )
01437                                 );
01438 
01439                 // sometimes we don't want to specify certain parameters.
01440                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpDropdown"] );
01441         }
01442 }
01443 
01444 
01448 class confirmEmail extends pageTest {
01449         function __construct() {
01450                 // sometimes we send a bogus confirmation code, and sometimes we don't.
01451                 $this->pagePath = "index.php?title=Special:Confirmemail" . wikiFuzz::chooseInput( array( "", "/" . wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 1 ) ) ) );
01452 
01453                 $this->params = array (
01454                                 "token" => wikiFuzz::makeFuzz( 2 )
01455                                 );
01456         }
01457 }
01458 
01459 
01464 class watchlistTest extends pageTest {
01465         function __construct() {
01466                 $this->pagePath = "index.php?title=Special:Watchlist";
01467 
01468                 $this->params = array (
01469                                 "remove"   => wikiFuzz::chooseInput( array( "Remove checked items from watchlist", wikiFuzz::makeFuzz( 2 ) ) ),
01470                                 'days'     => wikiFuzz::chooseInput( array( 0, -1, -230, "--", 3, 9, wikiFuzz::makeFuzz( 2 ) ) ),
01471                                 'hideOwn'  => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
01472                                 'hideBots' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
01473                                 'namespace' => wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
01474                                 'action'   => wikiFuzz::chooseInput( array( "submit", "clear", wikiFuzz::makeFuzz( 2 ) ) ),
01475                                 'id[]'     => wikiFuzz::makeFuzz( 2 ),
01476                                 'edit'     => wikiFuzz::makeFuzz( 2 ),
01477                                 'token'    => wikiFuzz::chooseInput( array( "", "1243213", wikiFuzz::makeFuzz( 2 ) ) )
01478                                 );
01479 
01480                 // sometimes we specifiy "reset", and sometimes we don't.
01481                 if ( wikiFuzz::randnum( 3 ) == 0 ) $this->params["reset"] = wikiFuzz::chooseInput( array( "", "0", "1", wikiFuzz::makeFuzz( 2 ) ) );
01482         }
01483 }
01484 
01485 
01489 class specialBlockmeTest extends pageTest {
01490         function __construct() {
01491                 $this->pagePath = "index.php?title=Special:Blockme";
01492 
01493                 $this->params = array ( );
01494 
01495                 // sometimes we specify "ip", and sometimes we don't.
01496                 if ( wikiFuzz::randnum( 1 ) == 0 ) {
01497                         $this->params["ip"] = wikiFuzz::chooseInput( array( "10.12.41.213", wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) );
01498                 }
01499         }
01500 }
01501 
01502 
01506 class specialMovePage extends pageTest {
01507         function __construct() {
01508                 $this->pagePath = "index.php?title=Special:Movepage";
01509 
01510                 $this->params = array (
01511                                 "action"      => wikiFuzz::chooseInput( array( "success", "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
01512                                 'wpEditToken' => wikiFuzz::chooseInput( array( '', 0, 34987987, wikiFuzz::makeFuzz( 2 ) ) ),
01513                                 'target'      => wikiFuzz::chooseInput( array( "x", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ) ) ),
01514                                 'wpOldTitle'  => wikiFuzz::chooseInput( array( "z", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ), wikiFuzz::makeFuzz( 2 ) ) ),
01515                                 'wpNewTitle'  => wikiFuzz::chooseInput( array( "y", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ), wikiFuzz::makeFuzz( 2 ) ) ),
01516                                 'wpReason'    => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ) ) ),
01517                                 'wpMovetalk'  => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01518                                 'wpDeleteAndMove'  => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01519                                 'wpConfirm'   => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01520                                 'talkmoved'   => wikiFuzz::chooseInput( array( "1", wikiFuzz::makeFuzz( 2 ), "articleexists", 'notalkpage' ) ),
01521                                 'oldtitle'    => wikiFuzz::makeFuzz( 2 ),
01522                                 'newtitle'    => wikiFuzz::makeFuzz( 2 ),
01523                                 'wpMovetalk'  => wikiFuzz::chooseInput( array( "1", "0", wikiFuzz::makeFuzz( 2 ) ) )
01524                                 );
01525 
01526                 // sometimes we don't want to specify certain parameters.
01527                 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["wpEditToken"] );
01528                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["target"] );
01529                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpNewTitle"] );
01530                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpReason"] );
01531                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpOldTitle"] );
01532         }
01533 }
01534 
01535 
01539 class specialUndeletePageTest extends pageTest {
01540         function __construct() {
01541                 $this->pagePath = "index.php?title=Special:Undelete";
01542 
01543                 $this->params = array (
01544                                 "action"      => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
01545                                 'wpEditToken' => wikiFuzz::chooseInput( array( '', 0, 34987987, wikiFuzz::makeFuzz( 2 ) ) ),
01546                                 'target'      => wikiFuzz::chooseInput( array( "x", wikiFuzz::makeTitleSafe( wikiFuzz::makeFuzz( 2 ) ) ) ),
01547                                 'timestamp'   => wikiFuzz::chooseInput( array( "125223", wikiFuzz::makeFuzz( 2 ) ) ),
01548                                 'file'        => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01549                                 'restore'     => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
01550                                 'preview'     => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
01551                                 'wpComment'   => wikiFuzz::makeFuzz( 2 )
01552                                 );
01553 
01554                 // sometimes we don't want to specify certain parameters.
01555                 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["wpEditToken"] );
01556                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["target"] );
01557                 if ( wikiFuzz::randnum( 1 ) == 0 ) unset( $this->params["restore"] );
01558                 if ( wikiFuzz::randnum( 1 ) == 0 ) unset( $this->params["preview"] );
01559         }
01560 }
01561 
01562 
01566 class specialUnlockdbPageTest extends pageTest {
01567         function __construct() {
01568                 $this->pagePath = "index.php?title=Special:Unlockdb";
01569 
01570                 $this->params = array (
01571                                 "action"        => wikiFuzz::chooseInput( array( "submit", "success", "", wikiFuzz::makeFuzz( 2 ) ) ),
01572                                 'wpEditToken'   => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
01573                                 'wpLockConfirm' => wikiFuzz::chooseInput( array( "0", "1", wikiFuzz::makeFuzz( 2 ) ) )
01574                                 );
01575 
01576                 // sometimes we don't want to specify certain parameters.
01577                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpEditToken"] );
01578                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
01579                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpLockConfirm"] );
01580         }
01581 }
01582 
01583 
01587 class specialLockdbPageTest extends pageTest {
01588         function __construct() {
01589                 $this->pagePath = "index.php?title=Special:Lockdb";
01590 
01591                 $this->params = array (
01592                                 "action"       => wikiFuzz::chooseInput( array( "submit", "success", "", wikiFuzz::makeFuzz( 2 ) ) ),
01593                                 'wpEditToken'  => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
01594                                 'wpLockReason' => wikiFuzz::makeFuzz( 2 ),
01595                                 'wpLockConfirm' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
01596                                 );
01597 
01598                 // sometimes we don't want to specify certain parameters.
01599                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpEditToken"] );
01600                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
01601                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpLockConfirm"] );
01602         }
01603 }
01604 
01605 
01609 class specialUserrights extends pageTest {
01610         function __construct() {
01611                 $this->pagePath = "index.php?title=Special:Userrights";
01612 
01613                 $this->params = array (
01614                                 'wpEditToken'   => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
01615                                 'user-editname' => wikiFuzz::chooseInput( array( "Nickj2", "Nickj2\n<xyz>", wikiFuzz::makeFuzz( 2 ) ) ),
01616                                 'ssearchuser'   => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01617                                 'saveusergroups' => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ), "Save User Groups" ),
01618                                 'member[]'      => wikiFuzz::chooseInput( array( "0", "bot", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01619                                 "available[]"   => wikiFuzz::chooseInput( array( "0", "sysop", "bureaucrat", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
01620                                 );
01621 
01622                 // sometimes we don't want to specify certain parameters.
01623                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['ssearchuser'] );
01624                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['saveusergroups'] );
01625         }
01626 }
01627 
01628 
01632 class pageProtectionForm extends pageTest {
01633         function __construct() {
01634                 $this->pagePath = "index.php?title=Main_Page";
01635 
01636                 $this->params = array (
01637                                 "action"               => "protect",
01638                                 'wpEditToken'          => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
01639                                 "mwProtect-level-edit" => wikiFuzz::chooseInput( array( '', 'autoconfirmed', 'sysop', wikiFuzz::makeFuzz( 2 ) ) ),
01640                                 "mwProtect-level-move" => wikiFuzz::chooseInput( array( '', 'autoconfirmed', 'sysop', wikiFuzz::makeFuzz( 2 ) ) ),
01641                                 "mwProtectUnchained"   => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01642                                 'mwProtect-reason'     => wikiFuzz::chooseInput( array( "because it was there", wikiFuzz::makeFuzz( 2 ) ) )
01643                                 );
01644 
01645 
01646                 // sometimes we don't want to specify certain parameters.
01647                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["mwProtectUnchained"] );
01648                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params['mwProtect-reason'] );
01649         }
01650 }
01651 
01652 
01656 class specialBlockip extends pageTest {
01657         function __construct() {
01658                 $this->pagePath = "index.php?title=Special:Blockip";
01659 
01660                 $this->params = array (
01661                                 "action"          => wikiFuzz::chooseInput( array( "submit", "",  wikiFuzz::makeFuzz( 2 ) ) ),
01662                                 'wpEditToken'     => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
01663                                 "wpBlockAddress"  => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
01664                                                                           // something like an IP address, sometimes invalid:
01665                                                                          ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
01666                                                                           . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
01667                                 "ip"              => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
01668                                                                           // something like an IP address, sometimes invalid:
01669                                                                          ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
01670                                                                           . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
01671                                 "wpBlockOther"    => wikiFuzz::chooseInput( array( '', 'Nickj2', wikiFuzz::makeFuzz( 2 ) ) ),
01672                                 "wpBlockExpiry"   => wikiFuzz::chooseInput( array( "other", "2 hours", "1 day", "3 days", "1 week", "2 weeks",
01673                                                                                   "1 month", "3 months", "6 months", "1 year", "infinite", wikiFuzz::makeFuzz( 2 ) ) ),
01674                                 "wpBlockReason"   => wikiFuzz::chooseInput( array( "because it was there", wikiFuzz::makeFuzz( 2 ) ) ),
01675                                 "wpAnonOnly"      => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01676                                 "wpCreateAccount" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01677                                 "wpBlock"         => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) )
01678                                 );
01679 
01680                 // sometimes we don't want to specify certain parameters.
01681                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockOther"] );
01682                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockExpiry"] );
01683                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockReason"] );
01684                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpAnonOnly"] );
01685                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpCreateAccount"] );
01686                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["wpBlockAddress"] );
01687                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["ip"] );
01688         }
01689 }
01690 
01691 
01695 class imagepageTest extends pageTest {
01696         function __construct() {
01697                 $this->pagePath = "index.php?title=Image:Small-email.png";
01698 
01699                 $this->params = array (
01700                                 "image"         => wikiFuzz::chooseInput( array( "Small-email.png", wikiFuzz::makeFuzz( 2 ) ) ),
01701                                 "wpReason"      => wikiFuzz::makeFuzz( 2 ),
01702                                 "oldimage"      => wikiFuzz::chooseInput( array( "Small-email.png", wikiFuzz::makeFuzz( 2 ) ) ),
01703                                 "wpEditToken"   => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
01704                                 );
01705 
01706                 // sometimes we don't want to specify certain parameters.
01707                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["image"] );
01708                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpReason"] );
01709                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldimage"] );
01710                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEditToken"] );
01711         }
01712 }
01713 
01714 
01718 class pageDeletion extends pageTest {
01719         function __construct() {
01720                 $this->pagePath = "index.php?title=Main_Page&action=delete";
01721 
01722                 $this->params = array (
01723                                 "wpEditToken" => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
01724                                 "wpReason"    => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01725                                 "wpConfirm"   => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01726                                 );
01727 
01728                 // sometimes we don't want to specify certain parameters.
01729                 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpReason"] );
01730                 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpEditToken"] );
01731                 if ( wikiFuzz::randnum( 5 ) == 0 ) unset( $this->params["wpConfirm"] );
01732         }
01733 }
01734 
01735 
01736 
01740 class specialRevisionDeletePageTest extends pageTest {
01741         function __construct() {
01742                 $this->pagePath = "index.php?title=Special:Revisiondelete";
01743 
01744                 $this->params = array (
01745                                 "target"               => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
01746                                 "oldid"                => wikiFuzz::makeFuzz( 2 ),
01747                                 "oldid[]"              => wikiFuzz::makeFuzz( 2 ),
01748                                 "wpReason"             => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01749                                 "revdelete-hide-text"  => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01750                                 "revdelete-hide-comment" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01751                                 "revdelete-hide-user"  => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01752                                 "revdelete-hide-restricted" => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01753                                 );
01754 
01755                 // sometimes we don't want to specify certain parameters.
01756                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["target"] );
01757                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldid"] );
01758                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["oldid[]"] );
01759                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpReason"] );
01760                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-text"] );
01761                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-comment"] );
01762                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-user"] );
01763                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["revdelete-hide-restricted"] );
01764         }
01765 }
01766 
01767 
01771 class specialImportPageTest extends pageTest {
01772         function __construct() {
01773                 $this->pagePath = "index.php?title=Special:Import";
01774 
01775                 $this->params = array (
01776                                 "action"         => "submit",
01777                                 "source"         => wikiFuzz::chooseInput( array( "upload", "interwiki", wikiFuzz::makeFuzz( 2 ) ) ),
01778                                 "MAX_FILE_SIZE"  => wikiFuzz::chooseInput( array( "0", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01779                                 "xmlimport"      => wikiFuzz::chooseInput( array( "/var/www/hosts/mediawiki/wiki/AdminSettings.php", "1", "++--34234", wikiFuzz::makeFuzz( 2 ) ) ),
01780                                 "namespace"      => wikiFuzz::chooseInput( array( wikiFuzz::randnum( 30, -6 ), wikiFuzz::makeFuzz( 2 ) ) ),
01781                                 "interwiki"      => wikiFuzz::makeFuzz( 2 ),
01782                                 "interwikiHistory" => wikiFuzz::makeFuzz( 2 ),
01783                                 "frompage"       => wikiFuzz::makeFuzz( 2 ),
01784                                 );
01785 
01786                 // sometimes we don't want to specify certain parameters.
01787                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["action"] );
01788                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["source"] );
01789                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["MAX_FILE_SIZE"] );
01790                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["xmlimport"] );
01791                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["interwiki"] );
01792                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["interwikiHistory"] );
01793                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["frompage"] );
01794 
01795                 // Note: Need to do a file upload to fully test this Special page.
01796         }
01797 }
01798 
01799 
01803 class thumbTest extends pageTest {
01804         function __construct() {
01805                 $this->pagePath = "thumb.php";
01806 
01807                 $this->params = array (
01808                                 "f"  => wikiFuzz::chooseInput( array( "..", "\\", "small-email.png", wikiFuzz::makeFuzz( 2 ) ) ),
01809                                 "w"  => wikiFuzz::chooseInput( array( "80", wikiFuzz::randnum( 6000, -200 ), wikiFuzz::makeFuzz( 2 ) ) ),
01810                                 "r"  => wikiFuzz::chooseInput( array( "0", wikiFuzz::makeFuzz( 2 ) ) ),
01811                                 );
01812 
01813                 // sometimes we don't want to specify certain parameters.
01814                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["f"] );
01815                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["w"] );
01816                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["r"] );
01817         }
01818 }
01819 
01823 class profileInfo extends pageTest {
01824         function __construct() {
01825                 $this->pagePath = "profileinfo.php";
01826 
01827                 $this->params = array (
01828                                 "expand"  => wikiFuzz::makeFuzz( 2 ),
01829                                 "sort"    => wikiFuzz::chooseInput( array( "time", "count", "name", wikiFuzz::makeFuzz( 2 ) ) ),
01830                                 "filter"  => wikiFuzz::chooseInput( array( "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
01831                                 );
01832 
01833                 // sometimes we don't want to specify certain parameters.
01834                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["sort"] );
01835                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["filter"] );
01836         }
01837 }
01838 
01839 
01843 class specialCitePageTest extends pageTest {
01844         function __construct() {
01845                 $this->pagePath = "index.php?title=Special:Cite";
01846 
01847                 $this->params = array (
01848                                 "page"    => wikiFuzz::chooseInput( array( "\" onmouseover=\"alert(1);\"", "Main Page", wikiFuzz::makeFuzz( 2 ) ) ),
01849                                 "id"      => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "-9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ),
01850                                 );
01851 
01852                 // sometimes we don't want to specify certain parameters.
01853                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["page"] );
01854                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["id"] );
01855         }
01856 }
01857 
01858 
01862 class specialFilepathPageTest extends pageTest {
01863         function __construct() {
01864                 $this->pagePath = "index.php?title=Special:Filepath";
01865 
01866                 $this->params = array (
01867                                 "file"    => wikiFuzz::chooseInput( array( "Small-email.png", "Small-email.png" . wikiFuzz::makeFuzz( 1 ), wikiFuzz::makeFuzz( 2 ) ) ),
01868                                 );
01869         }
01870 }
01871 
01872 
01876 class specialRenameuserPageTest extends pageTest {
01877         function __construct() {
01878                 $this->pagePath = "index.php?title=Special:Renameuser";
01879 
01880                 $this->params = array (
01881                                 "oldusername"   => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ),
01882                                 "newusername"   => wikiFuzz::chooseInput( array( "Nickj2", "192.168.0.2", wikiFuzz::makeFuzz( 1 ) ) ),
01883                                 "token"         => wikiFuzz::chooseInput( array( "20398702394", "", wikiFuzz::makeFuzz( 2 ) ) ),
01884                                 );
01885         }
01886 }
01887 
01888 
01892 class specialLinksearch extends pageTest {
01893         function __construct() {
01894                 $this->pagePath = "index.php?title=Special%3ALinksearch";
01895 
01896                 $this->params = array (
01897                                 "target" => wikiFuzz::makeFuzz( 2 ),
01898                                 );
01899 
01900                 // sometimes we don't want to specify certain parameters.
01901                 if ( wikiFuzz::randnum( 10 ) == 0 ) unset( $this->params["target"] );
01902         }
01903 }
01904 
01905 
01909 class specialCategoryTree extends pageTest {
01910         function __construct() {
01911                 $this->pagePath = "index.php?title=Special:CategoryTree";
01912 
01913                 $this->params = array (
01914                                 "target" => wikiFuzz::makeFuzz( 2 ),
01915                                 "from"   => wikiFuzz::makeFuzz( 2 ),
01916                                 "until"  => wikiFuzz::makeFuzz( 2 ),
01917                                 "showas" => wikiFuzz::makeFuzz( 2 ),
01918                                 "mode"   => wikiFuzz::chooseInput( array( "pages", "categories", "all", wikiFuzz::makeFuzz( 2 ) ) ),
01919                                 );
01920 
01921                 // sometimes we do want to specify certain parameters.
01922                 if ( wikiFuzz::randnum( 5 ) == 0 ) $this->params["notree"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
01923         }
01924 }
01925 
01926 
01930 class specialChemicalsourcesTest extends pageTest {
01931         function __construct() {
01932                 $this->pagePath = "index.php?title=Special:Chemicalsources";
01933 
01934                 // choose an input format to use.
01935                 $format =  wikiFuzz::chooseInput(
01936                                         array(  'go',
01937                                                         'CAS',
01938                                                         'EINECS',
01939                                                         'CHEBI',
01940                                                         'PubChem',
01941                                                         'SMILES',
01942                                                         'InChI',
01943                                                         'ATCCode',
01944                                                         'KEGG',
01945                                                         'RTECS',
01946                                                         'ECNumber',
01947                                                         'DrugBank',
01948                                                         'Formula',
01949                                                         'Name'
01950                                                  )
01951                                         );
01952 
01953                 // values for different formats usually start with either letters or numbers.
01954                 switch ( $format ) {
01955                         case 'Name'   : $value = "A"; break;
01956                         case 'InChI'  :
01957                         case 'SMILES' :
01958                         case 'Formula': $value = "C"; break;
01959                         default       : $value = "0"; break;
01960                 }
01961 
01962                 // and then we append the fuzz input.
01963                 $this->params = array ( $format => $value . wikiFuzz::makeFuzz( 2 ) );
01964         }
01965 }
01966 
01967 
01977 class api extends pageTest {
01978 
01979         // API login mode.
01980         private static function loginMode() {
01981                 $arr =  array ( "lgname"        => wikiFuzz::makeFuzz( 2 ),
01982                                                 "lgpassword"    => wikiFuzz::makeFuzz( 2 ),
01983                                            );
01984                 // sometimes we want to specify the extra "lgdomain" parameter.
01985                 if ( wikiFuzz::randnum( 3 ) == 0 ) {
01986                         $arr["lgdomain"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
01987                 }
01988 
01989                 return $arr;
01990         }
01991 
01992         // API OpenSearch mode.
01993         private static function opensearchMode() {
01994                 return array ( "search"        => wikiFuzz::makeFuzz( 2 ) );
01995         }
01996 
01997         // API watchlist feed mode.
01998         private static function feedwatchlistMode() {
01999                 // @todo FIXME: Add "wikiFuzz::makeFuzz(2)" as possible value below?
02000                 return array ( "feedformat"    => wikiFuzz::chooseInput( array( "rss", "atom" ) ) );
02001         }
02002 
02003         // API query mode.
02004         private static function queryMode() {
02005                 // @todo FIXME: Add "wikiFuzz::makeFuzz(2)" as possible params for the elements below?
02006                 //        Suspect this will stuff up the tests more, but need to check.
02007                 $params = array (
02008                                          // @todo FIXME: More titles.
02009                                          "titles"        => wikiFuzz::chooseInput( array( "Main Page" ) ),
02010                                          // @todo FIXME: More pageids.
02011                                          "pageids"       => 1,
02012                                          "prop"          => wikiFuzz::chooseInput( array( "info", "revisions", "watchlist" ) ),
02013                                          "list"          => wikiFuzz::chooseInput( array( "allpages", "logevents", "watchlist", "usercontribs", "recentchanges", "backlinks", "embeddedin", "imagelinks" ) ),
02014                                          "meta"          => wikiFuzz::chooseInput( array( "siteinfo" ) ),
02015                                          "generator"     => wikiFuzz::chooseInput( array( "allpages", "logevents", "watchlist", "info", "revisions" ) ),
02016                                          "siprop"        => wikiFuzz::chooseInput( array( "general", "namespaces", "general|namespaces" ) ),
02017                                    );
02018 
02019                  // Add extra parameters based on what list choice we got.
02020                  switch ( $params["list"] ) {
02021                         case "usercontribs" : self::addListParams ( $params, "uc", array( "limit", "start", "end", "user", "dir" ) ); break;
02022                         case "allpages"     : self::addListParams ( $params, "ap", array( "from", "prefix", "namespace", "filterredir", "limit" ) ); break;
02023                         case "watchlist"    : self::addListParams ( $params, "wl", array( "allrev", "start", "end", "namespace", "dir", "limit", "prop" ) ); break;
02024                         case "logevents"    : self::addListParams ( $params, "le", array( "limit", "type", "start", "end", "user", "dir" ) ); break;
02025                         case "recentchanges": self::addListParams ( $params, "rc", array( "limit", "prop", "show", "namespace", "start", "end", "dir" ) ); break;
02026                         case "backlinks"    : self::addListParams ( $params, "bl", array( "continue", "namespace", "redirect", "limit" ) ); break;
02027                         case "embeddedin"   : self::addListParams ( $params, "ei", array( "continue", "namespace", "redirect", "limit" ) ); break;
02028                         case "imagelinks"   : self::addListParams ( $params, "il", array( "continue", "namespace", "redirect", "limit" ) ); break;
02029                  }
02030 
02031                  if ( $params["prop"] == "revisions" ) {
02032                         self::addListParams ( $params, "rv", array( "prop", "limit", "startid", "endid", "end", "dir" ) );
02033                  }
02034 
02035                  // Sometimes we want redirects, sometimes we don't.
02036                  if ( wikiFuzz::randnum( 3 ) == 0 ) {
02037                         $params["redirects"] = wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
02038                  }
02039 
02040                  return $params;
02041         }
02042 
02043         // Adds all the elements to the array, using the specified prefix.
02044         private static function addListParams( &$array, $prefix, $elements )  {
02045                 foreach ( $elements as $element ) {
02046                         $array[$prefix . $element] = self::getParamDetails( $element );
02047                 }
02048         }
02049 
02050         // For a given element name, returns the data for that element.
02051         private static function getParamDetails( $element ) {
02052                 switch ( $element ) {
02053                         case 'startid'    :
02054                         case 'endid'      :
02055                         case 'start'      :
02056                         case 'end'        :
02057                         case 'limit'      : return wikiFuzz::chooseInput( array( "0", "-1", "---'----------0", "+1", "8134", "320742734234235", "20060230121212", wikiFuzz::randnum( 9000, -100 ), wikiFuzz::makeFuzz( 2 ) ) );
02058                         case 'dir'        : return wikiFuzz::chooseInput( array( "newer", "older", wikiFuzz::makeFuzz( 2 ) ) );
02059                         case 'user'       : return wikiFuzz::chooseInput( array( USER_ON_WIKI, wikiFuzz::makeFuzz( 2 ) ) );
02060                         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 ) ) );
02061                         case 'filterredir': return wikiFuzz::chooseInput( array( "all", "redirects", "nonredirectsallpages", wikiFuzz::makeFuzz( 2 ) ) );
02062                         case 'allrev'     : return wikiFuzz::chooseInput( array( "1", 0, "", wikiFuzz::makeFuzz( 2 ) ) );
02063                         case 'prop'       : return wikiFuzz::chooseInput( array( "user", "comment", "timestamp", "patrol", "flags", "user|user|comment|flags", wikiFuzz::makeFuzz( 2 ) ) );
02064                         case 'type'       : return wikiFuzz::chooseInput( array( "block", "protect", "rights", "delete", "upload", "move", "import", "renameuser", "newusers", "makebot", wikiFuzz::makeFuzz( 2 ) ) );
02065                         case 'hide'       : return wikiFuzz::chooseInput( array( "minor", "bots", "anons", "liu", "liu|bots|", wikiFuzz::makeFuzz( 2 ) ) );
02066                         case 'show'       : return wikiFuzz::chooseInput( array( 'minor', '!minor', 'bot', '!bot', 'anon', '!anon', wikiFuzz::makeFuzz( 2 ) ) );
02067                         default           : return wikiFuzz::makeFuzz( 2 );
02068                 }
02069         }
02070 
02071         // Entry point.
02072         function __construct() {
02073                 $this->pagePath = "api.php";
02074 
02075                 $modes = array ( "help",
02076                                                 "login",
02077                                                 "opensearch",
02078                                                 "feedwatchlist",
02079                                                 "query" );
02080                 $action = wikiFuzz::chooseInput( array_merge ( $modes, array( wikiFuzz::makeFuzz( 2 ) ) ) );
02081 
02082                 switch ( $action ) {
02083                         case "login"         : $this->params = self::loginMode();
02084                                                                    break;
02085                         case "opensearch"    : $this->params = self::opensearchMode();
02086                                                                    break;
02087                         case "feedwatchlist" : $this->params = self::feedwatchlistMode();
02088                                                                    break;
02089                         case "query"         : $this->params = self::queryMode();
02090                                                                    break;
02091                         case "help"         :
02092                         default             :  // Do something random - "Crazy Ivan" mode.
02093                                                                    $random_mode = wikiFuzz::chooseInput( $modes ) . "Mode";
02094                                                                    // There is no "helpMode".
02095                                                                    if ( $random_mode == "helpMode" ) $random_mode = "queryMode";
02096                                                                    $this->params = self::$random_mode();
02097                                                                    break;
02098                 }
02099 
02100                 // Save the selected action.
02101                 $this->params["action"] = $action;
02102 
02103                 // Set the cookie:
02104                 // @todo FIXME: Need to get this cookie dynamically set, rather than hard-coded.
02105                 $this->cookie = "wikidbUserID=10001; wikidbUserName=Test; wikidb_session=178df0fe68c75834643af65dec9ec98a; wikidbToken=1adc6753d62c44aec950c024d7ae0540";
02106 
02107                 // Output format
02108                 $this->params["format"] = wikiFuzz::chooseInput( array( "json", "jsonfm", "php", "phpfm",
02109                                                                                                                            "wddx", "wddxfm", "xml", "xmlfm",
02110                                                                                                                            "yaml", "yamlfm", "raw", "rawfm",
02111                                                                                                                            wikiFuzz::makeFuzz( 2 ) ) );
02112 
02113                 // Page does not produce HTML (sometimes).
02114                 $this->tidyValidate = false;
02115         }
02116 }
02117 
02118 
02122 class GeSHi_Test extends pageTest {
02123 
02124         private function getGeSHiContent() {
02125                 return "<source lang=\"" . $this->getLang() . "\" "
02126                            . ( wikiFuzz::randnum( 2 ) == 0 ? "line " : "" )
02127                            . ( wikiFuzz::randnum( 2 ) == 0 ? "strict " : "" )
02128                            . "start=" . wikiFuzz::chooseInput( array( wikiFuzz::randnum( 6000, -6000 ), wikiFuzz::makeFuzz( 2 ) ) )
02129                            . ">"
02130                            . wikiFuzz::makeFuzz( 2 )
02131                            . "</source>";
02132         }
02133 
02134         private function getLang() {
02135         return wikiFuzz::chooseInput( array( "actionscript", "ada", "apache", "applescript", "asm", "asp", "autoit", "bash", "blitzbasic", "bnf", "c", "c_mac", "caddcl", "cadlisp",
02136                                 "cfdg", "cfm", "cpp", "cpp-qt", "csharp", "css", "d", "delphi", "diff", "div", "dos", "eiffel", "fortran", "freebasic", "gml", "groovy", "html4strict", "idl",
02137                                 "ini", "inno", "io", "java", "java5", "javascript", "latex", "lisp", "lua", "matlab", "mirc", "mpasm", "mysql", "nsis", "objc", "ocaml", "ocaml-brief", "oobas",
02138                                 "oracle8", "pascal", "perl", "php", "php-brief", "plsql", "python", "qbasic", "rails", "reg", "robots", "ruby", "sas", "scheme", "sdlbasic", "smalltalk", "smarty",
02139                                 "sql", "tcl", "text", "thinbasic", "tsql", "vb", "vbnet", "vhdl", "visualfoxpro", "winbatch", "xml", "xpp", "z80", wikiFuzz::makeFuzz( 1 ) ) );
02140         }
02141 
02142         function __construct() {
02143                 $this->pagePath = "index.php?title=WIKIFUZZ";
02144 
02145                 $this->params = array (
02146                                 "action"        => "submit",
02147                                 "wpMinoredit"   => "test",
02148                                 "wpPreview"     => "test",
02149                                 "wpSection"     => "test",
02150                                 "wpEdittime"    => "test",
02151                                 "wpSummary"     => "test",
02152                                 "wpScrolltop"   => "test",
02153                                 "wpStarttime"   => "test",
02154                                 "wpAutoSummary" => "test",
02155                                 "wpTextbox1"    => $this->getGeSHiContent() // the main wiki text, contains fake GeSHi content.
02156                                 );
02157         }
02158 }
02159 
02165 function selectPageTest( $count ) {
02166 
02167         // if the user only wants a specific test, then only ever give them that.
02168         if ( defined( "SPECIFIC_TEST" ) ) {
02169                 $testType = SPECIFIC_TEST;
02170                 return new $testType ();
02171         }
02172 
02173         // Some of the time we test Special pages, the remaining
02174         // time we test using the standard edit page.
02175         switch ( $count % 100 ) {
02176                 case 0 : return new successfulUserLoginTest();
02177                 case 1 : return new listusersTest();
02178                 case 2 : return new searchTest();
02179                 case 3 : return new recentchangesTest();
02180                 case 4 : return new prefixindexTest();
02181                 case 5 : return new mimeSearchTest();
02182                 case 6 : return new specialLogTest();
02183                 case 7 : return new userLoginTest();
02184                 case 8 : return new ipblocklistTest();
02185                 case 9 : return new newImagesTest();
02186                 case 10: return new imagelistTest();
02187                 case 11: return new specialExportTest();
02188                 case 12: return new specialBooksourcesTest();
02189                 case 13: return new specialAllpagesTest();
02190                 case 14: return new pageHistoryTest();
02191                 case 15: return new contributionsTest();
02192                 case 16: return new viewPageTest();
02193                 case 17: return new specialAllmessagesTest();
02194                 case 18: return new specialNewpagesPageTest();
02195                 case 19: return new searchTest();
02196                 case 20: return new redirectTest();
02197                 case 21: return new confirmEmail();
02198                 case 22: return new watchlistTest();
02199                 case 23: return new specialBlockmeTest();
02200                 case 24: return new specialUndeletePageTest();
02201                 case 25: return new specialMovePage();
02202                 case 26: return new specialUnlockdbPageTest();
02203                 case 27: return new specialLockdbPageTest();
02204                 case 28: return new specialUserrights();
02205                 case 29: return new pageProtectionForm();
02206                 case 30: return new specialBlockip();
02207                 case 31: return new imagepageTest();
02208                 case 32: return new pageDeletion();
02209                 case 33: return new specialRevisionDeletePageTest();
02210                 case 34: return new specialImportPageTest();
02211                 case 35: return new thumbTest();
02212                 case 37: return new profileInfo();
02213                 case 38: return new specialCitePageTest();
02214                 case 39: return new specialFilepathPageTest();
02215                 case 40: return new specialRenameuserPageTest();
02216                 case 41: return new specialLinksearch();
02217                 case 42: return new specialCategoryTree();
02218                 case 43: return new api();
02219                 case 44: return new specialChemicalsourcesTest();
02220                 default: return new editPageTest();
02221         }
02222 }
02223 
02224 
02225 // /////////////////////  SAVING OUTPUT  /////////////////////////
02226 
02230 function saveFile( $data, $name ) {
02231         file_put_contents( $name, $data );
02232 }
02233 
02241 function getAsURL( pageTest $test ) {
02242         $used_question_mark = ( strpos( $test->getPagePath(), "?" ) !== false );
02243         $retval = "http://get-to-post.nickj.org/?" . WIKI_BASE_URL . $test->getPagePath();
02244         foreach ( $test->getParams() as $param => $value ) {
02245                 if ( !$used_question_mark ) {
02246                         $retval .= "?";
02247                         $used_question_mark = true;
02248                 }
02249                 else {
02250                         $retval .= "&";
02251                 }
02252                 $retval .= $param . "=" . urlencode( $value );
02253         }
02254         return $retval;
02255 }
02256 
02257 
02261 function saveTestAsText( pageTest $test, $filename ) {
02262         $str = "Test: " . $test->getPagePath();
02263         foreach ( $test->getParams() as $param => $value ) {
02264                 $str .= "\n$param: $value";
02265         }
02266         $str .= "\nGet-to-post URL: " . getAsURL( $test ) . "\n";
02267         saveFile( $str, $filename );
02268 }
02269 
02270 
02275 function saveTestAsPHP( pageTest $test, $filename ) {
02276         $str = "<?php\n"
02277                 . "\$params = " . var_export( escapeForCurl( $test->getParams() ), true ) . ";\n"
02278                 . "\$ch = curl_init();\n"
02279                 . "curl_setopt(\$ch, CURLOPT_POST, 1);\n"
02280                 . "curl_setopt(\$ch, CURLOPT_POSTFIELDS, \$params );\n"
02281                 . "curl_setopt(\$ch, CURLOPT_URL, " . var_export( WIKI_BASE_URL . $test->getPagePath(), true ) . ");\n"
02282                 . "curl_setopt(\$ch, CURLOPT_RETURNTRANSFER,1);\n"
02283                 .  ( $test->getCookie() ? "curl_setopt(\$ch, CURLOPT_COOKIE, " . var_export( $test->getCookie(), true ) . ");\n" : "" )
02284                 . "\$result=curl_exec(\$ch);\n"
02285                 . "curl_close (\$ch);\n"
02286                 . "print \$result;\n"
02287                 . "\n";
02288         saveFile( $str, $filename );
02289 }
02290 
02298 function escapeForCurl( array $input_params ) {
02299         $output_params = array();
02300         foreach ( $input_params as $param => $value ) {
02301                 if ( strlen( $value ) > 0 && ( $value[0] == "@" || $value[0] == "<" ) ) {
02302                         $value = "\\" . $value;
02303                 }
02304                 $output_params[$param] = $value;
02305         }
02306         return $output_params;
02307 }
02308 
02309 
02314 function saveTestAsCurl( pageTest $test, $filename ) {
02315         $str = "#!/bin/bash\n"
02316                 . "curl --silent --include --globoff \\\n"
02317                 . ( $test->getCookie() ? " --cookie " . escapeshellarg( $test->getCookie() ) . " \\\n" : "" );
02318         foreach ( escapeForCurl( $test->getParams() ) as $param => $value ) {
02319                 $str .= " -F " . escapeshellarg( $param ) . "=" . escapeshellarg( $value ) . " \\\n";
02320         }
02321         $str .= " " . escapeshellarg( WIKI_BASE_URL . $test->getPagePath() ); // beginning space matters.
02322         $str .= "\n";
02323         saveFile( $str, $filename );
02324         chmod( $filename, 0755 ); // make executable
02325 }
02326 
02327 
02331 function saveTestData ( pageTest $test, $filename ) {
02332         saveFile( serialize( $test ),  $filename );
02333 }
02334 
02335 
02339 function saveTest( pageTest $test, $testname ) {
02340         $base_name = DIRECTORY . "/" . $testname;
02341         saveTestAsText( $test, $base_name . INFO_FILE );
02342         saveTestAsPHP ( $test, $base_name . PHP_TEST );
02343         saveTestAsCurl( $test, $base_name . CURL_TEST );
02344         saveTestData  ( $test, $base_name . DATA_FILE );
02345 }
02346 
02347 // ////////////////// MEDIAWIKI OUTPUT /////////////////////////
02348 
02354 function wikiTestOutput( pageTest $test ) {
02355 
02356         $ch = curl_init();
02357 
02358         // specify the cookie, if required.
02359         if ( $test->getCookie() ) {
02360                 curl_setopt( $ch, CURLOPT_COOKIE, $test->getCookie() );
02361         }
02362         curl_setopt( $ch, CURLOPT_POST, 1 );                          // save form using a POST
02363 
02364         $params = escapeForCurl( $test->getParams() );
02365         curl_setopt( $ch, CURLOPT_POSTFIELDS, $params );             // load the POST variables
02366 
02367         curl_setopt( $ch, CURLOPT_URL, WIKI_BASE_URL . $test->getPagePath() );  // set url to post to
02368         curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );                 // return into a variable
02369 
02370         $result = curl_exec ( $ch );
02371 
02372         // if we encountered an error, then say so, and return an empty string.
02373         if ( curl_error( $ch ) ) {
02374                 print "\nCurl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch );
02375                 $result = "";
02376         }
02377 
02378         curl_close ( $ch );
02379 
02380         return $result;
02381 }
02382 
02383 
02384 // ////////////////// HTML VALIDATION /////////////////////////
02385 
02391 function validateHTML( $text ) {
02392 
02393         $params = array ( "fragment"   => $text );
02394 
02395         $ch = curl_init();
02396 
02397         curl_setopt( $ch, CURLOPT_POST, 1 );                    // save form using a POST
02398         curl_setopt( $ch, CURLOPT_POSTFIELDS, $params );        // load the POST variables
02399         curl_setopt( $ch, CURLOPT_URL, VALIDATOR_URL );         // set url to post to
02400         curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );           // return into a variable
02401 
02402         $result = curl_exec ( $ch );
02403 
02404         // if we encountered an error, then log it, and exit.
02405         if ( curl_error( $ch ) ) {
02406                 trigger_error( "Curl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ) );
02407                 print "Curl error #: " . curl_errno( $ch ) . " - " . curl_error ( $ch ) . " - exiting.\n";
02408                 exit( 1 );
02409         }
02410 
02411         curl_close ( $ch );
02412 
02413         $valid = ( strpos( $result, "Failed validation" ) === false );
02414 
02415         return array( $valid, $result );
02416 }
02417 
02423 function tidyCheckFile( $name ) {
02424         $file = DIRECTORY . "/" . $name;
02425         $command = PATH_TO_TIDY . " -output /tmp/out.html -quiet $file 2>&1";
02426         $x = `$command`;
02427 
02428         // Look for the most interesting Tidy errors and warnings.
02429         if (   strpos( $x, "end of file while parsing attributes" ) !== false
02430                         || strpos( $x, "attribute with missing trailing quote mark" ) !== false
02431                         || strpos( $x, "missing '>' for end of tag" ) !== false
02432                         || strpos( $x, "Error:" ) !== false ) {
02433                 print "\nTidy found something - view details with: $command";
02434                 return false;
02435         } else {
02436                 return true;
02437         }
02438 }
02439 
02445 function dbErrorLogged() {
02446         static $filesize;
02447 
02448         // first time running this function
02449         if ( !isset( $filesize ) ) {
02450                 // create log if it does not exist
02451                 if ( DB_ERROR_LOG_FILE && !file_exists( DB_ERROR_LOG_FILE ) ) {
02452                         saveFile( '', DB_ERROR_LOG_FILE );
02453                 }
02454                 $filesize = filesize( DB_ERROR_LOG_FILE );
02455                 return false;
02456         }
02457 
02458         $newsize = filesize( DB_ERROR_LOG_FILE );
02459         // if the log has grown, then assume the current test caused it.
02460         if ( $newsize != $filesize ) {
02461                 $filesize = $newsize;
02462                 return true;
02463         }
02464 
02465         return false;
02466 }
02467 
02468 // //////////////// TOP-LEVEL PROBLEM-FINDING FUNCTION ////////////////////////
02469 
02478 function runWikiTest( pageTest $test, &$testname, $can_overwrite = false ) {
02479 
02480         // by default don't overwrite a previous test of the same name.
02481         while ( ! $can_overwrite && file_exists( DIRECTORY . "/" . $testname . DATA_FILE ) ) {
02482                 $testname .= "-" . mt_rand( 0, 9 );
02483         }
02484 
02485         $filename = DIRECTORY . "/" . $testname . DATA_FILE;
02486 
02487         // Store the time before and after, to find slow pages.
02488         $before = microtime( true );
02489 
02490         // Get MediaWiki to give us the output of this test.
02491         $wiki_preview = wikiTestOutput( $test );
02492 
02493         $after = microtime( true );
02494 
02495         // if we received no response, then that's interesting.
02496         if ( $wiki_preview == "" ) {
02497                 print "\nNo response received for: $filename";
02498                 return false;
02499         }
02500 
02501         // save output HTML to file.
02502         $html_file = DIRECTORY . "/" . $testname . HTML_FILE;
02503         saveFile( $wiki_preview,  $html_file );
02504 
02505         // if there were PHP errors in the output, then that's interesting too.
02506         if (       strpos( $wiki_preview, "<b>Warning</b>: "        ) !== false
02507                         || strpos( $wiki_preview, "<b>Fatal error</b>: "    ) !== false
02508                         || strpos( $wiki_preview, "<b>Notice</b>: "         ) !== false
02509                         || strpos( $wiki_preview, "<b>Error</b>: "          ) !== false
02510                         || strpos( $wiki_preview, "<b>Strict Standards:</b>" ) !== false
02511                         ) {
02512                 $error = substr( $wiki_preview, strpos( $wiki_preview, "</b>:" ) + 7, 50 );
02513                 // Avoid probable PHP bug with bad session ids; http://bugs.php.net/bug.php?id=38224
02514                 if ( $error != "Unknown: The session id contains illegal character" ) {
02515                         print "\nPHP error/warning/notice in HTML output: $html_file ; $error";
02516                         return false;
02517                 }
02518         }
02519 
02520         // if there was a MediaWiki Backtrace message in the output, then that's also interesting.
02521         if ( strpos( $wiki_preview, "Backtrace:" ) !== false ) {
02522                 print "\nInternal MediaWiki error in HTML output: $html_file";
02523                 return false;
02524         }
02525 
02526         // if there was a Parser error comment in the output, then that's potentially interesting.
02527         if ( strpos( $wiki_preview, "!-- ERR" ) !== false ) {
02528                 print "\nParser Error comment in HTML output: $html_file";
02529                 return false;
02530         }
02531 
02532         // if a database error was logged, then that's definitely interesting.
02533         if ( dbErrorLogged() ) {
02534                 print "\nDatabase Error logged for: $filename";
02535                 return false;
02536         }
02537 
02538         // validate result
02539         $valid = true;
02540         if ( VALIDATE_ON_WEB ) {
02541                 list ( $valid, $validator_output ) = validateHTML( $wiki_preview );
02542                 if ( !$valid ) print "\nW3C web validation failed - view details with: html2text " . DIRECTORY . "/" . $testname . ".validator_output.html";
02543         }
02544 
02545         // Get tidy to check the page, unless we already know it produces non-XHTML output.
02546         if ( $test->tidyValidate() ) {
02547                 $valid = tidyCheckFile( $testname . HTML_FILE ) && $valid;
02548         }
02549 
02550         // if it took more than 2 seconds to render, then it may be interesting too. (Possible DoS attack?)
02551         if ( ( $after - $before ) >= 2 ) {
02552                 print "\nParticularly slow to render (" . round( $after - $before, 2 ) . " seconds): $filename";
02553                 return false;
02554         }
02555 
02556         if ( $valid ) {
02557                 // Remove temp HTML file if test was valid:
02558                 unlink( $html_file );
02559         } elseif ( VALIDATE_ON_WEB ) {
02560                 saveFile( $validator_output,   DIRECTORY . "/" . $testname . ".validator_output.html" );
02561         }
02562 
02563         return $valid;
02564 }
02565 
02566 
02567 // ///////////////// RERUNNING OLD TESTS ///////////////////
02568 
02573 function rerunPreviousTests() {
02574         print "Retesting previously found problems.\n";
02575 
02576         $dir_contents = scandir ( DIRECTORY );
02577 
02578         // sort file into the order a normal person would use.
02579         natsort ( $dir_contents );
02580 
02581         foreach ( $dir_contents as $file ) {
02582 
02583                 // if file is not a test, then skip it.
02584                 // Note we need to escape any periods or will be treated as "any character".
02585                 $matches = array();
02586                 if ( !preg_match( "/(.*)" . str_replace( ".", "\.", DATA_FILE ) . "$/", $file, $matches ) ) continue;
02587 
02588                 // reload the test.
02589                 $full_path = DIRECTORY . "/" . $file;
02590                 $test = unserialize( file_get_contents( $full_path ) );
02591 
02592                 // if this is not a valid test, then skip it.
02593                 if ( ! $test instanceof pageTest ) {
02594                         print "\nSkipping invalid test - $full_path";
02595                         continue;
02596                 }
02597 
02598                 // The date format is in Apache log format, which makes it easier to locate
02599                 // which retest caused which error in the Apache logs (only happens usually if
02600                 // apache segfaults).
02601                 if ( !QUIET ) print "[" . date ( "D M d H:i:s Y" ) . "] Retesting $file (" . get_class( $test ) . ")";
02602 
02603                 // run test
02604                 $testname = $matches[1];
02605                 $valid = runWikiTest( $test, $testname, true );
02606 
02607                 if ( !$valid ) {
02608                         saveTest( $test, $testname );
02609                         if ( QUIET ) {
02610                                 print "\nTest: " . get_class( $test ) . " ; Testname: $testname\n------";
02611                         } else {
02612                                 print "\n";
02613                         }
02614                 }
02615                 else {
02616                         if ( !QUIET ) print "\r";
02617                         if ( DELETE_PASSED_RETESTS ) {
02618                                 $prefix = DIRECTORY . "/" . $testname;
02619                                 if ( is_file( $prefix . DATA_FILE ) ) unlink( $prefix . DATA_FILE );
02620                                 if ( is_file( $prefix . PHP_TEST ) ) unlink( $prefix . PHP_TEST );
02621                                 if ( is_file( $prefix . CURL_TEST ) ) unlink( $prefix . CURL_TEST );
02622                                 if ( is_file( $prefix . INFO_FILE ) ) unlink( $prefix . INFO_FILE );
02623                         }
02624                 }
02625         }
02626 
02627         print "\nDone retesting.\n";
02628 }
02629 
02630 
02631 // ////////////////////  MAIN LOOP  ////////////////////////
02632 
02633 
02634 // first check whether CURL is installed, because sometimes it's not.
02635 if ( ! function_exists( 'curl_init' ) ) {
02636         die( "Could not find 'curl_init' function. Is the curl extension compiled into PHP?\n" );
02637 }
02638 
02639 // Initialization of types. wikiFuzz doesn't have a constructor because we want to
02640 // access it staticly and not have any globals.
02641 wikiFuzz::$types = array_keys( wikiFuzz::$data );
02642 
02643 // Make directory if doesn't exist
02644 if ( !is_dir( DIRECTORY ) ) {
02645         mkdir ( DIRECTORY, 0700 );
02646 }
02647 // otherwise, we first retest the things that we have found in previous runs
02648 elseif ( RERUN_OLD_TESTS ) {
02649         rerunPreviousTests();
02650 }
02651 
02652 // main loop.
02653 $start_time = date( "U" );
02654 $num_errors = 0;
02655 if ( !QUIET ) {
02656         print "Beginning main loop. Results are stored in the " . DIRECTORY . " directory.\n";
02657         print "Press CTRL+C to stop testing.\n";
02658 }
02659 
02660 for ( $count = 0; true; $count++ ) {
02661         if ( !QUIET ) {
02662                 // spinning progress indicator.
02663                 switch( $count % 4 ) {
02664                         case '0': print "\r/";  break;
02665                         case '1': print "\r-";  break;
02666                         case '2': print "\r\\"; break;
02667                         case '3': print "\r|";  break;
02668                 }
02669                 print " $count";
02670         }
02671 
02672         // generate a page test to run.
02673         $test = selectPageTest( $count );
02674 
02675         $mins = ( date( "U" ) - $start_time ) / 60;
02676         if ( !QUIET && $mins > 0 ) {
02677                 print ".  $num_errors poss errors. "
02678                         . floor( $mins ) . " mins. "
02679                         . round ( $count / $mins, 0 ) . " tests/min. "
02680                         . get_class( $test ); // includes the current test name.
02681         }
02682 
02683         // run this test against MediaWiki, and see if the output was valid.
02684         $testname = $count;
02685         $valid = runWikiTest( $test, $testname, false );
02686 
02687         // save the failed test
02688         if ( ! $valid ) {
02689                 if ( QUIET ) {
02690                         print "\nTest: " . get_class( $test ) . " ; Testname: $testname\n------";
02691                 } else {
02692                         print "\n";
02693                 }
02694                 saveTest( $test, $testname );
02695                 $num_errors += 1;
02696         } elseif ( KEEP_PASSED_TESTS ) {
02697                 // print current time, with microseconds (matches "strace" format), and the test name.
02698                 print " " . date( "H:i:s." ) . substr( current( explode( " ", microtime() ) ), 2 ) . " " . $testname;
02699                 saveTest( $test, $testname );
02700         }
02701 
02702         // stop if we have reached max number of errors.
02703         if ( defined( "MAX_ERRORS" ) && $num_errors >= MAX_ERRORS ) {
02704                 break;
02705         }
02706 
02707         // stop if we have reached max number of mins runtime.
02708         if ( defined( "MAX_RUNTIME" ) && $mins >= MAX_RUNTIME ) {
02709                 break;
02710         }
02711 }
02712 
02713