MediaWiki REL1_32
ParserTestPrinter.php
Go to the documentation of this file.
1<?php
28 private $total;
29 private $success;
30 private $skipped;
31 private $term;
32 private $showDiffs;
34 private $showFailure;
35 private $showOutput;
36 private $useDwdiff;
38 private $xmlError;
39
40 function __construct( $term, $options ) {
41 $this->term = $term;
42 $options += [
43 'showDiffs' => true,
44 'showProgress' => true,
45 'showFailure' => true,
46 'showOutput' => false,
47 'useDwdiff' => false,
48 'markWhitespace' => false,
49 ];
50 $this->showDiffs = $options['showDiffs'];
51 $this->showProgress = $options['showProgress'];
52 $this->showFailure = $options['showFailure'];
53 $this->showOutput = $options['showOutput'];
54 $this->useDwdiff = $options['useDwdiff'];
55 $this->markWhitespace = $options['markWhitespace'];
56 }
57
58 public function start() {
59 $this->total = 0;
60 $this->success = 0;
61 $this->skipped = 0;
62 }
63
64 public function startTest( $test ) {
65 if ( $this->showProgress ) {
66 $this->showTesting( $test['desc'] );
67 }
68 }
69
70 private function showTesting( $desc ) {
71 print "Running test $desc... ";
72 }
73
79 public function startSuite( $path ) {
80 print $this->term->color( 1 ) .
81 "Running parser tests from \"$path\"..." .
82 $this->term->reset() .
83 "\n";
84 }
85
86 public function endSuite( $path ) {
87 print "\n";
88 }
89
90 public function record( $test, ParserTestResult $result ) {
91 $this->total++;
92 $this->success += ( $result->isSuccess() ? 1 : 0 );
93
94 if ( $result->isSuccess() ) {
95 $this->showSuccess( $result );
96 } else {
97 $this->showFailure( $result );
98 }
99 }
100
107 private function showSuccess( ParserTestResult $testResult ) {
108 if ( $this->showProgress ) {
109 print $this->term->color( '1;32' ) . 'PASSED' . $this->term->reset() . "\n";
110 }
111 }
112
120 private function showFailure( ParserTestResult $testResult ) {
121 if ( $this->showFailure ) {
122 if ( !$this->showProgress ) {
123 # In quiet mode we didn't show the 'Testing' message before the
124 # test, in case it succeeded. Show it now:
125 $this->showTesting( $testResult->getDescription() );
126 }
127
128 print $this->term->color( '31' ) . 'FAILED!' . $this->term->reset() . "\n";
129
130 if ( $this->showOutput ) {
131 print "--- Expected ---\n{$testResult->expected}\n";
132 print "--- Actual ---\n{$testResult->actual}\n";
133 }
134
135 if ( $this->showDiffs ) {
136 print $this->quickDiff( $testResult->expected, $testResult->actual );
137 if ( !$this->wellFormed( $testResult->actual ) ) {
138 print "XML error: $this->xmlError\n";
139 }
140 }
141 }
142
143 return false;
144 }
145
156 private function quickDiff( $input, $output,
157 $inFileTail = 'expected', $outFileTail = 'actual'
158 ) {
159 if ( $this->markWhitespace ) {
160 $pairs = [
161 "\n" => '¶',
162 ' ' => '·',
163 "\t" => '→'
164 ];
165 $input = strtr( $input, $pairs );
166 $output = strtr( $output, $pairs );
167 }
168
169 # Windows, or at least the fc utility, is retarded
170 $slash = wfIsWindows() ? '\\' : '/';
171 $prefix = wfTempDir() . "{$slash}mwParser-" . mt_rand();
172
173 $infile = "$prefix-$inFileTail";
174 $this->dumpToFile( $input, $infile );
175
176 $outfile = "$prefix-$outFileTail";
177 $this->dumpToFile( $output, $outfile );
178
179 $shellInfile = wfEscapeShellArg( $infile );
180 $shellOutfile = wfEscapeShellArg( $outfile );
181
182 global $wgDiff3;
183 // we assume that people with diff3 also have usual diff
184 if ( $this->useDwdiff ) {
185 $shellCommand = 'dwdiff -Pc';
186 } else {
187 $shellCommand = ( wfIsWindows() && !$wgDiff3 ) ? 'fc' : 'diff -au';
188 }
189
190 $diff = wfShellExec( "$shellCommand $shellInfile $shellOutfile" );
191
192 unlink( $infile );
193 unlink( $outfile );
194
195 if ( $this->useDwdiff ) {
196 return $diff;
197 } else {
198 return $this->colorDiff( $diff );
199 }
200 }
201
208 private function dumpToFile( $data, $filename ) {
209 $file = fopen( $filename, "wt" );
210 fwrite( $file, $data . "\n" );
211 fclose( $file );
212 }
213
221 private function colorDiff( $text ) {
222 return preg_replace(
223 [ '/^(-.*)$/m', '/^(\+.*)$/m' ],
224 [ $this->term->color( 34 ) . '$1' . $this->term->reset(),
225 $this->term->color( 31 ) . '$1' . $this->term->reset() ],
226 $text );
227 }
228
229 private function wellFormed( $text ) {
230 $html =
231 Sanitizer::hackDocType() .
232 '<html>' .
233 $text .
234 '</html>';
235
236 $parser = xml_parser_create( "UTF-8" );
237
238 # case folding violates XML standard, turn it off
239 xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );
240
241 if ( !xml_parse( $parser, $html, true ) ) {
242 $err = xml_error_string( xml_get_error_code( $parser ) );
243 $position = xml_get_current_byte_index( $parser );
244 $fragment = $this->extractFragment( $html, $position );
245 $this->xmlError = "$err at byte $position:\n$fragment";
246 xml_parser_free( $parser );
247
248 return false;
249 }
250
251 xml_parser_free( $parser );
252
253 return true;
254 }
255
256 private function extractFragment( $text, $position ) {
257 $start = max( 0, $position - 10 );
258 $before = $position - $start;
259 $fragment = '...' .
260 $this->term->color( 34 ) .
261 substr( $text, $start, $before ) .
262 $this->term->color( 0 ) .
263 $this->term->color( 31 ) .
264 $this->term->color( 1 ) .
265 substr( $text, $position, 1 ) .
266 $this->term->color( 0 ) .
267 $this->term->color( 34 ) .
268 substr( $text, $position + 1, 9 ) .
269 $this->term->color( 0 ) .
270 '...';
271 $display = str_replace( "\n", ' ', $fragment );
272 $caret = ' ' .
273 str_repeat( ' ', $before ) .
274 $this->term->color( 31 ) .
275 '^' .
276 $this->term->color( 0 );
277
278 return "$display\n$caret";
279 }
280
285 public function warning( $message ) {
286 echo "$message\n";
287 }
288
294 public function skipped( $test, $subtest ) {
295 if ( $this->showProgress ) {
296 print $this->term->color( '1;33' ) . 'SKIPPED' . $this->term->reset() . "\n";
297 }
298 $this->skipped++;
299 }
300
301 public function report() {
302 if ( $this->total > 0 ) {
303 $this->reportPercentage( $this->success, $this->total );
304 } else {
305 print $this->term->color( 31 ) . "No tests found." . $this->term->reset() . "\n";
306 }
307 }
308
309 private function reportPercentage( $success, $total ) {
310 $ratio = wfPercent( 100 * $success / $total );
311 print $this->term->color( 1 ) . "Passed $success of $total tests ($ratio)";
312 if ( $this->skipped ) {
313 print ", skipped {$this->skipped}";
314 }
315 print "... ";
316
317 if ( $success == $total ) {
318 print $this->term->color( 32 ) . "ALL TESTS PASSED!";
319 } else {
320 $failed = $total - $success;
321 print $this->term->color( 31 ) . "$failed tests failed!";
322 }
323
324 print $this->term->reset() . "\n";
325
326 return ( $success == $total );
327 }
328}
which are not or by specifying more than one search term(only pages containing all of the search terms will appear in the result).</td >< td >
$wgDiff3
Path to the GNU diff3 utility.
wfTempDir()
Tries to get the system directory for temporary files.
wfEscapeShellArg(... $args)
Version of escapeshellarg() that works better on Windows.
wfPercent( $nr, $acc=2, $round=true)
wfShellExec( $cmd, &$retval=null, $environ=[], $limits=[], $options=[])
Execute a shell command, with time and memory limits mirrored from the PHP configuration if supported...
wfIsWindows()
Check if the operating system is Windows.
This is a TestRecorder responsible for printing information about progress, success and failure to th...
showSuccess(ParserTestResult $testResult)
Print a happy success message.
skipped( $test, $subtest)
Mark a test skipped.
startTest( $test)
Called before starting a test.
record( $test, ParserTestResult $result)
Called after each test.
dumpToFile( $data, $filename)
Write the given string to a file, adding a final newline.
reportPercentage( $success, $total)
colorDiff( $text)
Colorize unified diff output if set for ANSI color output.
startSuite( $path)
Show "Reading tests from ...".
warning( $message)
Show a warning to the user.
report()
Called before finishing the test run.
quickDiff( $input, $output, $inFileTail='expected', $outFileTail='actual')
Run given strings through a diff and return the (colorized) output.
endSuite( $path)
Called after ending an input file.
extractFragment( $text, $position)
start()
Called at beginning of the parser test run.
__construct( $term, $options)
showFailure(ParserTestResult $testResult)
Print a failure message and provide some explanatory output about what went wrong if so configured.
Represent the result of a parser test.
Interface to record parser test results.
see documentation in includes Linker php for Linker::makeImageLink or false for current used if you return false $parser
Definition hooks.txt:1873
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition hooks.txt:2050
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition hooks.txt:2062
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title e g db for database replication lag or jobqueue for job queue size converted to pseudo seconds It is possible to add more fields and they will be returned to the user in the API response after the basic globals have been set but before ordinary actions take place $output
Definition hooks.txt:2317
while(( $__line=Maintenance::readconsole()) !==false) print
Definition eval.php:64
if(is_array($mode)) switch( $mode) $input