tests: mock parser tests file access
authorAntoine Musso <hashar@free.fr>
Sun, 28 Apr 2013 21:13:49 +0000 (23:13 +0200)
committerAaron Schulz <aschulz@wikimedia.org>
Fri, 10 May 2013 17:16:55 +0000 (10:16 -0700)
I eventually got tired of our parser tests creating and deleting fixture
files over and over.  This patch mock the files in memory and just
expose the file metadata which is all we need for parser tests.

The mocked classes are under /tests/phpunit/mocks/ and respect the
hierarchy of /includes/.

The wiki.png and headbg.jpg files are still copied on each test :/

Change-Id: Iccdff67222e66d48d01dd1596d09df2ea24b8c2a

tests/TestsAutoLoader.php
tests/phpunit/includes/parser/NewParserTest.php
tests/phpunit/mocks/filebackend/MockFSFile.php [new file with mode: 0644]
tests/phpunit/mocks/filebackend/MockFileBackend.php [new file with mode: 0644]
tests/phpunit/mocks/media/MockBitmapHandler.php [new file with mode: 0644]

index ca92fe3..4a6e3fb 100644 (file)
@@ -79,6 +79,11 @@ $wgAutoloadClasses += array(
        'SiteTest' => "$testDir/phpunit/includes/site/SiteTest.php",
        'TestSites' => "$testDir/phpunit/includes/site/TestSites.php",
 
+       # tests/phpunit/mocks
+       'MockFSFile' => "$testDir/phpunit/mocks/filebackend/MockFSFile.php",
+       'MockFileBackend' => "$testDir/phpunit/mocks/filebackend/MockFileBackend.php",
+       'MockBitmapHandler' => "$testDir/phpunit/mocks/media/MockBitmapHandler.php",
+
        # tests/phpunit/languages
        'LanguageClassesTestCase' => "$testDir/phpunit/languages/LanguageClassesTestCase.php",
 
index d66fac7..f41c71c 100644 (file)
@@ -110,6 +110,14 @@ class NewParserTest extends MediaWikiTestCase {
                        $tmpGlobals['wgStyleDirectory'] = "$IP/skins";
                }
 
+               # Replace all media handlers with a mock. We do not need to generate
+               # actual thumbnails to do parser testing, we only care about receiving
+               # a ThumbnailImage properly initialized.
+               global $wgMediaHandlers;
+               foreach( $wgMediaHandlers as $type => $handler ) {
+                       $tmpGlobals['wgMediaHandlers'][$type] = 'MockBitmapHandler';
+               }
+
                $tmpHooks = $wgHooks;
                $tmpHooks['ParserTestParser'][] = 'ParserTestParserHook::setup';
                $tmpHooks['ParserGetVariableValueTs'][] = 'ParserTest::getFakeTimestamp';
@@ -301,7 +309,10 @@ class NewParserTest extends MediaWikiTestCase {
                                $backend = self::$backendToUse;
                        }
                } else {
-                       $backend = new FSFileBackend( array(
+                       # Replace with a mock. We do not care about generating real
+                       # files on the filesystem, just need to expose the file
+                       # informations.
+                       $backend = new MockFileBackend( array(
                                'name' => 'local-backend',
                                'lockManager' => 'nullLockManager',
                                'containerPaths' => array(
@@ -456,6 +467,12 @@ class NewParserTest extends MediaWikiTestCase {
                        return;
                }
 
+               $backend = RepoGroup::singleton()->getLocalRepo()->getBackend();
+               if( $backend instanceof MockFileBackend ) {
+                       # In memory backend, so dont bother cleaning them up.
+                       return;
+               }
+
                $base = $this->getBaseDir();
                // delete the files first, then the dirs.
                self::deleteFiles(
diff --git a/tests/phpunit/mocks/filebackend/MockFSFile.php b/tests/phpunit/mocks/filebackend/MockFSFile.php
new file mode 100644 (file)
index 0000000..31deaf7
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Mock of a filesystem file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ */
+
+/**
+ * Class representing an in memory fake file.
+ * This is intended for unit testing / developement when you do not want
+ * to hit the filesystem.
+ *
+ * It reimplements abstract methods with some hardcoded values. Might
+ * not be suitable for all tests but is good enough for the parser tests.
+ *
+ * @ingroup FileBackend
+ */
+class MockFSFile extends FSFile {
+       private $sha1Base36 = null; // File Sha1Base36
+
+       public function exists() {
+               return true;
+       }
+
+       /**
+        * August 22 – The theft of the Mona Lisa is discovered in the Louvre."
+        * @bug 20281
+        */
+       public function getSize() {
+               return 1911;
+       }
+
+       public function getTimestamp() {
+               return wfTimestamp( TS_MW );
+       }
+
+       public function getMimeType() {
+               return 'text/mock';
+       }
+
+       public function getProps( $ext = true ) {
+               return array(
+                       'fileExists' => $this->exists(),
+                       'size' => $this->getSize(),
+                       'file-mime' => $this->getMimeType(),
+                       'sha1' => $this->getSha1Base36(),
+               );
+       }
+
+       public function getSha1Base36( $recache = false ) {
+               return '1234567890123456789012345678901';
+       }
+}
diff --git a/tests/phpunit/mocks/filebackend/MockFileBackend.php b/tests/phpunit/mocks/filebackend/MockFileBackend.php
new file mode 100644 (file)
index 0000000..c681989
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+/**
+ * Simulation (mock) of a backend storage.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup FileBackend
+ * @author Antoine Musso <hashar@free.fr>
+ */
+
+/**
+ * Class simulating a backend store.
+ *
+ * @ingroup FileBackend
+ * @since 1.22
+ */
+class MockFileBackend extends FileBackendStore {
+
+       protected $mocked = array();
+
+       /** Poor man debugging */
+       protected function debug( $msg = '' ) {
+               wfDebug( wfGetCaller() . "$msg\n" );
+       }
+
+       public function isPathUsableInternal( $storagePath ) {
+               return true;
+       }
+
+       protected function doCreateInternal( array $params ) {
+               if( isset( $params['content'] ) ) {
+                       $content = $params['content'];
+               } else {
+                       $content = 'Default mocked file content';
+               }
+               $this->debug(serialize($params));
+               $dst = $params['dst'];
+               $this->mocked[$dst] = $content;
+               return Status::newGood();
+       }
+
+       protected function doStoreInternal( array $params ) {
+               $this->debug(serialize($params));
+               return $this->doCreateInternal( $params );
+       }
+
+       protected function doCopyInternal( array $params ) {
+               $this->debug(serialize($params));
+               $src = $params['src'];
+               $dst = $params['dst'];
+               $this->mocked[$dst] = $this->mocked[$src];
+               return Status::newGood();
+       }
+
+       protected function doDeleteInternal( array $params ) {
+               $this->debug(serialize($params));
+               $src = $params['src'];
+               unset( $this->mocked[$src] );
+               return Status::newGood();
+       }
+
+       protected function doGetFileStat( array $params ) {
+               $src = $params['src'];
+               if( array_key_exists( $src, $this->mocked ) ) {
+                       $this->debug( "('$src') found" );
+                       return array(
+                               'mtime' => wfTimestamp( TS_MW ),
+                               'size' => strlen( $this->mocked[$src] ),
+                               # No sha1, stat does not need it.
+                       );
+               } else {
+                       $this->debug( "('$src') not found" );
+                       return false;
+               }
+       }
+
+       protected function doGetLocalCopyMulti( array $params ) {
+               $tmpFiles = array(); // (path => MockFSFile)
+
+               $this->debug( '(' . serialize($params) . ')' );
+               foreach( $params['srcs'] as $src ) {
+                       $tmpFiles[$src] = new MockFSFile(
+                               wfTempDir() . '/' . wfRandomString(32)
+                       );
+               }
+               return $tmpFiles;
+       }
+
+       protected function doDirectoryExists( $container, $dir, array $params ) {
+               $this->debug();
+               return true;
+       }
+
+       public function getDirectoryListInternal( $container, $dir, array $params ) {
+               $this->debug();
+               return array();
+       }
+
+       public function getFileListInternal( $container, $dir, array $params ) {
+               $this->debug();
+               return array();
+       }
+
+       protected function directoriesAreVirtual() {
+               $this->debug();
+               return true;
+       }
+}
diff --git a/tests/phpunit/mocks/media/MockBitmapHandler.php b/tests/phpunit/mocks/media/MockBitmapHandler.php
new file mode 100644 (file)
index 0000000..2ae30a3
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Fake handler for images.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Media
+ */
+
+/**
+ * Mock handler for images.
+ *
+ * This is really intended for unit testing.
+ *
+ * @ingroup Media
+ */
+class MockBitmapHandler extends BitmapHandler {
+
+       /**
+        * Override BitmapHandler::doTransform() making sure we do not generate
+        * a thumbnail at all. That is merely returning a ThumbnailImage that
+        * will be consumed by the unit test.  There is no need to create a real
+        * thumbnail on the filesystem.
+        */
+       function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) {
+               # Example of what we receive:
+               # $image: LocalFile
+               # $dstPath: /tmp/transform_7d0a7a2f1a09-1.jpg
+               # $dstUrl : http://example.com/images/thumb/0/09/Bad.jpg/320px-Bad.jpg
+               # $params:  width: 320,  descriptionUrl http://trunk.dev/wiki/File:Bad.jpg
+
+               $this->normaliseParams( $image, $params );
+
+               $scalerParams = array(
+                       # The size to which the image will be resized
+                       'physicalWidth' => $params['physicalWidth'],
+                       'physicalHeight' => $params['physicalHeight'],
+                       'physicalDimensions' => "{$params['physicalWidth']}x{$params['physicalHeight']}",
+                       # The size of the image on the page
+                       'clientWidth' => $params['width'],
+                       'clientHeight' => $params['height'],
+                       # Comment as will be added to the EXIF of the thumbnail
+                       'comment' => isset( $params['descriptionUrl'] ) ?
+                       "File source: {$params['descriptionUrl']}" : '',
+                       # Properties of the original image
+                       'srcWidth' => $image->getWidth(),
+                       'srcHeight' => $image->getHeight(),
+                       'mimeType' => $image->getMimeType(),
+                       'dstPath' => $dstPath,
+                       'dstUrl' => $dstUrl,
+               );
+
+               # In some cases, we do not bother generating a thumbnail.
+               if ( !$image->mustRender() &&
+                       $scalerParams['physicalWidth'] == $scalerParams['srcWidth']
+                       && $scalerParams['physicalHeight'] == $scalerParams['srcHeight'] ) {
+                       wfDebug( __METHOD__ . ": returning unscaled image\n" );
+                       return $this->getClientScalingThumbnailImage( $image, $scalerParams );
+               }
+
+               return new ThumbnailImage( $image, $dstUrl, false, $params );
+       }
+}