Add sslCAFile option to DatabaseMysqli
[mediawiki.git] / tests / phpunit / includes / api / ApiErrorFormatterTest.php
blobd47481cbe4f006981fc99bbb1e9cd5c765aee349
1 <?php
3 use Wikimedia\TestingAccessWrapper;
5 /**
6 * @group API
7 */
8 class ApiErrorFormatterTest extends MediaWikiLangTestCase {
10 /**
11 * @covers ApiErrorFormatter
13 public function testErrorFormatterBasics() {
14 $result = new ApiResult( 8388608 );
15 $formatter = new ApiErrorFormatter( $result, Language::factory( 'de' ), 'wikitext', false );
16 $this->assertSame( 'de', $formatter->getLanguage()->getCode() );
18 $formatter->addMessagesFromStatus( null, Status::newGood() );
19 $this->assertSame(
20 [ ApiResult::META_TYPE => 'assoc' ],
21 $result->getResultData()
24 $this->assertSame( [], $formatter->arrayFromStatus( Status::newGood() ) );
26 $wrappedFormatter = TestingAccessWrapper::newFromObject( $formatter );
27 $this->assertSame(
28 'Blah "kbd" <X> 😊',
29 $wrappedFormatter->stripMarkup( 'Blah <kbd>kbd</kbd> <b>&lt;X&gt;</b> &#x1f60a;' ),
30 'stripMarkup'
34 /**
35 * @covers ApiErrorFormatter
36 * @dataProvider provideErrorFormatter
38 public function testErrorFormatter( $format, $lang, $useDB,
39 $expect1, $expect2, $expect3
40 ) {
41 $result = new ApiResult( 8388608 );
42 $formatter = new ApiErrorFormatter( $result, Language::factory( $lang ), $format, $useDB );
44 // Add default type
45 $expect1[ApiResult::META_TYPE] = 'assoc';
46 $expect2[ApiResult::META_TYPE] = 'assoc';
47 $expect3[ApiResult::META_TYPE] = 'assoc';
49 $formatter->addWarning( 'string', 'mainpage' );
50 $formatter->addError( 'err', 'mainpage' );
51 $this->assertEquals( $expect1, $result->getResultData(), 'Simple test' );
53 $result->reset();
54 $formatter->addWarning( 'foo', 'mainpage' );
55 $formatter->addWarning( 'foo', 'mainpage' );
56 $formatter->addWarning( 'foo', [ 'parentheses', 'foobar' ] );
57 $msg1 = wfMessage( 'mainpage' );
58 $formatter->addWarning( 'message', $msg1 );
59 $msg2 = new ApiMessage( 'mainpage', 'overriddenCode', [ 'overriddenData' => true ] );
60 $formatter->addWarning( 'messageWithData', $msg2 );
61 $formatter->addError( 'errWithData', $msg2 );
62 $this->assertSame( $expect2, $result->getResultData(), 'Complex test' );
64 $this->assertEquals(
65 $this->removeModuleTag( $expect2['warnings'][2] ),
66 $formatter->formatMessage( $msg1 ),
67 'formatMessage test 1'
69 $this->assertEquals(
70 $this->removeModuleTag( $expect2['warnings'][3] ),
71 $formatter->formatMessage( $msg2 ),
72 'formatMessage test 2'
75 $result->reset();
76 $status = Status::newGood();
77 $status->warning( 'mainpage' );
78 $status->warning( 'parentheses', 'foobar' );
79 $status->warning( $msg1 );
80 $status->warning( $msg2 );
81 $status->error( 'mainpage' );
82 $status->error( 'parentheses', 'foobar' );
83 $formatter->addMessagesFromStatus( 'status', $status );
84 $this->assertSame( $expect3, $result->getResultData(), 'Status test' );
86 $this->assertSame(
87 array_map( [ $this, 'removeModuleTag' ], $expect3['errors'] ),
88 $formatter->arrayFromStatus( $status, 'error' ),
89 'arrayFromStatus test for error'
91 $this->assertSame(
92 array_map( [ $this, 'removeModuleTag' ], $expect3['warnings'] ),
93 $formatter->arrayFromStatus( $status, 'warning' ),
94 'arrayFromStatus test for warning'
98 private function removeModuleTag( $s ) {
99 if ( is_array( $s ) ) {
100 unset( $s['module'] );
102 return $s;
105 public static function provideErrorFormatter() {
106 $mainpageText = wfMessage( 'mainpage' )->inLanguage( 'de' )->useDatabase( false )->text();
107 $parensText = wfMessage( 'parentheses', 'foobar' )->inLanguage( 'de' )
108 ->useDatabase( false )->text();
109 $mainpageHTML = wfMessage( 'mainpage' )->inLanguage( 'en' )->parse();
110 $parensHTML = wfMessage( 'parentheses', 'foobar' )->inLanguage( 'en' )->parse();
111 $C = ApiResult::META_CONTENT;
112 $I = ApiResult::META_INDEXED_TAG_NAME;
113 $overriddenData = [ 'overriddenData' => true, ApiResult::META_TYPE => 'assoc' ];
115 return [
116 $tmp = [ 'wikitext', 'de', false,
118 'errors' => [
119 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'err', $C => 'text' ],
120 $I => 'error',
122 'warnings' => [
123 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'string', $C => 'text' ],
124 $I => 'warning',
128 'errors' => [
129 [ 'code' => 'overriddenCode', 'text' => $mainpageText,
130 'data' => $overriddenData, 'module' => 'errWithData', $C => 'text' ],
131 $I => 'error',
133 'warnings' => [
134 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'foo', $C => 'text' ],
135 [ 'code' => 'parentheses', 'text' => $parensText, 'module' => 'foo', $C => 'text' ],
136 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'message', $C => 'text' ],
137 [ 'code' => 'overriddenCode', 'text' => $mainpageText,
138 'data' => $overriddenData, 'module' => 'messageWithData', $C => 'text' ],
139 $I => 'warning',
143 'errors' => [
144 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'status', $C => 'text' ],
145 [ 'code' => 'parentheses', 'text' => $parensText, 'module' => 'status', $C => 'text' ],
146 $I => 'error',
148 'warnings' => [
149 [ 'code' => 'mainpage', 'text' => $mainpageText, 'module' => 'status', $C => 'text' ],
150 [ 'code' => 'parentheses', 'text' => $parensText, 'module' => 'status', $C => 'text' ],
151 [ 'code' => 'overriddenCode', 'text' => $mainpageText,
152 'data' => $overriddenData, 'module' => 'status', $C => 'text' ],
153 $I => 'warning',
157 [ 'plaintext' ] + $tmp, // For these messages, plaintext and wikitext are the same
158 [ 'html', 'en', true,
160 'errors' => [
161 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'err', $C => 'html' ],
162 $I => 'error',
164 'warnings' => [
165 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'string', $C => 'html' ],
166 $I => 'warning',
170 'errors' => [
171 [ 'code' => 'overriddenCode', 'html' => $mainpageHTML,
172 'data' => $overriddenData, 'module' => 'errWithData', $C => 'html' ],
173 $I => 'error',
175 'warnings' => [
176 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'foo', $C => 'html' ],
177 [ 'code' => 'parentheses', 'html' => $parensHTML, 'module' => 'foo', $C => 'html' ],
178 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'message', $C => 'html' ],
179 [ 'code' => 'overriddenCode', 'html' => $mainpageHTML,
180 'data' => $overriddenData, 'module' => 'messageWithData', $C => 'html' ],
181 $I => 'warning',
185 'errors' => [
186 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'status', $C => 'html' ],
187 [ 'code' => 'parentheses', 'html' => $parensHTML, 'module' => 'status', $C => 'html' ],
188 $I => 'error',
190 'warnings' => [
191 [ 'code' => 'mainpage', 'html' => $mainpageHTML, 'module' => 'status', $C => 'html' ],
192 [ 'code' => 'parentheses', 'html' => $parensHTML, 'module' => 'status', $C => 'html' ],
193 [ 'code' => 'overriddenCode', 'html' => $mainpageHTML,
194 'data' => $overriddenData, 'module' => 'status', $C => 'html' ],
195 $I => 'warning',
199 [ 'raw', 'fr', true,
201 'errors' => [
203 'code' => 'mainpage',
204 'key' => 'mainpage',
205 'params' => [ $I => 'param' ],
206 'module' => 'err',
208 $I => 'error',
210 'warnings' => [
212 'code' => 'mainpage',
213 'key' => 'mainpage',
214 'params' => [ $I => 'param' ],
215 'module' => 'string',
217 $I => 'warning',
221 'errors' => [
223 'code' => 'overriddenCode',
224 'key' => 'mainpage',
225 'params' => [ $I => 'param' ],
226 'data' => $overriddenData,
227 'module' => 'errWithData',
229 $I => 'error',
231 'warnings' => [
233 'code' => 'mainpage',
234 'key' => 'mainpage',
235 'params' => [ $I => 'param' ],
236 'module' => 'foo',
239 'code' => 'parentheses',
240 'key' => 'parentheses',
241 'params' => [ 'foobar', $I => 'param' ],
242 'module' => 'foo',
245 'code' => 'mainpage',
246 'key' => 'mainpage',
247 'params' => [ $I => 'param' ],
248 'module' => 'message',
251 'code' => 'overriddenCode',
252 'key' => 'mainpage',
253 'params' => [ $I => 'param' ],
254 'data' => $overriddenData,
255 'module' => 'messageWithData',
257 $I => 'warning',
261 'errors' => [
263 'code' => 'mainpage',
264 'key' => 'mainpage',
265 'params' => [ $I => 'param' ],
266 'module' => 'status',
269 'code' => 'parentheses',
270 'key' => 'parentheses',
271 'params' => [ 'foobar', $I => 'param' ],
272 'module' => 'status',
274 $I => 'error',
276 'warnings' => [
278 'code' => 'mainpage',
279 'key' => 'mainpage',
280 'params' => [ $I => 'param' ],
281 'module' => 'status',
284 'code' => 'parentheses',
285 'key' => 'parentheses',
286 'params' => [ 'foobar', $I => 'param' ],
287 'module' => 'status',
290 'code' => 'overriddenCode',
291 'key' => 'mainpage',
292 'params' => [ $I => 'param' ],
293 'data' => $overriddenData,
294 'module' => 'status',
296 $I => 'warning',
300 [ 'none', 'fr', true,
302 'errors' => [
303 [ 'code' => 'mainpage', 'module' => 'err' ],
304 $I => 'error',
306 'warnings' => [
307 [ 'code' => 'mainpage', 'module' => 'string' ],
308 $I => 'warning',
312 'errors' => [
313 [ 'code' => 'overriddenCode', 'data' => $overriddenData,
314 'module' => 'errWithData' ],
315 $I => 'error',
317 'warnings' => [
318 [ 'code' => 'mainpage', 'module' => 'foo' ],
319 [ 'code' => 'parentheses', 'module' => 'foo' ],
320 [ 'code' => 'mainpage', 'module' => 'message' ],
321 [ 'code' => 'overriddenCode', 'data' => $overriddenData,
322 'module' => 'messageWithData' ],
323 $I => 'warning',
327 'errors' => [
328 [ 'code' => 'mainpage', 'module' => 'status' ],
329 [ 'code' => 'parentheses', 'module' => 'status' ],
330 $I => 'error',
332 'warnings' => [
333 [ 'code' => 'mainpage', 'module' => 'status' ],
334 [ 'code' => 'parentheses', 'module' => 'status' ],
335 [ 'code' => 'overriddenCode', 'data' => $overriddenData, 'module' => 'status' ],
336 $I => 'warning',
344 * @covers ApiErrorFormatter_BackCompat
346 public function testErrorFormatterBC() {
347 $mainpagePlain = wfMessage( 'mainpage' )->useDatabase( false )->plain();
348 $parensPlain = wfMessage( 'parentheses', 'foobar' )->useDatabase( false )->plain();
350 $result = new ApiResult( 8388608 );
351 $formatter = new ApiErrorFormatter_BackCompat( $result );
353 $this->assertSame( 'en', $formatter->getLanguage()->getCode() );
355 $this->assertSame( [], $formatter->arrayFromStatus( Status::newGood() ) );
357 $formatter->addWarning( 'string', 'mainpage' );
358 $formatter->addWarning( 'raw',
359 new RawMessage( 'Blah <kbd>kbd</kbd> <b>&lt;X&gt;</b> &#x1f61e;' )
361 $formatter->addError( 'err', 'mainpage' );
362 $this->assertSame( [
363 'error' => [
364 'code' => 'mainpage',
365 'info' => $mainpagePlain,
367 'warnings' => [
368 'raw' => [
369 'warnings' => 'Blah "kbd" <X> 😞',
370 ApiResult::META_CONTENT => 'warnings',
372 'string' => [
373 'warnings' => $mainpagePlain,
374 ApiResult::META_CONTENT => 'warnings',
377 ApiResult::META_TYPE => 'assoc',
378 ], $result->getResultData(), 'Simple test' );
380 $result->reset();
381 $formatter->addWarning( 'foo', 'mainpage' );
382 $formatter->addWarning( 'foo', 'mainpage' );
383 $formatter->addWarning( 'xxx+foo', [ 'parentheses', 'foobar' ] );
384 $msg1 = wfMessage( 'mainpage' );
385 $formatter->addWarning( 'message', $msg1 );
386 $msg2 = new ApiMessage( 'mainpage', 'overriddenCode', [ 'overriddenData' => true ] );
387 $formatter->addWarning( 'messageWithData', $msg2 );
388 $formatter->addError( 'errWithData', $msg2 );
389 $formatter->addWarning( null, 'mainpage' );
390 $this->assertSame( [
391 'error' => [
392 'code' => 'overriddenCode',
393 'info' => $mainpagePlain,
394 'overriddenData' => true,
396 'warnings' => [
397 'unknown' => [
398 'warnings' => $mainpagePlain,
399 ApiResult::META_CONTENT => 'warnings',
401 'messageWithData' => [
402 'warnings' => $mainpagePlain,
403 ApiResult::META_CONTENT => 'warnings',
405 'message' => [
406 'warnings' => $mainpagePlain,
407 ApiResult::META_CONTENT => 'warnings',
409 'foo' => [
410 'warnings' => "$mainpagePlain\n$parensPlain",
411 ApiResult::META_CONTENT => 'warnings',
414 ApiResult::META_TYPE => 'assoc',
415 ], $result->getResultData(), 'Complex test' );
417 $this->assertSame(
419 'code' => 'mainpage',
420 'info' => 'Main Page',
422 $formatter->formatMessage( $msg1 )
424 $this->assertSame(
426 'code' => 'overriddenCode',
427 'info' => 'Main Page',
428 'overriddenData' => true,
430 $formatter->formatMessage( $msg2 )
433 $result->reset();
434 $status = Status::newGood();
435 $status->warning( 'mainpage' );
436 $status->warning( 'parentheses', 'foobar' );
437 $status->warning( $msg1 );
438 $status->warning( $msg2 );
439 $status->error( 'mainpage' );
440 $status->error( 'parentheses', 'foobar' );
441 $formatter->addMessagesFromStatus( 'status', $status );
442 $this->assertSame( [
443 'error' => [
444 'code' => 'mainpage',
445 'info' => $mainpagePlain,
447 'warnings' => [
448 'status' => [
449 'warnings' => "$mainpagePlain\n$parensPlain",
450 ApiResult::META_CONTENT => 'warnings',
453 ApiResult::META_TYPE => 'assoc',
454 ], $result->getResultData(), 'Status test' );
456 $I = ApiResult::META_INDEXED_TAG_NAME;
457 $this->assertSame(
460 'message' => 'mainpage',
461 'params' => [ $I => 'param' ],
462 'code' => 'mainpage',
463 'type' => 'error',
466 'message' => 'parentheses',
467 'params' => [ 'foobar', $I => 'param' ],
468 'code' => 'parentheses',
469 'type' => 'error',
471 $I => 'error',
473 $formatter->arrayFromStatus( $status, 'error' ),
474 'arrayFromStatus test for error'
476 $this->assertSame(
479 'message' => 'mainpage',
480 'params' => [ $I => 'param' ],
481 'code' => 'mainpage',
482 'type' => 'warning',
485 'message' => 'parentheses',
486 'params' => [ 'foobar', $I => 'param' ],
487 'code' => 'parentheses',
488 'type' => 'warning',
491 'message' => 'mainpage',
492 'params' => [ $I => 'param' ],
493 'code' => 'mainpage',
494 'type' => 'warning',
497 'message' => 'mainpage',
498 'params' => [ $I => 'param' ],
499 'code' => 'overriddenCode',
500 'type' => 'warning',
502 $I => 'warning',
504 $formatter->arrayFromStatus( $status, 'warning' ),
505 'arrayFromStatus test for warning'
508 $result->reset();
509 $result->addValue( null, 'error', [ 'bogus' ] );
510 $formatter->addError( 'err', 'mainpage' );
511 $this->assertSame( [
512 'error' => [
513 'code' => 'mainpage',
514 'info' => $mainpagePlain,
516 ApiResult::META_TYPE => 'assoc',
517 ], $result->getResultData(), 'Overwrites bogus "error" value with real error' );
521 * @dataProvider provideGetMessageFromException
522 * @covers ApiErrorFormatter::getMessageFromException
523 * @covers ApiErrorFormatter::formatException
524 * @param Exception $exception
525 * @param array $options
526 * @param array $expect
528 public function testGetMessageFromException( $exception, $options, $expect ) {
529 if ( $exception instanceof UsageException ) {
530 $this->hideDeprecated( 'UsageException::getMessageArray' );
533 $result = new ApiResult( 8388608 );
534 $formatter = new ApiErrorFormatter( $result, Language::factory( 'en' ), 'html', false );
536 $msg = $formatter->getMessageFromException( $exception, $options );
537 $this->assertInstanceOf( Message::class, $msg );
538 $this->assertInstanceOf( IApiMessage::class, $msg );
539 $this->assertSame( $expect, [
540 'text' => $msg->parse(),
541 'code' => $msg->getApiCode(),
542 'data' => $msg->getApiData(),
543 ] );
545 $expectFormatted = $formatter->formatMessage( $msg );
546 $formatted = $formatter->formatException( $exception, $options );
547 $this->assertSame( $expectFormatted, $formatted );
551 * @dataProvider provideGetMessageFromException
552 * @covers ApiErrorFormatter_BackCompat::formatException
553 * @param Exception $exception
554 * @param array $options
555 * @param array $expect
557 public function testGetMessageFromException_BC( $exception, $options, $expect ) {
558 $result = new ApiResult( 8388608 );
559 $formatter = new ApiErrorFormatter_BackCompat( $result );
561 $msg = $formatter->getMessageFromException( $exception, $options );
562 $this->assertInstanceOf( Message::class, $msg );
563 $this->assertInstanceOf( IApiMessage::class, $msg );
564 $this->assertSame( $expect, [
565 'text' => $msg->parse(),
566 'code' => $msg->getApiCode(),
567 'data' => $msg->getApiData(),
568 ] );
570 $expectFormatted = $formatter->formatMessage( $msg );
571 $formatted = $formatter->formatException( $exception, $options );
572 $this->assertSame( $expectFormatted, $formatted );
573 $formatted = $formatter->formatException( $exception, $options + [ 'bc' => true ] );
574 $this->assertSame( $expectFormatted['info'], $formatted );
577 public static function provideGetMessageFromException() {
578 MediaWiki\suppressWarnings();
579 $usageException = new UsageException(
580 '<b>Something broke!</b>', 'ue-code', 0, [ 'xxx' => 'yyy', 'baz' => 23 ]
582 MediaWiki\restoreWarnings();
584 return [
585 'Normal exception' => [
586 new RuntimeException( '<b>Something broke!</b>' ),
589 'text' => '&#60;b&#62;Something broke!&#60;/b&#62;',
590 'code' => 'internal_api_error_RuntimeException',
591 'data' => [],
594 'Normal exception, wrapped' => [
595 new RuntimeException( '<b>Something broke!</b>' ),
596 [ 'wrap' => 'parentheses', 'code' => 'some-code', 'data' => [ 'foo' => 'bar', 'baz' => 42 ] ],
598 'text' => '(&#60;b&#62;Something broke!&#60;/b&#62;)',
599 'code' => 'some-code',
600 'data' => [ 'foo' => 'bar', 'baz' => 42 ],
603 'UsageException' => [
604 $usageException,
607 'text' => '&#60;b&#62;Something broke!&#60;/b&#62;',
608 'code' => 'ue-code',
609 'data' => [ 'xxx' => 'yyy', 'baz' => 23 ],
612 'UsageException, wrapped' => [
613 $usageException,
614 [ 'wrap' => 'parentheses', 'code' => 'some-code', 'data' => [ 'foo' => 'bar', 'baz' => 42 ] ],
616 'text' => '(&#60;b&#62;Something broke!&#60;/b&#62;)',
617 'code' => 'some-code',
618 'data' => [ 'xxx' => 'yyy', 'baz' => 42, 'foo' => 'bar' ],
621 'LocalizedException' => [
622 new LocalizedException( [ 'returnto', '<b>FooBar</b>' ] ),
625 'text' => 'Return to <b>FooBar</b>.',
626 'code' => 'returnto',
627 'data' => [],
630 'LocalizedException, wrapped' => [
631 new LocalizedException( [ 'returnto', '<b>FooBar</b>' ] ),
632 [ 'wrap' => 'parentheses', 'code' => 'some-code', 'data' => [ 'foo' => 'bar', 'baz' => 42 ] ],
634 'text' => 'Return to <b>FooBar</b>.',
635 'code' => 'some-code',
636 'data' => [ 'foo' => 'bar', 'baz' => 42 ],