Merge "mw.htmlform: Fix hiding of the textbox for 'selectorother' fields on page...
[lhc/web/wiklou.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 }