mediawiki-extensions-Scribunto/tests/engines/LuaCommon/LuaEngineTestBase.php

281 lines
7.6 KiB
PHP
Raw Normal View History

<?php
/**
* This is the subclass for Lua library tests. It will automatically run all
* tests against LuaSandbox and LuaStandalone.
*
* Most of the time, you'll only need to override the following:
* - $moduleName: Name of the module being tested
* - getTestModules(): Add a mapping from $moduleName to the file containing
* the code.
*/
abstract class Scribunto_LuaEngineTestBase extends MediaWikiTestCase {
private static $engineConfigurations = array(
'LuaSandbox' => array(
'memoryLimit' => 50000000,
'cpuLimit' => 30,
'allowEnvFuncs' => true,
),
'LuaStandalone' => array(
'errorFile' => null,
'luaPath' => null,
'memoryLimit' => 50000000,
'cpuLimit' => 30,
'allowEnvFuncs' => true,
),
);
private static $staticEngineName = null;
private $engineName = null;
private $engine = null;
private $luaDataProvider = null;
/**
* Name to display instead of the default
* @var string
*/
protected $luaTestName = null;
/**
* Name of the module being tested
* @var string
*/
protected static $moduleName = null;
/**
* Class to use for the data provider
* @var string
*/
protected static $dataProviderClass = 'Scribunto_LuaDataProvider';
/**
* Tests to skip. Associative array mapping test name to skip reason.
* @var array
*/
protected $skipTests = array();
public function __construct( $name = null, array $data = array(), $dataName = '', $engineName = null ) {
if ( $engineName === null ) {
$engineName = self::$staticEngineName;
}
$this->engineName = $engineName;
parent::__construct( $name, $data, $dataName );
}
public static function suite( $className ) {
return self::makeSuite( $className );
}
protected static function makeSuite( $className, $group = null ) {
$suite = new PHPUnit_Framework_TestSuite;
$suite->setName( $className );
$class = new ReflectionClass( $className );
foreach ( self::$engineConfigurations as $engineName => $opts ) {
if ( $group !== null && $group !== $engineName ) {
continue;
}
try {
$parser = new Parser;
$parser->startExternalParse( Title::newMainPage(), new ParserOptions, Parser::OT_HTML, true );
$engineClass = "Scribunto_{$engineName}Engine";
$engine = new $engineClass(
self::$engineConfigurations[$engineName] + array( 'parser' => $parser )
);
$parser->scribunto_engine = $engine;
$engine->setTitle( $parser->getTitle() );
$engine->getInterpreter();
} catch ( Scribunto_LuaInterpreterNotFoundError $e ) {
$suite->addTest(
new Scribunto_LuaEngineTestSkip(
$className, "interpreter for $engineName is not available"
), array( 'Lua', $engineName )
);
continue;
}
// Work around PHPUnit breakage: the only straightforward way to
// get the data provider is to call
// PHPUnit_Util_Test::getProvidedData, but that instantiates the
// class without passing any parameters to the constructor. But we
// *need* that engine name.
self::$staticEngineName = $engineName;
$engineSuite = new PHPUnit_Framework_TestSuite;
$engineSuite->setName( "$engineName: $className" );
foreach ( $class->getMethods() as $method ) {
if ( PHPUnit_Framework_TestSuite::isTestMethod( $method ) && $method->isPublic() ) {
$name = $method->getName();
$groups = PHPUnit_Util_Test::getGroups( $className, $name );
$groups[] = 'Lua';
$groups[] = $engineName;
$groups = array_unique( $groups );
$data = PHPUnit_Util_Test::getProvidedData( $className, $name );
if ( is_array( $data ) || $data instanceof Iterator ) {
// with @dataProvider
$dataSuite = new PHPUnit_Framework_TestSuite_DataProvider(
$className . '::' . $name
);
foreach ( $data as $k => $v ) {
$dataSuite->addTest(
new $className( $name, $v, $k, $engineName ),
$groups
);
}
$engineSuite->addTest( $dataSuite );
} elseif ( $data === false ) {
// invalid @dataProvider
$engineSuite->addTest( new PHPUnit_Framework_Warning(
"The data provider specified for {$className}::$name is invalid."
) );
} else {
// no @dataProvider
$engineSuite->addTest(
new $className( $name, array(), '', $engineName ),
$groups
);
}
}
}
$suite->addTest( $engineSuite );
}
return $suite;
}
protected function tearDown() {
if ( $this->luaDataProvider ) {
$this->luaDataProvider->destroy();
$this->luaDataProvider = null;
}
if ( $this->engine ) {
$this->engine->destroy();
$this->engine = null;
}
parent::tearDown();
}
/**
* Get the title used for unit tests
*
* @return Title
*/
protected function getTestTitle() {
return Title::newMainPage();
}
/**
* @return ScribuntoEngineBase
*/
protected function getEngine() {
if ( !$this->engine ) {
$parser = new Parser;
$options = new ParserOptions;
$options->setTemplateCallback( array( $this, 'templateCallback' ) );
$parser->startExternalParse( $this->getTestTitle(), $options, Parser::OT_HTML, true );
$class = "Scribunto_{$this->engineName}Engine";
$this->engine = new $class(
self::$engineConfigurations[$this->engineName] + array( 'parser' => $parser )
);
$parser->scribunto_engine = $this->engine;
$this->engine->setTitle( $parser->getTitle() );
}
return $this->engine;
}
public function templateCallback( $title, $parser ) {
if ( isset($this->extraModules[$title->getFullText()]) ) {
return array(
'text' => $this->extraModules[$title->getFullText()],
'finalTitle' => $title,
'deps' => array()
);
}
$modules = $this->getTestModules();
foreach ( $modules as $name => $fileName ) {
$modTitle = Title::makeTitle( NS_MODULE, $name );
if ( $modTitle->equals( $title ) ) {
return array(
'text' => file_get_contents( $fileName ),
'finalTitle' => $title,
'deps' => array()
);
}
}
return Parser::statelessFetchTemplate( $title, $parser );
}
public function toString() {
// When running tests written in Lua, return a nicer representation in
// the failure message.
if ( $this->luaTestName ) {
return $this->engineName . ': ' . $this->luaTestName;
}
return $this->engineName . ': ' . parent::toString();
}
protected function getTestModules() {
return array(
'TestFramework' => __DIR__ . '/TestFramework.lua',
);
}
public function provideLuaData() {
if ( !$this->luaDataProvider ) {
$class = static::$dataProviderClass;
$this->luaDataProvider = new $class ( $this->getEngine(), static::$moduleName );
}
return $this->luaDataProvider;
}
/** @dataProvider provideLuaData */
public function testLua( $key, $testName, $expected ) {
$this->luaTestName = static::$moduleName."[$key]: $testName";
if ( isset( $this->skipTests[$testName] ) ) {
$this->markTestSkipped( $this->skipTests[$testName] );
} else {
try {
$actual = $this->provideLuaData()->run( $key );
} catch ( Scribunto_LuaError $ex ) {
if ( substr( $ex->getLuaMessage(), 0, 6 ) === 'SKIP: ' ) {
$this->markTestSkipped( substr( $ex->getLuaMessage(), 6 ) );
} else {
throw $ex;
}
}
$this->assertSame( $expected, $actual );
}
$this->luaTestName = null;
}
}
class Scribunto_LuaEngineTestSkip extends PHPUnit_Framework_TestCase {
private $className = '';
private $message = '';
public function __construct( $className = '', $message = '' ) {
$this->className = $className;
$this->message = $message;
parent::__construct( 'testDummy' );
}
public function testDummy() {
if ( $this->className ) {
$this->markTestSkipped( $this->message );
} else {
// Dummy
$this->assertTrue( true );
}
}
public function toString() {
return $this->className;
}
}