(bug 43762) Mark slow unit test as @group medium
[mediawiki.git] / tests / phpunit / includes / GlobalFunctions / GlobalTest.php
blob1a02cb82bbd38445bfe46bb1b2180dcbc81860d6
1 <?php
3 class GlobalTest extends MediaWikiTestCase {
4 protected function setUp() {
5 parent::setUp();
7 $readOnlyFile = tempnam( wfTempDir(), "mwtest_readonly" );
8 unlink( $readOnlyFile );
10 $this->setMwGlobals( array(
11 'wgReadOnlyFile' => $readOnlyFile,
12 'wgUrlProtocols' => array(
13 'http://',
14 'https://',
15 'mailto:',
16 '//',
17 'file://', # Non-default
19 ) );
22 protected function tearDown() {
23 global $wgReadOnlyFile;
25 if ( file_exists( $wgReadOnlyFile ) ) {
26 unlink( $wgReadOnlyFile );
29 parent::tearDown();
32 /** @dataProvider provideForWfArrayDiff2 */
33 public function testWfArrayDiff2( $a, $b, $expected ) {
34 $this->assertEquals(
35 wfArrayDiff2( $a, $b), $expected
39 // @todo Provide more tests
40 public static function provideForWfArrayDiff2() {
41 // $a $b $expected
42 return array(
43 array(
44 array( 'a', 'b'),
45 array( 'a', 'b'),
46 array(),
48 array(
49 array( array( 'a'), array( 'a', 'b', 'c' )),
50 array( array( 'a'), array( 'a', 'b' )),
51 array( 1 => array( 'a', 'b', 'c' ) ),
56 function testRandom() {
57 # This could hypothetically fail, but it shouldn't ;)
58 $this->assertFalse(
59 wfRandom() == wfRandom() );
62 function testUrlencode() {
63 $this->assertEquals(
64 "%E7%89%B9%E5%88%A5:Contributions/Foobar",
65 wfUrlencode( "\xE7\x89\xB9\xE5\x88\xA5:Contributions/Foobar" ) );
68 function testExpandIRI() {
69 $this->assertEquals(
70 "https://te.wikibooks.org/wiki/ఉబుంటు_వాడుకరి_మార్గదర్శని",
71 wfExpandIRI( "https://te.wikibooks.org/wiki/%E0%B0%89%E0%B0%AC%E0%B1%81%E0%B0%82%E0%B0%9F%E0%B1%81_%E0%B0%B5%E0%B0%BE%E0%B0%A1%E0%B1%81%E0%B0%95%E0%B0%B0%E0%B0%BF_%E0%B0%AE%E0%B0%BE%E0%B0%B0%E0%B1%8D%E0%B0%97%E0%B0%A6%E0%B0%B0%E0%B1%8D%E0%B0%B6%E0%B0%A8%E0%B0%BF" ) );
74 function testReadOnlyEmpty() {
75 global $wgReadOnly;
76 $wgReadOnly = null;
78 $this->assertFalse( wfReadOnly() );
79 $this->assertFalse( wfReadOnly() );
82 function testReadOnlySet() {
83 global $wgReadOnly, $wgReadOnlyFile;
85 $f = fopen( $wgReadOnlyFile, "wt" );
86 fwrite( $f, 'Message' );
87 fclose( $f );
88 $wgReadOnly = null; # Check on $wgReadOnlyFile
90 $this->assertTrue( wfReadOnly() );
91 $this->assertTrue( wfReadOnly() ); # Check cached
93 unlink( $wgReadOnlyFile );
94 $wgReadOnly = null; # Clean cache
96 $this->assertFalse( wfReadOnly() );
97 $this->assertFalse( wfReadOnly() );
100 function testQuotedPrintable() {
101 $this->assertEquals(
102 "=?UTF-8?Q?=C4=88u=20legebla=3F?=",
103 UserMailer::quotedPrintable( "\xc4\x88u legebla?", "UTF-8" ) );
106 function testTime() {
107 $start = wfTime();
108 $this->assertInternalType( 'float', $start );
109 $end = wfTime();
110 $this->assertTrue( $end > $start, "Time is running backwards!" );
113 public static function provideArrayToCGI() {
114 return array(
115 array( array(), '' ), // empty
116 array( array( 'foo' => 'bar' ), 'foo=bar' ), // string test
117 array( array( 'foo' => '' ), 'foo=' ), // empty string test
118 array( array( 'foo' => 1 ), 'foo=1' ), // number test
119 array( array( 'foo' => true ), 'foo=1' ), // true test
120 array( array( 'foo' => false ), '' ), // false test
121 array( array( 'foo' => null ), '' ), // null test
122 array( array( 'foo' => 'A&B=5+6@!"\'' ), 'foo=A%26B%3D5%2B6%40%21%22%27' ), // urlencoding test
123 array( array( 'foo' => 'bar', 'baz' => 'is', 'asdf' => 'qwerty' ), 'foo=bar&baz=is&asdf=qwerty' ), // multi-item test
124 array( array( 'foo' => array( 'bar' => 'baz' ) ), 'foo%5Bbar%5D=baz' ),
125 array( array( 'foo' => array( 'bar' => 'baz', 'qwerty' => 'asdf' ) ), 'foo%5Bbar%5D=baz&foo%5Bqwerty%5D=asdf' ),
126 array( array( 'foo' => array( 'bar', 'baz' ) ), 'foo%5B0%5D=bar&foo%5B1%5D=baz' ),
127 array( array( 'foo' => array( 'bar' => array( 'bar' => 'baz' ) ) ), 'foo%5Bbar%5D%5Bbar%5D=baz' ),
132 * @dataProvider provideArrayToCGI
134 function testArrayToCGI( $array, $result ) {
135 $this->assertEquals( $result, wfArrayToCGI( $array ) );
139 function testArrayToCGI2() {
140 $this->assertEquals(
141 "baz=bar&foo=bar",
142 wfArrayToCGI(
143 array( 'baz' => 'bar' ),
144 array( 'foo' => 'bar', 'baz' => 'overridden value' ) ) );
147 public static function provideCgiToArray() {
148 return array(
149 array( '', array() ), // empty
150 array( 'foo=bar', array( 'foo' => 'bar' ) ), // string
151 array( 'foo=', array( 'foo' => '' ) ), // empty string
152 array( 'foo', array( 'foo' => '' ) ), // missing =
153 array( 'foo=bar&qwerty=asdf', array( 'foo' => 'bar', 'qwerty' => 'asdf' ) ), // multiple value
154 array( 'foo=A%26B%3D5%2B6%40%21%22%27', array( 'foo' => 'A&B=5+6@!"\'' ) ), // urldecoding test
155 array( 'foo%5Bbar%5D=baz', array( 'foo' => array( 'bar' => 'baz' ) ) ),
156 array( 'foo%5Bbar%5D=baz&foo%5Bqwerty%5D=asdf', array( 'foo' => array( 'bar' => 'baz', 'qwerty' => 'asdf' ) ) ),
157 array( 'foo%5B0%5D=bar&foo%5B1%5D=baz', array( 'foo' => array( 0 => 'bar', 1 => 'baz' ) ) ),
158 array( 'foo%5Bbar%5D%5Bbar%5D=baz', array( 'foo' => array( 'bar' => array( 'bar' => 'baz' ) ) ) ),
163 * @dataProvider provideCgiToArray
165 function testCgiToArray( $cgi, $result ) {
166 $this->assertEquals( $result, wfCgiToArray( $cgi ) );
169 public static function provideCgiRoundTrip() {
170 return array(
171 array( '' ),
172 array( 'foo=bar' ),
173 array( 'foo=' ),
174 array( 'foo=bar&baz=biz' ),
175 array( 'foo=A%26B%3D5%2B6%40%21%22%27' ),
176 array( 'foo%5Bbar%5D=baz' ),
177 array( 'foo%5B0%5D=bar&foo%5B1%5D=baz' ),
178 array( 'foo%5Bbar%5D%5Bbar%5D=baz' ),
183 * @dataProvider provideCgiRoundTrip
185 function testCgiRoundTrip( $cgi ) {
186 $this->assertEquals( $cgi, wfArrayToCGI( wfCgiToArray( $cgi ) ) );
189 function testMimeTypeMatch() {
190 $this->assertEquals(
191 'text/html',
192 mimeTypeMatch( 'text/html',
193 array( 'application/xhtml+xml' => 1.0,
194 'text/html' => 0.7,
195 'text/plain' => 0.3 ) ) );
196 $this->assertEquals(
197 'text/*',
198 mimeTypeMatch( 'text/html',
199 array( 'image/*' => 1.0,
200 'text/*' => 0.5 ) ) );
201 $this->assertEquals(
202 '*/*',
203 mimeTypeMatch( 'text/html',
204 array( '*/*' => 1.0 ) ) );
205 $this->assertNull(
206 mimeTypeMatch( 'text/html',
207 array( 'image/png' => 1.0,
208 'image/svg+xml' => 0.5 ) ) );
211 function testNegotiateType() {
212 $this->assertEquals(
213 'text/html',
214 wfNegotiateType(
215 array( 'application/xhtml+xml' => 1.0,
216 'text/html' => 0.7,
217 'text/plain' => 0.5,
218 'text/*' => 0.2 ),
219 array( 'text/html' => 1.0 ) ) );
220 $this->assertEquals(
221 'application/xhtml+xml',
222 wfNegotiateType(
223 array( 'application/xhtml+xml' => 1.0,
224 'text/html' => 0.7,
225 'text/plain' => 0.5,
226 'text/*' => 0.2 ),
227 array( 'application/xhtml+xml' => 1.0,
228 'text/html' => 0.5 ) ) );
229 $this->assertEquals(
230 'text/html',
231 wfNegotiateType(
232 array( 'text/html' => 1.0,
233 'text/plain' => 0.5,
234 'text/*' => 0.5,
235 'application/xhtml+xml' => 0.2 ),
236 array( 'application/xhtml+xml' => 1.0,
237 'text/html' => 0.5 ) ) );
238 $this->assertEquals(
239 'text/html',
240 wfNegotiateType(
241 array( 'text/*' => 1.0,
242 'image/*' => 0.7,
243 '*/*' => 0.3 ),
244 array( 'application/xhtml+xml' => 1.0,
245 'text/html' => 0.5 ) ) );
246 $this->assertNull(
247 wfNegotiateType(
248 array( 'text/*' => 1.0 ),
249 array( 'application/xhtml+xml' => 1.0 ) ) );
252 function testFallbackMbstringFunctions() {
254 if( !extension_loaded( 'mbstring' ) ) {
255 $this->markTestSkipped( "The mb_string functions must be installed to test the fallback functions" );
258 $sampleUTF = "Östergötland_coat_of_arms.png";
261 //mb_substr
262 $substr_params = array(
263 array( 0, 0 ),
264 array( 5, -4 ),
265 array( 33 ),
266 array( 100, -5 ),
267 array( -8, 10 ),
268 array( 1, 1 ),
269 array( 2, -1 )
272 foreach( $substr_params as $param_set ) {
273 $old_param_set = $param_set;
274 array_unshift( $param_set, $sampleUTF );
276 $this->assertEquals(
277 MWFunction::callArray( 'mb_substr', $param_set ),
278 MWFunction::callArray( 'Fallback::mb_substr', $param_set ),
279 'Fallback mb_substr with params ' . implode( ', ', $old_param_set )
284 //mb_strlen
285 $this->assertEquals(
286 mb_strlen( $sampleUTF ),
287 Fallback::mb_strlen( $sampleUTF ),
288 'Fallback mb_strlen'
292 //mb_str(r?)pos
293 $strpos_params = array(
294 //array( 'ter' ),
295 //array( 'Ö' ),
296 //array( 'Ö', 3 ),
297 //array( 'oat_', 100 ),
298 //array( 'c', -10 ),
299 //Broken for now
302 foreach( $strpos_params as $param_set ) {
303 $old_param_set = $param_set;
304 array_unshift( $param_set, $sampleUTF );
306 $this->assertEquals(
307 MWFunction::callArray( 'mb_strpos', $param_set ),
308 MWFunction::callArray( 'Fallback::mb_strpos', $param_set ),
309 'Fallback mb_strpos with params ' . implode( ', ', $old_param_set )
312 $this->assertEquals(
313 MWFunction::callArray( 'mb_strrpos', $param_set ),
314 MWFunction::callArray( 'Fallback::mb_strrpos', $param_set ),
315 'Fallback mb_strrpos with params ' . implode( ', ', $old_param_set )
322 function testDebugFunctionTest() {
324 global $wgDebugLogFile, $wgDebugTimestamps;
326 $old_log_file = $wgDebugLogFile;
327 $wgDebugLogFile = tempnam( wfTempDir(), 'mw-' );
328 # @todo FIXME: $wgDebugTimestamps should be tested
329 $old_wgDebugTimestamps = $wgDebugTimestamps;
330 $wgDebugTimestamps = false;
333 wfDebug( "This is a normal string" );
334 $this->assertEquals( "This is a normal string", file_get_contents( $wgDebugLogFile ) );
335 unlink( $wgDebugLogFile );
337 wfDebug( "This is nöt an ASCII string" );
338 $this->assertEquals( "This is nöt an ASCII string", file_get_contents( $wgDebugLogFile ) );
339 unlink( $wgDebugLogFile );
342 wfDebug( "\00305This has böth UTF and control chars\003" );
343 $this->assertEquals( " 05This has böth UTF and control chars ", file_get_contents( $wgDebugLogFile ) );
344 unlink( $wgDebugLogFile );
346 wfDebugMem();
347 $this->assertGreaterThan( 5000, preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) ) );
348 unlink( $wgDebugLogFile );
350 wfDebugMem(true);
351 $this->assertGreaterThan( 5000000, preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) ) );
352 unlink( $wgDebugLogFile );
355 $wgDebugLogFile = $old_log_file;
356 $wgDebugTimestamps = $old_wgDebugTimestamps;
359 function testClientAcceptsGzipTest() {
361 $settings = array(
362 'gzip' => true,
363 'bzip' => false,
364 '*' => false,
365 'compress, gzip' => true,
366 'gzip;q=1.0' => true,
367 'foozip' => false,
368 'foo*zip' => false,
369 'gzip;q=abcde' => true, //is this REALLY valid?
370 'gzip;q=12345678.9' => true,
371 ' gzip' => true,
374 if( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) $old_server_setting = $_SERVER['HTTP_ACCEPT_ENCODING'];
376 foreach ( $settings as $encoding => $expect ) {
377 $_SERVER['HTTP_ACCEPT_ENCODING'] = $encoding;
379 $this->assertEquals( $expect, wfClientAcceptsGzip( true ),
380 "'$encoding' => " . wfBoolToStr( $expect ) );
383 if( isset( $old_server_setting ) ) $_SERVER['HTTP_ACCEPT_ENCODING'] = $old_server_setting;
389 function testSwapVarsTest() {
392 $var1 = 1;
393 $var2 = 2;
395 $this->assertEquals( $var1, 1, 'var1 is set originally' );
396 $this->assertEquals( $var2, 2, 'var1 is set originally' );
398 swap( $var1, $var2 );
400 $this->assertEquals( $var1, 2, 'var1 is swapped' );
401 $this->assertEquals( $var2, 1, 'var2 is swapped' );
406 function testWfPercentTest() {
408 $pcts = array(
409 array( 6/7, '0.86%', 2, false ),
410 array( 3/3, '1%' ),
411 array( 22/7, '3.14286%', 5 ),
412 array( 3/6, '0.5%' ),
413 array( 1/3, '0%', 0 ),
414 array( 10/3, '0%', -1 ),
415 array( 3/4/5, '0.1%', 1 ),
416 array( 6/7*8, '6.8571428571%', 10 ),
419 foreach( $pcts as $pct ) {
420 if( !isset( $pct[2] ) ) $pct[2] = 2;
421 if( !isset( $pct[3] ) ) $pct[3] = true;
423 $this->assertEquals( wfPercent( $pct[0], $pct[2], $pct[3] ), $pct[1], $pct[1] );
429 function testInStringTest() {
431 $this->assertTrue( in_string( 'foo', 'foobar' ), 'foo is in foobar' );
432 $this->assertFalse( in_string( 'Bar', 'foobar' ), 'Case-sensitive by default' );
433 $this->assertTrue( in_string( 'Foo', 'foobar', true ), 'Case-insensitive when asked' );
438 * test @see wfShorthandToInteger()
439 * @dataProvider provideShorthand
441 public function testWfShorthandToInteger( $shorthand, $expected ) {
442 $this->assertEquals( $expected,
443 wfShorthandToInteger( $shorthand )
447 /** array( shorthand, expected integer ) */
448 public static function provideShorthand() {
449 return array(
450 # Null, empty ...
451 array( '', -1),
452 array( ' ', -1),
453 array( null, -1),
455 # Failures returns 0 :(
456 array( 'ABCDEFG', 0 ),
457 array( 'Ak', 0 ),
459 # Int, strings with spaces
460 array( 1, 1 ),
461 array( ' 1 ', 1 ),
462 array( 1023, 1023 ),
463 array( ' 1023 ', 1023 ),
465 # kilo, Mega, Giga
466 array( '1k', 1024 ),
467 array( '1K', 1024 ),
468 array( '1m', 1024 * 1024 ),
469 array( '1M', 1024 * 1024 ),
470 array( '1g', 1024 * 1024 * 1024 ),
471 array( '1G', 1024 * 1024 * 1024 ),
473 # Negatives
474 array( -1, -1 ),
475 array( -500, -500 ),
476 array( '-500', -500 ),
477 array( '-1k', -1024 ),
479 # Zeroes
480 array( '0', 0 ),
481 array( '0k', 0 ),
482 array( '0M', 0 ),
483 array( '0G', 0 ),
484 array( '-0', 0 ),
485 array( '-0k', 0 ),
486 array( '-0M', 0 ),
487 array( '-0G', 0 ),
492 * @param String $old: Text as it was in the database
493 * @param String $mine: Text submitted while user was editing
494 * @param String $yours: Text submitted by the user
495 * @param Boolean $expectedMergeResult Whether the merge should be a success
496 * @param String $expectedText: Text after merge has been completed
498 * @dataProvider provideMerge()
499 * @group medium
501 public function testMerge( $old, $mine, $yours, $expectedMergeResult, $expectedText ) {
502 $this->checkHasDiff3();
504 $mergedText = null;
505 $isMerged = wfMerge( $old, $mine, $yours, $mergedText );
507 $msg = 'Merge should be a ';
508 $msg .= $expectedMergeResult ? 'success' : 'failure';
509 $this->assertEquals( $expectedMergeResult, $isMerged, $msg );
511 if( $isMerged ) {
512 // Verify the merged text
513 $this->assertEquals( $expectedText, $mergedText,
514 'is merged text as expected?' );
518 public static function provideMerge() {
519 $EXPECT_MERGE_SUCCESS = true;
520 $EXPECT_MERGE_FAILURE = false;
522 return array(
524 // #0: clean merge
525 array(
526 // old:
527 "one one one\n" . // trimmed
528 "\n" .
529 "two two two",
531 // mine:
532 "one one one ONE ONE\n" .
533 "\n" .
534 "two two two\n", // with tailing whitespace
536 // yours:
537 "one one one\n" .
538 "\n" .
539 "two two TWO TWO", // trimmed
541 // ok:
542 $EXPECT_MERGE_SUCCESS,
544 // result:
545 "one one one ONE ONE\n" .
546 "\n" .
547 "two two TWO TWO\n", // note: will always end in a newline
550 // #1: conflict, fail
551 array(
552 // old:
553 "one one one", // trimmed
555 // mine:
556 "one one one ONE ONE\n" .
557 "\n" .
558 "bla bla\n" .
559 "\n", // with tailing whitespace
561 // yours:
562 "one one one\n" .
563 "\n" .
564 "two two", // trimmed
566 $EXPECT_MERGE_FAILURE,
568 // result:
569 null,
575 * @dataProvider provideMakeUrlIndexes()
577 function testMakeUrlIndexes( $url, $expected ) {
578 $index = wfMakeUrlIndexes( $url );
579 $this->assertEquals( $expected, $index, "wfMakeUrlIndexes(\"$url\")" );
582 function provideMakeUrlIndexes() {
583 return array(
584 array(
585 // just a regular :)
586 'https://bugzilla.wikimedia.org/show_bug.cgi?id=28627',
587 array( 'https://org.wikimedia.bugzilla./show_bug.cgi?id=28627' )
589 array(
590 // mailtos are handled special
591 // is this really right though? that final . probably belongs earlier?
592 'mailto:wiki@wikimedia.org',
593 array( 'mailto:org.wikimedia@wiki.' )
596 // file URL cases per bug 28627...
597 array(
598 // three slashes: local filesystem path Unix-style
599 'file:///whatever/you/like.txt',
600 array( 'file://./whatever/you/like.txt' )
602 array(
603 // three slashes: local filesystem path Windows-style
604 'file:///c:/whatever/you/like.txt',
605 array( 'file://./c:/whatever/you/like.txt' )
607 array(
608 // two slashes: UNC filesystem path Windows-style
609 'file://intranet/whatever/you/like.txt',
610 array( 'file://intranet./whatever/you/like.txt' )
612 // Multiple-slash cases that can sorta work on Mozilla
613 // if you hack it just right are kinda pathological,
614 // and unreliable cross-platform or on IE which means they're
615 // unlikely to appear on intranets.
617 // Those will survive the algorithm but with results that
618 // are less consistent.
620 // protocol-relative URL cases per bug 29854...
621 array(
622 '//bugzilla.wikimedia.org/show_bug.cgi?id=28627',
623 array(
624 'http://org.wikimedia.bugzilla./show_bug.cgi?id=28627',
625 'https://org.wikimedia.bugzilla./show_bug.cgi?id=28627'
632 * @dataProvider provideWfMatchesDomainList
634 function testWfMatchesDomainList( $url, $domains, $expected, $description ) {
635 $actual = wfMatchesDomainList( $url, $domains );
636 $this->assertEquals( $expected, $actual, $description );
639 function provideWfMatchesDomainList() {
640 $a = array();
641 $protocols = array( 'HTTP' => 'http:', 'HTTPS' => 'https:', 'protocol-relative' => '' );
642 foreach ( $protocols as $pDesc => $p ) {
643 $a = array_merge( $a, array(
644 array( "$p//www.example.com", array(), false, "No matches for empty domains array, $pDesc URL" ),
645 array( "$p//www.example.com", array( 'www.example.com' ), true, "Exact match in domains array, $pDesc URL" ),
646 array( "$p//www.example.com", array( 'example.com' ), true, "Match without subdomain in domains array, $pDesc URL" ),
647 array( "$p//www.example2.com", array( 'www.example.com', 'www.example2.com', 'www.example3.com' ), true, "Exact match with other domains in array, $pDesc URL" ),
648 array( "$p//www.example2.com", array( 'example.com', 'example2.com', 'example3,com' ), true, "Match without subdomain with other domains in array, $pDesc URL" ),
649 array( "$p//www.example4.com", array( 'example.com', 'example2.com', 'example3,com' ), false, "Domain not in array, $pDesc URL" ),
651 // FIXME: This is a bug in wfMatchesDomainList(). If and when this is fixed, update this test case
652 array( "$p//nds-nl.wikipedia.org", array( 'nl.wikipedia.org' ), true, "Substrings of domains match while they shouldn't, $pDesc URL" ),
653 ) );
655 return $a;
659 * @dataProvider provideWfShellMaintenanceCmdList
661 function testWfShellMaintenanceCmd( $script, $parameters, $options, $expected, $description ) {
662 if( wfIsWindows() ) {
663 // Approximation that's good enough for our purposes just now
664 $expected = str_replace( "'", '"', $expected );
666 $actual = wfShellMaintenanceCmd( $script, $parameters, $options );
667 $this->assertEquals( $expected, $actual, $description );
670 function provideWfShellMaintenanceCmdList() {
671 global $wgPhpCli;
672 return array(
673 array( 'eval.php', array( '--help', '--test' ), array(),
674 "'$wgPhpCli' 'eval.php' '--help' '--test'",
675 "Called eval.php --help --test" ),
676 array( 'eval.php', array( '--help', '--test space' ), array('php' => 'php5'),
677 "'php5' 'eval.php' '--help' '--test space'",
678 "Called eval.php --help --test with php option" ),
679 array( 'eval.php', array( '--help', '--test', 'X' ), array('wrapper' => 'MWScript.php'),
680 "'$wgPhpCli' 'MWScript.php' 'eval.php' '--help' '--test' 'X'",
681 "Called eval.php --help --test with wrapper option" ),
682 array( 'eval.php', array( '--help', '--test', 'y' ), array('php' => 'php5', 'wrapper' => 'MWScript.php'),
683 "'php5' 'MWScript.php' 'eval.php' '--help' '--test' 'y'",
684 "Called eval.php --help --test with wrapper and php option" ),
687 /* TODO: many more! */