MediaWiki  REL1_19
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( dirname( __FILE__ ) . '/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                         "dl"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00385                         "ruby"       => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00386                         "rt"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00387                         "rp"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00388                         "dt"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00389                         "dl"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00390                         "em"         => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00391                         "strong"     => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00392                         "i"          => array( "CLASS", "ID", "STYLE", "lang", "dir", "title" ),
00393                         "thead"      => array( "CLASS", "ID", "STYLE", "lang", "dir", "title",  'align', 'char', 'charoff', 'valign' ),
00394                         "tfoot"      => array( "CLASS", "ID", "STYLE", "lang", "dir", "title",  'align', 'char', 'charoff', 'valign' ),
00395                         "tbody"      => array( "CLASS", "ID", "STYLE", "lang", "dir", "title",  'align', 'char', 'charoff', 'valign' ),
00396                         "colgroup"   => array( "CLASS", "ID", "STYLE", "lang", "dir", "title",  'align', 'char', 'charoff', 'valign', 'span', 'width' ),
00397                         "col"        => array( "CLASS", "ID", "STYLE", "lang", "dir", "title",  'align', 'char', 'charoff', 'valign', 'span', 'width' ),
00398                         "pre"        => array( "CLASS", "ID", "STYLE", "lang", "dir", "title", "width" ),
00399 
00400                         // extension tags that accept parameters:
00401                         "sort"         => array( "order", "class" ),
00402                         "ref"          => array( "name" ),
00403                         "categorytree" => array( "hideroot", "mode", "style" ),
00404                         "chemform"     => array( "link", "wikilink", "query" ),
00405                         "section"      => array( "begin", "new" ),
00406 
00407                         // older MW transclusion.
00408                         "transclude"   => array( "page" ),
00409                                 );
00410 
00411         // The types of the HTML that we will be testing were defined above
00412         // Note: this needs to be initialized later to be equal to: array_keys(wikiFuzz::$data);
00413         // as such, it also needs to also be publicly modifiable.
00414         public static $types;
00415 
00416 
00417         // Some attribute values.
00418         static private $other = array( "&", "=", ":", "?", "\"", "\n", "%n%n%n%n%n%n%n%n%n%n%n%n", "\\" );
00419         static private $ints  = array(
00420                         // various numbers
00421                         "0", "-1", "127", "-7897", "89000", "808080", "90928345",
00422                         "0xfffffff", "ffff",
00423 
00424                         // Different ways of saying: '
00425                         "&#0000039;", // Long UTF-8 Unicode encoding
00426                         "&#39;",  // dec version.
00427                         "&#x27;", // hex version.
00428                         "&#xA7;", // malformed hex variant, MSB not zero.
00429 
00430                         // Different ways of saying: "
00431                         "&#0000034;", // Long UTF-8 Unicode encoding
00432                         "&#34;",
00433                         "&#x22;", // hex version.
00434                         "&#xA2;", // malformed hex variant, MSB not zero.
00435 
00436                         // Different ways of saying: <
00437                         "<",
00438                         "&#0000060",  // Long UTF-8 Unicode encoding without semicolon (Mediawiki wants the colon)
00439                         "&#0000060;", // Long UTF-8 Unicode encoding with semicolon
00440                         "&#60;",
00441                         "&#x3C;",     // hex version.
00442                         "&#xBC;",     // malformed hex variant, MSB not zero.
00443                         "&#x0003C;",  // mid-length hex version
00444                         "&#X00003C;", // slightly longer hex version, with capital "X"
00445 
00446                         // Different ways of saying: >
00447                         ">",
00448                         "&#0000062;", // Long UTF-8 Unicode encoding
00449                         "&#62;",
00450                         "&#x3E;",     // hex version.
00451                         "&#xBE;",     // malformed variant, MSB not zero.
00452 
00453                         // Different ways of saying: [
00454                         "&#0000091;", // Long UTF-8 Unicode encoding
00455                         "&#91;",
00456                         "&#x5B;",     // hex version.
00457 
00458                         // Different ways of saying: {{
00459                         "&#0000123;&#0000123;", // Long UTF-8 Unicode encoding
00460                         "&#123;&#123;",
00461                         "&#x7B;&#x7B;",         // hex version.
00462 
00463                         // Different ways of saying: |
00464                         "&#0000124;", // Long UTF-8 Unicode encoding
00465                         "&#124;",
00466                         "&#x7C;",     // hex version.
00467                         "&#xFC;",     // malformed hex variant, MSB not zero.
00468 
00469                         // a "lignature" - http://www.robinlionheart.com/stds/html4/spchars#ligature
00470                         // &#8204; == &zwnj;
00471                         "&#8204;"
00472                                 );
00473 
00474         // Defines various wiki-related bits of syntax, that can potentially cause
00475         // MediaWiki to do something other than just print that literal text.
00476         static private $ext = array(
00477                         // links, templates, parameters.
00478                         "[[", "]]", "{{", "}}", "|", "[", "]", "{{{", "}}}", "|]]",
00479 
00480                         // wiki tables.
00481                         "\n{|", "\n|}",
00482                         "!",
00483                         "\n!",
00484                         "!!",
00485                         "||",
00486                         "\n|-", "| ", "\n|",
00487 
00488                         // section headings.
00489                         "=", "==", "===", "====", "=====", "======",
00490 
00491                         // lists (ordered and unordered) and indentation.
00492                         "\n*", "*", "\n:", ":",
00493                         "\n#", "#",
00494 
00495                         // definition lists (dl, dt, dd), newline, and newline with pre, and a tab.
00496                         "\n;", ";", "\n ",
00497 
00498                         // Whitespace: newline, tab, space.
00499                         "\n", "\t", " ",
00500 
00501                         // Some XSS attack vectors from http://ha.ckers.org/xss.html
00502                         "&#x09;", // tab
00503                         "&#x0A;", // newline
00504                         "&#x0D;", // carriage return
00505                         "\0",     // null character
00506                         " &#14; ", // spaces and meta characters
00507                         "'';!--\"<XSS>=&{()}", // compact injection of XSS & SQL tester
00508 
00509                         // various NULL fields
00510                         "%00",
00511                         "&#00;",
00512                         "\0",
00513 
00514                         // horizontal rule.
00515                         "-----", "\n-----",
00516 
00517                         // signature, redirect, bold, italics.
00518                         "~~~~", "#REDIRECT [[", "'''", "''",
00519 
00520                         // comments.
00521                         "<!--", "-->",
00522 
00523                         // quotes.
00524                         "\"", "'",
00525 
00526                         // tag start and tag end.
00527                         "<", ">",
00528 
00529                         // implicit link creation on URIs.
00530                         "http://",
00531                         "https://",
00532                         "ftp://",
00533                         "irc://",
00534                         "news:",
00535                         'gopher://',
00536                         'telnet://',
00537                         'nntp://',
00538                         'worldwind://',
00539                         'mailto:',
00540 
00541                         // images.
00542                         "[[image:",
00543                         ".gif",
00544                         ".png",
00545                         ".jpg",
00546                         ".jpeg",
00547                         'thumbnail=',
00548                         'thumbnail',
00549                         'thumb=',
00550                         'thumb',
00551                         'right',
00552                         'none',
00553                         'left',
00554                         'framed',
00555                         'frame',
00556                         'enframed',
00557                         'centre',
00558                         'center',
00559                         "Image:",
00560                         "[[:Image",
00561                         'px',
00562                         'upright=',
00563                         'border',
00564 
00565                         // misc stuff to throw at the Parser.
00566                         '%08X',
00567                         '/',
00568                         ":x{|",
00569                         "\n|+",
00570                         "<noinclude>",
00571                         "</noinclude>",
00572                         " \302\273",
00573                         " :",
00574                         " !",
00575                         " ;",
00576                         "\302\253",
00577                         "[[category:",
00578                         "?=",
00579                         "(",
00580                         ")",
00581                         "]]]",
00582                         "../",
00583                         "{{{{",
00584                         "}}}}",
00585                         "[[Special:",
00586                         "<includeonly>",
00587                         "</includeonly>",
00588                         "<!--MWTEMPLATESECTION=",
00589                         '<!--MWTOC-->',
00590 
00591                         // implicit link creation on booknum, RFC, and PubMed ID usage (both with and without IDs)
00592                         "ISBN 2",
00593                         "RFC 000",
00594                         "PMID 000",
00595                         "ISBN ",
00596                         "RFC ",
00597                         "PMID ",
00598 
00599                         // magic words:
00600                         '__NOTOC__',
00601                         '__FORCETOC__',
00602                         '__NOEDITSECTION__',
00603                         '__START__',
00604                         '__NOTITLECONVERT__',
00605                         '__NOCONTENTCONVERT__',
00606                         '__END__',
00607                         '__TOC__',
00608                         '__NOTC__',
00609                         '__NOCC__',
00610                         "__FORCETOC__",
00611                         "__NEWSECTIONLINK__",
00612                         "__NOGALLERY__",
00613 
00614                         // more magic words / internal templates.
00615                         '{{PAGENAME}}',
00616                         '{{PAGENAMEE}}',
00617                         '{{NAMESPACE}}',
00618                         "{{MSG:",
00619                         "}}",
00620                         "{{MSGNW:",
00621                         "}}",
00622                         "{{INT:",
00623                         "}}",
00624                         '{{SITENAME}}',
00625                         "{{NS:",
00626                         "}}",
00627                         "{{LOCALURL:",
00628                         "}}",
00629                         "{{LOCALURLE:",
00630                         "}}",
00631                         "{{SCRIPTPATH}}",
00632                         "{{GRAMMAR:gentiv|",
00633                         "}}",
00634                         "{{REVISIONID}}",
00635                         "{{SUBPAGENAME}}",
00636                         "{{SUBPAGENAMEE}}",
00637                         "{{ns:0}}",
00638                         "{{fullurle:",
00639                         "}}",
00640                         "{{subst::",
00641                         "}}",
00642                         "{{UCFIRST:",
00643                         "}}",
00644                         "{{UC:",
00645                         '{{SERVERNAME}}',
00646                         '{{SERVER}}',
00647                         "{{RAW:",
00648                         "}}",
00649                         "{{PLURAL:",
00650                         "}}",
00651                         "{{LCFIRST:",
00652                         "}}",
00653                         "{{LC:",
00654                         "}}",
00655                         '{{CURRENTWEEK}}',
00656                         '{{CURRENTDOW}}',
00657                         "{{INT:{{LC:contribs-showhideminor}}|",
00658                         "}}",
00659                         "{{INT:googlesearch|",
00660                         "}}",
00661                         "{{BASEPAGENAME}}",
00662                         "{{CONTENTLANGUAGE}}",
00663                         "{{PAGESINNAMESPACE:}}",
00664                         "{{#language:",
00665                         "}}",
00666                         "{{#special:",
00667                         "}}",
00668                         "{{#special:emailuser",
00669                         "}}",
00670 
00671                         // Some raw link for magic words.
00672                         "{{NUMBEROFPAGES:R",
00673                         "}}",
00674                         "{{NUMBEROFUSERS:R",
00675                         "}}",
00676                         "{{NUMBEROFARTICLES:R",
00677                         "}}",
00678                         "{{NUMBEROFFILES:R",
00679                         "}}",
00680                         "{{NUMBEROFADMINS:R",
00681                         "}}",
00682                         "{{padleft:",
00683                         "}}",
00684                         "{{padright:",
00685                         "}}",
00686                         "{{DEFAULTSORT:",
00687                         "}}",
00688 
00689                         // internal Math "extension":
00690                         "<math>",
00691                         "</math>",
00692 
00693                         // Parser extension functions:
00694                         "{{#expr:",
00695                         "{{#if:",
00696                         "{{#ifeq:",
00697                         "{{#ifexist:",
00698                         "{{#ifexpr:",
00699                         "{{#switch:",
00700                         "{{#time:",
00701                         "}}",
00702 
00703                         // references table for the Cite extension.
00704                         "<references/>",
00705 
00706                         // Internal Parser tokens - try inserting some of these.
00707                         "UNIQ25f46b0524f13e67NOPARSE",
00708                         "UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002",
00709                         "\x07UNIQ17197916557e7cd6-HTMLCommentStrip46238afc3bb0cf5f00000002-QINU",
00710 
00711                         // Inputbox extension:
00712                         "<inputbox>\ntype=search\nsearchbuttonlabel=\n",
00713                         "</inputbox>",
00714 
00715                         // charInsert extension:
00716                         "<charInsert>",
00717                         "</charInsert>",
00718 
00719                         // wikiHiero extension:
00720                         "<hiero>",
00721                         "</hiero>",
00722 
00723                         // Image gallery:
00724                         "<gallery>",
00725                         "</gallery>",
00726 
00727                         // FixedImage extension.
00728                         "<fundraising/>",
00729 
00730                         // Timeline extension: currently untested.
00731 
00732                         // Nowiki:
00733                         "<nOwIkI>",
00734                         "</nowiki>",
00735 
00736                         // an external image to test the external image displaying code
00737                         "http://debian.org/Pics/debian.png",
00738 
00739                         // LabeledSectionTransclusion extension.
00740                         "{{#lstx:",
00741                         "}}",
00742                         "{{#lst:",
00743                         "}}",
00744                         "{{#lst:Main Page|",
00745                         "}}"
00746                         );
00747 
00751         static public function chooseInput( array $input ) {
00752                 $randindex = wikiFuzz::randnum( count( $input ) - 1 );
00753                 return $input[$randindex];
00754         }
00755 
00756         // Max number of parameters for HTML attributes.
00757         static private $maxparams = 10;
00758 
00765         static public function randnum( $finish, $start = 0 ) {
00766                 return mt_rand( $start, $finish );
00767         }
00768 
00773         static private function randstring() {
00774                 $thestring = "";
00775 
00776                 for ( $i = 0; $i < 40; $i++ ) {
00777                         $what = wikiFuzz::randnum( 1 );
00778 
00779                         if ( $what == 0 ) { // include some random wiki syntax
00780                                 $which = wikiFuzz::randnum( count( wikiFuzz::$ext ) - 1 );
00781                                 $thestring .= wikiFuzz::$ext[$which];
00782                         }
00783                         else { // include some random text
00784                                 $char = INCLUDE_BINARY
00785                                         // Decimal version:
00786                                         // "&#" . wikiFuzz::randnum(255) . ";"
00787                                         // Hex version:
00788                                         ? "&#x" . str_pad( dechex( wikiFuzz::randnum( 255 ) ), wikiFuzz::randnum( 2, 7 ), "0", STR_PAD_LEFT ) . ";"
00789                                         // A truly binary version:
00790                                         // ? chr(wikiFuzz::randnum(0,255))
00791                                         : chr( wikiFuzz::randnum( 126, 32 ) );
00792 
00793                                 $length = wikiFuzz::randnum( 8 );
00794                                 $thestring .= str_repeat ( $char, $length );
00795                         }
00796                 }
00797                 return $thestring;
00798         }
00799 
00805         static private function makestring() {
00806                 $what = wikiFuzz::randnum( 2 );
00807                 if ( $what == 0 ) {
00808                         return wikiFuzz::randstring();
00809                 } elseif ( $what == 1 ) {
00810                         return wikiFuzz::$ints[wikiFuzz::randnum( count( wikiFuzz::$ints ) - 1 )];
00811                 } else {
00812                         return wikiFuzz::$other[wikiFuzz::randnum( count( wikiFuzz::$other ) - 1 )];
00813                 }
00814         }
00815 
00822         static private function stringEscape( $matches ) {
00823                 return sprintf( "\\x%02x", ord( $matches[1] ) );
00824         }
00825 
00832         static public function makeTitleSafe( $str ) {
00833                 $legalTitleChars = " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF";
00834                 return preg_replace_callback(
00835                                 "/([^$legalTitleChars])/", 'wikiFuzz::stringEscape',
00836                                 $str );
00837         }
00838 
00843         static private function loop() {
00844                 switch ( wikiFuzz::randnum( 3 ) ) {
00845                         case 1: // an opening tag, with parameters.
00846                                 $string = "";
00847                                 $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 );
00848                                 $t = wikiFuzz::$types[$i];
00849                                 $arr = wikiFuzz::$data[$t];
00850                                 $string .= "<" . $t . " ";
00851                                 $num_params = min( wikiFuzz::$maxparams, count( $arr ) );
00852                                 for ( $z = 0; $z < $num_params; $z++ ) {
00853                                         $badparam = $arr[wikiFuzz::randnum( count( $arr ) - 1 )];
00854                                         $badstring = wikiFuzz::makestring();
00855                                         $string .= $badparam . "=" . wikiFuzz::getRandQuote() . $badstring . wikiFuzz::getRandQuote() . " ";
00856                                 }
00857                                 $string .= ">\n";
00858                                 return $string;
00859                         case 2: // a closing tag.
00860                                 $i = wikiFuzz::randnum( count( wikiFuzz::$types ) - 1 );
00861                                 return "</" . wikiFuzz::$types[$i] . ">";
00862                         case 3: // a random string, between tags.
00863                                 return wikiFuzz::makeString();
00864                 }
00865                 return "";    // catch-all, should never be called.
00866         }
00867 
00872         static private function getRandQuote() {
00873                 switch ( wikiFuzz::randnum( 3 ) ) {
00874                         case 1 : return "'";
00875                         case 2 : return "\"";
00876                         default: return "";
00877                 }
00878         }
00879 
00885         static public function makeFuzz( $maxtypes = 2 ) {
00886                 $page = "";
00887                 for ( $k = 0; $k < $maxtypes; $k++ ) {
00888                         $page .= wikiFuzz::loop();
00889                 }
00890                 return $page;
00891         }
00892 }
00893 
00894 
00895 // //////   MEDIAWIKI PAGES TO TEST, AND HOW TO TEST THEM  ///////
00896 
00906 abstract class pageTest {
00907         protected $params;
00908         protected $pagePath;
00909         protected $cookie = "";
00910         protected $tidyValidate = true;
00911 
00912         public function getParams() {
00913                 return $this->params;
00914         }
00915 
00916         public function getPagePath() {
00917                 return $this->pagePath;
00918         }
00919 
00920         public function getCookie() {
00921                 return $this->cookie;
00922         }
00923 
00924         public function tidyValidate() {
00925                 return $this->tidyValidate;
00926         }
00927 }
00928 
00929 
00933 class editPageTest extends pageTest {
00934         function __construct() {
00935                 $this->pagePath = "index.php?title=WIKIFUZZ";
00936 
00937                 $this->params = array (
00938                                 "action"        => "submit",
00939                                 "wpMinoredit"   => wikiFuzz::makeFuzz( 2 ),
00940                                 "wpPreview"     => wikiFuzz::makeFuzz( 2 ),
00941                                 "wpSection"     => wikiFuzz::makeFuzz( 2 ),
00942                                 "wpEdittime"    => wikiFuzz::makeFuzz( 2 ),
00943                                 "wpSummary"     => wikiFuzz::makeFuzz( 2 ),
00944                                 "wpScrolltop"   => wikiFuzz::makeFuzz( 2 ),
00945                                 "wpStarttime"   => wikiFuzz::makeFuzz( 2 ),
00946                                 "wpAutoSummary" => wikiFuzz::makeFuzz( 2 ),
00947                                 "wpTextbox1"    => wikiFuzz::makeFuzz( 40 )  // the main wiki text, need lots of this.
00948                                 );
00949 
00950                 // sometimes we don't want to specify certain parameters.
00951                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSection"] );
00952                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpEdittime"] );
00953                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpSummary"] );
00954                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpScrolltop"] );
00955                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpStarttime"] );
00956                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpAutoSummary"] );
00957                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["wpTextbox1"] );
00958         }
00959 }
00960 
00961 
00965 class listusersTest extends pageTest {
00966         function __construct() {
00967                 $this->pagePath = "index.php?title=Special:Listusers";
00968 
00969                 $this->params = array (
00970                                 "title"        => wikiFuzz::makeFuzz( 2 ),
00971                                 "group"        => wikiFuzz::makeFuzz( 2 ),
00972                                 "username"     => wikiFuzz::makeFuzz( 2 ),
00973                                 "Go"           => wikiFuzz::makeFuzz( 2 ),
00974                                 "limit"        => wikiFuzz::chooseInput( array( "0", "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
00975                                 "offset"       => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) )
00976                                 );
00977         }
00978 }
00979 
00980 
00984 class searchTest extends pageTest {
00985         function __construct() {
00986                 $this->pagePath = "index.php?title=Special:Search";
00987 
00988                 $this->params = array (
00989                                 "action"        => "index.php?title=Special:Search",
00990                                 "ns0"           => wikiFuzz::makeFuzz( 2 ),
00991                                 "ns1"           => wikiFuzz::makeFuzz( 2 ),
00992                                 "ns2"           => wikiFuzz::makeFuzz( 2 ),
00993                                 "ns3"           => wikiFuzz::makeFuzz( 2 ),
00994                                 "ns4"           => wikiFuzz::makeFuzz( 2 ),
00995                                 "ns5"           => wikiFuzz::makeFuzz( 2 ),
00996                                 "ns6"           => wikiFuzz::makeFuzz( 2 ),
00997                                 "ns7"           => wikiFuzz::makeFuzz( 2 ),
00998                                 "ns8"           => wikiFuzz::makeFuzz( 2 ),
00999                                 "ns9"           => wikiFuzz::makeFuzz( 2 ),
01000                                 "ns10"          => wikiFuzz::makeFuzz( 2 ),
01001                                 "ns11"          => wikiFuzz::makeFuzz( 2 ),
01002                                 "ns12"          => wikiFuzz::makeFuzz( 2 ),
01003                                 "ns13"          => wikiFuzz::makeFuzz( 2 ),
01004                                 "ns14"          => wikiFuzz::makeFuzz( 2 ),
01005                                 "ns15"          => wikiFuzz::makeFuzz( 2 ),
01006                                 "redirs"        => wikiFuzz::makeFuzz( 2 ),
01007                                 "search"        => wikiFuzz::makeFuzz( 2 ),
01008                                 "offset"        => wikiFuzz::chooseInput( array( "", "0", "-1", "--------'-----0", "+1", "81343242346234234", wikiFuzz::makeFuzz( 2 ) ) ),
01009                                 "fulltext"      => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) ),
01010                                 "searchx"       => wikiFuzz::chooseInput( array( "", "0", "1", "--------'-----0", "+1", wikiFuzz::makeFuzz( 2 ) ) )
01011                                         );
01012         }
01013 }
01014 
01015 
01019 class recentchangesTest extends pageTest {
01020         function __construct() {
01021                 $this->pagePath = "index.php?title=Special:Recentchanges";
01022 
01023                 $this->params = array (
01024                                 "action"        => wikiFuzz::makeFuzz( 2 ),
01025                                 "title"         => wikiFuzz::makeFuzz( 2 ),
01026                                 "namespace"     => wikiFuzz::chooseInput( range( -1, 15 ) ),
01027                                 "Go"            => wikiFuzz::makeFuzz( 2 ),
01028                                 "invert"        => wikiFuzz::chooseInput( array( "-1", "---'----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01029                                 "hideanons"     => wikiFuzz::chooseInput( array( "-1", "------'-------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01030                                 'limit'         => wikiFuzz::chooseInput( array( "0", "-1", "---------'----0", "+1", "81340909772349234",  wikiFuzz::makeFuzz( 2 ) ) ),
01031                                 "days"          => wikiFuzz::chooseInput( array( "-1", "----------'---0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01032                                 "hideminor"     => wikiFuzz::chooseInput( array( "-1", "-----------'--0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01033                                 "hidebots"      => wikiFuzz::chooseInput( array( "-1", "---------'----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01034                                 "hideliu"       => wikiFuzz::chooseInput( array( "-1", "-------'------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01035                                 "hidepatrolled" => wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01036                                 "hidemyself"    => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01037                                 'categories_any' => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01038                                 'categories'    => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01039                                 'feed'          => wikiFuzz::chooseInput( array( "-1", "--'-----------0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) )
01040                                 );
01041         }
01042 }
01043 
01044 
01048 class prefixindexTest extends pageTest {
01049         function __construct() {
01050                 $this->pagePath = "index.php?title=Special:Prefixindex";
01051 
01052                 $this->params = array (
01053                                 "title"         => "Special:Prefixindex",
01054                                 "namespace"     => wikiFuzz::randnum( 101, -10 ),
01055                                 "Go"            => wikiFuzz::makeFuzz( 2 )
01056                                 );
01057 
01058                 // sometimes we want 'prefix', sometimes we want 'from', and sometimes we want nothing.
01059                 if ( wikiFuzz::randnum( 3 ) == 0 ) {
01060                         $this->params["prefix"] = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1",
01061                                                                                                  wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) );
01062                 }
01063                 if ( wikiFuzz::randnum( 3 ) == 0 ) {
01064                         $this->params["from"]   = wikiFuzz::chooseInput( array( "-1", "-----'--------0", "+++--+1",
01065                                                                                                 wikiFuzz::randnum( 8134, -10 ), wikiFuzz::makeFuzz( 2 ) ) );
01066                 }
01067         }
01068 }
01069 
01070 
01074 class mimeSearchTest extends pageTest {
01075         function __construct() {
01076                 $this->pagePath = "index.php?title=Special:MIMEsearch";
01077 
01078                 $this->params = array (
01079                                 "action"        => "index.php?title=Special:MIMEsearch",
01080                                 "mime"          => wikiFuzz::makeFuzz( 3 ),
01081                                 'limit'         => wikiFuzz::chooseInput( array( "0", "-1", "-------'------0", "+1", "81342321351235325",  wikiFuzz::makeFuzz( 2 ) ) ),
01082                                 'offset'        => wikiFuzz::chooseInput( array( "0", "-1", "-----'--------0", "+1", "81341231235365252234324",  wikiFuzz::makeFuzz( 2 ) ) )
01083                                 );
01084         }
01085 }
01086 
01087 
01091 class specialLogTest extends pageTest {
01092         function __construct() {
01093                 $this->pagePath = "index.php?title=Special:Log";
01094 
01095                 $this->params = array (
01096                                 "type"        => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
01097                                 "par"         => wikiFuzz::makeFuzz( 2 ),
01098                                 "user"        => wikiFuzz::makeFuzz( 2 ),
01099                                 "page"        => wikiFuzz::makeFuzz( 2 ),
01100                                 "from"        => wikiFuzz::makeFuzz( 2 ),
01101                                 "until"       => wikiFuzz::makeFuzz( 2 ),
01102                                 "title"       => wikiFuzz::makeFuzz( 2 )
01103                                 );
01104         }
01105 }
01106 
01107 
01111 class successfulUserLoginTest extends pageTest {
01112         function __construct() {
01113                 $this->pagePath = "index.php?title=Special:Userlogin&action=submitlogin&type=login&returnto=" . wikiFuzz::makeFuzz( 2 );
01114 
01115                 $this->params = array (
01116                                 "wpName"          => USER_ON_WIKI,
01117                                 // sometimes real password, sometimes not:
01118                                 'wpPassword'      => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), USER_PASSWORD ) ),
01119                                 'wpRemember'      => wikiFuzz::makeFuzz( 2 )
01120                                 );
01121 
01122                 $this->cookie = "wikidb_session=" .  wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) );
01123         }
01124 }
01125 
01126 
01130 class userLoginTest extends pageTest {
01131         function __construct() {
01132 
01133                 $this->pagePath = "index.php?title=Special:Userlogin";
01134 
01135                 $this->params = array (
01136                                 'wpRetype'        => wikiFuzz::makeFuzz( 2 ),
01137                                 'wpRemember'      => wikiFuzz::makeFuzz( 2 ),
01138                                 'wpRealName'      => wikiFuzz::makeFuzz( 2 ),
01139                                 'wpPassword'      => wikiFuzz::makeFuzz( 2 ),
01140                                 'wpName'          => wikiFuzz::makeFuzz( 2 ),
01141                                 'wpMailmypassword' => wikiFuzz::makeFuzz( 2 ),
01142                                 'wpLoginattempt'  => wikiFuzz::makeFuzz( 2 ),
01143                                 'wpEmail'         => wikiFuzz::makeFuzz( 2 ),
01144                                 'wpDomain'        => wikiFuzz::chooseInput( array( "", "local", wikiFuzz::makeFuzz( 2 ) ) ),
01145                                 'wpCreateaccountMail' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
01146                                 'wpCreateaccount' => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
01147                                 'wpCookieCheck'   => wikiFuzz::chooseInput( array( "", wikiFuzz::makeFuzz( 2 ) ) ),
01148                                 'type'            => wikiFuzz::chooseInput( array( "signup", "login", "", wikiFuzz::makeFuzz( 2 ) ) ),
01149                                 'returnto'        => wikiFuzz::makeFuzz( 2 ),
01150                                 'action'          => wikiFuzz::chooseInput( array( "", "submitlogin", wikiFuzz::makeFuzz( 2 ) ) )
01151                                 );
01152 
01153                 $this->cookie = "wikidb_session=" . wikiFuzz::chooseInput( array( "1" , wikiFuzz::makeFuzz( 2 ) ) );
01154         }
01155 }
01156 
01157 
01161 class ipblocklistTest extends pageTest {
01162         function __construct() {
01163                 $this->pagePath = "index.php?title=Special:Ipblocklist";
01164 
01165                 $this->params = array (
01166                                 'wpUnblockAddress' => wikiFuzz::makeFuzz( 2 ),
01167                                 'ip'              => wikiFuzz::chooseInput( array( "20398702394", "", "Nickj2", wikiFuzz::makeFuzz( 2 ),
01168                                                                          // something like an IP address, sometimes invalid:
01169                                                                          ( wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) . "."
01170                                                                            . wikiFuzz::randnum( 300, -20 ) . "." . wikiFuzz::randnum( 300, -20 ) ) ) ),
01171                                 'id'              => wikiFuzz::makeFuzz( 2 ),
01172                                 'wpUnblockReason' => wikiFuzz::makeFuzz( 2 ),
01173                                 'action'          => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "success", "submit", "unblock" ) ),
01174                                 'wpEditToken'     => wikiFuzz::makeFuzz( 2 ),
01175                                 'wpBlock'         => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "" ) ),
01176                                 'limit'           => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1",
01177                                                                                                  "09700982312351132098234",  wikiFuzz::makeFuzz( 2 ) ) ),
01178                                 'offset'          => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1",
01179                                                                                                  "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) )
01180                                 );
01181 
01182                 // sometimes we don't want to specify certain parameters.
01183                 if ( wikiFuzz::randnum( 4 ) == 0 ) unset( $this->params["action"] );
01184                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["ip"] );
01185                 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["id"] );
01186                 if ( wikiFuzz::randnum( 3 ) == 0 ) unset( $this->params["wpUnblockAddress"] );
01187         }
01188 }
01189 
01190 
01194 class newImagesTest extends  pageTest {
01195         function __construct() {
01196                 $this->pagePath = "index.php?title=Special:Newimages";
01197 
01198                 $this->params = array (
01199                                 'hidebots'  => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "1", "", "-1" ) ),
01200                                 'wpIlMatch' => wikiFuzz::makeFuzz( 2 ),
01201                                 'until'     => wikiFuzz::makeFuzz( 2 ),
01202                                 'from'      => wikiFuzz::makeFuzz( 2 )
01203                                 );
01204 
01205                 // sometimes we don't want to specify certain parameters.
01206                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["until"] );
01207                 if ( wikiFuzz::randnum( 6 ) == 0 ) unset( $this->params["from"] );
01208         }
01209 }
01210 
01211 
01215 class imagelistTest extends pageTest {
01216         function __construct() {
01217                 $this->pagePath = "index.php?title=Special:Imagelist";
01218 
01219                 $this->params = array (
01220                                 'sort'      => wikiFuzz::chooseInput( array( "bysize", "byname" , "bydate", wikiFuzz::makeFuzz( 2 ) ) ),
01221                                 'limit'     => wikiFuzz::chooseInput( array( "0", "-1", "--------'-----0", "+1", "09700982312351132098234",  wikiFuzz::makeFuzz( 2 ) ) ),
01222                                 'offset'    => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ),
01223                                 'wpIlMatch' => wikiFuzz::makeFuzz( 2 )
01224                                 );
01225         }
01226 }
01227 
01228 
01232 class specialExportTest extends pageTest {
01233         function __construct() {
01234                 $this->pagePath = "index.php?title=Special:Export";
01235 
01236                 $this->params = array (
01237                                 'action'      => wikiFuzz::chooseInput( array( "submit", "", wikiFuzz::makeFuzz( 2 ) ) ),
01238                                 'pages'       => wikiFuzz::makeFuzz( 2 ),
01239                                 'curonly'     => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ),
01240                                 'listauthors' => wikiFuzz::chooseInput( array( "", "0", "-1", wikiFuzz::makeFuzz( 2 ) ) ),
01241                                 'history'     => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "09700980982341535324234234", wikiFuzz::makeFuzz( 2 ) ) ),
01242 
01243                                 );
01244 
01245                 // For the time being, need to disable "submit" action as Tidy barfs on MediaWiki's XML export.
01246                 if ( $this->params['action'] == 'submit' ) $this->params['action'] = '';
01247 
01248                 // Sometimes remove the history field.
01249                 if ( wikiFuzz::randnum( 2 ) == 0 ) unset( $this->params["history"] );
01250 
01251                 // page does not produce HTML.
01252                 $this->tidyValidate = false;
01253         }
01254 }
01255 
01256 
01260 class specialBooksourcesTest extends pageTest {
01261         function __construct() {
01262                 $this->pagePath = "index.php?title=Special:Booksources";
01263 
01264                 $this->params = array (
01265                                 'go'    => wikiFuzz::makeFuzz( 2 ),
01266                                 // ISBN codes have to contain some semi-numeric stuff or will be ignored:
01267                                 'isbn'  => "0X0" . wikiFuzz::makeFuzz( 2 )
01268                                 );
01269         }
01270 }
01271 
01272 
01276 class specialAllpagesTest extends pageTest {
01277         function __construct() {
01278                 $this->pagePath = "index.php?title=Special%3AAllpages";
01279 
01280                 $this->params = array (
01281                                 'from'      => wikiFuzz::makeFuzz( 2 ),
01282                                 'namespace' => wikiFuzz::chooseInput( range( -1, 15 ) ),
01283                                 'go'        => wikiFuzz::makeFuzz( 2 )
01284                                 );
01285         }
01286 }
01287 
01288 
01292 class pageHistoryTest extends pageTest {
01293         function __construct() {
01294                 $this->pagePath = "index.php?title=Main_Page&action=history";
01295 
01296                 $this->params = array (
01297                                 'limit'     => wikiFuzz::chooseInput( array( "-1", "0", "-------'------0", "+1", "8134",  wikiFuzz::makeFuzz( 2 ) ) ),
01298                                 'offset'    => wikiFuzz::chooseInput( array( "-1", "0", "------'-------0", "+1", "9823412312312412435", wikiFuzz::makeFuzz( 2 ) ) ),
01299                                 "go"        => wikiFuzz::chooseInput( array( "first", "last", wikiFuzz::makeFuzz( 2 ) ) ),
01300                                 "dir"       => wikiFuzz::chooseInput( array( "prev", "next", wikiFuzz::makeFuzz( 2 ) ) ),
01301                                 "diff"      => wikiFuzz::chooseInput( array( "-1", "--------'-----0", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01302                                 "oldid"     => wikiFuzz::chooseInput( array( "prev", "-1", "+1", "8134", wikiFuzz::makeFuzz( 2 ) ) ),
01303                                 "feed"      => wikiFuzz::makeFuzz( 2 )
01304                                 );
01305         }
01306 }
01307 
01308 
01312 class contributionsTest extends pageTest {
01313         function __construct() {
01314                 $this->pagePath = "index.php?title=Special:Contributions/" . USER_ON_WIKI;
01315 
01316                 $this->params = array (
01317                                 'target'    => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ), "newbies", USER_ON_WIKI ) ),
01318                                 'namespace' => wikiFuzz::chooseInput( array( -1, 15, 1, wikiFuzz::makeFuzz( 2 ) ) ),
01319                                 'offset'    => wikiFuzz::chooseInput( array( "0", "-1", "------'-------0", "+1", "982342131232131231241", wikiFuzz::makeFuzz( 2 ) ) ),
01320                                 'bot'       => wikiFuzz::chooseInput( array( "", "-1", "0", "1", wikiFuzz::makeFuzz( 2 ) ) ),
01321                                 'go'        => wikiFuzz::chooseInput( array( "-1", 'prev', 'next', wikiFuzz::makeFuzz( 2 ) ) )
01322                                 );
01323         }
01324 }
01325 
01326 
01330 class viewPageTest extends pageTest {
01331         function __construct() {
01332                 $this->pagePath = "index.php?title=Main_Page";
01333 
01334                 $this->params = array (
01335                                 "useskin"        => wikiFuzz::chooseInput( array( "chick", "cologneblue", "myskin",
01336                                                                                 "nostalgia", "simple", "standard", wikiFuzz::makeFuzz( 2 ) ) ),
01337                                 "uselang"        => wikiFuzz::chooseInput( array( wikiFuzz::makeFuzz( 2 ),
01338                                                 "ab", "af", "an", "ar", "arc", "as", "ast", "av", "ay", "az", "ba",
01339                                                 "bat-smg", "be", "bg", "bm", "bn", "bo", "bpy", "br", "bs", "ca",
01340                                                 "ce", "cs", "csb", "cv", "cy", "da", "de", "dv", "dz", "el", "en",
01341                                                 "eo", "es", "et", "eu", "fa", "fi", "fo", "fr", "fur", "fy", "ga",
01342                                                 "gn", "gsw", "gu", "he", "hi", "hr", "hu", "ia", "id", "ii", "is",
01343                                                 "it", "ja", "jv", "ka", "km", "kn", "ko", "ks", "ku", "kv", "la",
01344                                                 "li", "lo", "lt", "lv", "mk", "ml", "ms", "nah", "nap", "nds",
01345                                                 "nds-nl", "nl", "nn", "no", "non", "nv", "oc", "or", "os", "pa",
01346                                                 "pl", "pms", "ps", "pt", "pt-br", "qu", "rmy", "ro", "ru", "sc",
01347                                                 "sd", "sk", "sl", "sq", "sr", "sr-ec", "sr-el",
01348                                                 "su", "sv", "ta", "te", "th", "tr", "tt", "ty", "tyv", "udm",
01349                                                 "ug", "uk", "ur", "utf8", "vec", "vi", "wa", "xal", "yi", "za",
01350                                                 "zh", "zh-cn", "zh-hk", "zh-sg", "zh-tw", "zh-tw" ) ),
01351                                 "returnto"       => wikiFuzz::makeFuzz( 2 ),
01352                                 "feed"           => wikiFuzz::chooseInput( array( "atom", "rss", wikiFuzz::makeFuzz( 2 ) ) ),
01353                                 "rcid"           => wikiFuzz::makeFuzz( 2 ),
01354                                 "action"         => wikiFuzz::chooseInput( array( "view", "raw", "render", wikiFuzz::makeFuzz( 2 ), "markpatrolled" ) ),
01355                                 "printable"      => wikiFuzz::makeFuzz( 2 ),
01356                                 "oldid"          => wikiFuzz::makeFuzz( 2 ),
01357                                 "redirect"       => wikiFuzz::makeFuzz( 2 ),
01358                                 "diff"           => wikiFuzz::makeFuzz( 2 ),
01359                                 "search"         => wikiFuzz::makeFuzz( 2 ),
01360                                 "rdfrom"         => wikiFuzz::makeFuzz( 2 ),  // things from Article.php from here on:
01361                                 "token"          => wikiFuzz::makeFuzz( 2 ),
01362                                 "tbid"           => wikiFuzz::makeFuzz( 2 ),
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