Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 146 |
|
0.00% |
0 / 12 |
CRAP | |
0.00% |
0 / 1 |
SpecialMathDebug | |
0.00% |
0 / 146 |
|
0.00% |
0 / 12 |
870 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
setHeaders | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
56 | |||
displayButtons | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
2 | |||
compareParser | |
0.00% |
0 / 42 |
|
0.00% |
0 / 1 |
30 | |||
testParser | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
12 | |||
generateParserTests | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 | |||
generateLaTeXMLOutput | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
20 | |||
render | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
getMathTagsFromPage | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getTexvcTex | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | use MediaWiki\Extension\Math\MathLaTeXML; |
4 | use MediaWiki\Extension\Math\MathMathML; |
5 | use MediaWiki\Extension\Math\MathRenderer; |
6 | use MediaWiki\Logger\LoggerFactory; |
7 | use Wikimedia\Diff\Diff; |
8 | use Wikimedia\Diff\TableDiffFormatter; |
9 | |
10 | class SpecialMathDebug extends SpecialPage { |
11 | |
12 | function __construct() { |
13 | parent::__construct( 'MathDebug' ); |
14 | } |
15 | |
16 | /** |
17 | * Sets headers - this should be called from the execute() method of all derived classes! |
18 | */ |
19 | function setHeaders() { |
20 | $out = $this->getOutput(); |
21 | $out->setArticleRelated( false ); |
22 | $out->setRobotPolicy( "noindex,nofollow" ); |
23 | $out->setPageTitle( $this->getDescription() ); |
24 | } |
25 | |
26 | /** @inheritDoc */ |
27 | function execute( $par ) { |
28 | $offset = $this->getRequest()->getVal( 'offset', 0 ); |
29 | $length = $this->getRequest()->getVal( 'length', 10 ); |
30 | $page = $this->getRequest()->getVal( 'page', 'Testpage' ); |
31 | $action = $this->getRequest()->getVal( 'action', 'show' ); |
32 | $purge = $this->getRequest()->getVal( 'purge', '' ); |
33 | if ( !$this->userCanExecute( $this->getUser() ) ) { |
34 | $this->displayRestrictionError(); |
35 | } else { |
36 | if ( $action != 'generateParserTests' ) { |
37 | $this->setHeaders(); |
38 | $this->displayButtons( $offset, $length, $page, $action, $purge ); |
39 | } |
40 | switch ( $action ) { |
41 | case 'parserTest': |
42 | $this->generateLaTeXMLOutput( $offset, $length, $page ); |
43 | break; |
44 | case 'parserDiff': |
45 | $this->compareParser( $offset, $length, $page ); |
46 | break; |
47 | case 'generateParserTests': |
48 | $this->generateParserTests( $offset, $length, $page ); |
49 | break; |
50 | default: |
51 | $this->testParser( $offset, $length, $page, $purge === 'checked' ); |
52 | } |
53 | } |
54 | } |
55 | |
56 | function displayButtons( |
57 | $offset = 0, $length = 10, $page = 'Testpage', $action = 'show', $purge = '' |
58 | ) { |
59 | $out = $this->getOutput(); |
60 | // TODO check if addHTML has to be sanitized |
61 | $out->addHTML( '<form method=\'get\'>' |
62 | . '<input value="Show :" type="submit">' |
63 | . ' <input name="length" size="3" value="' |
64 | . $length |
65 | . '" class="textfield" onfocus="this.select()" type="text">' |
66 | . ' test(s) starting from test # <input name="offset" size="6" value="' |
67 | . ( $offset + $length ) |
68 | . '" class="textfield" onfocus="this.select()" type="text"> for page' |
69 | . ' <input name="page" size="12" value="' |
70 | . $page |
71 | . '" class="textfield" onfocus="this.select()" type="text">' |
72 | . ' <input name="action" size="12" value="' |
73 | . $action |
74 | . '" class="textfield" onfocus="this.select()" type="text">' |
75 | . ' purge <input type="checkbox" name="purge" value="checked"' |
76 | . $purge |
77 | . '></form>' |
78 | ); |
79 | } |
80 | |
81 | public function compareParser( $offset = 0, $length = 10, $page = 'Testpage' ) { |
82 | // phpcs:ignore MediaWiki.Usage.ExtendClassUsage.FunctionConfigUsage |
83 | global $wgMathLaTeXMLUrl; |
84 | $out = $this->getOutput(); |
85 | if ( !$this->getConfig()->get( 'MathUseLaTeXML' ) ) { |
86 | $out->addWikiTextAsInterface( "MahtML support must be enabled." ); |
87 | return false; |
88 | } |
89 | $parserA = $this->getRequest()->getVal( 'parserA', 'http://latexml.mathweb.org/convert' ); |
90 | $parserB = $this->getRequest()->getVal( 'parserB', 'http://latexml-test.instance-proxy.wmflabs.org/' ); |
91 | $formulae = self::getMathTagsFromPage( $page ); |
92 | $i = 0; |
93 | $str_out = ''; |
94 | $renderer = new MathLaTeXML(); |
95 | $renderer->setPurge(); |
96 | $diffFormatter = new TableDiffFormatter(); |
97 | if ( count( $formulae ) ) { |
98 | foreach ( array_slice( $formulae, $offset, $length, true ) as $key => $formula ) { |
99 | $out->addWikiTextAsInterface( "=== Test #" . ( $offset + $i++ ) . ": $key === " ); |
100 | $renderer->setTex( $formula ); |
101 | $wgMathLaTeXMLUrl = $parserA; |
102 | $stringA = $renderer->render( true ); |
103 | $wgMathLaTeXMLUrl = $parserB; |
104 | $stringB = $renderer->render( true ); |
105 | $diff = new Diff( [ $stringA ], [ $stringB ] ); |
106 | if ( $diff->isEmpty() ) { |
107 | $out->addWikiTextAsInterface( 'Output is identical' ); |
108 | } else { |
109 | $out->addWikiTextAsInterface( 'Request A <source lang="bash"> curl -d \'' . |
110 | $renderer->getPostData() . '\' ' . $parserA . '</source>' ); |
111 | $out->addWikiTextAsInterface( 'Request B <source lang="bash"> curl -d \'' . |
112 | $renderer->getPostData() . '\' ' . $parserB . '</source>' ); |
113 | $out->addWikiTextAsInterface( |
114 | 'Diff: <source lang="diff">' . $diffFormatter->format( $diff ) . '</source>' |
115 | ); |
116 | $out->addWikiTextAsInterface( 'XML Element based:' ); |
117 | $XMLA = explode( '>', $stringA ); |
118 | $XMLB = explode( '>', $stringB ); |
119 | $diff = new Diff( $XMLA, $XMLB ); |
120 | $out->addWikiTextAsInterface( |
121 | '<source lang="diff">' . $diffFormatter->format( $diff ) . '</source>' |
122 | ); |
123 | } |
124 | $i++; |
125 | } |
126 | } else { |
127 | $str_out = "No math elements found"; |
128 | } |
129 | $out->addWikiTextAsInterface( $str_out ); |
130 | return true; |
131 | } |
132 | |
133 | public function testParser( $offset = 0, $length = 10, $page = 'Testpage', $purge = true ) { |
134 | $out = $this->getOutput(); |
135 | $i = 0; |
136 | foreach ( |
137 | array_slice( self::getMathTagsFromPage( $page ), $offset, $length, true ) as $key => $t |
138 | ) { |
139 | $out->addWikiTextAsInterface( "=== Test #" . ( $offset + $i++ ) . ": $key === " ); |
140 | $out->addHTML( self::render( $t, 'source', $purge ) ); |
141 | $out->addWikiTextAsInterface( |
142 | 'Texvc`s TeX output:<source lang="latex">' . $this->getTexvcTex( $t ) . '</source>' |
143 | ); |
144 | if ( in_array( 'latexml', $this->getConfig()->get( 'MathMathValidModes' ) ) ) { |
145 | $out->addHTML( self::render( $t, 'latexml', $purge ) ); |
146 | } |
147 | } |
148 | } |
149 | |
150 | /** |
151 | * Generates test cases for texvcjs |
152 | * |
153 | * @param int $offset |
154 | * @param int $length |
155 | * @param string $page |
156 | * @param bool $purge |
157 | * @return bool |
158 | */ |
159 | public function generateParserTests( |
160 | $offset = 0, $length = 10, $page = 'Testpage', $purge = true |
161 | ) { |
162 | $res = $this->getRequest()->response(); |
163 | $res->header( 'Content-Type: application/json' ); |
164 | $res->header( 'Content-Disposition: attachment;filename=ParserTest.json' ); |
165 | |
166 | $out = $this->getOutput(); |
167 | $out->setArticleBodyOnly( true ); |
168 | $parserTests = []; |
169 | foreach ( |
170 | array_slice( self::getMathTagsFromPage( $page ), $offset, $length, true ) as $key => $input |
171 | ) { |
172 | $m = new MathMathML( $input ); |
173 | $m->checkTeX(); |
174 | $parserTests[] = [ 'id' => $key, 'input' => (string)$input, 'texvcjs' => $m->getTex() ]; |
175 | } |
176 | $out->addHTML( json_encode( $parserTests ) ); |
177 | return true; |
178 | } |
179 | |
180 | function generateLaTeXMLOutput( $offset = 0, $length = 10, $page = 'Testpage' ) { |
181 | $out = $this->getOutput(); |
182 | if ( !$this->getConfig()->get( 'MathUseLaTeXML' ) ) { |
183 | $out->addWikiTextAsInterface( "MahtML support must be enabled." ); |
184 | return false; |
185 | } |
186 | |
187 | $formulae = self::getMathTagsFromPage( $page ); |
188 | $i = 0; |
189 | $renderer = new MathLaTeXML(); |
190 | $renderer->setPurge(); |
191 | $tstring = ''; |
192 | if ( count( $formulae ) ) { |
193 | foreach ( array_slice( $formulae, $offset, $length, true ) as $key => $formula ) { |
194 | $tstring .= "\n!! test\n Test #" . ( $offset + $i++ ) . ": $key \n!! input" |
195 | . "\n<math>$formula</math>\n!! result\n"; |
196 | $renderer->setTex( $formula ); |
197 | $tstring .= $renderer->render( true ); |
198 | $tstring .= "\n!! end\n"; |
199 | } |
200 | } else { |
201 | $tstring = "No math elements found"; |
202 | } |
203 | $out->addWikiTextAsInterface( '<source>' . $tstring . '<\source>' ); |
204 | return true; |
205 | } |
206 | |
207 | private static function render( $t, $mode, $purge = true ) { |
208 | $modeInt = (int)substr( $mode, 0, 1 ); |
209 | $renderer = MathRenderer::getRenderer( $t, [], $modeInt ); |
210 | $renderer->setPurge( $purge ); |
211 | $renderer->render(); |
212 | $fragment = $renderer->getHtmlOutput(); |
213 | $res = $mode . ':' . $fragment; |
214 | LoggerFactory::getInstance( 'MathSearch' )->warning( 'rendered:' . $res . ' in mode ' . $mode ); |
215 | return $res . '<br/>'; |
216 | } |
217 | |
218 | private static function getMathTagsFromPage( $titleString = 'Testpage' ) { |
219 | $title = Title::newFromText( $titleString ); |
220 | if ( $title->exists() ) { |
221 | $idGenerator = MathIdGenerator::newFromTitle( $title ); |
222 | $tags = $idGenerator->getMathTags(); |
223 | $keys = $idGenerator->formatIds( $tags ); |
224 | return array_combine( $keys, array_column( $tags, MathIdGenerator::CONTENT_POS ) ); |
225 | } else { |
226 | return []; |
227 | } |
228 | } |
229 | |
230 | private function getTexvcTex( $tex ) { |
231 | $renderer = MathRenderer::getRenderer( $tex, [], 'source' ); |
232 | $renderer->checkTeX(); |
233 | return $renderer->getTex(); |
234 | } |
235 | |
236 | protected function getGroupName() { |
237 | return 'mathsearch'; |
238 | } |
239 | } |