]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - tests/phpunit/maintenance/MaintenanceTest.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / tests / phpunit / maintenance / MaintenanceTest.php
1 <?php
2
3 // It would be great if we were able to use PHPUnit's getMockForAbstractClass
4 // instead of the MaintenanceFixup hack below. However, we cannot do
5 // without changing the visibility and without working around hacks in
6 // Maintenance.php
7 // For the same reason, we cannot just use FakeMaintenance.
8 use MediaWiki\MediaWikiServices;
9
10 /**
11  * makes parts of the API of Maintenance that is hidden by protected visibily
12  * visible for testing, and makes up for a stream closing hack in Maintenance.php.
13  *
14  * This class is solely used for being able to test Maintenance right now
15  * without having to apply major refactorings to fix some design issues in
16  * Maintenance.php. Before adding more functions here, please consider whether
17  * this approach is correct, or a refactoring Maintenance to separate concers
18  * is more appropriate.
19  *
20  * Upon refactoring, keep in mind that besides the maintenance scrits themselves
21  * and tests right here, also at least Extension:Maintenance make use of
22  * Maintenance.
23  *
24  * Due to a hack in Maintenance.php using register_shutdown_function, be sure to
25  * finally call simulateShutdown on MaintenanceFixup instance before a test
26  * ends.
27  */
28 class MaintenanceFixup extends Maintenance {
29
30         // --- Making up for the register_shutdown_function hack in Maintenance.php
31
32         /**
33          * The test case that generated this instance.
34          *
35          * This member is motivated by allowing the destructor to check whether or not
36          * the test failed, in order to avoid unnecessary nags about omitted shutdown
37          * simulation.
38          * But as it is already available, we also usi it to flagging tests as failed
39          *
40          * @var MediaWikiTestCase
41          */
42         private $testCase;
43
44         /**
45          * shutdownSimulated === true if simulateShutdown has done it's work
46          *
47          * @var bool
48          */
49         private $shutdownSimulated = false;
50
51         /**
52          * Simulates what Maintenance wants to happen at script's end.
53          */
54         public function simulateShutdown() {
55                 if ( $this->shutdownSimulated ) {
56                         $this->testCase->fail( __METHOD__ . " called more than once" );
57                 }
58
59                 // The cleanup action.
60                 $this->outputChanneled( false );
61
62                 // Bookkeeping that we simulated the clean up.
63                 $this->shutdownSimulated = true;
64         }
65
66         // Note that the "public" here does not change visibility
67         public function outputChanneled( $msg, $channel = null ) {
68                 if ( $this->shutdownSimulated ) {
69                         if ( $msg !== false ) {
70                                 $this->testCase->fail( "Already past simulated shutdown, but msg is "
71                                         . "not false. Did the hack in Maintenance.php change? Please "
72                                         . "adapt the test case or Maintenance.php" );
73                         }
74
75                         // The current call is the one registered via register_shutdown_function.
76                         // We can safely ignore it, as we simulated this one via simulateShutdown
77                         // before (if we did not, the destructor of this instance will warn about
78                         // it)
79                         return;
80                 }
81
82                 call_user_func_array( [ "parent", __FUNCTION__ ], func_get_args() );
83         }
84
85         /**
86          * Safety net around register_shutdown_function of Maintenance.php
87          */
88         public function __destruct() {
89                 if ( !$this->shutdownSimulated ) {
90                         // Someone generated a MaintenanceFixup instance without calling
91                         // simulateShutdown. We'd have to raise a PHPUnit exception to correctly
92                         // flag this illegal usage. However, we are already in a destruktor, which
93                         // would trigger undefined behavior. Hence, we can only report to the
94                         // error output :( Hopefully people read the PHPUnit output.
95                         $name = $this->testCase->getName();
96                         fwrite( STDERR, "ERROR! Instance of " . __CLASS__ . " for test $name "
97                                 . "destructed without calling simulateShutdown method. Call "
98                                 . "simulateShutdown on the instance before it gets destructed." );
99                 }
100
101                 // The following guard is required, as PHP does not offer default destructors :(
102                 if ( is_callable( "parent::__destruct" ) ) {
103                         parent::__destruct();
104                 }
105         }
106
107         public function __construct( MediaWikiTestCase $testCase ) {
108                 parent::__construct();
109                 $this->testCase = $testCase;
110         }
111
112         // --- Making protected functions visible for test
113
114         public function output( $out, $channel = null ) {
115                 // Just to make PHP not nag about signature mismatches, we copied
116                 // Maintenance::output signature. However, we do not use (or rely on)
117                 // those variables. Instead we pass to Maintenance::output whatever we
118                 // receive at runtime.
119                 return call_user_func_array( [ "parent", __FUNCTION__ ], func_get_args() );
120         }
121
122         public function addOption( $name, $description, $required = false,
123                 $withArg = false, $shortName = false, $multiOccurance = false
124         ) {
125                 return call_user_func_array( [ "parent", __FUNCTION__ ], func_get_args() );
126         }
127
128         public function getOption( $name, $default = null ) {
129                 return call_user_func_array( [ "parent", __FUNCTION__ ], func_get_args() );
130         }
131
132         // --- Requirements for getting instance of abstract class
133
134         public function execute() {
135                 $this->testCase->fail( __METHOD__ . " called unexpectedly" );
136         }
137 }
138
139 /**
140  * @covers Maintenance
141  */
142 class MaintenanceTest extends MediaWikiTestCase {
143
144         /**
145          * The main Maintenance instance that is used for testing.
146          *
147          * @var MaintenanceFixup
148          */
149         private $m;
150
151         protected function setUp() {
152                 parent::setUp();
153                 $this->m = new MaintenanceFixup( $this );
154         }
155
156         protected function tearDown() {
157                 if ( $this->m ) {
158                         $this->m->simulateShutdown();
159                         $this->m = null;
160                 }
161                 parent::tearDown();
162         }
163
164         /**
165          * asserts the output before and after simulating shutdown
166          *
167          * This function simulates shutdown of self::m.
168          *
169          * @param string $preShutdownOutput Expected output before simulating shutdown
170          * @param bool $expectNLAppending Whether or not shutdown simulation is expected
171          *   to add a newline to the output. If false, $preShutdownOutput is the
172          *   expected output after shutdown simulation. Otherwise,
173          *   $preShutdownOutput with an appended newline is the expected output
174          *   after shutdown simulation.
175          */
176         private function assertOutputPrePostShutdown( $preShutdownOutput, $expectNLAppending ) {
177                 $this->assertEquals( $preShutdownOutput, $this->getActualOutput(),
178                         "Output before shutdown simulation" );
179
180                 $this->m->simulateShutdown();
181                 $this->m = null;
182
183                 $postShutdownOutput = $preShutdownOutput . ( $expectNLAppending ? "\n" : "" );
184                 $this->expectOutputString( $postShutdownOutput );
185         }
186
187         // Although the following tests do not seem to be too consistent (compare for
188         // example the newlines within the test.*StringString tests, or the
189         // test.*Intermittent.* tests), the objective of these tests is not to describe
190         // consistent behavior, but rather currently existing behavior.
191
192         function testOutputEmpty() {
193                 $this->m->output( "" );
194                 $this->assertOutputPrePostShutdown( "", false );
195         }
196
197         function testOutputString() {
198                 $this->m->output( "foo" );
199                 $this->assertOutputPrePostShutdown( "foo", false );
200         }
201
202         function testOutputStringString() {
203                 $this->m->output( "foo" );
204                 $this->m->output( "bar" );
205                 $this->assertOutputPrePostShutdown( "foobar", false );
206         }
207
208         function testOutputStringNL() {
209                 $this->m->output( "foo\n" );
210                 $this->assertOutputPrePostShutdown( "foo\n", false );
211         }
212
213         function testOutputStringNLNL() {
214                 $this->m->output( "foo\n\n" );
215                 $this->assertOutputPrePostShutdown( "foo\n\n", false );
216         }
217
218         function testOutputStringNLString() {
219                 $this->m->output( "foo\nbar" );
220                 $this->assertOutputPrePostShutdown( "foo\nbar", false );
221         }
222
223         function testOutputStringNLStringNL() {
224                 $this->m->output( "foo\nbar\n" );
225                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
226         }
227
228         function testOutputStringNLStringNLLinewise() {
229                 $this->m->output( "foo\n" );
230                 $this->m->output( "bar\n" );
231                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
232         }
233
234         function testOutputStringNLStringNLArbitrary() {
235                 $this->m->output( "" );
236                 $this->m->output( "foo" );
237                 $this->m->output( "" );
238                 $this->m->output( "\n" );
239                 $this->m->output( "ba" );
240                 $this->m->output( "" );
241                 $this->m->output( "r\n" );
242                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
243         }
244
245         function testOutputStringNLStringNLArbitraryAgain() {
246                 $this->m->output( "" );
247                 $this->m->output( "foo" );
248                 $this->m->output( "" );
249                 $this->m->output( "\nb" );
250                 $this->m->output( "a" );
251                 $this->m->output( "" );
252                 $this->m->output( "r\n" );
253                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
254         }
255
256         function testOutputWNullChannelEmpty() {
257                 $this->m->output( "", null );
258                 $this->assertOutputPrePostShutdown( "", false );
259         }
260
261         function testOutputWNullChannelString() {
262                 $this->m->output( "foo", null );
263                 $this->assertOutputPrePostShutdown( "foo", false );
264         }
265
266         function testOutputWNullChannelStringString() {
267                 $this->m->output( "foo", null );
268                 $this->m->output( "bar", null );
269                 $this->assertOutputPrePostShutdown( "foobar", false );
270         }
271
272         function testOutputWNullChannelStringNL() {
273                 $this->m->output( "foo\n", null );
274                 $this->assertOutputPrePostShutdown( "foo\n", false );
275         }
276
277         function testOutputWNullChannelStringNLNL() {
278                 $this->m->output( "foo\n\n", null );
279                 $this->assertOutputPrePostShutdown( "foo\n\n", false );
280         }
281
282         function testOutputWNullChannelStringNLString() {
283                 $this->m->output( "foo\nbar", null );
284                 $this->assertOutputPrePostShutdown( "foo\nbar", false );
285         }
286
287         function testOutputWNullChannelStringNLStringNL() {
288                 $this->m->output( "foo\nbar\n", null );
289                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
290         }
291
292         function testOutputWNullChannelStringNLStringNLLinewise() {
293                 $this->m->output( "foo\n", null );
294                 $this->m->output( "bar\n", null );
295                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
296         }
297
298         function testOutputWNullChannelStringNLStringNLArbitrary() {
299                 $this->m->output( "", null );
300                 $this->m->output( "foo", null );
301                 $this->m->output( "", null );
302                 $this->m->output( "\n", null );
303                 $this->m->output( "ba", null );
304                 $this->m->output( "", null );
305                 $this->m->output( "r\n", null );
306                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
307         }
308
309         function testOutputWNullChannelStringNLStringNLArbitraryAgain() {
310                 $this->m->output( "", null );
311                 $this->m->output( "foo", null );
312                 $this->m->output( "", null );
313                 $this->m->output( "\nb", null );
314                 $this->m->output( "a", null );
315                 $this->m->output( "", null );
316                 $this->m->output( "r\n", null );
317                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
318         }
319
320         function testOutputWChannelString() {
321                 $this->m->output( "foo", "bazChannel" );
322                 $this->assertOutputPrePostShutdown( "foo", true );
323         }
324
325         function testOutputWChannelStringNL() {
326                 $this->m->output( "foo\n", "bazChannel" );
327                 $this->assertOutputPrePostShutdown( "foo", true );
328         }
329
330         function testOutputWChannelStringNLNL() {
331                 // If this test fails, note that output takes strings with double line
332                 // endings (although output's implementation in this situation calls
333                 // outputChanneled with a string ending in a nl ... which is not allowed
334                 // according to the documentation of outputChanneled)
335                 $this->m->output( "foo\n\n", "bazChannel" );
336                 $this->assertOutputPrePostShutdown( "foo\n", true );
337         }
338
339         function testOutputWChannelStringNLString() {
340                 $this->m->output( "foo\nbar", "bazChannel" );
341                 $this->assertOutputPrePostShutdown( "foo\nbar", true );
342         }
343
344         function testOutputWChannelStringNLStringNL() {
345                 $this->m->output( "foo\nbar\n", "bazChannel" );
346                 $this->assertOutputPrePostShutdown( "foo\nbar", true );
347         }
348
349         function testOutputWChannelStringNLStringNLLinewise() {
350                 $this->m->output( "foo\n", "bazChannel" );
351                 $this->m->output( "bar\n", "bazChannel" );
352                 $this->assertOutputPrePostShutdown( "foobar", true );
353         }
354
355         function testOutputWChannelStringNLStringNLArbitrary() {
356                 $this->m->output( "", "bazChannel" );
357                 $this->m->output( "foo", "bazChannel" );
358                 $this->m->output( "", "bazChannel" );
359                 $this->m->output( "\n", "bazChannel" );
360                 $this->m->output( "ba", "bazChannel" );
361                 $this->m->output( "", "bazChannel" );
362                 $this->m->output( "r\n", "bazChannel" );
363                 $this->assertOutputPrePostShutdown( "foobar", true );
364         }
365
366         function testOutputWChannelStringNLStringNLArbitraryAgain() {
367                 $this->m->output( "", "bazChannel" );
368                 $this->m->output( "foo", "bazChannel" );
369                 $this->m->output( "", "bazChannel" );
370                 $this->m->output( "\nb", "bazChannel" );
371                 $this->m->output( "a", "bazChannel" );
372                 $this->m->output( "", "bazChannel" );
373                 $this->m->output( "r\n", "bazChannel" );
374                 $this->assertOutputPrePostShutdown( "foo\nbar", true );
375         }
376
377         function testOutputWMultipleChannelsChannelChange() {
378                 $this->m->output( "foo", "bazChannel" );
379                 $this->m->output( "bar", "bazChannel" );
380                 $this->m->output( "qux", "quuxChannel" );
381                 $this->m->output( "corge", "bazChannel" );
382                 $this->assertOutputPrePostShutdown( "foobar\nqux\ncorge", true );
383         }
384
385         function testOutputWMultipleChannelsChannelChangeNL() {
386                 $this->m->output( "foo", "bazChannel" );
387                 $this->m->output( "bar\n", "bazChannel" );
388                 $this->m->output( "qux\n", "quuxChannel" );
389                 $this->m->output( "corge", "bazChannel" );
390                 $this->assertOutputPrePostShutdown( "foobar\nqux\ncorge", true );
391         }
392
393         function testOutputWAndWOChannelStringStartWO() {
394                 $this->m->output( "foo" );
395                 $this->m->output( "bar", "bazChannel" );
396                 $this->m->output( "qux" );
397                 $this->m->output( "quux", "bazChannel" );
398                 $this->assertOutputPrePostShutdown( "foobar\nquxquux", true );
399         }
400
401         function testOutputWAndWOChannelStringStartW() {
402                 $this->m->output( "foo", "bazChannel" );
403                 $this->m->output( "bar" );
404                 $this->m->output( "qux", "bazChannel" );
405                 $this->m->output( "quux" );
406                 $this->assertOutputPrePostShutdown( "foo\nbarqux\nquux", false );
407         }
408
409         function testOutputWChannelTypeSwitch() {
410                 $this->m->output( "foo", 1 );
411                 $this->m->output( "bar", 1.0 );
412                 $this->assertOutputPrePostShutdown( "foo\nbar", true );
413         }
414
415         function testOutputIntermittentEmpty() {
416                 $this->m->output( "foo" );
417                 $this->m->output( "" );
418                 $this->m->output( "bar" );
419                 $this->assertOutputPrePostShutdown( "foobar", false );
420         }
421
422         function testOutputIntermittentFalse() {
423                 $this->m->output( "foo" );
424                 $this->m->output( false );
425                 $this->m->output( "bar" );
426                 $this->assertOutputPrePostShutdown( "foobar", false );
427         }
428
429         function testOutputIntermittentFalseAfterOtherChannel() {
430                 $this->m->output( "qux", "quuxChannel" );
431                 $this->m->output( "foo" );
432                 $this->m->output( false );
433                 $this->m->output( "bar" );
434                 $this->assertOutputPrePostShutdown( "qux\nfoobar", false );
435         }
436
437         function testOutputWNullChannelIntermittentEmpty() {
438                 $this->m->output( "foo", null );
439                 $this->m->output( "", null );
440                 $this->m->output( "bar", null );
441                 $this->assertOutputPrePostShutdown( "foobar", false );
442         }
443
444         function testOutputWNullChannelIntermittentFalse() {
445                 $this->m->output( "foo", null );
446                 $this->m->output( false, null );
447                 $this->m->output( "bar", null );
448                 $this->assertOutputPrePostShutdown( "foobar", false );
449         }
450
451         function testOutputWChannelIntermittentEmpty() {
452                 $this->m->output( "foo", "bazChannel" );
453                 $this->m->output( "", "bazChannel" );
454                 $this->m->output( "bar", "bazChannel" );
455                 $this->assertOutputPrePostShutdown( "foobar", true );
456         }
457
458         function testOutputWChannelIntermittentFalse() {
459                 $this->m->output( "foo", "bazChannel" );
460                 $this->m->output( false, "bazChannel" );
461                 $this->m->output( "bar", "bazChannel" );
462                 $this->assertOutputPrePostShutdown( "foobar", true );
463         }
464
465         // Note that (per documentation) outputChanneled does take strings that end
466         // in \n, hence we do not test such strings.
467
468         function testOutputChanneledEmpty() {
469                 $this->m->outputChanneled( "" );
470                 $this->assertOutputPrePostShutdown( "\n", false );
471         }
472
473         function testOutputChanneledString() {
474                 $this->m->outputChanneled( "foo" );
475                 $this->assertOutputPrePostShutdown( "foo\n", false );
476         }
477
478         function testOutputChanneledStringString() {
479                 $this->m->outputChanneled( "foo" );
480                 $this->m->outputChanneled( "bar" );
481                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
482         }
483
484         function testOutputChanneledStringNLString() {
485                 $this->m->outputChanneled( "foo\nbar" );
486                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
487         }
488
489         function testOutputChanneledStringNLStringNLArbitraryAgain() {
490                 $this->m->outputChanneled( "" );
491                 $this->m->outputChanneled( "foo" );
492                 $this->m->outputChanneled( "" );
493                 $this->m->outputChanneled( "\nb" );
494                 $this->m->outputChanneled( "a" );
495                 $this->m->outputChanneled( "" );
496                 $this->m->outputChanneled( "r" );
497                 $this->assertOutputPrePostShutdown( "\nfoo\n\n\nb\na\n\nr\n", false );
498         }
499
500         function testOutputChanneledWNullChannelEmpty() {
501                 $this->m->outputChanneled( "", null );
502                 $this->assertOutputPrePostShutdown( "\n", false );
503         }
504
505         function testOutputChanneledWNullChannelString() {
506                 $this->m->outputChanneled( "foo", null );
507                 $this->assertOutputPrePostShutdown( "foo\n", false );
508         }
509
510         function testOutputChanneledWNullChannelStringString() {
511                 $this->m->outputChanneled( "foo", null );
512                 $this->m->outputChanneled( "bar", null );
513                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
514         }
515
516         function testOutputChanneledWNullChannelStringNLString() {
517                 $this->m->outputChanneled( "foo\nbar", null );
518                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
519         }
520
521         function testOutputChanneledWNullChannelStringNLStringNLArbitraryAgain() {
522                 $this->m->outputChanneled( "", null );
523                 $this->m->outputChanneled( "foo", null );
524                 $this->m->outputChanneled( "", null );
525                 $this->m->outputChanneled( "\nb", null );
526                 $this->m->outputChanneled( "a", null );
527                 $this->m->outputChanneled( "", null );
528                 $this->m->outputChanneled( "r", null );
529                 $this->assertOutputPrePostShutdown( "\nfoo\n\n\nb\na\n\nr\n", false );
530         }
531
532         function testOutputChanneledWChannelString() {
533                 $this->m->outputChanneled( "foo", "bazChannel" );
534                 $this->assertOutputPrePostShutdown( "foo", true );
535         }
536
537         function testOutputChanneledWChannelStringNLString() {
538                 $this->m->outputChanneled( "foo\nbar", "bazChannel" );
539                 $this->assertOutputPrePostShutdown( "foo\nbar", true );
540         }
541
542         function testOutputChanneledWChannelStringString() {
543                 $this->m->outputChanneled( "foo", "bazChannel" );
544                 $this->m->outputChanneled( "bar", "bazChannel" );
545                 $this->assertOutputPrePostShutdown( "foobar", true );
546         }
547
548         function testOutputChanneledWChannelStringNLStringNLArbitraryAgain() {
549                 $this->m->outputChanneled( "", "bazChannel" );
550                 $this->m->outputChanneled( "foo", "bazChannel" );
551                 $this->m->outputChanneled( "", "bazChannel" );
552                 $this->m->outputChanneled( "\nb", "bazChannel" );
553                 $this->m->outputChanneled( "a", "bazChannel" );
554                 $this->m->outputChanneled( "", "bazChannel" );
555                 $this->m->outputChanneled( "r", "bazChannel" );
556                 $this->assertOutputPrePostShutdown( "foo\nbar", true );
557         }
558
559         function testOutputChanneledWMultipleChannelsChannelChange() {
560                 $this->m->outputChanneled( "foo", "bazChannel" );
561                 $this->m->outputChanneled( "bar", "bazChannel" );
562                 $this->m->outputChanneled( "qux", "quuxChannel" );
563                 $this->m->outputChanneled( "corge", "bazChannel" );
564                 $this->assertOutputPrePostShutdown( "foobar\nqux\ncorge", true );
565         }
566
567         function testOutputChanneledWMultipleChannelsChannelChangeEnclosedNull() {
568                 $this->m->outputChanneled( "foo", "bazChannel" );
569                 $this->m->outputChanneled( "bar", null );
570                 $this->m->outputChanneled( "qux", null );
571                 $this->m->outputChanneled( "corge", "bazChannel" );
572                 $this->assertOutputPrePostShutdown( "foo\nbar\nqux\ncorge", true );
573         }
574
575         function testOutputChanneledWMultipleChannelsChannelAfterNullChange() {
576                 $this->m->outputChanneled( "foo", "bazChannel" );
577                 $this->m->outputChanneled( "bar", null );
578                 $this->m->outputChanneled( "qux", null );
579                 $this->m->outputChanneled( "corge", "quuxChannel" );
580                 $this->assertOutputPrePostShutdown( "foo\nbar\nqux\ncorge", true );
581         }
582
583         function testOutputChanneledWAndWOChannelStringStartWO() {
584                 $this->m->outputChanneled( "foo" );
585                 $this->m->outputChanneled( "bar", "bazChannel" );
586                 $this->m->outputChanneled( "qux" );
587                 $this->m->outputChanneled( "quux", "bazChannel" );
588                 $this->assertOutputPrePostShutdown( "foo\nbar\nqux\nquux", true );
589         }
590
591         function testOutputChanneledWAndWOChannelStringStartW() {
592                 $this->m->outputChanneled( "foo", "bazChannel" );
593                 $this->m->outputChanneled( "bar" );
594                 $this->m->outputChanneled( "qux", "bazChannel" );
595                 $this->m->outputChanneled( "quux" );
596                 $this->assertOutputPrePostShutdown( "foo\nbar\nqux\nquux\n", false );
597         }
598
599         function testOutputChanneledWChannelTypeSwitch() {
600                 $this->m->outputChanneled( "foo", 1 );
601                 $this->m->outputChanneled( "bar", 1.0 );
602                 $this->assertOutputPrePostShutdown( "foo\nbar", true );
603         }
604
605         function testOutputChanneledWOChannelIntermittentEmpty() {
606                 $this->m->outputChanneled( "foo" );
607                 $this->m->outputChanneled( "" );
608                 $this->m->outputChanneled( "bar" );
609                 $this->assertOutputPrePostShutdown( "foo\n\nbar\n", false );
610         }
611
612         function testOutputChanneledWOChannelIntermittentFalse() {
613                 $this->m->outputChanneled( "foo" );
614                 $this->m->outputChanneled( false );
615                 $this->m->outputChanneled( "bar" );
616                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
617         }
618
619         function testOutputChanneledWNullChannelIntermittentEmpty() {
620                 $this->m->outputChanneled( "foo", null );
621                 $this->m->outputChanneled( "", null );
622                 $this->m->outputChanneled( "bar", null );
623                 $this->assertOutputPrePostShutdown( "foo\n\nbar\n", false );
624         }
625
626         function testOutputChanneledWNullChannelIntermittentFalse() {
627                 $this->m->outputChanneled( "foo", null );
628                 $this->m->outputChanneled( false, null );
629                 $this->m->outputChanneled( "bar", null );
630                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
631         }
632
633         function testOutputChanneledWChannelIntermittentEmpty() {
634                 $this->m->outputChanneled( "foo", "bazChannel" );
635                 $this->m->outputChanneled( "", "bazChannel" );
636                 $this->m->outputChanneled( "bar", "bazChannel" );
637                 $this->assertOutputPrePostShutdown( "foobar", true );
638         }
639
640         function testOutputChanneledWChannelIntermittentFalse() {
641                 $this->m->outputChanneled( "foo", "bazChannel" );
642                 $this->m->outputChanneled( false, "bazChannel" );
643                 $this->m->outputChanneled( "bar", "bazChannel" );
644                 $this->assertOutputPrePostShutdown( "foo\nbar", true );
645         }
646
647         function testCleanupChanneledClean() {
648                 $this->m->cleanupChanneled();
649                 $this->assertOutputPrePostShutdown( "", false );
650         }
651
652         function testCleanupChanneledAfterOutput() {
653                 $this->m->output( "foo" );
654                 $this->m->cleanupChanneled();
655                 $this->assertOutputPrePostShutdown( "foo", false );
656         }
657
658         function testCleanupChanneledAfterOutputWNullChannel() {
659                 $this->m->output( "foo", null );
660                 $this->m->cleanupChanneled();
661                 $this->assertOutputPrePostShutdown( "foo", false );
662         }
663
664         function testCleanupChanneledAfterOutputWChannel() {
665                 $this->m->output( "foo", "bazChannel" );
666                 $this->m->cleanupChanneled();
667                 $this->assertOutputPrePostShutdown( "foo\n", false );
668         }
669
670         function testCleanupChanneledAfterNLOutput() {
671                 $this->m->output( "foo\n" );
672                 $this->m->cleanupChanneled();
673                 $this->assertOutputPrePostShutdown( "foo\n", false );
674         }
675
676         function testCleanupChanneledAfterNLOutputWNullChannel() {
677                 $this->m->output( "foo\n", null );
678                 $this->m->cleanupChanneled();
679                 $this->assertOutputPrePostShutdown( "foo\n", false );
680         }
681
682         function testCleanupChanneledAfterNLOutputWChannel() {
683                 $this->m->output( "foo\n", "bazChannel" );
684                 $this->m->cleanupChanneled();
685                 $this->assertOutputPrePostShutdown( "foo\n", false );
686         }
687
688         function testCleanupChanneledAfterOutputChanneledWOChannel() {
689                 $this->m->outputChanneled( "foo" );
690                 $this->m->cleanupChanneled();
691                 $this->assertOutputPrePostShutdown( "foo\n", false );
692         }
693
694         function testCleanupChanneledAfterOutputChanneledWNullChannel() {
695                 $this->m->outputChanneled( "foo", null );
696                 $this->m->cleanupChanneled();
697                 $this->assertOutputPrePostShutdown( "foo\n", false );
698         }
699
700         function testCleanupChanneledAfterOutputChanneledWChannel() {
701                 $this->m->outputChanneled( "foo", "bazChannel" );
702                 $this->m->cleanupChanneled();
703                 $this->assertOutputPrePostShutdown( "foo\n", false );
704         }
705
706         function testMultipleMaintenanceObjectsInteractionOutput() {
707                 $m2 = new MaintenanceFixup( $this );
708
709                 $this->m->output( "foo" );
710                 $m2->output( "bar" );
711
712                 $this->assertEquals( "foobar", $this->getActualOutput(),
713                         "Output before shutdown simulation (m2)" );
714                 $m2->simulateShutdown();
715                 $this->assertOutputPrePostShutdown( "foobar", false );
716         }
717
718         function testMultipleMaintenanceObjectsInteractionOutputWNullChannel() {
719                 $m2 = new MaintenanceFixup( $this );
720
721                 $this->m->output( "foo", null );
722                 $m2->output( "bar", null );
723
724                 $this->assertEquals( "foobar", $this->getActualOutput(),
725                         "Output before shutdown simulation (m2)" );
726                 $m2->simulateShutdown();
727                 $this->assertOutputPrePostShutdown( "foobar", false );
728         }
729
730         function testMultipleMaintenanceObjectsInteractionOutputWChannel() {
731                 $m2 = new MaintenanceFixup( $this );
732
733                 $this->m->output( "foo", "bazChannel" );
734                 $m2->output( "bar", "bazChannel" );
735
736                 $this->assertEquals( "foobar", $this->getActualOutput(),
737                         "Output before shutdown simulation (m2)" );
738                 $m2->simulateShutdown();
739                 $this->assertOutputPrePostShutdown( "foobar\n", true );
740         }
741
742         function testMultipleMaintenanceObjectsInteractionOutputWNullChannelNL() {
743                 $m2 = new MaintenanceFixup( $this );
744
745                 $this->m->output( "foo\n", null );
746                 $m2->output( "bar\n", null );
747
748                 $this->assertEquals( "foo\nbar\n", $this->getActualOutput(),
749                         "Output before shutdown simulation (m2)" );
750                 $m2->simulateShutdown();
751                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
752         }
753
754         function testMultipleMaintenanceObjectsInteractionOutputWChannelNL() {
755                 $m2 = new MaintenanceFixup( $this );
756
757                 $this->m->output( "foo\n", "bazChannel" );
758                 $m2->output( "bar\n", "bazChannel" );
759
760                 $this->assertEquals( "foobar", $this->getActualOutput(),
761                         "Output before shutdown simulation (m2)" );
762                 $m2->simulateShutdown();
763                 $this->assertOutputPrePostShutdown( "foobar\n", true );
764         }
765
766         function testMultipleMaintenanceObjectsInteractionOutputChanneled() {
767                 $m2 = new MaintenanceFixup( $this );
768
769                 $this->m->outputChanneled( "foo" );
770                 $m2->outputChanneled( "bar" );
771
772                 $this->assertEquals( "foo\nbar\n", $this->getActualOutput(),
773                         "Output before shutdown simulation (m2)" );
774                 $m2->simulateShutdown();
775                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
776         }
777
778         function testMultipleMaintenanceObjectsInteractionOutputChanneledWNullChannel() {
779                 $m2 = new MaintenanceFixup( $this );
780
781                 $this->m->outputChanneled( "foo", null );
782                 $m2->outputChanneled( "bar", null );
783
784                 $this->assertEquals( "foo\nbar\n", $this->getActualOutput(),
785                         "Output before shutdown simulation (m2)" );
786                 $m2->simulateShutdown();
787                 $this->assertOutputPrePostShutdown( "foo\nbar\n", false );
788         }
789
790         function testMultipleMaintenanceObjectsInteractionOutputChanneledWChannel() {
791                 $m2 = new MaintenanceFixup( $this );
792
793                 $this->m->outputChanneled( "foo", "bazChannel" );
794                 $m2->outputChanneled( "bar", "bazChannel" );
795
796                 $this->assertEquals( "foobar", $this->getActualOutput(),
797                         "Output before shutdown simulation (m2)" );
798                 $m2->simulateShutdown();
799                 $this->assertOutputPrePostShutdown( "foobar\n", true );
800         }
801
802         function testMultipleMaintenanceObjectsInteractionCleanupChanneledWChannel() {
803                 $m2 = new MaintenanceFixup( $this );
804
805                 $this->m->outputChanneled( "foo", "bazChannel" );
806                 $m2->outputChanneled( "bar", "bazChannel" );
807
808                 $this->assertEquals( "foobar", $this->getActualOutput(),
809                         "Output before first cleanup" );
810                 $this->m->cleanupChanneled();
811                 $this->assertEquals( "foobar\n", $this->getActualOutput(),
812                         "Output after first cleanup" );
813                 $m2->cleanupChanneled();
814                 $this->assertEquals( "foobar\n\n", $this->getActualOutput(),
815                         "Output after second cleanup" );
816
817                 $m2->simulateShutdown();
818                 $this->assertOutputPrePostShutdown( "foobar\n\n", false );
819         }
820
821         /**
822          * @covers Maintenance::getConfig
823          */
824         public function testGetConfig() {
825                 $this->assertInstanceOf( 'Config', $this->m->getConfig() );
826                 $this->assertSame(
827                         MediaWikiServices::getInstance()->getMainConfig(),
828                         $this->m->getConfig()
829                 );
830         }
831
832         /**
833          * @covers Maintenance::setConfig
834          */
835         public function testSetConfig() {
836                 $conf = $this->createMock( 'Config' );
837                 $this->m->setConfig( $conf );
838                 $this->assertSame( $conf, $this->m->getConfig() );
839         }
840
841         function testParseArgs() {
842                 $m2 = new MaintenanceFixup( $this );
843                 // Create an option with an argument allowed to be specified multiple times
844                 $m2->addOption( 'multi', 'This option does stuff', false, true, false, true );
845                 $m2->loadWithArgv( [ '--multi', 'this1', '--multi', 'this2' ] );
846
847                 $this->assertEquals( [ 'this1', 'this2' ], $m2->getOption( 'multi' ) );
848                 $this->assertEquals( [ [ 'multi', 'this1' ], [ 'multi', 'this2' ] ],
849                         $m2->orderedOptions );
850
851                 $m2->simulateShutdown();
852
853                 $m2 = new MaintenanceFixup( $this );
854
855                 $m2->addOption( 'multi', 'This option does stuff', false, false, false, true );
856                 $m2->loadWithArgv( [ '--multi', '--multi' ] );
857
858                 $this->assertEquals( [ 1, 1 ], $m2->getOption( 'multi' ) );
859                 $this->assertEquals( [ [ 'multi', 1 ], [ 'multi', 1 ] ], $m2->orderedOptions );
860
861                 $m2->simulateShutdown();
862
863                 $m2 = new MaintenanceFixup( $this );
864                 // Create an option with an argument allowed to be specified multiple times
865                 $m2->addOption( 'multi', 'This option doesn\'t actually support multiple occurrences' );
866                 $m2->loadWithArgv( [ '--multi=yo' ] );
867
868                 $this->assertEquals( 'yo', $m2->getOption( 'multi' ) );
869                 $this->assertEquals( [ [ 'multi', 'yo' ] ], $m2->orderedOptions );
870
871                 $m2->simulateShutdown();
872         }
873 }