6 class ApiErrorFormatterTest
extends MediaWikiLangTestCase
{
9 * @covers ApiErrorFormatter
11 public function testErrorFormatterBasics() {
12 $result = new ApiResult( 8388608 );
13 $formatter = new ApiErrorFormatter( $result, Language
::factory( 'de' ), 'wikitext', false );
14 $this->assertSame( 'de', $formatter->getLanguage()->getCode() );
16 $formatter->addMessagesFromStatus( null, Status
::newGood() );
18 [ ApiResult
::META_TYPE
=> 'assoc' ],
19 $result->getResultData()
22 $this->assertSame( [], $formatter->arrayFromStatus( Status
::newGood() ) );
24 $wrappedFormatter = TestingAccessWrapper
::newFromObject( $formatter );
26 'Blah "kbd" <X> 😊',
27 $wrappedFormatter->stripMarkup( 'Blah <kbd>kbd</kbd> <b><X></b> 😊' ),
33 * @covers ApiErrorFormatter
34 * @dataProvider provideErrorFormatter
36 public function testErrorFormatter( $format, $lang, $useDB,
37 $expect1, $expect2, $expect3
39 $result = new ApiResult( 8388608 );
40 $formatter = new ApiErrorFormatter( $result, Language
::factory( $lang ), $format, $useDB );
43 $expect1[ApiResult
::META_TYPE
] = 'assoc';
44 $expect2[ApiResult
::META_TYPE
] = 'assoc';
45 $expect3[ApiResult
::META_TYPE
] = 'assoc';
47 $formatter->addWarning( 'string', 'mainpage' );
48 $formatter->addError( 'err', 'mainpage' );
49 $this->assertEquals( $expect1, $result->getResultData(), 'Simple test' );
52 $formatter->addWarning( 'foo', 'mainpage' );
53 $formatter->addWarning( 'foo', 'mainpage' );
54 $formatter->addWarning( 'foo', [ 'parentheses', 'foobar' ] );
55 $msg1 = wfMessage( 'mainpage' );
56 $formatter->addWarning( 'message', $msg1 );
57 $msg2 = new ApiMessage( 'mainpage', 'overriddenCode', [ 'overriddenData' => true ] );
58 $formatter->addWarning( 'messageWithData', $msg2 );
59 $formatter->addError( 'errWithData', $msg2 );
60 $this->assertSame( $expect2, $result->getResultData(), 'Complex test' );
63 $this->removeModuleTag( $expect2['warnings'][2] ),
64 $formatter->formatMessage( $msg1 ),
65 'formatMessage test 1'
68 $this->removeModuleTag( $expect2['warnings'][3] ),
69 $formatter->formatMessage( $msg2 ),
70 'formatMessage test 2'
74 $status = Status
::newGood();
75 $status->warning( 'mainpage' );
76 $status->warning( 'parentheses', 'foobar' );
77 $status->warning( $msg1 );
78 $status->warning( $msg2 );
79 $status->error( 'mainpage' );
80 $status->error( 'parentheses', 'foobar' );
81 $formatter->addMessagesFromStatus( 'status', $status );
82 $this->assertSame( $expect3, $result->getResultData(), 'Status test' );
85 array_map( [ $this, 'removeModuleTag' ], $expect3['errors'] ),
86 $formatter->arrayFromStatus( $status, 'error' ),
87 'arrayFromStatus test for error'
90 array_map( [ $this, 'removeModuleTag' ], $expect3['warnings'] ),
91 $formatter->arrayFromStatus( $status, 'warning' ),
92 'arrayFromStatus test for warning'
96 private function removeModuleTag( $s ) {
97 if ( is_array( $s ) ) {
98 unset( $s['module'] );
103 public static function provideErrorFormatter() {
104 $mainpageText = wfMessage( 'mainpage' )->inLanguage( 'de' )->useDatabase( false )->text();
105 $parensText = wfMessage( 'parentheses', 'foobar' )->inLanguage( 'de' )
106 ->useDatabase( false )->text();
107 $mainpageHTML = wfMessage( 'mainpage' )->inLanguage( 'en' )->parse();
108 $parensHTML = wfMessage( 'parentheses', 'foobar' )->inLanguage( 'en' )->parse();
109 $C = ApiResult
::META_CONTENT
;
110 $I = ApiResult
::META_INDEXED_TAG_NAME
;
111 $overriddenData = [ 'overriddenData' => true, ApiResult
::META_TYPE
=> 'assoc' ];
114 $tmp = [ 'wikitext', 'de', false,
117 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'err', $C => 'text' ],
121 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'string', $C => 'text' ],
127 [ 'code' => 'overriddenCode', 'text' => $mainpageText,
128 'data' => $overriddenData, 'module' => 'errWithData', $C => 'text' ],
132 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'foo', $C => 'text' ],
133 [ 'code' => 'parentheses', 'text' => $parensText, 'module' => 'foo', $C => 'text' ],
134 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'message', $C => 'text' ],
135 [ 'code' => 'overriddenCode', 'text' => $mainpageText,
136 'data' => $overriddenData, 'module' => 'messageWithData', $C => 'text' ],
142 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'status', $C => 'text' ],
143 [ 'code' => 'parentheses', 'text' => $parensText, 'module' => 'status', $C => 'text' ],
147 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'status', $C => 'text' ],
148 [ 'code' => 'parentheses', 'text' => $parensText, 'module' => 'status', $C => 'text' ],
149 [ 'code' => 'overriddenCode', 'text' => $mainpageText,
150 'data' => $overriddenData, 'module' => 'status', $C => 'text' ],
155 [ 'plaintext' ] +
$tmp, // For these messages, plaintext and wikitext are the same
156 [ 'html', 'en', true,
159 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'err', $C => 'html' ],
163 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'string', $C => 'html' ],
169 [ 'code' => 'overriddenCode', 'html' => $mainpageHTML,
170 'data' => $overriddenData, 'module' => 'errWithData', $C => 'html' ],
174 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'foo', $C => 'html' ],
175 [ 'code' => 'parentheses', 'html' => $parensHTML, 'module' => 'foo', $C => 'html' ],
176 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'message', $C => 'html' ],
177 [ 'code' => 'overriddenCode', 'html' => $mainpageHTML,
178 'data' => $overriddenData, 'module' => 'messageWithData', $C => 'html' ],
184 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'status', $C => 'html' ],
185 [ 'code' => 'parentheses', 'html' => $parensHTML, 'module' => 'status', $C => 'html' ],
189 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'status', $C => 'html' ],
190 [ 'code' => 'parentheses', 'html' => $parensHTML, 'module' => 'status', $C => 'html' ],
191 [ 'code' => 'overriddenCode', 'html' => $mainpageHTML,
192 'data' => $overriddenData, 'module' => 'status', $C => 'html' ],
201 'code' => 'mainpage',
203 'params' => [ $I => 'param' ],
210 'code' => 'mainpage',
212 'params' => [ $I => 'param' ],
213 'module' => 'string',
221 'code' => 'overriddenCode',
223 'params' => [ $I => 'param' ],
224 'data' => $overriddenData,
225 'module' => 'errWithData',
231 'code' => 'mainpage',
233 'params' => [ $I => 'param' ],
237 'code' => 'parentheses',
238 'key' => 'parentheses',
239 'params' => [ 'foobar', $I => 'param' ],
243 'code' => 'mainpage',
245 'params' => [ $I => 'param' ],
246 'module' => 'message',
249 'code' => 'overriddenCode',
251 'params' => [ $I => 'param' ],
252 'data' => $overriddenData,
253 'module' => 'messageWithData',
261 'code' => 'mainpage',
263 'params' => [ $I => 'param' ],
264 'module' => 'status',
267 'code' => 'parentheses',
268 'key' => 'parentheses',
269 'params' => [ 'foobar', $I => 'param' ],
270 'module' => 'status',
276 'code' => 'mainpage',
278 'params' => [ $I => 'param' ],
279 'module' => 'status',
282 'code' => 'parentheses',
283 'key' => 'parentheses',
284 'params' => [ 'foobar', $I => 'param' ],
285 'module' => 'status',
288 'code' => 'overriddenCode',
290 'params' => [ $I => 'param' ],
291 'data' => $overriddenData,
292 'module' => 'status',
298 [ 'none', 'fr', true,
301 [ 'code' => 'mainpage', 'module' => 'err' ],
305 [ 'code' => 'mainpage', 'module' => 'string' ],
311 [ 'code' => 'overriddenCode', 'data' => $overriddenData,
312 'module' => 'errWithData' ],
316 [ 'code' => 'mainpage', 'module' => 'foo' ],
317 [ 'code' => 'parentheses', 'module' => 'foo' ],
318 [ 'code' => 'mainpage', 'module' => 'message' ],
319 [ 'code' => 'overriddenCode', 'data' => $overriddenData,
320 'module' => 'messageWithData' ],
326 [ 'code' => 'mainpage', 'module' => 'status' ],
327 [ 'code' => 'parentheses', 'module' => 'status' ],
331 [ 'code' => 'mainpage', 'module' => 'status' ],
332 [ 'code' => 'parentheses', 'module' => 'status' ],
333 [ 'code' => 'overriddenCode', 'data' => $overriddenData, 'module' => 'status' ],
342 * @covers ApiErrorFormatter_BackCompat
344 public function testErrorFormatterBC() {
345 $mainpagePlain = wfMessage( 'mainpage' )->useDatabase( false )->plain();
346 $parensPlain = wfMessage( 'parentheses', 'foobar' )->useDatabase( false )->plain();
348 $result = new ApiResult( 8388608 );
349 $formatter = new ApiErrorFormatter_BackCompat( $result );
351 $this->assertSame( 'en', $formatter->getLanguage()->getCode() );
353 $this->assertSame( [], $formatter->arrayFromStatus( Status
::newGood() ) );
355 $formatter->addWarning( 'string', 'mainpage' );
356 $formatter->addWarning( 'raw',
357 new RawMessage( 'Blah <kbd>kbd</kbd> <b><X></b> 😞' )
359 $formatter->addError( 'err', 'mainpage' );
362 'code' => 'mainpage',
363 'info' => $mainpagePlain,
367 'warnings' => 'Blah "kbd" <X> 😞',
368 ApiResult
::META_CONTENT
=> 'warnings',
371 'warnings' => $mainpagePlain,
372 ApiResult
::META_CONTENT
=> 'warnings',
375 ApiResult
::META_TYPE
=> 'assoc',
376 ], $result->getResultData(), 'Simple test' );
379 $formatter->addWarning( 'foo', 'mainpage' );
380 $formatter->addWarning( 'foo', 'mainpage' );
381 $formatter->addWarning( 'xxx+foo', [ 'parentheses', 'foobar' ] );
382 $msg1 = wfMessage( 'mainpage' );
383 $formatter->addWarning( 'message', $msg1 );
384 $msg2 = new ApiMessage( 'mainpage', 'overriddenCode', [ 'overriddenData' => true ] );
385 $formatter->addWarning( 'messageWithData', $msg2 );
386 $formatter->addError( 'errWithData', $msg2 );
387 $formatter->addWarning( null, 'mainpage' );
390 'code' => 'overriddenCode',
391 'info' => $mainpagePlain,
392 'overriddenData' => true,
396 'warnings' => $mainpagePlain,
397 ApiResult
::META_CONTENT
=> 'warnings',
399 'messageWithData' => [
400 'warnings' => $mainpagePlain,
401 ApiResult
::META_CONTENT
=> 'warnings',
404 'warnings' => $mainpagePlain,
405 ApiResult
::META_CONTENT
=> 'warnings',
408 'warnings' => "$mainpagePlain\n$parensPlain",
409 ApiResult
::META_CONTENT
=> 'warnings',
412 ApiResult
::META_TYPE
=> 'assoc',
413 ], $result->getResultData(), 'Complex test' );
417 'code' => 'mainpage',
418 'info' => 'Main Page',
420 $formatter->formatMessage( $msg1 )
424 'code' => 'overriddenCode',
425 'info' => 'Main Page',
426 'overriddenData' => true,
428 $formatter->formatMessage( $msg2 )
432 $status = Status
::newGood();
433 $status->warning( 'mainpage' );
434 $status->warning( 'parentheses', 'foobar' );
435 $status->warning( $msg1 );
436 $status->warning( $msg2 );
437 $status->error( 'mainpage' );
438 $status->error( 'parentheses', 'foobar' );
439 $formatter->addMessagesFromStatus( 'status', $status );
442 'code' => 'parentheses',
443 'info' => $parensPlain,
447 'warnings' => "$mainpagePlain\n$parensPlain",
448 ApiResult
::META_CONTENT
=> 'warnings',
451 ApiResult
::META_TYPE
=> 'assoc',
452 ], $result->getResultData(), 'Status test' );
454 $I = ApiResult
::META_INDEXED_TAG_NAME
;
458 'message' => 'mainpage',
459 'params' => [ $I => 'param' ],
460 'code' => 'mainpage',
464 'message' => 'parentheses',
465 'params' => [ 'foobar', $I => 'param' ],
466 'code' => 'parentheses',
471 $formatter->arrayFromStatus( $status, 'error' ),
472 'arrayFromStatus test for error'
477 'message' => 'mainpage',
478 'params' => [ $I => 'param' ],
479 'code' => 'mainpage',
483 'message' => 'parentheses',
484 'params' => [ 'foobar', $I => 'param' ],
485 'code' => 'parentheses',
489 'message' => 'mainpage',
490 'params' => [ $I => 'param' ],
491 'code' => 'mainpage',
495 'message' => 'mainpage',
496 'params' => [ $I => 'param' ],
497 'code' => 'overriddenCode',
502 $formatter->arrayFromStatus( $status, 'warning' ),
503 'arrayFromStatus test for warning'
508 * @dataProvider provideGetMessageFromException
509 * @covers ApiErrorFormatter::getMessageFromException
510 * @covers ApiErrorFormatter::formatException
511 * @param Exception $exception
512 * @param array $options
513 * @param array $expect
515 public function testGetMessageFromException( $exception, $options, $expect ) {
516 $result = new ApiResult( 8388608 );
517 $formatter = new ApiErrorFormatter( $result, Language
::factory( 'en' ), 'html', false );
519 $msg = $formatter->getMessageFromException( $exception, $options );
520 $this->assertInstanceOf( Message
::class, $msg );
521 $this->assertInstanceOf( IApiMessage
::class, $msg );
522 $this->assertSame( $expect, [
523 'text' => $msg->parse(),
524 'code' => $msg->getApiCode(),
525 'data' => $msg->getApiData(),
528 $expectFormatted = $formatter->formatMessage( $msg );
529 $formatted = $formatter->formatException( $exception, $options );
530 $this->assertSame( $expectFormatted, $formatted );
534 * @dataProvider provideGetMessageFromException
535 * @covers ApiErrorFormatter_BackCompat::formatException
536 * @param Exception $exception
537 * @param array $options
538 * @param array $expect
540 public function testGetMessageFromException_BC( $exception, $options, $expect ) {
541 $result = new ApiResult( 8388608 );
542 $formatter = new ApiErrorFormatter_BackCompat( $result );
544 $msg = $formatter->getMessageFromException( $exception, $options );
545 $this->assertInstanceOf( Message
::class, $msg );
546 $this->assertInstanceOf( IApiMessage
::class, $msg );
547 $this->assertSame( $expect, [
548 'text' => $msg->parse(),
549 'code' => $msg->getApiCode(),
550 'data' => $msg->getApiData(),
553 $expectFormatted = $formatter->formatMessage( $msg );
554 $formatted = $formatter->formatException( $exception, $options );
555 $this->assertSame( $expectFormatted, $formatted );
556 $formatted = $formatter->formatException( $exception, $options +
[ 'bc' => true ] );
557 $this->assertSame( $expectFormatted['info'], $formatted );
560 public static function provideGetMessageFromException() {
562 'Normal exception' => [
563 new RuntimeException( '<b>Something broke!</b>' ),
566 'text' => '<b>Something broke!</b>',
567 'code' => 'internal_api_error_RuntimeException',
571 'Normal exception, wrapped' => [
572 new RuntimeException( '<b>Something broke!</b>' ),
573 [ 'wrap' => 'parentheses', 'code' => 'some-code', 'data' => [ 'foo' => 'bar', 'baz' => 42 ] ],
575 'text' => '(<b>Something broke!</b>)',
576 'code' => 'some-code',
577 'data' => [ 'foo' => 'bar', 'baz' => 42 ],
580 'UsageException' => [
581 new UsageException( '<b>Something broke!</b>', 'ue-code', 0, [ 'xxx' => 'yyy', 'baz' => 23 ] ),
584 'text' => '<b>Something broke!</b>',
586 'data' => [ 'xxx' => 'yyy', 'baz' => 23 ],
589 'UsageException, wrapped' => [
590 new UsageException( '<b>Something broke!</b>', 'ue-code', 0, [ 'xxx' => 'yyy', 'baz' => 23 ] ),
591 [ 'wrap' => 'parentheses', 'code' => 'some-code', 'data' => [ 'foo' => 'bar', 'baz' => 42 ] ],
593 'text' => '(<b>Something broke!</b>)',
594 'code' => 'some-code',
595 'data' => [ 'xxx' => 'yyy', 'baz' => 42, 'foo' => 'bar' ],
598 'LocalizedException' => [
599 new LocalizedException( [ 'returnto', '<b>FooBar</b>' ] ),
602 'text' => 'Return to <b>FooBar</b>.',
603 'code' => 'returnto',
607 'LocalizedException, wrapped' => [
608 new LocalizedException( [ 'returnto', '<b>FooBar</b>' ] ),
609 [ 'wrap' => 'parentheses', 'code' => 'some-code', 'data' => [ 'foo' => 'bar', 'baz' => 42 ] ],
611 'text' => 'Return to <b>FooBar</b>.',
612 'code' => 'some-code',
613 'data' => [ 'foo' => 'bar', 'baz' => 42 ],