Merge "Fix sessionfailure i18n message during authentication"
[lhc/web/wiklou.git] / tests / phpunit / includes / StatusTest.php
1 <?php
2
3 /**
4 * @author Addshore
5 */
6 class StatusTest extends MediaWikiLangTestCase {
7
8 /**
9 * @dataProvider provideValues
10 * @covers Status::newGood
11 */
12 public function testNewGood( $value = null ) {
13 $status = Status::newGood( $value );
14 $this->assertTrue( $status->isGood() );
15 $this->assertTrue( $status->isOK() );
16 $this->assertEquals( $value, $status->getValue() );
17 }
18
19 public static function provideValues() {
20 return [
21 [],
22 [ 'foo' ],
23 [ [ 'foo' => 'bar' ] ],
24 [ new Exception() ],
25 [ 1234 ],
26 ];
27 }
28
29 /**
30 * @covers Status::newFatal
31 */
32 public function testNewFatalWithMessage() {
33 $message = $this->getMockBuilder( Message::class )
34 ->disableOriginalConstructor()
35 ->getMock();
36
37 $status = Status::newFatal( $message );
38 $this->assertFalse( $status->isGood() );
39 $this->assertFalse( $status->isOK() );
40 $this->assertEquals( $message, $status->getMessage() );
41 }
42
43 /**
44 * @covers Status::newFatal
45 */
46 public function testNewFatalWithString() {
47 $message = 'foo';
48 $status = Status::newFatal( $message );
49 $this->assertFalse( $status->isGood() );
50 $this->assertFalse( $status->isOK() );
51 $this->assertEquals( $message, $status->getMessage()->getKey() );
52 }
53
54 /**
55 * Test 'ok' and 'errors' getters.
56 *
57 * @covers Status::__get
58 */
59 public function testOkAndErrorsGetters() {
60 $status = Status::newGood( 'foo' );
61 $this->assertTrue( $status->ok );
62 $status = Status::newFatal( 'foo', 1, 2 );
63 $this->assertFalse( $status->ok );
64 $this->assertArrayEquals(
65 [
66 [
67 'type' => 'error',
68 'message' => 'foo',
69 'params' => [ 1, 2 ]
70 ]
71 ],
72 $status->errors
73 );
74 }
75
76 /**
77 * Test 'ok' setter.
78 *
79 * @covers Status::__set
80 */
81 public function testOkSetter() {
82 $status = new Status();
83 $status->ok = false;
84 $this->assertFalse( $status->isOK() );
85 $status->ok = true;
86 $this->assertTrue( $status->isOK() );
87 }
88
89 /**
90 * @dataProvider provideSetResult
91 * @covers Status::setResult
92 */
93 public function testSetResult( $ok, $value = null ) {
94 $status = new Status();
95 $status->setResult( $ok, $value );
96 $this->assertEquals( $ok, $status->isOK() );
97 $this->assertEquals( $value, $status->getValue() );
98 }
99
100 public static function provideSetResult() {
101 return [
102 [ true ],
103 [ false ],
104 [ true, 'value' ],
105 [ false, 'value' ],
106 ];
107 }
108
109 /**
110 * @dataProvider provideIsOk
111 * @covers Status::setOK
112 * @covers Status::isOK
113 */
114 public function testIsOk( $ok ) {
115 $status = new Status();
116 $status->setOK( $ok );
117 $this->assertEquals( $ok, $status->isOK() );
118 }
119
120 public static function provideIsOk() {
121 return [
122 [ true ],
123 [ false ],
124 ];
125 }
126
127 /**
128 * @covers Status::getValue
129 */
130 public function testGetValue() {
131 $status = new Status();
132 $status->value = 'foobar';
133 $this->assertEquals( 'foobar', $status->getValue() );
134 }
135
136 /**
137 * @dataProvider provideIsGood
138 * @covers Status::isGood
139 */
140 public function testIsGood( $ok, $errors, $expected ) {
141 $status = new Status();
142 $status->setOK( $ok );
143 foreach ( $errors as $error ) {
144 $status->warning( $error );
145 }
146 $this->assertEquals( $expected, $status->isGood() );
147 }
148
149 public static function provideIsGood() {
150 return [
151 [ true, [], true ],
152 [ true, [ 'foo' ], false ],
153 [ false, [], false ],
154 [ false, [ 'foo' ], false ],
155 ];
156 }
157
158 /**
159 * @dataProvider provideMockMessageDetails
160 * @covers Status::warning
161 * @covers Status::getWarningsArray
162 * @covers Status::getStatusArray
163 */
164 public function testWarningWithMessage( $mockDetails ) {
165 $status = new Status();
166 $messages = $this->getMockMessages( $mockDetails );
167
168 foreach ( $messages as $message ) {
169 $status->warning( $message );
170 }
171 $warnings = $status->getWarningsArray();
172
173 $this->assertEquals( count( $messages ), count( $warnings ) );
174 foreach ( $messages as $key => $message ) {
175 $expectedArray = array_merge( [ $message->getKey() ], $message->getParams() );
176 $this->assertEquals( $warnings[$key], $expectedArray );
177 }
178 }
179
180 /**
181 * @dataProvider provideMockMessageDetails
182 * @covers Status::error
183 * @covers Status::getErrorsArray
184 * @covers Status::getStatusArray
185 * @covers Status::getErrors
186 */
187 public function testErrorWithMessage( $mockDetails ) {
188 $status = new Status();
189 $messages = $this->getMockMessages( $mockDetails );
190
191 foreach ( $messages as $message ) {
192 $status->error( $message );
193 }
194 $errors = $status->getErrorsArray();
195
196 $this->assertEquals( count( $messages ), count( $errors ) );
197 foreach ( $messages as $key => $message ) {
198 $expectedArray = array_merge( [ $message->getKey() ], $message->getParams() );
199 $this->assertEquals( $errors[$key], $expectedArray );
200 }
201 }
202
203 /**
204 * @dataProvider provideMockMessageDetails
205 * @covers Status::fatal
206 * @covers Status::getErrorsArray
207 * @covers Status::getStatusArray
208 */
209 public function testFatalWithMessage( $mockDetails ) {
210 $status = new Status();
211 $messages = $this->getMockMessages( $mockDetails );
212
213 foreach ( $messages as $message ) {
214 $status->fatal( $message );
215 }
216 $errors = $status->getErrorsArray();
217
218 $this->assertEquals( count( $messages ), count( $errors ) );
219 foreach ( $messages as $key => $message ) {
220 $expectedArray = array_merge( [ $message->getKey() ], $message->getParams() );
221 $this->assertEquals( $errors[$key], $expectedArray );
222 }
223 $this->assertFalse( $status->isOK() );
224 }
225
226 protected function getMockMessage( $key = 'key', $params = [] ) {
227 $message = $this->getMockBuilder( Message::class )
228 ->disableOriginalConstructor()
229 ->getMock();
230 $message->expects( $this->atLeastOnce() )
231 ->method( 'getKey' )
232 ->will( $this->returnValue( $key ) );
233 $message->expects( $this->atLeastOnce() )
234 ->method( 'getParams' )
235 ->will( $this->returnValue( $params ) );
236 return $message;
237 }
238
239 /**
240 * @param array $messageDetails E.g. array( 'KEY' => array(/PARAMS/) )
241 * @return Message[]
242 */
243 protected function getMockMessages( $messageDetails ) {
244 $messages = [];
245 foreach ( $messageDetails as $key => $paramsArray ) {
246 $messages[] = $this->getMockMessage( $key, $paramsArray );
247 }
248 return $messages;
249 }
250
251 public static function provideMockMessageDetails() {
252 return [
253 [ [ 'key1' => [ 'foo' => 'bar' ] ] ],
254 [ [ 'key1' => [ 'foo' => 'bar' ], 'key2' => [ 'foo2' => 'bar2' ] ] ],
255 ];
256 }
257
258 /**
259 * @covers Status::merge
260 */
261 public function testMerge() {
262 $status1 = new Status();
263 $status2 = new Status();
264 $message1 = $this->getMockMessage( 'warn1' );
265 $message2 = $this->getMockMessage( 'error2' );
266 $status1->warning( $message1 );
267 $status2->error( $message2 );
268
269 $status1->merge( $status2 );
270 $this->assertEquals(
271 2,
272 count( $status1->getWarningsArray() ) + count( $status1->getErrorsArray() )
273 );
274 }
275
276 /**
277 * @covers Status::merge
278 */
279 public function testMergeWithOverwriteValue() {
280 $status1 = new Status();
281 $status2 = new Status();
282 $message1 = $this->getMockMessage( 'warn1' );
283 $message2 = $this->getMockMessage( 'error2' );
284 $status1->warning( $message1 );
285 $status2->error( $message2 );
286 $status2->value = 'FooValue';
287
288 $status1->merge( $status2, true );
289 $this->assertEquals(
290 2,
291 count( $status1->getWarningsArray() ) + count( $status1->getErrorsArray() )
292 );
293 $this->assertEquals( 'FooValue', $status1->getValue() );
294 }
295
296 /**
297 * @covers Status::hasMessage
298 */
299 public function testHasMessage() {
300 $status = new Status();
301 $status->fatal( 'bad' );
302 $status->fatal( wfMessage( 'bad-msg' ) );
303 $this->assertTrue( $status->hasMessage( 'bad' ) );
304 $this->assertTrue( $status->hasMessage( 'bad-msg' ) );
305 $this->assertTrue( $status->hasMessage( wfMessage( 'bad-msg' ) ) );
306 $this->assertFalse( $status->hasMessage( 'good' ) );
307 }
308
309 /**
310 * @dataProvider provideCleanParams
311 * @covers Status::cleanParams
312 */
313 public function testCleanParams( $cleanCallback, $params, $expected ) {
314 $method = new ReflectionMethod( Status::class, 'cleanParams' );
315 $method->setAccessible( true );
316 $status = new Status();
317 $status->cleanCallback = $cleanCallback;
318
319 $this->assertEquals( $expected, $method->invoke( $status, $params ) );
320 }
321
322 public static function provideCleanParams() {
323 $cleanCallback = function ( $value ) {
324 return '-' . $value . '-';
325 };
326
327 return [
328 [ false, [ 'foo' => 'bar' ], [ 'foo' => 'bar' ] ],
329 [ $cleanCallback, [ 'foo' => 'bar' ], [ 'foo' => '-bar-' ] ],
330 ];
331 }
332
333 /**
334 * @dataProvider provideGetWikiTextAndHtml
335 * @covers Status::getWikiText
336 */
337 public function testGetWikiText(
338 Status $status, $wikitext, $wrappedWikitext, $html, $wrappedHtml
339 ) {
340 $this->assertEquals( $wikitext, $status->getWikiText() );
341
342 $this->assertEquals( $wrappedWikitext, $status->getWikiText( 'wrap-short', 'wrap-long', 'qqx' ) );
343 }
344
345 /**
346 * @dataProvider provideGetWikiTextAndHtml
347 * @covers Status::getHtml
348 */
349 public function testGetHtml(
350 Status $status, $wikitext, $wrappedWikitext, $html, $wrappedHtml
351 ) {
352 $this->assertEquals( $html, $status->getHTML() );
353
354 $this->assertEquals( $wrappedHtml, $status->getHTML( 'wrap-short', 'wrap-long', 'qqx' ) );
355 }
356
357 /**
358 * @return array Array of arrays with values;
359 * 0 => status object
360 * 1 => expected string (with no context)
361 */
362 public static function provideGetWikiTextAndHtml() {
363 $testCases = [];
364
365 $testCases['GoodStatus'] = [
366 new Status(),
367 "Internal error: Status::getWikiText called for a good result, this is incorrect\n",
368 "(wrap-short: (internalerror_info: Status::getWikiText called for a good result, " .
369 "this is incorrect\n))",
370 "<p>Internal error: Status::getWikiText called for a good result, this is incorrect\n</p>",
371 "<p>(wrap-short: (internalerror_info: Status::getWikiText called for a good result, " .
372 "this is incorrect\n))\n</p>",
373 ];
374
375 $status = new Status();
376 $status->setOK( false );
377 $testCases['GoodButNoError'] = [
378 $status,
379 "Internal error: Status::getWikiText: Invalid result object: no error text but not OK\n",
380 "(wrap-short: (internalerror_info: Status::getWikiText: Invalid result object: " .
381 "no error text but not OK\n))",
382 "<p>Internal error: Status::getWikiText: Invalid result object: no error text but not OK\n</p>",
383 "<p>(wrap-short: (internalerror_info: Status::getWikiText: Invalid result object: " .
384 "no error text but not OK\n))\n</p>",
385 ];
386
387 $status = new Status();
388 $status->warning( 'fooBar!' );
389 $testCases['1StringWarning'] = [
390 $status,
391 "⧼fooBar!⧽",
392 "(wrap-short: (fooBar!))",
393 "<p>⧼fooBar!⧽\n</p>",
394 "<p>(wrap-short: (fooBar!))\n</p>",
395 ];
396
397 $status = new Status();
398 $status->warning( 'fooBar!' );
399 $status->warning( 'fooBar2!' );
400 $testCases['2StringWarnings'] = [
401 $status,
402 "* ⧼fooBar!⧽\n* ⧼fooBar2!⧽\n",
403 "(wrap-long: * (fooBar!)\n* (fooBar2!)\n)",
404 "<ul><li> ⧼fooBar!⧽</li>\n<li> ⧼fooBar2!⧽</li></ul>\n",
405 "<p>(wrap-long: * (fooBar!)\n</p>\n<ul><li> (fooBar2!)</li></ul>\n<p>)\n</p>",
406 ];
407
408 $status = new Status();
409 $status->warning( new Message( 'fooBar!', [ 'foo', 'bar' ] ) );
410 $testCases['1MessageWarning'] = [
411 $status,
412 "⧼fooBar!⧽",
413 "(wrap-short: (fooBar!: foo, bar))",
414 "<p>⧼fooBar!⧽\n</p>",
415 "<p>(wrap-short: (fooBar!: foo, bar))\n</p>",
416 ];
417
418 $status = new Status();
419 $status->warning( new Message( 'fooBar!', [ 'foo', 'bar' ] ) );
420 $status->warning( new Message( 'fooBar2!' ) );
421 $testCases['2MessageWarnings'] = [
422 $status,
423 "* ⧼fooBar!⧽\n* ⧼fooBar2!⧽\n",
424 "(wrap-long: * (fooBar!: foo, bar)\n* (fooBar2!)\n)",
425 "<ul><li> ⧼fooBar!⧽</li>\n<li> ⧼fooBar2!⧽</li></ul>\n",
426 "<p>(wrap-long: * (fooBar!: foo, bar)\n</p>\n<ul><li> (fooBar2!)</li></ul>\n<p>)\n</p>",
427 ];
428
429 return $testCases;
430 }
431
432 private static function sanitizedMessageParams( Message $message ) {
433 return array_map( function ( $p ) {
434 return $p instanceof Message
435 ? [
436 'key' => $p->getKey(),
437 'params' => self::sanitizedMessageParams( $p ),
438 'lang' => $p->getLanguage()->getCode(),
439 ]
440 : $p;
441 }, $message->getParams() );
442 }
443
444 /**
445 * @dataProvider provideGetMessage
446 * @covers Status::getMessage
447 */
448 public function testGetMessage(
449 Status $status, $expectedParams = [], $expectedKey, $expectedWrapper
450 ) {
451 $message = $status->getMessage( null, null, 'qqx' );
452 $this->assertInstanceOf( Message::class, $message );
453 $this->assertEquals( $expectedParams, self::sanitizedMessageParams( $message ),
454 'Message::getParams' );
455 $this->assertEquals( $expectedKey, $message->getKey(), 'Message::getKey' );
456
457 $message = $status->getMessage( 'wrapper-short', 'wrapper-long' );
458 $this->assertInstanceOf( Message::class, $message );
459 $this->assertEquals( $expectedWrapper, $message->getKey(), 'Message::getKey with wrappers' );
460 $this->assertCount( 1, $message->getParams(), 'Message::getParams with wrappers' );
461
462 $message = $status->getMessage( 'wrapper' );
463 $this->assertInstanceOf( Message::class, $message );
464 $this->assertEquals( 'wrapper', $message->getKey(), 'Message::getKey with wrappers' );
465 $this->assertCount( 1, $message->getParams(), 'Message::getParams with wrappers' );
466
467 $message = $status->getMessage( false, 'wrapper' );
468 $this->assertInstanceOf( Message::class, $message );
469 $this->assertEquals( 'wrapper', $message->getKey(), 'Message::getKey with wrappers' );
470 $this->assertCount( 1, $message->getParams(), 'Message::getParams with wrappers' );
471 }
472
473 /**
474 * @return array Array of arrays with values;
475 * 0 => status object
476 * 1 => expected Message parameters (with no context)
477 * 2 => expected Message key
478 */
479 public static function provideGetMessage() {
480 $testCases = [];
481
482 $testCases['GoodStatus'] = [
483 new Status(),
484 [ "Status::getMessage called for a good result, this is incorrect\n" ],
485 'internalerror_info',
486 'wrapper-short'
487 ];
488
489 $status = new Status();
490 $status->setOK( false );
491 $testCases['GoodButNoError'] = [
492 $status,
493 [ "Status::getMessage: Invalid result object: no error text but not OK\n" ],
494 'internalerror_info',
495 'wrapper-short'
496 ];
497
498 $status = new Status();
499 $status->warning( 'fooBar!' );
500 $testCases['1StringWarning'] = [
501 $status,
502 [],
503 'fooBar!',
504 'wrapper-short'
505 ];
506
507 $status = new Status();
508 $status->warning( 'fooBar!' );
509 $status->warning( 'fooBar2!' );
510 $testCases[ '2StringWarnings' ] = [
511 $status,
512 [
513 [ 'key' => 'fooBar!', 'params' => [], 'lang' => 'qqx' ],
514 [ 'key' => 'fooBar2!', 'params' => [], 'lang' => 'qqx' ]
515 ],
516 "* \$1\n* \$2",
517 'wrapper-long'
518 ];
519
520 $status = new Status();
521 $status->warning( new Message( 'fooBar!', [ 'foo', 'bar' ] ) );
522 $testCases['1MessageWarning'] = [
523 $status,
524 [ 'foo', 'bar' ],
525 'fooBar!',
526 'wrapper-short'
527 ];
528
529 $status = new Status();
530 $status->warning( new Message( 'fooBar!', [ 'foo', 'bar' ] ) );
531 $status->warning( new Message( 'fooBar2!' ) );
532 $testCases['2MessageWarnings'] = [
533 $status,
534 [
535 [ 'key' => 'fooBar!', 'params' => [ 'foo', 'bar' ], 'lang' => 'qqx' ],
536 [ 'key' => 'fooBar2!', 'params' => [], 'lang' => 'qqx' ]
537 ],
538 "* \$1\n* \$2",
539 'wrapper-long'
540 ];
541
542 return $testCases;
543 }
544
545 /**
546 * @covers Status::replaceMessage
547 */
548 public function testReplaceMessage() {
549 $status = new Status();
550 $message = new Message( 'key1', [ 'foo1', 'bar1' ] );
551 $status->error( $message );
552 $newMessage = new Message( 'key2', [ 'foo2', 'bar2' ] );
553
554 $status->replaceMessage( $message, $newMessage );
555
556 $this->assertEquals( $newMessage, $status->errors[0]['message'] );
557 }
558
559 /**
560 * @covers Status::getErrorMessage
561 */
562 public function testGetErrorMessage() {
563 $method = new ReflectionMethod( Status::class, 'getErrorMessage' );
564 $method->setAccessible( true );
565 $status = new Status();
566 $key = 'foo';
567 $params = [ 'bar' ];
568
569 /** @var Message $message */
570 $message = $method->invoke( $status, array_merge( [ $key ], $params ) );
571 $this->assertInstanceOf( Message::class, $message );
572 $this->assertEquals( $key, $message->getKey() );
573 $this->assertEquals( $params, $message->getParams() );
574 }
575
576 /**
577 * @covers Status::getErrorMessageArray
578 */
579 public function testGetErrorMessageArray() {
580 $method = new ReflectionMethod( Status::class, 'getErrorMessageArray' );
581 $method->setAccessible( true );
582 $status = new Status();
583 $key = 'foo';
584 $params = [ 'bar' ];
585
586 /** @var Message[] $messageArray */
587 $messageArray = $method->invoke(
588 $status,
589 [
590 array_merge( [ $key ], $params ),
591 array_merge( [ $key ], $params )
592 ]
593 );
594
595 $this->assertInternalType( 'array', $messageArray );
596 $this->assertCount( 2, $messageArray );
597 foreach ( $messageArray as $message ) {
598 $this->assertInstanceOf( Message::class, $message );
599 $this->assertEquals( $key, $message->getKey() );
600 $this->assertEquals( $params, $message->getParams() );
601 }
602 }
603
604 /**
605 * @covers Status::getErrorsByType
606 */
607 public function testGetErrorsByType() {
608 $status = new Status();
609 $warning = new Message( 'warning111' );
610 $error = new Message( 'error111' );
611 $status->warning( $warning );
612 $status->error( $error );
613
614 $warnings = $status->getErrorsByType( 'warning' );
615 $errors = $status->getErrorsByType( 'error' );
616
617 $this->assertCount( 1, $warnings );
618 $this->assertCount( 1, $errors );
619 $this->assertEquals( $warning, $warnings[0]['message'] );
620 $this->assertEquals( $error, $errors[0]['message'] );
621 }
622
623 /**
624 * @covers Status::__wakeup
625 */
626 public function testWakeUpSanitizesCallback() {
627 $status = new Status();
628 $status->cleanCallback = function ( $value ) {
629 return '-' . $value . '-';
630 };
631 $status->__wakeup();
632 $this->assertEquals( false, $status->cleanCallback );
633 }
634
635 /**
636 * @dataProvider provideNonObjectMessages
637 * @covers Status::getStatusArray
638 */
639 public function testGetStatusArrayWithNonObjectMessages( $nonObjMsg ) {
640 $status = new Status();
641 if ( !array_key_exists( 1, $nonObjMsg ) ) {
642 $status->warning( $nonObjMsg[0] );
643 } else {
644 $status->warning( $nonObjMsg[0], $nonObjMsg[1] );
645 }
646
647 $array = $status->getWarningsArray(); // We use getWarningsArray to access getStatusArray
648
649 $this->assertEquals( 1, count( $array ) );
650 $this->assertEquals( $nonObjMsg, $array[0] );
651 }
652
653 public static function provideNonObjectMessages() {
654 return [
655 [ [ 'ImaString', [ 'param1' => 'value1' ] ] ],
656 [ [ 'ImaString' ] ],
657 ];
658 }
659
660 /**
661 * @dataProvider provideErrorsWarningsOnly
662 * @covers Status::splitByErrorType
663 * @covers StatusValue::splitByErrorType
664 */
665 public function testGetErrorsWarningsOnlyStatus( $errorText, $warningText, $type, $errorResult,
666 $warningResult
667 ) {
668 $status = Status::newGood();
669 if ( $errorText ) {
670 $status->fatal( $errorText );
671 }
672 if ( $warningText ) {
673 $status->warning( $warningText );
674 }
675 $testStatus = $status->splitByErrorType()[$type];
676 $this->assertEquals( $errorResult, $testStatus->getErrorsByType( 'error' ) );
677 $this->assertEquals( $warningResult, $testStatus->getErrorsByType( 'warning' ) );
678 }
679
680 public static function provideErrorsWarningsOnly() {
681 return [
682 [
683 'Just an error',
684 'Just a warning',
685 0,
686 [
687 0 => [
688 'type' => 'error',
689 'message' => 'Just an error',
690 'params' => []
691 ],
692 ],
693 [],
694 ], [
695 'Just an error',
696 'Just a warning',
697 1,
698 [],
699 [
700 0 => [
701 'type' => 'warning',
702 'message' => 'Just a warning',
703 'params' => []
704 ],
705 ],
706 ], [
707 null,
708 null,
709 1,
710 [],
711 [],
712 ], [
713 null,
714 null,
715 0,
716 [],
717 [],
718 ]
719 ];
720 }
721
722 }