<?php
-# Copyright (C) 2004 Brion Vibber <brion@pobox.com>
+# Copyright (C) 2004, 2010 Brion Vibber <brion@pobox.com>
# http://www.mediawiki.org/
#
# This program is free software; you can redistribute it and/or modify
$this->recorder = new DbTestPreviewer( $this );
} elseif( isset( $options['upload'] ) ) {
$this->recorder = new RemoteTestRecorder( $this );
+ } elseif( class_exists( 'PHPUnitTestRecorder' ) ) {
+ $this->recorder = new PHPUnitTestRecorder( $this );
} else {
$this->recorder = new TestRecorder( $this );
}
/**
* Remove last character if it is a newline
*/
- private function chomp($s) {
+ public function chomp($s) {
if (substr($s, -1) === "\n") {
return substr($s, 0, -1);
}
$this->setupDatabase();
$ok = true;
foreach( $filenames as $filename ) {
- $ok = $this->runFile( $filename ) && $ok;
+ $tests = new TestFileIterator( $filename, $this );
+ $ok = $this->runTests( $tests ) && $ok;
}
$this->teardownDatabase();
$this->recorder->report();
return $ok;
}
- private function runFile( $filename ) {
- $infile = fopen( $filename, 'rt' );
- if( !$infile ) {
- wfDie( "Couldn't open file '$filename'\n" );
- } else {
- global $IP;
- $relative = wfRelativePath( $filename, $IP );
- $this->showRunFile( $relative );
- }
-
- $data = array();
- $section = null;
- $n = 0;
+ function runTests($tests) {
$ok = true;
- while( false !== ($line = fgets( $infile ) ) ) {
- $n++;
- $matches = array();
- if( preg_match( '/^!!\s*(\w+)/', $line, $matches ) ) {
- $section = strtolower( $matches[1] );
- if( $section == 'endarticle') {
- if( !isset( $data['text'] ) ) {
- wfDie( "'endarticle' without 'text' at line $n of $filename\n" );
- }
- if( !isset( $data['article'] ) ) {
- wfDie( "'endarticle' without 'article' at line $n of $filename\n" );
- }
- $this->addArticle($this->chomp($data['article']), $this->chomp($data['text']), $n);
- $data = array();
- $section = null;
- continue;
- }
- if( $section == 'endhooks' ) {
- if( !isset( $data['hooks'] ) ) {
- wfDie( "'endhooks' without 'hooks' at line $n of $filename\n" );
- }
- foreach( explode( "\n", $data['hooks'] ) as $line ) {
- $line = trim( $line );
- if( $line ) {
- $this->requireHook( $line );
- }
- }
- $data = array();
- $section = null;
- continue;
- }
- if( $section == 'endfunctionhooks' ) {
- if( !isset( $data['functionhooks'] ) ) {
- wfDie( "'endfunctionhooks' without 'functionhooks' at line $n of $filename\n" );
- }
- foreach( explode( "\n", $data['functionhooks'] ) as $line ) {
- $line = trim( $line );
- if( $line ) {
- $this->requireFunctionHook( $line );
- }
- }
- $data = array();
- $section = null;
- continue;
- }
- if( $section == 'end' ) {
- if( !isset( $data['test'] ) ) {
- wfDie( "'end' without 'test' at line $n of $filename\n" );
- }
- if( !isset( $data['input'] ) ) {
- wfDie( "'end' without 'input' at line $n of $filename\n" );
- }
- if( !isset( $data['result'] ) ) {
- wfDie( "'end' without 'result' at line $n of $filename\n" );
- }
- if( !isset( $data['options'] ) ) {
- $data['options'] = '';
- }
- else {
- $data['options'] = $this->chomp( $data['options'] );
- }
- if (!isset( $data['config'] ) )
- $data['config'] = '';
-
- if ( (preg_match('/\\bdisabled\\b/i', $data['options'])
- || !preg_match("/{$this->regex}/i", $data['test'])) && !$this->runDisabled ) {
- # disabled test
- $data = array();
- $section = null;
- continue;
- }
- if ( preg_match('/\\bmath\\b/i', $data['options']) && !$this->savedGlobals['wgUseTeX'] ) {
- # don't run math tests if $wgUseTeX is set to false in LocalSettings
- $data = array();
- $section = null;
- continue;
- }
- $result = $this->runTest(
- $this->chomp( $data['test'] ),
- $this->chomp( $data['input'] ),
- $this->chomp( $data['result'] ),
- $this->chomp( $data['options'] ),
- $this->chomp( $data['config'] )
- );
- $ok = $ok && $result;
- $this->recorder->record( $this->chomp( $data['test'] ), $result );
- $data = array();
- $section = null;
- continue;
- }
- if ( isset ($data[$section] ) ) {
- wfDie( "duplicate section '$section' at line $n of $filename\n" );
- }
- $data[$section] = '';
- continue;
- }
- if( $section ) {
- $data[$section] .= $line;
- }
+ foreach($tests as $i => $t) {
+ $result =
+ $this->runTest($t['test'], $t['input'], $t['result'], $t['options'], $t['config']);
+ $ok = $ok && $result;
+ $this->recorder->record( $t['test'], $result );
}
if ( $this->showProgress ) {
print "\n";
}
- return $ok;
}
/**
* @param string $result Result to output
* @return bool
*/
- private function runTest( $desc, $input, $result, $opts, $config ) {
+ public function runTest( $desc, $input, $result, $opts, $config ) {
if( $this->showProgress ) {
$this->showTesting( $desc );
}
* Currently this will only be done once per run, and any changes to
* the db will be visible to later tests in the run.
*/
- private function setupDatabase() {
+ function setupDatabase() {
global $wgDBprefix, $wgDBtype;
if ( $this->databaseSetupDone ) {
return;
*
* @param String $path
*/
- protected function showRunFile( $path ){
+ public function showRunFile( $path ){
print $this->term->color( 1 ) .
"Reading tests from \"$path\"..." .
$this->term->reset() .
* @param string $text the article text
* @param int $line the input line number, for reporting errors
*/
- private function addArticle($name, $text, $line) {
+ public function addArticle($name, $text, $line) {
$this->setupGlobals();
$title = Title::newFromText( $name );
if ( is_null($title) ) {
* die a painful dead to warn the others.
* @param string $name
*/
- private function requireHook( $name ) {
+ public function requireHook( $name ) {
global $wgParser;
$wgParser->firstCallInit( ); //make sure hooks are loaded.
if( isset( $wgParser->mTagHooks[$name] ) ) {
return Http::post( $url, array( 'postData' => $data) );
}
}
+
+class TestFileIterator implements Iterator {
+ private $file;
+ private $fh;
+ private $parser;
+ private $index = 0;
+ private $test;
+ private $lineNum;
+ private $eof;
+
+ function __construct( $file, $parser = null ) {
+ global $IP;
+
+ $this->file = $file;
+ $this->fh = fopen($this->file, "r");
+ if( !$this->fh ) {
+ wfDie( "Couldn't open file '$file'\n" );
+ }
+
+ $this->parser = $parser;
+
+ if( $this->parser ) $this->parser->showRunFile( wfRelativePath( $this->file, $IP ) );
+ $this->lineNum = $this->index = 0;
+ }
+
+ function setParser( ParserTest $parser ) {
+ $this->parser = $parser;
+ }
+
+ function rewind() {
+ if(fseek($this->fh, 0)) {
+ wfDie( "Couldn't fseek to the start of '$filename'\n" );
+ }
+ $this->index = 0;
+ $this->lineNum = 0;
+ $this->eof = false;
+ $this->readNextTest();
+
+ return true;
+ }
+
+ function current() {
+ return $this->test;
+ }
+
+ function key() {
+ return $this->index;
+ }
+
+ function next() {
+ if($this->readNextTest()) {
+ $this->index++;
+ return true;
+ } else {
+ $this->eof = true;
+ }
+ }
+
+ function valid() {
+ return $this->eof != true;
+ }
+
+ function readNextTest() {
+ $data = array();
+ $section = null;
+
+ while( false !== ($line = fgets( $this->fh ) ) ) {
+ $this->lineNum++;
+ $matches = array();
+ if( preg_match( '/^!!\s*(\w+)/', $line, $matches ) ) {
+ $section = strtolower( $matches[1] );
+ if( $section == 'endarticle') {
+ if( !isset( $data['text'] ) ) {
+ wfDie( "'endarticle' without 'text' at line {$this->lineNum} of $filename\n" );
+ }
+ if( !isset( $data['article'] ) ) {
+ wfDie( "'endarticle' without 'article' at line {$this->lineNum} of $filename\n" );
+ }
+ if( $this->parser ) $this->parser->addArticle($this->parser->chomp($data['article']), $this->parser->chomp($data['text']),
+ $this->lineNum);
+ $data = array();
+ $section = null;
+ continue;
+ }
+ if( $section == 'endhooks' ) {
+ if( !isset( $data['hooks'] ) ) {
+ wfDie( "'endhooks' without 'hooks' at line {$this->lineNum} of $filename\n" );
+ }
+ foreach( explode( "\n", $data['hooks'] ) as $line ) {
+ $line = trim( $line );
+ if( $line ) {
+ if( $this->parser ) $this->parser->requireHook( $line );
+ }
+ }
+ $data = array();
+ $section = null;
+ continue;
+ }
+ if( $section == 'endfunctionhooks' ) {
+ if( !isset( $data['functionhooks'] ) ) {
+ wfDie( "'endfunctionhooks' without 'functionhooks' at line {$this->lineNum} of $filename\n" );
+ }
+ foreach( explode( "\n", $data['functionhooks'] ) as $line ) {
+ $line = trim( $line );
+ if( $line ) {
+ if( $this->parser ) $this->parser->requireFunctionHook( $line );
+ }
+ }
+ $data = array();
+ $section = null;
+ continue;
+ }
+ if( $section == 'end' ) {
+ if( !isset( $data['test'] ) ) {
+ wfDie( "'end' without 'test' at line {$this->lineNum} of $filename\n" );
+ }
+ if( !isset( $data['input'] ) ) {
+ wfDie( "'end' without 'input' at line {$this->lineNum} of $filename\n" );
+ }
+ if( !isset( $data['result'] ) ) {
+ wfDie( "'end' without 'result' at line {$this->lineNum} of $filename\n" );
+ }
+ if( !isset( $data['options'] ) ) {
+ $data['options'] = '';
+ }
+ if (!isset( $data['config'] ) )
+ $data['config'] = '';
+
+ if ( $this->parser && (preg_match('/\\bdisabled\\b/i', $data['options'])
+ || !preg_match("/{$this->parser->regex}/i", $data['test'])) && !$this->parser->runDisabled ) {
+ # disabled test
+ $data = array();
+ $section = null;
+ continue;
+ }
+ if ( $this->parser &&
+ preg_match('/\\bmath\\b/i', $data['options']) && !$this->parser->savedGlobals['wgUseTeX'] ) {
+ # don't run math tests if $wgUseTeX is set to false in LocalSettings
+ $data = array();
+ $section = null;
+ continue;
+ }
+
+ if( $this->parser ) {
+ $this->test = array(
+ 'test' => $this->parser->chomp( $data['test'] ),
+ 'input' => $this->parser->chomp( $data['input'] ),
+ 'result' => $this->parser->chomp( $data['result'] ),
+ 'options' => $this->parser->chomp( $data['options'] ),
+ 'config' => $this->parser->chomp( $data['config'] ) );
+ } else {
+ $this->test['test'] = $data['test'];
+ }
+ return true;
+ }
+ if ( isset ($data[$section] ) ) {
+ wfDie( "duplicate section '$section' at line {$this->lineNum} of $filename\n" );
+ }
+ $data[$section] = '';
+ continue;
+ }
+ if( $section ) {
+ $data[$section] .= $line;
+ }
+ }
+ return false;
+ }
+}
\ No newline at end of file
global $IP;
define( "NO_COMMAND_LINE", 1 );
+define( "PARSER_TESTS", "$IP/maintenance/parserTests.txt" );
+
require_once( "$IP/maintenance/parserTests.inc" );
-require_once( "ImageFunctions.php" );
-require_once( "ProxyTools.php" );
-require_once( "ObjectCache.php" );
-class PTShell extends ParserTest {
+class PHPUnitTestRecorder extends TestRecorder {
- private $cb;
+ function record( $test, $result ) {
+ $this->total++;
+ $this->success += $result;
- function setCallback( $cb ) {
- $this->cb = $cb;
}
- function showTesting( $desc ) {
- }
+ function reportPercentage( $success, $total ) {}
+}
- function showRunFile( $path ) {
+class MediaWikiParserTestSuite extends PHPUnit_Framework_TestSuite {
+#implements PHPUnit_Framework_SelfDescribing {
+ static private $count;
+ static public $parser;
+ static public $iter;
+
+ public static function suite() {
+ $suite = new PHPUnit_Framework_TestSuite();
+
+ self::$iter = new TestFileIterator( PARSER_TESTS );
+
+ foreach(self::$iter as $i => $test) {
+ $suite->addTest(new ParserUnitTest($i, $test['test']));
+ self::$count++;
+ }
+ unset($tests);
+
+ self::$parser = new PTShell;
+ self::$iter->setParser(self::$parser);
+ self::$parser->recorder->start();
+ self::$parser->setupDatabase();
+ self::$iter->rewind();
+ /* } */
+ /* function setUp() { */
+ global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc, $wgDeferredUpdateList,
+ $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache,
+ $wgMessageCache, $wgUseDatabaseMessages, $wgMsgCacheExpiry, $parserMemc,
+ $wgNamespaceAliases, $wgNamespaceProtection, $wgLocalFileRepo,
+ $wgNamespacesWithSubpages, $wgThumbnailScriptPath, $wgScriptPath,
+ $wgArticlePath, $wgStyleSheetPath, $wgScript, $wgStylePath;
+
+ $wgScript = '/index.php';
+ $wgScriptPath = '/';
+ $wgArticlePath = '/wiki/$1';
+ $wgStyleSheetPath = '/skins';
+ $wgStylePath = '/skins';
+ $wgThumbnailScriptPath = false;
+ $wgLocalFileRepo = array(
+ 'class' => 'LocalRepo',
+ 'name' => 'local',
+ 'directory' => '',
+ 'url' => 'http://example.com/images',
+ 'hashLevels' => 2,
+ 'transformVia404' => false,
+ );
+ $wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';
+ $wgNamespaceAliases['Image'] = NS_FILE;
+ $wgNamespaceAliases['Image_talk'] = NS_FILE_TALK;
+
+
+ $wgEnableParserCache = false;
+ $wgDeferredUpdateList = array();
+ $wgMemc =& wfGetMainCache();
+ $messageMemc =& wfGetMessageCacheStorage();
+ $parserMemc =& wfGetParserCacheStorage();
+
+ $wgContLang = new StubContLang;
+ $wgUser = new StubUser;
+ $wgLang = new StubUserLang;
+ $wgOut = new StubObject( 'wgOut', 'OutputPage' );
+ $wgParser = new StubObject( 'wgParser', $wgParserConf['class'], array( $wgParserConf ) );
+ $wgRequest = new WebRequest;
+
+ $wgMessageCache = new StubObject( 'wgMessageCache', 'MessageCache',
+ array( $messageMemc, $wgUseDatabaseMessages,
+ $wgMsgCacheExpiry, wfWikiID() ) );
+ if( $wgStyleDirectory === false) $wgStyleDirectory = "$IP/skins";
+
+ return $suite;
}
- function showSuccess( $desc ) {
- $this->cb->assertTrue( true, $desc );
- echo "PASSED: $desc\n";
- return true;
+ public function tearDown() {
+ $this->teardownDatabase();
+ $this->recorder->report();
+ $this->recorder->end();
+ $this->teardownUploadDir($this->uploadDir);
}
- function showFailure( $desc, $expected, $got ) {
- /* $this->cb->assertEquals( $expected, $got, $desc ); */
- echo "FAILED: $desc\n";
- echo "got: $got\n";
- echo "expected: $expected\n";
+ public function count() {return self::$count;}
+
+ public function toString() {
+ return "MediaWiki Parser Tests";
}
-}
-class MediaWikiParserTest extends PHPUnit_Framework_TestCase {
- private $parserTester;
+
private $db;
private $uploadDir;
private $keepUploads;
-
/**
* Remove the dummy uploads directory
*/
copy( "$IP/skins/monobook/headbg.jpg", "$dir/0/09/Bad.jpg" );
return $dir;
}
+}
+
+class ParserUnitTest extends PHPUnit_Framework_TestCase {
+ private $number = 0;
+ private $test = "";
+
+ public function __construct($number, $test) {
+ $this->number = $number;
+ $this->test = $test;
+ }
- function setUp() {
- global $wgParser, $wgParserConf, $IP, $messageMemc, $wgMemc, $wgDeferredUpdateList,
- $wgUser, $wgLang, $wgOut, $wgRequest, $wgStyleDirectory, $wgEnableParserCache, $wgMessageCache,
- $wgUseDatabaseMessages, $wgMsgCacheExpiry, $parserMemc, $wgNamespaceAliases, $wgNamespaceProtection,
- $wgLocalFileRepo, $wgNamespacesWithSubpages, $wgThumbnailScriptPath, $wgScriptPath,
- $wgArticlePath, $wgStyleSheetPath, $wgScript, $wgStylePath;
+ function count() {return 1;}
- $wgScript = '/index.php';
- $wgScriptPath = '/';
- $wgArticlePath = '/wiki/$1';
- $wgStyleSheetPath = '/skins';
- $wgStylePath = '/skins';
- $wgThumbnailScriptPath = false;
- $this->uploadDir = $this->setupUploadDir();
- $wgLocalFileRepo = array(
- 'class' => 'LocalRepo',
- 'name' => 'local',
- 'directory' => $this->uploadDir,
- 'url' => 'http://example.com/images',
- 'hashLevels' => 2,
- 'transformVia404' => false,
- );
- //$wgNamespacesWithSubpages = array( 0 => isset( $opts['subpage'] ) );
- $wgNamespaceProtection[NS_MEDIAWIKI] = 'editinterface';
- $wgNamespaceAliases['Image'] = NS_FILE;
- $wgNamespaceAliases['Image_talk'] = NS_FILE_TALK;
+ public function run(PHPUnit_Framework_TestResult $result = NULL) {
+ PHPUnit_Framework_Assert::resetCount();
+ if ($result === NULL) {
+ $result = new PHPUnit_Framework_TestResult;
+ }
+ $t = MediaWikiParserTestSuite::$iter->current();
+ $k = MediaWikiParserTestSuite::$iter->key();
- $wgEnableParserCache = false;
- $wgDeferredUpdateList = array();
- $wgMemc =& wfGetMainCache();
- $messageMemc =& wfGetMessageCacheStorage();
- $parserMemc =& wfGetParserCacheStorage();
+ if(!MediaWikiParserTestSuite::$iter->valid()) {
+ return;
+ }
- $wgContLang = new StubContLang;
- $wgUser = new StubUser;
- $wgLang = new StubUserLang;
- $wgOut = new StubObject( 'wgOut', 'OutputPage' );
- $wgParser = new StubObject( 'wgParser', $wgParserConf['class'], array( $wgParserConf ) );
- $wgRequest = new WebRequest;
+ // The only way this should happen is if the parserTest.txt
+ // file were modified while the script is running.
+ if($k != $this->number) {
+ $i = $this->number;
+ wfDie("I got confused!\n");
+ }
- $wgMessageCache = new StubObject( 'wgMessageCache', 'MessageCache',
- array( $messageMemc, $wgUseDatabaseMessages, $wgMsgCacheExpiry, wfWikiID() ) );
- if( $wgStyleDirectory === false) $wgStyleDirectory = "$IP/skins";
+ $result->startTest($this);
+ PHPUnit_Util_Timer::start();
+
+ $r = false;
+ try {
+ $r = MediaWikiParserTestSuite::$parser->runTest(
+ $t['test'], $t['input'], $t['result'], $t['options'], $t['config']
+ );
+ PHPUnit_Framework_Assert::assertTrue(true, $t['test']);
+ }
+ catch (PHPUnit_Framework_AssertionFailedError $e) {
+ $result->addFailure($this, $e, PHPUnit_Util_Timer::stop());
+ }
+ catch (Exception $e) {
+ $result->addError($this, $e, PHPUnit_Util_Timer::stop());
+ }
+ PHPUnit_Framework_Assert::assertTrue(true, $t['test']);
+
+ $result->endTest($this, PHPUnit_Util_Timer::stop());
+
+ MediaWikiParserTestSuite::$parser->recorder->record($t['test'], $r);
+ MediaWikiParserTestSuite::$iter->next();
+ $this->addToAssertionCount(PHPUnit_Framework_Assert::getCount());
- $this->parserTester = new PTShell();
- $this->parserTester->setCallback( $this );
-
- /* global $wgDBtype, $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBport, $wgDBmwschema, $wgDBts2chema; */
- /* $this->db['type'] = $wgDBtype; */
- /* $this->db['server'] = $wgDBserver; */
- /* $this->db['name'] = $wgDBname; */
- /* $this->db['user'] = $wgDBuser; */
- /* $this->db['password'] = $wgDBpassword; */
- /* $this->db['port'] = $wgDBport; */
- /* $this->db['mwschema'] = $wgDBmwschema; */
- /* $this->db['ts2schema'] = $wgDBts2chema; */
+ return $result;
}
- function tearDown() {
- $this->teardownUploadDir($this->uploadDir);
- /* $db = wfGetDB( DB_MASTER ); */
- /* $db->close(); */
- /* global $wgDBtype, $wgDBserver, $wgDBname, $wgDBuser, $wgDBpassword, $wgDBport, $wgDBmwschema, $wgDBts2chema; */
-
- /* $wgDBtype = $this->db['type']; */
- /* $wgDBserver = $this->db['server']; */
- /* $wgDBname = $this->db['name']; */
- /* $wgDBuser = $this->db['user']; */
- /* $wgDBpassword = $this->db['password']; */
- /* $wgDBport = $this->db['port']; */
- /* $wgDBmwschema = $this->db['mwschema']; */
- /* $wgDBts2chema = $this->db['ts2schema']; */
+}
+class PTShell extends ParserTest {
+ function showTesting( $desc ) {
}
+ function showRunFile( $path ) {
+ }
- function testParser() {
- global $IP;
+ function showSuccess( $desc ) {
+ PHPUnit_Framework_Assert::assertTrue(true, $desc);
+ return true;
+ }
- $this->parserTester->runTestsFromFiles( array( "$IP/maintenance/parserTests.txt" ) );
+ function showFailure( $desc, $expected, $got ) {
+ PHPUnit_Framework_Assert::assertEquals($expected, $got, $desc);
}
+
}
+