Merge "Bug 36785 Special:Shortpages lists only NS_MAIN pages. (pages from all $wgCont...
[lhc/web/wiklou.git] / tests / parser / parserTest.inc
index a97f2c5..deb5c5a 100644 (file)
@@ -50,9 +50,16 @@ class ParserTest {
 
        /**
         * Our connection to the database
+        * @var DatabaseBase
         */
        private $db;
 
+       /**
+        * Database clone helper
+        * @var CloneDatabase
+        */
+       private $dbClone;
+
        /**
         * string $oldTablePrefix Original table prefix
         */
@@ -71,7 +78,7 @@ class ParserTest {
         */
        public function __construct( $options = array() ) {
                # Only colorize output if stdout is a terminal.
-               $this->color = !wfIsWindows() && posix_isatty( 1 );
+               $this->color = !wfIsWindows() && Maintenance::posix_isatty( 1 );
 
                if ( isset( $options['color'] ) ) {
                        switch( $options['color'] ) {
@@ -98,6 +105,9 @@ class ParserTest {
 
                $this->showOutput = isset( $options['show-output'] );
 
+               if ( isset( $options['filter'] ) ) {
+                       $options['regex'] = $options['filter'];
+               }
 
                if ( isset( $options['regex'] ) ) {
                        if ( isset( $options['record'] ) ) {
@@ -125,49 +135,71 @@ class ParserTest {
        }
 
        static function setUp() {
-               global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc, $wgDeferredUpdateList,
+               global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc,
                        $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache,
-                       $wgMessageCache, $wgUseDatabaseMessages, $wgMsgCacheExpiry, $parserMemc,
                        $wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
-                       $wgThumbnailScriptPath, $wgScriptPath,
-                       $wgArticlePath, $wgStyleSheetPath, $wgScript, $wgStylePath;
+                       $parserMemc, $wgThumbnailScriptPath, $wgScriptPath,
+                       $wgArticlePath, $wgStyleSheetPath, $wgScript, $wgStylePath, $wgExtensionAssetsPath,
+                       $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType, $wgLockManagers;
 
                $wgScript = '/index.php';
                $wgScriptPath = '/';
                $wgArticlePath = '/wiki/$1';
                $wgStyleSheetPath = '/skins';
                $wgStylePath = '/skins';
+               $wgExtensionAssetsPath = '/extensions';
                $wgThumbnailScriptPath = false;
+               $wgLockManagers = array( array(
+                       'name'          => 'fsLockManager',
+                       'class'         => 'FSLockManager',
+                       'lockDirectory' => wfTempDir() . '/test-repo/lockdir',
+               ) );
                $wgLocalFileRepo = array(
-                       'class' => 'LocalRepo',
-                       'name' => 'local',
-                       'directory' => wfTempDir() . '/test-repo',
-                       'url' => 'http://example.com/images',
-                       'deletedDir' => wfTempDir() . '/test-repo/delete',
-                       'hashLevels' => 2,
+                       'class'           => 'LocalRepo',
+                       'name'            => 'local',
+                       'url'             => 'http://example.com/images',
+                       'hashLevels'      => 2,
                        'transformVia404' => false,
+                       'backend'         => new FSFileBackend( array(
+                               'name'        => 'local-backend',
+                               'lockManager' => 'fsLockManager',
+                               'containerPaths' => array(
+                                       'local-public'  => wfTempDir() . '/test-repo/public',
+                                       'local-thumb'   => wfTempDir() . '/test-repo/thumb',
+                                       'local-temp'    => wfTempDir() . '/test-repo/temp',
+                                       'local-deleted' => wfTempDir() . '/test-repo/deleted',
+                               )
+                       ) )
                );
                $wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';
                $wgNamespaceAliases['Image'] = NS_FILE;
                $wgNamespaceAliases['Image_talk'] = NS_FILE_TALK;
 
+               // XXX: tests won't run without this (for CACHE_DB)
+               if ( $wgMainCacheType === CACHE_DB ) {
+                       $wgMainCacheType = CACHE_NONE;
+               }
+               if ( $wgMessageCacheType === CACHE_DB ) {
+                       $wgMessageCacheType = CACHE_NONE;
+               }
+               if ( $wgParserCacheType === CACHE_DB ) {
+                       $wgParserCacheType = CACHE_NONE;
+               }
 
                $wgEnableParserCache = false;
-               $wgDeferredUpdateList = array();
-               $wgMemc = &wfGetMainCache();
-               $messageMemc = &wfGetMessageCacheStorage();
-               $parserMemc = &wfGetParserCacheStorage();
+               DeferredUpdates::clearPendingUpdates();
+               $wgMemc = wfGetMainCache(); // checks $wgMainCacheType
+               $messageMemc = wfGetMessageCacheStorage();
+               $parserMemc = wfGetParserCacheStorage();
 
                // $wgContLang = new StubContLang;
                $wgUser = new User;
-               $wgLang = new StubUserLang;
-               $wgOut = new StubObject( 'wgOut', 'OutputPage' );
+               $context = new RequestContext;
+               $wgLang = $context->getLanguage();
+               $wgOut = $context->getOutput();
                $wgParser = new StubObject( 'wgParser', $wgParserConf['class'], array( $wgParserConf ) );
-               $wgRequest = new WebRequest;
+               $wgRequest = $context->getRequest();
 
-               $wgMessageCache = new StubObject( 'wgMessageCache', 'MessageCache',
-                                                                                 array( $messageMemc, $wgUseDatabaseMessages,
-                                                                                                $wgMsgCacheExpiry ) );
                if ( $wgStyleDirectory === false ) {
                        $wgStyleDirectory   = "$IP/skins";
                }
@@ -181,8 +213,6 @@ class ParserTest {
                                        $options['setversion'] : SpecialVersion::getVersion();
                } elseif ( isset( $options['compare'] ) ) {
                        $this->recorder = new DbTestPreviewer( $this );
-               } elseif ( isset( $options['upload'] ) ) {
-                       $this->recorder = new RemoteTestRecorder( $this );
                } else {
                        $this->recorder = new TestRecorder( $this );
                }
@@ -246,8 +276,7 @@ class ParserTest {
                        if ( $fail ) {
                                echo "Test failed with seed {$this->fuzzSeed}\n";
                                echo "Input:\n";
-                               var_dump( $input );
-                               echo "\n\n";
+                               printf( "string(%d) \"%s\"\n\n", strlen( $input ), $input );
                                echo "$exception\n";
                        } else {
                                $numSuccess++;
@@ -422,10 +451,10 @@ class ParserTest {
                }
 
                $opts = $this->parseOptions( $opts );
-               $this->setupGlobals( $opts, $config );
+               $context = $this->setupGlobals( $opts, $config );
 
-               $user = new User();
-               $options = ParserOptions::newFromUser( $user );
+               $user = $context->getUser();
+               $options = ParserOptions::newFromContext( $context );
 
                if ( isset( $opts['title'] ) ) {
                        $titleText = $opts['title'];
@@ -442,7 +471,7 @@ class ParserTest {
                if ( isset( $opts['pst'] ) ) {
                        $out = $parser->preSaveTransform( $input, $title, $user, $options );
                } elseif ( isset( $opts['msg'] ) ) {
-                       $out = $parser->transformMsg( $input, $options );
+                       $out = $parser->transformMsg( $input, $options, $title );
                } elseif ( isset( $opts['section'] ) ) {
                        $section = $opts['section'];
                        $out = $parser->getSection( $input, $section );
@@ -451,8 +480,7 @@ class ParserTest {
                        $replace = $opts['replace'][1];
                        $out = $parser->replaceSection( $input, $section, $replace );
                } elseif ( isset( $opts['comment'] ) ) {
-                       $linker = $user->getSkin();
-                       $out = $linker->formatComment( $input, $title, $local );
+                       $out = Linker::formatComment( $input, $title, $local );
                } elseif ( isset( $opts['preload'] ) ) {
                        $out = $parser->getpreloadText( $input, $title, $options );
                } else {
@@ -470,10 +498,9 @@ class ParserTest {
                        if ( isset( $opts['ill'] ) ) {
                                $out = $this->tidy( implode( ' ', $output->getLanguageLinks() ) );
                        } elseif ( isset( $opts['cat'] ) ) {
-                               global $wgOut;
-
-                               $wgOut->addCategoryLinks( $output->getCategories() );
-                               $cats = $wgOut->getCategoryLinks();
+                               $outputPage = $context->getOutput();
+                               $outputPage->addCategoryLinks( $output->getCategories() );
+                               $cats = $outputPage->getCategoryLinks();
 
                                if ( isset( $cats['normal'] ) ) {
                                        $out = $this->tidy( implode( ' ', $cats['normal'] ) );
@@ -605,13 +632,27 @@ class ParserTest {
                        'wgScriptPath' => '/',
                        'wgArticlePath' => '/wiki/$1',
                        'wgActionPaths' => array(),
+                       'wgLockManagers' => array(
+                               'name'          => 'fsLockManager',
+                               'class'         => 'FSLockManager',
+                               'lockDirectory' => $this->uploadDir . '/lockdir',
+                       ),
                        'wgLocalFileRepo' => array(
                                'class' => 'LocalRepo',
                                'name' => 'local',
-                               'directory' => $this->uploadDir,
                                'url' => 'http://example.com/images',
                                'hashLevels' => 2,
                                'transformVia404' => false,
+                               'backend'         => new FSFileBackend( array(
+                                       'name'        => 'local-backend',
+                                       'lockManager' => 'fsLockManager',
+                                       'containerPaths' => array(
+                                               'local-public'  => $this->uploadDir,
+                                               'local-thumb'   => $this->uploadDir . '/thumb',
+                                               'local-temp'    => $this->uploadDir . '/temp',
+                                               'local-deleted' => $this->uploadDir . '/delete',
+                                       )
+                               ) )
                        ),
                        'wgEnableUploads' => self::getOptionValue( 'wgEnableUploads', $opts, true ),
                        'wgStylePath' => '/skins',
@@ -629,8 +670,6 @@ class ParserTest {
                        'wgNoFollowDomainExceptions' => array(),
                        'wgThumbnailScriptPath' => false,
                        'wgUseImageResize' => false,
-                       'wgUseTeX' => isset( $opts['math'] ),
-                       'wgMathDirectory' => $this->uploadDir . '/math',
                        'wgLocaltimezone' => 'UTC',
                        'wgAllowExternalImages' => true,
                        'wgUseTidy' => false,
@@ -651,8 +690,12 @@ class ParserTest {
                        'wgExternalLinkTarget' => false,
                        'wgAlwaysUseTidy' => false,
                        'wgHtml5' => true,
+                       'wgCleanupPresentationalAttributes' => true,
                        'wgWellFormedXml' => true,
                        'wgAllowMicrodataAttributes' => true,
+                       'wgAdaptiveMessageCache' => true,
+                       'wgDisableLangConversion' => false,
+                       'wgDisableTitleConversion' => false,
                );
 
                if ( $config ) {
@@ -675,22 +718,23 @@ class ParserTest {
                        $GLOBALS[$var] = $val;
                }
 
-               $langObj = Language::factory( $lang );
-               $GLOBALS['wgLang'] = $langObj;
-               $GLOBALS['wgContLang'] = $langObj;
-               $GLOBALS['wgMemc'] = new FakeMemCachedClient;
-               $GLOBALS['wgOut'] = new OutputPage;
+               $GLOBALS['wgContLang'] = Language::factory( $lang );
+               $GLOBALS['wgMemc'] = new EmptyBagOStuff;
+
+               $context = new RequestContext();
+               $GLOBALS['wgLang'] = $context->getLanguage();
+               $GLOBALS['wgOut'] = $context->getOutput();
+
+               $GLOBALS['wgUser'] = new User();
 
                global $wgHooks;
 
                $wgHooks['ParserTestParser'][] = 'ParserTestParserHook::setup';
-               $wgHooks['ParserTestParser'][] = 'ParserTestStaticParserHook::setup';
                $wgHooks['ParserGetVariableValueTs'][] = 'ParserTest::getFakeTimestamp';
 
                MagicWord::clearCache();
 
-               global $wgUser;
-               $wgUser = new User();
+               return $context;
        }
 
        /**
@@ -698,17 +742,18 @@ class ParserTest {
         * Some of these probably aren't necessary.
         */
        private function listTables() {
-               $tables = array( 'user', 'user_properties', 'page', 'page_restrictions',
+               $tables = array( 'user', 'user_properties', 'user_former_groups', 'page', 'page_restrictions',
                        'protected_titles', 'revision', 'text', 'pagelinks', 'imagelinks',
                        'categorylinks', 'templatelinks', 'externallinks', 'langlinks', 'iwlinks',
                        'site_stats', 'hitcounter',     'ipblocks', 'image', 'oldimage',
-                       'recentchanges', 'watchlist', 'math', 'interwiki', 'logging',
+                       'recentchanges', 'watchlist', 'interwiki', 'logging',
                        'querycache', 'objectcache', 'job', 'l10n_cache', 'redirect', 'querycachetwo',
                        'archive', 'user_groups', 'page_props', 'category', 'msg_resource', 'msg_resource_links'
                );
 
-               if ( in_array( $this->db->getType(), array( 'mysql', 'sqlite', 'oracle' ) ) )
+               if ( in_array( $this->db->getType(), array( 'mysql', 'sqlite', 'oracle' ) ) ) {
                        array_push( $tables, 'searchindex' );
+               }
 
                // Allow extensions to add to the list of tables to duplicate;
                // may be necessary if they hook into page save or other code
@@ -741,8 +786,9 @@ class ParserTest {
                $this->oldTablePrefix = $wgDBprefix;
 
                # SqlBagOStuff broke when using temporary tables on r40209 (bug 15892).
-               # It seems to have been fixed since (r55079?).
-               # If it fails, $wgCaches[CACHE_DB] = new HashBagOStuff(); should work around it.
+               # It seems to have been fixed since (r55079?), but regressed at some point before r85701.
+               # This works around it for now...
+               ObjectCache::$instances[CACHE_DB] = new HashBagOStuff;
 
                # CREATE TEMPORARY TABLE breaks if there is more than one server
                if ( wfGetLB()->getServerCount() != 1 ) {
@@ -750,17 +796,14 @@ class ParserTest {
                }
 
                $temporary = $this->useTemporaryTables || $dbType == 'postgres';
-               $tables = $this->listTables();
                $prefix = $dbType != 'oracle' ? 'parsertest_' : 'pt_';
 
                $this->dbClone = new CloneDatabase( $this->db, $this->listTables(), $prefix );
                $this->dbClone->useTemporaryTables( $temporary );
                $this->dbClone->cloneTableStructure();
 
-               if ( $dbType == 'oracle' )
-                       $this->db->query( 'BEGIN FILL_WIKI_INFO; END;' );
-
                if ( $dbType == 'oracle' ) {
+                       $this->db->query( 'BEGIN FILL_WIKI_INFO; END;' );
                        # Insert 0 user to prevent FK violations
 
                        # Anonymous user
@@ -804,16 +847,14 @@ class ParserTest {
                                   'iw_local'  => 1 ),
                        ) );
 
-
                # Update certain things in site_stats
                $this->db->insert( 'site_stats', array( 'ss_row_id' => 1, 'ss_images' => 2, 'ss_good_articles' => 1 ) );
 
                # Reinitialise the LocalisationCache to match the database state
                Language::getLocalisationCache()->unloadAll();
 
-               # Make a new message cache
-               global $wgMessageCache, $wgMemc;
-               $wgMessageCache = new MessageCache( $wgMemc, true, 3600 );
+               # Clear the message cache
+               MessageCache::singleton()->clear();
 
                $this->uploadDir = $this->setupUploadDir();
                $user = User::createNew( 'WikiSysop' );
@@ -852,10 +893,17 @@ class ParserTest {
                }
                $this->teardownUploadDir( $this->uploadDir );
 
-               $this->db->tablePrefix( $this->oldTablePrefix );
+               $this->dbClone->destroy();
                $this->databaseSetupDone = false;
 
                if ( $this->useTemporaryTables ) {
+                       if( $this->db->getType() == 'sqlite' ) {
+                               # Under SQLite the searchindex table is virtual and need
+                               # to be explicitly destroyed. See bug 29912
+                               # See also MediaWikiTestCase::destroyDB()
+                               wfDebug( __METHOD__ . " explicitly destroying sqlite virtual table parsertest_searchindex\n" );
+                               $this->db->query( "DROP TABLE `parsertest_searchindex`" );
+                       }
                        # Don't need to do anything
                        $this->teardownGlobals();
                        return;
@@ -899,9 +947,9 @@ class ParserTest {
                        return $dir;
                }
 
-               wfMkdirParents( $dir . '/3/3a' );
+               wfMkdirParents( $dir . '/3/3a', null, __METHOD__ );
                copy( "$IP/skins/monobook/headbg.jpg", "$dir/3/3a/Foobar.jpg" );
-               wfMkdirParents( $dir . '/0/09' );
+               wfMkdirParents( $dir . '/0/09', null, __METHOD__ );
                copy( "$IP/skins/monobook/headbg.jpg", "$dir/0/09/Bad.jpg" );
 
                return $dir;
@@ -913,6 +961,8 @@ class ParserTest {
         */
        private function teardownGlobals() {
                RepoGroup::destroySingleton();
+               FileBackendGroup::destroySingleton();
+               LockManagerGroup::destroySingleton();
                LinkCache::singleton()->clear();
 
                foreach ( $this->savedGlobals as $var => $val ) {
@@ -1055,7 +1105,9 @@ class ParserTest {
         * @return String
         */
        protected function quickDiff( $input, $output, $inFileTail = 'expected', $outFileTail = 'actual' ) {
-               $prefix = wfTempDir() . "/mwParser-" . mt_rand();
+               # Windows, or at least the fc utility, is retarded
+               $slash = wfIsWindows() ? '\\' : '/';
+               $prefix = wfTempDir() . "{$slash}mwParser-" . mt_rand();
 
                $infile = "$prefix-$inFileTail";
                $this->dumpToFile( $input, $infile );
@@ -1063,7 +1115,14 @@ class ParserTest {
                $outfile = "$prefix-$outFileTail";
                $this->dumpToFile( $output, $outfile );
 
-               $diff = `diff -au $infile $outfile`;
+               $shellInfile = wfEscapeShellArg($infile);
+               $shellOutfile = wfEscapeShellArg($outfile);
+
+               global $wgDiff3;
+               // we assume that people with diff3 also have usual diff
+               $diff = ( wfIsWindows() && !$wgDiff3 )
+                       ? `fc $shellInfile $shellOutfile`
+                       : `diff -au $shellInfile $shellOutfile`;
                unlink( $infile );
                unlink( $outfile );
 
@@ -1114,31 +1173,35 @@ class ParserTest {
         * @param $name String: the title, including any prefix
         * @param $text String: the article text
         * @param $line Integer: the input line number, for reporting errors
+        * @param $ignoreDuplicate Boolean: whether to silently ignore duplicate pages
         */
-       static public function addArticle( $name, $text, $line = 'unknown' ) {
+       static public function addArticle( $name, $text, $line = 'unknown', $ignoreDuplicate = '' ) {
                global $wgCapitalLinks;
 
-               $text = self::chomp($text);
-
                $oldCapitalLinks = $wgCapitalLinks;
                $wgCapitalLinks = true; // We only need this from SetupGlobals() See r70917#c8637
 
+               $text = self::chomp( $text );
                $name = self::chomp( $name );
+
                $title = Title::newFromText( $name );
 
                if ( is_null( $title ) ) {
-                       wfDie( "invalid title ('$name' => '$title') at line $line\n" );
+                       throw new MWException( "invalid title '$name' at line $line\n" );
                }
 
-               $aid = $title->getArticleID( Title::GAID_FOR_UPDATE );
+               $page = WikiPage::factory( $title );
+               $page->loadPageData( 'fromdbmaster' );
 
-               if ( $aid != 0 ) {
-                       debug_print_backtrace();
-                       wfDie( "duplicate article '$name' at line $line\n" );
+               if ( $page->exists() ) {
+                       if ( $ignoreDuplicate == 'ignoreduplicate' ) {
+                               return;
+                       } else {
+                               throw new MWException( "duplicate article '$name' at line $line\n" );
+                       }
                }
 
-               $art = new Article( $title );
-               $art->doEdit( $text, '', EDIT_NEW );
+               $page->doEdit( $text, '', EDIT_NEW );
 
                $wgCapitalLinks = $oldCapitalLinks;
        }
@@ -1189,13 +1252,12 @@ class ParserTest {
                return true;
        }
 
-       /*
+       /**
         * Run the "tidy" command on text if the $wgUseTidy
         * global is true
         *
         * @param $text String: the text to tidy
         * @return String
-        * @static
         */
        private function tidy( $text ) {
                global $wgUseTidy;