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