Coverage tests for the Math extension

* Include generated tests for a better test coverage
of the Math extension.
* Compiles texvc in testsuite (if required)
* Test generator now included
* Replaces the old parser tests
* Fixes whitspace issues

Bug: 61090
Change-Id: Iff7eeb5ee72137492c3f6659e4d4d106e5715586
This commit is contained in:
physikerwelt 2014-02-09 19:02:15 +00:00 committed by Physikerwelt
parent 02477fa877
commit 94b035b26a
17 changed files with 311 additions and 262 deletions

View File

@ -235,22 +235,6 @@ class MathHooks {
return true;
}
/**
* Hack to fake a default $wgMathPath value so parser test output
* that renders to images doesn't vary by who runs it.
*
* @global string $wgMathPath
* @param Parser $parser
* @return bool
*/
static function onParserTestParser( &$parser ) {
global $wgMathPath;
$wgMathPath = '/images/math';
return true;
}
/**
* Links to the unit test files for the test cases.
*

View File

@ -150,7 +150,6 @@ $wgHooks['ParserFirstCallInit'][] = 'MathHooks::onParserFirstCallInit';
$wgHooks['GetPreferences'][] = 'MathHooks::onGetPreferences';
$wgHooks['LoadExtensionSchemaUpdates'][] = 'MathHooks::onLoadExtensionSchemaUpdates';
$wgHooks['ParserTestTables'][] = 'MathHooks::onParserTestTables';
$wgHooks['ParserTestParser'][] = 'MathHooks::onParserTestParser';
$wgHooks['UnitTestsList'][] = 'MathHooks::onRegisterUnitTests';
$wgHooks['PageRenderingHash'][] = 'MathHooks::onPageRenderingHash';

View File

@ -13,6 +13,8 @@ class MathInputCheckTexvc extends MathInputCheck {
* Converts an error returned by texvc to a localized exception
*
* @param string $texvcResult error result returned by texvc
* @param bool|MathRenderer $errorRenderer
* @return string
*/
public function convertTexvcError( $texvcResult, $errorRenderer = false ) {
$texvcStatus = substr( $texvcResult, 0, 1 );

View File

@ -271,6 +271,7 @@ class MathLaTeXML extends MathRenderer {
* Embeds the MathML-XML element in a HTML span element with class tex
* @param string $mml : the MathML string
* @param string $tagId : optional tagID for references like (pagename#equation2)
* @param bool $attribs
* @return html element with rendered math
*/
public static function embedMathML( $mml, $tagId = '', $attribs = false ) {

View File

@ -117,7 +117,7 @@ abstract class MathRenderer {
* Returns an internationalized HTML error string
*
* @param string $msg message key for specific error
* @param Varargs $parameters (optional) zero or more message parameters for specific error
* @internal param \Varargs $parameters (optional) zero or more message parameters for specific error
* @return string HTML error string
*/
public function getError( $msg /*, ... */ ) {
@ -221,7 +221,6 @@ abstract class MathRenderer {
* @return array
*/
private function dbOutArray() {
global $wgDebugMath;
$dbr = wfGetDB( DB_SLAVE );
if ( $this->hash ) {
$outmd5_sql = $dbr->encodeBlob( pack( 'H32', $this->hash ) );
@ -411,6 +410,7 @@ abstract class MathRenderer {
/**
* Sets purge. If set to true the render is forced to rerender and must not
* use a cached version.
* @param bool $purge
* @return boolean
*/
function setPurge( $purge = true ) {
@ -441,6 +441,8 @@ abstract class MathRenderer {
$this->lastError = $checker->getError();
return false;
}
} else {
return true;
}
}

View File

@ -98,6 +98,7 @@ class MathTexvc extends MathRenderer {
* Converts an error returned by texvc to a localized exception
*
* @param string $texvcResult error result returned by texvc
* @return string
*/
public function convertTexvcError( $texvcResult ) {
$errorConverter = new MathInputCheckTexvc();

View File

@ -0,0 +1,96 @@
<?php
/**
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @ingroup Maintenance
*/
require_once( dirname( __FILE__ ) . '/../../../maintenance/Maintenance.php' );
class MathGenerateTests extends Maintenance
{
const REFERENCE_PAGE = 'mediawikiwiki:Extension:Math/CoverageTest';
public function __construct()
{
parent::__construct();
$this->mDescription = 'Rebuilds the MathCoverage tests';
$this->addArg( 'page', "The page ues for the testset generation.", false );
$this->addOption( 'offset', "If set the first n equations on the page are skipped", false, true, "o" );
$this->addOption( 'length', "If set the only n equations were processed", false, true, "l" );
$this->addOption( 'user', "User with rights to view the page", false, true, "u" );
}
private static function getMathTagsFromPage( $titleString )
{
global $wgEnableScaryTranscluding;
$title = Title::newFromText( $titleString );
if ( $title->exists() ) {
$article = new Article( $title );
$wikiText = $article->getPage()->getContent()->getNativeData();
} else {
if ( $title == self::REFERENCE_PAGE ) {
$wgEnableScaryTranscluding = true;
$parser = new Parser();
$wikiText = $parser->interwikiTransclude( $title, 'raw' );
} else {
return 'Page does not exist';
}
}
// TODO: find a better way to extract math elements from a page
$wikiText = Sanitizer::removeHTMLcomments( $wikiText );
$wikiText = preg_replace( '#<nowiki>(.*)</nowiki>#', '', $wikiText );
preg_match_all( "#<math>(.*?)</math>#s", $wikiText, $math );
// TODO: Find a way to specify a key e.g '\nRenderTest:(.?)#<math>(.*?)</math>#s\n'
// leads to array('\1'->'\2') with \1 eg Bug 2345 and \2 the math content
return $math[1];
}
public function execute()
{
global $wgUser;
$parserTests = array();
$page = $this->getArg( 0, self::REFERENCE_PAGE );
$offset = $this->getOption( 'offset', 0 );
$length = $this->getOption( 'length', PHP_INT_MAX );
$userName = $this->getOption( 'user', 'Maintenance script' );
$wgUser = User::newFromName( $userName );
$allEquations = self::getMathTagsFromPage( $page );
if ( !is_array( $allEquations ) ) {
echo "Could not get equations from page '$page'\n";
echo $allEquations . PHP_EOL;
return;
} else {
echo 'got ' . count( $allEquations ) . " math tags. Start processing.";
}
$i = 0;
foreach ( array_slice( $allEquations, $offset, $length, true ) as $input ) {
$output = MathRenderer::renderMath( $input, array(), MW_MATH_PNG );
$parserTests[] = array( (string)$input, $output );
$i++;
echo '.';
}
echo "Generated $i tests\n";
file_put_contents( dirname( __FILE__ ) . '/../tests/ParserTest.data', serialize( $parserTests ) );
}
}
$maintClass = "MathGenerateTests";
require_once( RUN_MAINTENANCE_IF_MAIN );

View File

@ -7,196 +7,3 @@ pst
!!result
<!-- <math>data</math> -->
!!end
#!! test
#BUG 1887: A <math> with a thumbnail- we don't render math in the parsertests by default,
#so math is not stripped and turns up as escaped &lt;math&gt; tags.
#!! input
#[[Image:foobar.jpg|thumb|<math>2+2</math>]]
#!! result
#<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/3/3a/Foobar.jpg" width="180" height="20" class="thumbimage" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>&lt;math&gt;2+2&lt;/math&gt;</div></div></div>
#
#!! end
!! test
BUG 1887, part 2: A <math> with a thumbnail- math enabled
!! options
texvc
!! input
[[Image:foobar.jpg|thumb|<math>2+2</math>]]
!! result
<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div><img class="tex" alt="2+2" src="/images/math/f/a/5/fa50b8b616463173474302ca3e63586b.png" /></div></div></div>
!! end
#!! test
#Math section safety when disabled
#!! input
#<math><script>alert(document.cookies);</script></math>
#!! result
#<p>&lt;math&gt;&lt;script&gt;alert(document.cookies);&lt;/script&gt;&lt;/math&gt;
#</p>
#!! end
!! test
BUG 26380: Add \widetilde support to match \widehat
!! options
texvc
!! input
<math>\widehat{x}</math>
<math>\widetilde{x}</math>
!! result
<p><img class="tex" alt="\widehat{x}" src="/images/math/9/9/8/998309e831dfb051f233c92b4b8a825b.png" />
<img class="tex" alt="\widetilde{x}" src="/images/math/e/9/e/e9e91996778a6d6f5cdf4cc951955206.png" />
</p>
!! end
!! test
BUG 27324: Euro symbol for math
!! options
texvc
!! input
<math>\euro 200</math>
<math>\geneuro</math>
<math>\geneuronarrow</math>
<math>\geneurowide</math>
<math>\officialeuro</math>
!! result
<p><img class="tex" alt="\euro 200" src="/images/math/1/8/8/18867d4c568a19ae7b2388346e504ec3.png" />
<img class="tex" alt="\geneuro" src="/images/math/9/8/b/98b63c235ee187a38267e0e170b10e9d.png" />
<img class="tex" alt="\geneuronarrow" src="/images/math/a/a/4/aa4a1ed370f4ee705c6930384bf89502.png" />
<img class="tex" alt="\geneurowide" src="/images/math/4/4/0/4404468e6187fb04e4f7e1f15e550825.png" />
<img class="tex" alt="\officialeuro" src="/images/math/d/7/0/d708de0eed23dbd6f02b99ea9073547b.png" />
</p>
!! end
!! test
BUG 27754: Archaic Greek letters for math (may require texlive-lang-greek)
!! options
texvc
!! input
<math>\digamma</math><!-- Lowercase digamma was already available -->
<math>\Coppa\coppa\varcoppa</math>
<math>\Digamma</math>
<math>\Koppa\koppa</math>
<math>\Sampi\sampi</math>
<math>\Stigma\stigma\varstigma</math>
!! result
<p><img class="tex" alt="\digamma" src="/images/math/2/f/0/2f057b6e514c8ca2d9cf9a3e549f8865.png" />
<img class="tex" alt="\Coppa\coppa\varcoppa" src="/images/math/8/3/0/8308ee5003aa36112414cad8ef874f85.png" />
<img class="tex" alt="\Digamma" src="/images/math/5/c/f/5cfd6e5df6c87798542dca2e22c1e7cb.png" />
<img class="tex" alt="\Koppa\koppa" src="/images/math/5/2/5/52593a0cdac178d165985ac014788b97.png" />
<img class="tex" alt="\Sampi\sampi" src="/images/math/e/9/d/e9dabb19e4c27bf23d3c2a3629474562.png" />
<img class="tex" alt="\Stigma\stigma\varstigma" src="/images/math/7/b/9/7b9233276816994a33a5e968202cef6e.png" />
</p>
!! end
!! test
BUG 19547: Apostrophe / single quotes in math \text{...}
!! options
texvc
!! input
<math>\text{next years}</math>
<math>\text{next year's}</math>
<math>\text{`next' year}</math>
!! result
<p><img class="tex" alt="\text{next years}" src="/images/math/6/6/9/6691dbc0b36631a68b78dd5ace256d80.png" />
<img class="tex" alt="\text{next year&#39;s}" src="/images/math/2/3/6/236fd262b1976d04bc0e7a969d61aede.png" />
<img class="tex" alt="\text{`next&#39; year}" src="/images/math/0/5/8/05854b483a833f067cb6ae72319b44bc.png" />
</p>
!! end
!! test
BUG 6722: Spacing fix for functions in math HTML output
!! options
texvc
!! input
<math>\sin x</math>
<math>\sin(x)</math>
<math>\sin{x}</math>
<math>\sin x \,</math>
<math>\sin(x) \,</math>
<math>\sin{x} \,</math>
!!result
<p><img class="tex" alt="\sin x" src="/images/math/c/d/b/cdba58911c590ced3e2435dfa39f6873.png" />
<img class="tex" alt="\sin(x)" src="/images/math/3/e/2/3e21673ce6c9b09f9ec50b7237248576.png" />
<img class="tex" alt="\sin{x}" src="/images/math/f/b/5/fb5551723991d4dcb974a23c162ae813.png" />
</p><p><img class="tex" alt="\sin x \," src="/images/math/7/6/a/76a8e1a01bd233c1e4e16d63b2bbf939.png" />
<img class="tex" alt="\sin(x) \," src="/images/math/1/6/c/16c69b0a3658d3b398f72c518d869a03.png" />
<img class="tex" alt="\sin{x} \," src="/images/math/8/3/9/839639707da39f691e702c2399cbf943.png" />
</p>
!! end
!! test
BUG 18912: Add \sen function for Spanish sin to math
!! options
texvc
!! input
<math>\sen x</math>
<math>\sen(x)</math>
<math>\sen{x}</math>
<math>\sen x \,</math>
<math>\sen(x) \,</math>
<math>\sen{x} \,</math>
!! result
<p><img class="tex" alt="\sen x" src="/images/math/f/b/8/fb82a78d580396c62cecb4cf018f3769.png" />
<img class="tex" alt="\sen(x)" src="/images/math/8/3/a/83a10e6756c8e59055178dc1f593130a.png" />
<img class="tex" alt="\sen{x}" src="/images/math/0/4/f/04fde4f7a7e478015066f378050b1979.png" />
</p><p><img class="tex" alt="\sen x \," src="/images/math/0/a/c/0ac592b8f31b4698766c50c532f446a7.png" />
<img class="tex" alt="\sen(x) \," src="/images/math/b/b/5/bb5469d24fcdd52aa60cb9ee90ba697d.png" />
<img class="tex" alt="\sen{x} \," src="/images/math/d/4/8/d4882a4bcf5db1da3e30d905da8b394e.png" />
</p>
!! end
!! test
BUG 18912: \operatorname{sen} x gets wrong spacing in math
!! options
texvc
!! input
<math>\operatorname{sen}</math>
!! result
<p><img class="tex" alt="\operatorname{sen}" src="/images/math/f/a/9/fa9660c7eb053ca8d3c9a87fa86635d9.png" />
</p>
!! end
!! test
BUG 31442: Multiple math accents without braces fails to parse
!! options
texvc
!! input
<math>\dot \vec B</math>
!! result
<p><img class="tex" alt="\dot \vec B" src="/images/math/e/6/4/e64939568ecb506a86a392373cec0458.png" />
</p>
!! end
!! test
BUG 31442: Math accents with math font fail to parse if braces not used
!! options
texvc
!! input
<math>\tilde \mathcal{M}</math>
!! result
<p><img class="tex" alt="\tilde \mathcal{M}" src="/images/math/5/5/0/55072ce6ef8c840c4b7687bd8a028bde.png" />
</p>
!! end
!! test
BUG 31824: Empty math tag returns uniq
!! options
texvc
!! input
<math></math>
!! result
!! end
!! test
BUG 31824: Empty math tag returns uniq
!! options
texvc
!! input
<math> </math>
!! result
!! end

View File

@ -0,0 +1,86 @@
<?php
/**
* PHPUnit tests to test the wide range of all typical use cases for formulae at Wikipedia.
* To generate the page https://www.mediawiki.org/wiki/Extension:Math/CoverageTest is used to
* generate the test data.
* The testData is generated by the maintenance script Math/maintenance/MathGenerateTests.php.
* To update the test data locally with vagrant the following procedure is recommended:
*
* 1. copy the source from https://www.mediawiki.org/wiki/Extension:Math/CoverageTest to a new page e.g.
* MathTest at your local vagrant instance
* 2. run <code>php MathGenerateTests.php MathTest</code> in the maitenance folder of the Math extension.
* 3. Test local e.g. via
* <code>sudo php /vagrant/mediawiki/tests/phpunit/phpunit.php /vagrant/mediawiki/extensions/Math/tests/MathCoverageTest.php</code>
* (If you don't use sudo you might have problems with the permissions set at vagrant.)
*
* @group Extensions
* @group Math
*/
class MathCoverageTest extends MediaWikiTestCase {
protected static $hasTexvc;
protected static $texvcPath;
public static function setUpBeforeClass() {
global $wgTexvc;
if ( is_executable( $wgTexvc ) ) {
wfDebugLog( __CLASS__, " using build in texvc from "
. "\$wgMathTexvcCheckExecutable = $wgTexvc" );
# Using build-in
self::$hasTexvc = true;
self::$texvcPath = $wgTexvc;
} else {
# Attempt to compile
wfDebugLog( __CLASS__, " compiling texvc..." );
$cmd = 'cd ' . dirname( __DIR__ ) . '/math; make --always-make 2>&1';
wfShellExec( $cmd, $retval );
if ( $retval === 0 ) {
self::$hasTexvc = true;
self::$texvcPath = dirname( __DIR__ ) . '/math/texvc';
wfDebugLog( __CLASS__, ' compiled texvc at ' . self::$texvcPath );
} else {
wfDebugLog( __CLASS__, ' ocaml not available or compilation of texvc failed' );
}
}
}
/**
* 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::$hasTexvc ) {
$this->markTestSkipped( "No texvc installed on server" );
} else {
$this->setMwGlobals( 'wgTexvc',
self::$texvcPath );
}
}
/**
* Loops over all test cases provided by the provider function.
* Compares each the rendering result of each input with the expected output.
* @dataProvider testProvider
*/
public function testCoverage( $input, $output )
{
// TODO: Make rendering mode configurable
// TODO: Provide test-ids
// TODO: Link to the wikipage that contains the reference rendering
$this->assertEquals( $this->normalize( $output ), $this->normalize( MathRenderer::renderMath( $input , array(), MW_MATH_PNG ) ), "Failed to render $input" );
}
/**
* Gets the test-data from the file ParserTest.data
* @return array($input, $output) where $input is the test input string and $output is the rendered html5-output string
*/
public function testProvider()
{
return unserialize( file_get_contents( dirname( __FILE__ ) . '/ParserTest.data' ) );
}
private function normalize( $input ) {
return preg_replace( '#src="(.*?)/(([a-f]|\d)*).png"#', 'src="\2.png"', $input );
}
}

View File

@ -63,7 +63,6 @@ class MathDatabaseTest extends MediaWikiTestCase {
public function testDBBasics() {
// ;
$this->setValues();
$wgDebugMath = false;
$this->renderer->writeToDatabase();

View File

@ -27,7 +27,7 @@ class MathInputCheckTexvcTest extends MediaWikiTestCase {
# Attempt to compile
wfDebugLog( __CLASS__, " compiling texvccheck..." );
$cmd = 'cd ' . dirname( __DIR__ ) . '/texvccheck; make --always-make 2>&1';
$stdout = wfShellExec( $cmd, $retval );
wfShellExec( $cmd, $retval );
if ( $retval === 0 ) {
self::$hasTexvccheck = true;
self::$texvccheckPath = dirname( __DIR__ ) . '/texvccheck/texvccheck';
@ -43,7 +43,6 @@ class MathInputCheckTexvcTest extends MediaWikiTestCase {
* This method is called before a test is executed.
*/
protected function setUp() {
global $wgMathTexvcCheckExecutable;
parent::setUp();
$this->BadObject = new MathInputCheckTexvc( '\newcommand{\text{do evil things}}' );
$this->GoodObject = new MathInputCheckTexvc( '\sin\left(\frac12x\right)' );

73
tests/ParserTest.data Normal file

File diff suppressed because one or more lines are too long