From 946a18d14c21fff2251ec2cc5451b62e4df61276 Mon Sep 17 00:00:00 2001 From: lyrianos93 Date: Mon, 14 Dec 2015 20:26:29 +0000 Subject: [PATCH] Implement datatype 'Math' for Wikidata This change implements all components to use the datatype 'Math' in Wikidata. Because 'String 'is used as value type, only the Formatter and Validator are needed to be implemended. The components are: * hooks * Formatter class * Validator class * Test cases Bug: T67397 Change-Id: Ic64fd6c8560f48052e2db24ae1f013d48a82b5e9 --- MathFormatter.php | 83 ++++++++++++++++++++++++++++++ MathValidator.php | 50 ++++++++++++++++++ MathWikidataHook.php | 56 ++++++++++++++++++++ extension.json | 11 +++- tests/MathFormatterTest.php | 100 ++++++++++++++++++++++++++++++++++++ tests/MathValidatorTest.php | 69 +++++++++++++++++++++++++ 6 files changed, 368 insertions(+), 1 deletion(-) create mode 100644 MathFormatter.php create mode 100644 MathValidator.php create mode 100644 MathWikidataHook.php create mode 100644 tests/MathFormatterTest.php create mode 100644 tests/MathValidatorTest.php diff --git a/MathFormatter.php b/MathFormatter.php new file mode 100644 index 000000000..d7c48265d --- /dev/null +++ b/MathFormatter.php @@ -0,0 +1,83 @@ +format = $format; + break; + default: + throw new InvalidArgumentException( 'Unsupported output format: ' . $format ); + } + } + + /* + * + * @param StringValue $value + * + * @return string + * @throws \ValueFormatters\Exceptions\MismatchingDataValueTypeException + */ + public function format( $value ) { + if ( !( $value instanceof StringValue ) ) { + throw new MismatchingDataValueTypeException( 'StringValue', get_class( $value ) ); + } + $tex = $value->getValue(); + + switch ( $this->format ) { + case ( SnakFormatter::FORMAT_PLAIN ): + return "$tex"; + case ( SnakFormatter::FORMAT_WIKI ): + return "$tex"; + case ( SnakFormatter::FORMAT_HTML ): + case ( SnakFormatter::FORMAT_HTML_WIDGET ): + case ( SnakFormatter::FORMAT_HTML_DIFF ): + $renderer = new MathMathML( $tex ); + if ( $renderer->checkTex() ) { + if ( $renderer->render() ) { + return $renderer->getHtmlOutput(); + } + } + // TeX string is not valid or rendering failed + return $renderer->getLastError(); + } + } + + /** + * + * @return format + */ + + public function getFormat() { + return $this->format; + } +} diff --git a/MathValidator.php b/MathValidator.php new file mode 100644 index 000000000..ad3bf2d3c --- /dev/null +++ b/MathValidator.php @@ -0,0 +1,50 @@ +getValue(); + + $checker = new MathInputCheckRestbase( $tex ); + if ( $checker->isValid() ) { + return Result::newSuccess(); + } + + // TeX string is not valid + return Result::newError( + array( + Error::newError( null, null, 'malformed-value', $checker->getError() ) + ) + ); + } + + /** + * @see ValueValidator::setOptions() + * + * @param array $options + */ + public function setOptions( array $options ) { + // Do nothing. This method shouldn't even be in the interface. + } +} diff --git a/MathWikidataHook.php b/MathWikidataHook.php new file mode 100644 index 000000000..04c488f82 --- /dev/null +++ b/MathWikidataHook.php @@ -0,0 +1,56 @@ + 'string', + 'validator-factory-callback' => function() { + // load validator builders + $factory = WikibaseRepo::getDefaultValidatorBuilders(); + + // initialize an array with string validators + // returns an array of validators + // that add basic string validation such as preventing empty strings + $validators = $factory->buildStringValidators(); + $validators[] = new MathValidator(); + return $validators; + }, + 'parser-factory-callback' => function( ParserOptions $options ) { + $repo = WikibaseRepo::getDefaultInstance(); + $normalizer = new WikibaseStringValueNormalizer( $repo->getStringNormalizer() ); + return new StringParser( $normalizer ); + }, + 'formatter-factory-callback' => function( $format, FormatterOptions $options ) { + global $wgOut; + $styles = array( 'ext.math.desktop.styles', 'ext.math.scripts', 'ext.math.styles' ); + $wgOut->addModuleStyles( $styles ); + return new MathFormatter( $format ); + }, + ); + } + + /* + * Add Datatype "Math" to the Wikibase Client + */ + public static function onWikibaseClientDataTypes( array &$dataTypeDefinitions ) { + $dataTypeDefinitions['PT:math'] = array( + 'value-type' => 'string', + 'formatter-factory-callback' => function( $format, FormatterOptions $options ) { + global $wgOut; + $styles = array( 'ext.math.desktop.styles', 'ext.math.scripts', 'ext.math.styles' ); + $wgOut->addModuleStyles( $styles ); + return new MathFormatter( $format ); + }, + ); + } + +} diff --git a/extension.json b/extension.json index 1d65200e6..5d05bb11f 100644 --- a/extension.json +++ b/extension.json @@ -24,7 +24,10 @@ "MathInputCheckTexvc": "MathInputCheckTexvc.php", "MathInputCheckRestbase": "MathInputCheckRestbase.php", "SpecialMathShowImage": "SpecialMathShowImage.php", - "SpecialMathStatus": "SpecialMathStatus.php" + "SpecialMathStatus": "SpecialMathStatus.php", + "MathValidator": "MathValidator.php", + "MathFormatter": "MathFormatter.php", + "MathWikidataHook": "MathWikidataHook.php" }, "DefaultUserOptions": { "math": "png" @@ -57,6 +60,12 @@ ], "EditPageBeforeEditToolbar": [ "MathHooks::onEditPageBeforeEditToolbar" + ], + "WikibaseClientDataTypes": [ + "MathWikidataHook::onWikibaseClientDataTypes" + ], + "WikibaseRepoDataTypes": [ + "MathWikidataHook::onWikibaseRepoDataTypes" ] }, "config": { diff --git a/tests/MathFormatterTest.php b/tests/MathFormatterTest.php new file mode 100644 index 000000000..9a499ce0a --- /dev/null +++ b/tests/MathFormatterTest.php @@ -0,0 +1,100 @@ +checkBackend( true ); + } + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() { + parent::setUp(); + if ( !self::$hasRestbase ) { + $this->markTestSkipped( "Can not connect to Restbase Math interface." ); + } + } + + protected function tearDown() { + parent::tearDown(); + } + + /** + * Checks the + * @covers MathFormatter::__construct() + */ + public function testBasics() { + $formatter = new MathFormatter( self::FORMAT_PLAIN ); + // check if the format input was corretly passed to the class + $this->assertEquals( self::FORMAT_PLAIN, $formatter->getFormat(), 'test getFormat' ); + } + + /** + * @expectedException ValueFormatters\Exceptions\MismatchingDataValueTypeException + */ + public function testNotStringValue() { + $formatter = new MathFormatter( self::FORMAT_PLAIN ); + $formatter->format( new NumberValue( 0 ) ); + } + + /** + * @expectedException ValueFormatters\Exceptions\MismatchingDataValueTypeException + */ + public function testNullValue() { + $formatter = new MathFormatter( self::FORMAT_PLAIN ); + $formatter->format( null ); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testUnknownFormat() { + $formatter = new MathFormatter( self::FORMAT_UNKNOWN ); + } + + public function testFormatPlain() { + $formatter = new MathFormatter( self::FORMAT_PLAIN ); + $value = new StringValue( self::SOME_TEX ); + $resultFormat = $formatter->format( $value ); + $this->assertEquals( self::SOME_TEX, $resultFormat, + 'Results should be equal' ); + + } + + public function testFormatHtml() { + $formatter = new MathFormatter( self::FORMAT_HTML ); + $value = new StringValue( self::SOME_TEX ); + $resultFormat = $formatter->format( $value ); + $this->assertContains( '', $resultFormat, + 'Result must contain math-tag' ); + } + + public function testFormatXWiki() { + $tex = self::SOME_TEX; + $formatter = new MathFormatter( self::FORMAT_XWIKI ); + $value = new StringValue( self::SOME_TEX ); + $resultFormat = $formatter->format( $value ); + $this->assertEquals( "$tex", $resultFormat, + 'Tex wasn\'t properly wrapped' ); + + } +} diff --git a/tests/MathValidatorTest.php b/tests/MathValidatorTest.php new file mode 100644 index 000000000..8d40ef7b8 --- /dev/null +++ b/tests/MathValidatorTest.php @@ -0,0 +1,69 @@ +checkBackend( true ); + } + + /** + * Sets up the fixture, for example, opens a network connection. + * This method is called before a test is executed. + */ + protected function setUp() { + parent::setUp(); + + if ( !self::$hasRestbase ) { + $this->markTestSkipped( "Can not connect to Restbase Math interface." ); + } + } + + protected function tearDown() { + parent::tearDown(); + } + + /** + * @expectedException ValueFormatters\Exceptions\MismatchingDataValueTypeException + */ + public function testNotStringValue() { + $validator = new MathValidator(); + $validator->validate( new NumberValue( 0 ) ); + } + + /** + * @expectedException ValueFormatters\Exceptions\MismatchingDataValueTypeException + */ + public function testNullValue() { + $validator = new MathValidator(); + $validator->validate( null ); + } + + public function testValidInput() { + $validator = new MathValidator(); + $result = $validator->validate( new StringValue( self::VADLID_TEX ) ); + // not supported by jenkins php version + // $this->assertType( \ValueValidators\Result::class, $result ); + $this->assertTrue( $result->isValid() ); + } + + public function testInvalidInput() { + $validator = new MathValidator(); + $result = $validator->validate( new StringValue( self::INVADLID_TEX ) ); + // not supported by jenkins php version + // $this->assertType( \ValueValidators\Result::class, $result ); + $this->assertFalse( $result->isValid() ); + } +}