summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php')
-rw-r--r--www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php291
1 files changed, 291 insertions, 0 deletions
diff --git a/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php
new file mode 100644
index 00000000..31aeff67
--- /dev/null
+++ b/www/wiki/extensions/Scribunto/tests/phpunit/engines/LuaCommon/LuaEngineTestBase.php
@@ -0,0 +1,291 @@
+<?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.
+ */
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+abstract class Scribunto_LuaEngineTestBase extends MediaWikiLangTestCase {
+ private static $engineConfigurations = [
+ 'LuaSandbox' => [
+ 'memoryLimit' => 50000000,
+ 'cpuLimit' => 30,
+ 'allowEnvFuncs' => true,
+ 'maxLangCacheSize' => 30,
+ ],
+ 'LuaStandalone' => [
+ 'errorFile' => null,
+ 'luaPath' => null,
+ 'memoryLimit' => 50000000,
+ 'cpuLimit' => 30,
+ 'allowEnvFuncs' => true,
+ 'maxLangCacheSize' => 30,
+ ],
+ ];
+
+ 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 = [];
+
+ public function __construct(
+ $name = null, array $data = [], $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] + [ '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"
+ ), [ '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, [], '', $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( [ $this, 'templateCallback' ] );
+ $parser->startExternalParse( $this->getTestTitle(), $options, Parser::OT_HTML, true );
+ $class = "Scribunto_{$this->engineName}Engine";
+ $this->engine = new $class(
+ self::$engineConfigurations[$this->engineName] + [ '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 [
+ 'text' => $this->extraModules[$title->getFullText()],
+ 'finalTitle' => $title,
+ 'deps' => []
+ ];
+ }
+
+ $modules = $this->getTestModules();
+ foreach ( $modules as $name => $fileName ) {
+ $modTitle = Title::makeTitle( NS_MODULE, $name );
+ if ( $modTitle->equals( $title ) ) {
+ return [
+ 'text' => file_get_contents( $fileName ),
+ 'finalTitle' => $title,
+ 'deps' => []
+ ];
+ }
+ }
+ 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 [
+ '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
+ * @param string $key
+ * @param string $testName
+ * @param mixed $expected
+ */
+ 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;
+ }
+}
+
+// @codingStandardsIgnoreLine Squiz.Classes.ValidClassName.NotCamelCaps
+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;
+ }
+}