setHeaders(); if ( ! ( $this->getUser()->isAllowed( 'purge' ) ) ) { // The effect of loading this page is comparable to purge a page. // If desired a dedicated right e.g. "viewmathstatus" could be used instead. throw new PermissionsError( 'purge' ); } $out = $this->getOutput(); $enabledMathModes = MathHooks::getMathNames(); $out->addWikiMsg( 'math-status-introduction', count( $enabledMathModes ) ); foreach ( $enabledMathModes as $modeNr => $modeName ){ $out->addWikiText( "=== $modeName ===" ); switch ( $modeNr ) { case 'mathml': $this->runMathMLTest( $modeName ); break; case 'latexml': $this->runMathLaTeXMLTest( $modeName ); } } } private function runMathMLTest( $modeName ) { $this->getOutput()->addWikiMsgArray( 'math-test-start', $modeName ); $this->testSpecialCaseText(); $this->testMathMLIntegration(); $this->testPmmlInput(); $this->getOutput()->addWikiMsgArray( 'math-test-end', $modeName ); } private function runMathLaTeXMLTest( $modeName ) { $this->getOutput()->addWikiMsgArray( 'math-test-start', $modeName ); $this->testLaTeXMLIntegration(); $this->testLaTeXMLLinebreak(); $this->getOutput()->addWikiMsgArray( 'math-test-end', $modeName ); } public function testSpecialCaseText() { $renderer = MathRenderer::getRenderer( 'x^2+\text{a sample Text}', [], 'mathml' ); $expected = 'a sample Text'; $this->assertTrue( $renderer->render(), 'Rendering the input "x^2+\text{a sample Text}"' ); $this->assertContains( $expected, $renderer->getHtmlOutput(), 'Comparing to the reference rendering' ); } /** * Checks the basic functionality * i.e. if the span element is generated right. */ public function testMathMLIntegration() { $svgRef = file_get_contents( __DIR__ .'/images/reference.svg' ); $svgRefNoSpeech = file_get_contents( __DIR__ .'/images/reference-nospeech.svg' ); $renderer = MathRenderer::getRenderer( "a+b", [], 'mathml' ); $this->assertTrue( $renderer->render( true ), "Rendering of a+b in plain MathML mode" ); $real = str_replace( "\n", '', $renderer->getHtmlOutput() ); $expected = '+'; $this->assertContains( $expected, $real, "Checking the presence of '+' in the MathML output" ); $this->assertEquals( [ $svgRef, $svgRefNoSpeech ], $renderer->getSvg(), "Comparing the generated SVG with the reference" ); } /** * Checks the experimental option to 'render' MathML input */ public function testPmmlInput() { // sample from 'Navajo Coal Combustion and Respiratory Health Near Shiprock, // New Mexico' in ''Journal of Environmental and Public Health'' , vol. 2010p. // authors Joseph E. Bunnell; Linda V. Garcia; Jill M. Furst; // Harry Lerch; Ricardo A. Olea; Stephen E. Suitt; Allan Kolker // @codingStandardsIgnoreStart $inputSample = ' P i j = 100 d i j 6.75 r j , '; // @codingStandardsIgnoreEnd $attribs = [ 'type' => 'pmml' ]; $renderer = new MathMathML( $inputSample, $attribs ); $this->assertEquals( 'pmml', $renderer->getInputType(), 'Checking if MathML input is supported' ); $this->assertTrue( $renderer->render(), 'Rendering Presentation MathML sample' ); $real = MathRenderer::renderMath( $inputSample, $attribs, 'mathml' ); $expected = 'hash=5628b8248b79267ecac656102334d5e3&mode=mathml'; $this->assertContains( $expected, $real, 'Checking if the link to SVG image is correct' ); } /** * Checks the basic functionality * i.e. if the span element is generated right. */ public function testLaTeXMLIntegration() { $renderer = MathRenderer::getRenderer( "a+b", [], 'latexml' ); $this->assertTrue( $renderer->render( true ), "Rendering of a+b in LaTeXML mode" ); // @codingStandardsIgnoreStart $expected = 'a+bab{\displaystyle a+b}'; // @codingStandardsIgnoreEnd $real = preg_replace( "/\n\\s*/", '', $renderer->getHtmlOutput() ); $this->assertContains( $expected, $real, "Comparing the output to the MathML reference rendering" . $renderer->getLastError() ); } /** * Checks LaTeXML line break functionality * i.e. if a long line contains a mtr element. * http://www.w3.org/TR/REC-MathML/chap3_5.html#sec3.5.2 */ public function testLaTeXMLLinebreak() { global $wgMathDefaultLaTeXMLSetting; $tex = ''; $testMax = ceil( $wgMathDefaultLaTeXMLSetting[ 'linelength' ] / 2 ); for ( $i = 0; $i < $testMax; $i++ ) { $tex .= "$i+"; } $tex .= $testMax; $renderer = new MathLaTeXML( $tex, [ 'display' => 'linebreak' ] ); $this->assertTrue( $renderer->render( true ), "Rendering of linebreak test in LaTeXML mode" ); $expected = 'mtr'; $real = preg_replace( "/\n\\s*/", '', $renderer->getHtmlOutput() ); $this->assertContains( $expected, $real, "Checking for linebreak" . $renderer->getLastError() ); } private function assertTrue( $expression, $message = '' ) { if ( $expression ){ $this->getOutput()->addWikiMsgArray( 'math-test-success', $message ); return true; } else { $this->getOutput()->addWikiMsgArray( 'math-test-fail', $message ); return false; } } private function assertContains( $expected, $real, $message = '' ) { if ( ! $this->assertTrue( strpos( $real, $expected ) !== false, $message ) ) { $this->printDiff( $expected, $real, 'math-test-contains-diff' ); } } private function assertEquals( $expected, $real, $message = '' ) { if ( is_array( $expected ) ) { foreach ( $expected as $alternative ){ if ( $alternative === $real ) { $this->getOutput()->addWikiMsgArray( 'math-test-success', $message ); return true; } } // non of the alternatives matched $this->getOutput()->addWikiMsgArray( 'math-test-fail', $message ); return false; } if ( !$this->assertTrue( $expected === $real, $message ) ) { $this->printDiff( $expected, $real, 'math-test-equals-diff' ); return false; } return true; } private function printDiff( $expected, $real, $message = '' ) { if ( ExtensionRegistry::getInstance()->isLoaded( "SyntaxHighlight" ) ) { $expected = "$expected"; $real = "$real"; $this->getOutput()->addWikiMsgArray( $message, [ $real, $expected ] ); } else { LoggerFactory::getInstance( 'Math' )->warning( 'Can not display expected and real value.'. 'SyntaxHighlight is not installed.' ); } } protected function getGroupName() { return 'other'; } }