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