Localisation updates from https://translatewiki.net.
[mediawiki.git] / tests / phpunit / includes / api / ApiResultTest.php
blob60f7cb7ac9cf175d707510520cfd7f6a321ceb74
1 <?php
3 namespace MediaWiki\Tests\Api;
5 use AllowDynamicProperties;
6 use Exception;
7 use InvalidArgumentException;
8 use MediaWiki\Api\ApiErrorFormatter;
9 use MediaWiki\Api\ApiResult;
10 use MediaWiki\Title\Title;
11 use MediaWikiIntegrationTestCase;
12 use RuntimeException;
13 use Stringable;
14 use UnexpectedValueException;
16 /**
17 * @covers \MediaWiki\Api\ApiResult
18 * @group API
20 class ApiResultTest extends MediaWikiIntegrationTestCase {
22 /**
23 * @covers \MediaWiki\Api\ApiResult
25 public function testStaticDataMethods() {
26 $arr = [];
28 ApiResult::setValue( $arr, 'setValue', '1' );
30 ApiResult::setValue( $arr, null, 'unnamed 1' );
31 ApiResult::setValue( $arr, null, 'unnamed 2' );
33 ApiResult::setValue( $arr, 'deleteValue', '2' );
34 ApiResult::unsetValue( $arr, 'deleteValue' );
36 ApiResult::setContentValue( $arr, 'setContentValue', '3' );
38 $this->assertSame( [
39 'setValue' => '1',
40 'unnamed 1',
41 'unnamed 2',
42 ApiResult::META_CONTENT => 'setContentValue',
43 'setContentValue' => '3',
44 ], $arr );
46 ApiResult::setValue( $arr, 'setValue', '1' );
47 $this->assertSame( '1', $arr['setValue'] );
49 try {
50 ApiResult::setValue( $arr, 'setValue', '99' );
51 $this->fail( 'Expected exception not thrown' );
52 } catch ( RuntimeException $ex ) {
53 $this->assertSame(
54 'Attempting to add element setValue=99, existing value is 1',
55 $ex->getMessage(),
56 'Expected exception'
60 try {
61 ApiResult::setContentValue( $arr, 'setContentValue2', '99' );
62 $this->fail( 'Expected exception not thrown' );
63 } catch ( RuntimeException $ex ) {
64 $this->assertSame(
65 'Attempting to set content element as setContentValue2 when setContentValue ' .
66 'is already set as the content element',
67 $ex->getMessage(),
68 'Expected exception'
72 ApiResult::setValue( $arr, 'setValue', '99', ApiResult::OVERRIDE );
73 $this->assertSame( '99', $arr['setValue'] );
75 ApiResult::setContentValue( $arr, 'setContentValue2', '99', ApiResult::OVERRIDE );
76 $this->assertSame( 'setContentValue2', $arr[ApiResult::META_CONTENT] );
78 $arr = [ 'foo' => 1, 'bar' => 1 ];
79 ApiResult::setValue( $arr, 'top', '2', ApiResult::ADD_ON_TOP );
80 ApiResult::setValue( $arr, null, '2', ApiResult::ADD_ON_TOP );
81 ApiResult::setValue( $arr, 'bottom', '2' );
82 ApiResult::setValue( $arr, 'foo', '2', ApiResult::OVERRIDE );
83 ApiResult::setValue( $arr, 'bar', '2', ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP );
84 $this->assertSame( [ 0, 'top', 'foo', 'bar', 'bottom' ], array_keys( $arr ) );
86 $arr = [];
87 ApiResult::setValue( $arr, 'sub', [ 'foo' => 1 ] );
88 ApiResult::setValue( $arr, 'sub', [ 'bar' => 1 ] );
89 $this->assertSame( [ 'sub' => [ 'foo' => 1, 'bar' => 1 ] ], $arr );
91 try {
92 ApiResult::setValue( $arr, 'sub', [ 'foo' => 2, 'baz' => 2 ] );
93 $this->fail( 'Expected exception not thrown' );
94 } catch ( RuntimeException $ex ) {
95 $this->assertSame(
96 'Conflicting keys (foo) when attempting to merge element sub',
97 $ex->getMessage(),
98 'Expected exception'
102 $arr = [];
103 $title = Title::makeTitle( NS_MEDIAWIKI, "Foobar" );
104 $obj = (object)[ 'foo' => 1, 'bar' => 2 ];
105 ApiResult::setValue( $arr, 'title', $title );
106 ApiResult::setValue( $arr, 'obj', $obj );
107 $this->assertSame( [
108 'title' => (string)$title,
109 'obj' => [ 'foo' => 1, 'bar' => 2, ApiResult::META_TYPE => 'assoc' ],
110 ], $arr );
112 $fh = tmpfile();
113 try {
114 ApiResult::setValue( $arr, 'file', $fh );
115 $this->fail( 'Expected exception not thrown' );
116 } catch ( InvalidArgumentException $ex ) {
117 $this->assertSame(
118 'Cannot add resource (stream) to ApiResult',
119 $ex->getMessage(),
120 'Expected exception'
123 try {
124 ApiResult::setValue( $arr, null, $fh );
125 $this->fail( 'Expected exception not thrown' );
126 } catch ( InvalidArgumentException $ex ) {
127 $this->assertSame(
128 'Cannot add resource (stream) to ApiResult',
129 $ex->getMessage(),
130 'Expected exception'
133 try {
134 $obj->file = $fh;
135 ApiResult::setValue( $arr, 'sub', $obj );
136 $this->fail( 'Expected exception not thrown' );
137 } catch ( InvalidArgumentException $ex ) {
138 $this->assertSame(
139 'Cannot add resource (stream) to ApiResult',
140 $ex->getMessage(),
141 'Expected exception'
144 try {
145 $obj->file = $fh;
146 ApiResult::setValue( $arr, null, $obj );
147 $this->fail( 'Expected exception not thrown' );
148 } catch ( InvalidArgumentException $ex ) {
149 $this->assertSame(
150 'Cannot add resource (stream) to ApiResult',
151 $ex->getMessage(),
152 'Expected exception'
155 fclose( $fh );
157 try {
158 ApiResult::setValue( $arr, 'inf', INF );
159 $this->fail( 'Expected exception not thrown' );
160 } catch ( InvalidArgumentException $ex ) {
161 $this->assertSame(
162 'Cannot add non-finite floats to ApiResult',
163 $ex->getMessage(),
164 'Expected exception'
167 try {
168 ApiResult::setValue( $arr, null, INF );
169 $this->fail( 'Expected exception not thrown' );
170 } catch ( InvalidArgumentException $ex ) {
171 $this->assertSame(
172 'Cannot add non-finite floats to ApiResult',
173 $ex->getMessage(),
174 'Expected exception'
177 try {
178 ApiResult::setValue( $arr, 'nan', NAN );
179 $this->fail( 'Expected exception not thrown' );
180 } catch ( InvalidArgumentException $ex ) {
181 $this->assertSame(
182 'Cannot add non-finite floats to ApiResult',
183 $ex->getMessage(),
184 'Expected exception'
187 try {
188 ApiResult::setValue( $arr, null, NAN );
189 $this->fail( 'Expected exception not thrown' );
190 } catch ( InvalidArgumentException $ex ) {
191 $this->assertSame(
192 'Cannot add non-finite floats to ApiResult',
193 $ex->getMessage(),
194 'Expected exception'
198 ApiResult::setValue( $arr, null, NAN, ApiResult::NO_VALIDATE );
200 try {
201 ApiResult::setValue( $arr, null, NAN, ApiResult::NO_SIZE_CHECK );
202 $this->fail( 'Expected exception not thrown' );
203 } catch ( InvalidArgumentException $ex ) {
204 $this->assertSame(
205 'Cannot add non-finite floats to ApiResult',
206 $ex->getMessage(),
207 'Expected exception'
211 $arr = [];
212 $result2 = new ApiResult( 8_388_608 );
213 $result2->addValue( null, 'foo', 'bar' );
214 ApiResult::setValue( $arr, 'baz', $result2 );
215 $this->assertSame( [
216 'baz' => [
217 ApiResult::META_TYPE => 'assoc',
218 'foo' => 'bar',
220 ], $arr );
222 $arr = [];
223 ApiResult::setValue( $arr, 'foo', "foo\x80bar" );
224 ApiResult::setValue( $arr, 'bar', "a\xcc\x81" );
225 ApiResult::setValue( $arr, 'baz', 74 );
226 ApiResult::setValue( $arr, null, "foo\x80bar" );
227 ApiResult::setValue( $arr, null, "a\xcc\x81" );
228 $this->assertSame( [
229 'foo' => "foo\xef\xbf\xbdbar",
230 'bar' => "\xc3\xa1",
231 'baz' => 74,
232 0 => "foo\xef\xbf\xbdbar",
233 1 => "\xc3\xa1",
234 ], $arr );
236 $obj = (object)[ 1 => 'one' ];
237 $arr = [];
238 ApiResult::setValue( $arr, 'foo', $obj );
239 $this->assertSame( [
240 'foo' => [
241 1 => 'one',
242 ApiResult::META_TYPE => 'assoc',
244 ], $arr );
248 * @covers \MediaWiki\Api\ApiResult
250 public function testInstanceDataMethods() {
251 $result = new ApiResult( 8_388_608 );
253 $result->addValue( null, 'setValue', '1' );
255 $result->addValue( null, null, 'unnamed 1' );
256 $result->addValue( null, null, 'unnamed 2' );
258 $result->addValue( null, 'deleteValue', '2' );
259 $result->removeValue( null, 'deleteValue' );
261 $result->addValue( [ 'a', 'b' ], 'deleteValue', '3' );
262 $result->removeValue( [ 'a', 'b', 'deleteValue' ], null, '3' );
264 $result->addContentValue( null, 'setContentValue', '3' );
266 $this->assertSame( [
267 'setValue' => '1',
268 'unnamed 1',
269 'unnamed 2',
270 'a' => [ 'b' => [] ],
271 'setContentValue' => '3',
272 ApiResult::META_TYPE => 'assoc',
273 ApiResult::META_CONTENT => 'setContentValue',
274 ], $result->getResultData() );
275 $this->assertSame( 20, $result->getSize() );
277 try {
278 $result->addValue( null, 'setValue', '99' );
279 $this->fail( 'Expected exception not thrown' );
280 } catch ( RuntimeException $ex ) {
281 $this->assertSame(
282 'Attempting to add element setValue=99, existing value is 1',
283 $ex->getMessage(),
284 'Expected exception'
288 try {
289 $result->addContentValue( null, 'setContentValue2', '99' );
290 $this->fail( 'Expected exception not thrown' );
291 } catch ( RuntimeException $ex ) {
292 $this->assertSame(
293 'Attempting to set content element as setContentValue2 when setContentValue ' .
294 'is already set as the content element',
295 $ex->getMessage(),
296 'Expected exception'
300 $result->addValue( null, 'setValue', '99', ApiResult::OVERRIDE );
301 $this->assertSame( '99', $result->getResultData( [ 'setValue' ] ) );
303 $result->addContentValue( null, 'setContentValue2', '99', ApiResult::OVERRIDE );
304 $this->assertSame( 'setContentValue2',
305 $result->getResultData( [ ApiResult::META_CONTENT ] ) );
307 $result->reset();
308 $this->assertSame( [
309 ApiResult::META_TYPE => 'assoc',
310 ], $result->getResultData() );
311 $this->assertSame( 0, $result->getSize() );
313 $result->addValue( null, 'foo', 1 );
314 $result->addValue( null, 'bar', 1 );
315 $result->addValue( null, 'top', '2', ApiResult::ADD_ON_TOP );
316 $result->addValue( null, null, '2', ApiResult::ADD_ON_TOP );
317 $result->addValue( null, 'bottom', '2' );
318 $result->addValue( null, 'foo', '2', ApiResult::OVERRIDE );
319 $result->addValue( null, 'bar', '2', ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP );
320 $this->assertSame( [ 0, 'top', 'foo', 'bar', 'bottom', ApiResult::META_TYPE ],
321 array_keys( $result->getResultData() ) );
323 $result->reset();
324 $result->addValue( null, 'foo', [ 'bar' => 1 ] );
325 $result->addValue( [ 'foo', 'top' ], 'x', 2, ApiResult::ADD_ON_TOP );
326 $result->addValue( [ 'foo', 'bottom' ], 'x', 2 );
327 $this->assertSame( [ 'top', 'bar', 'bottom' ],
328 array_keys( $result->getResultData( [ 'foo' ] ) ) );
330 $result->reset();
331 $result->addValue( null, 'sub', [ 'foo' => 1 ] );
332 $result->addValue( null, 'sub', [ 'bar' => 1 ] );
333 $this->assertSame( [
334 'sub' => [ 'foo' => 1, 'bar' => 1 ],
335 ApiResult::META_TYPE => 'assoc',
336 ], $result->getResultData() );
338 try {
339 $result->addValue( null, 'sub', [ 'foo' => 2, 'baz' => 2 ] );
340 $this->fail( 'Expected exception not thrown' );
341 } catch ( RuntimeException $ex ) {
342 $this->assertSame(
343 'Conflicting keys (foo) when attempting to merge element sub',
344 $ex->getMessage(),
345 'Expected exception'
349 $result->reset();
350 $title = Title::makeTitle( NS_MEDIAWIKI, "Foobar" );
351 $obj = (object)[ 'foo' => 1, 'bar' => 2 ];
352 $result->addValue( null, 'title', $title );
353 $result->addValue( null, 'obj', $obj );
354 $this->assertSame( [
355 'title' => (string)$title,
356 'obj' => [ 'foo' => 1, 'bar' => 2, ApiResult::META_TYPE => 'assoc' ],
357 ApiResult::META_TYPE => 'assoc',
358 ], $result->getResultData() );
360 $fh = tmpfile();
361 try {
362 $result->addValue( null, 'file', $fh );
363 $this->fail( 'Expected exception not thrown' );
364 } catch ( InvalidArgumentException $ex ) {
365 $this->assertSame(
366 'Cannot add resource (stream) to ApiResult',
367 $ex->getMessage(),
368 'Expected exception'
371 try {
372 $result->addValue( null, null, $fh );
373 $this->fail( 'Expected exception not thrown' );
374 } catch ( InvalidArgumentException $ex ) {
375 $this->assertSame(
376 'Cannot add resource (stream) to ApiResult',
377 $ex->getMessage(),
378 'Expected exception'
381 try {
382 $obj->file = $fh;
383 $result->addValue( null, 'sub', $obj );
384 $this->fail( 'Expected exception not thrown' );
385 } catch ( InvalidArgumentException $ex ) {
386 $this->assertSame(
387 'Cannot add resource (stream) to ApiResult',
388 $ex->getMessage(),
389 'Expected exception'
392 try {
393 $obj->file = $fh;
394 $result->addValue( null, null, $obj );
395 $this->fail( 'Expected exception not thrown' );
396 } catch ( InvalidArgumentException $ex ) {
397 $this->assertSame(
398 'Cannot add resource (stream) to ApiResult',
399 $ex->getMessage(),
400 'Expected exception'
403 fclose( $fh );
405 try {
406 $result->addValue( null, 'inf', INF );
407 $this->fail( 'Expected exception not thrown' );
408 } catch ( InvalidArgumentException $ex ) {
409 $this->assertSame(
410 'Cannot add non-finite floats to ApiResult',
411 $ex->getMessage(),
412 'Expected exception'
415 try {
416 $result->addValue( null, null, INF );
417 $this->fail( 'Expected exception not thrown' );
418 } catch ( InvalidArgumentException $ex ) {
419 $this->assertSame(
420 'Cannot add non-finite floats to ApiResult',
421 $ex->getMessage(),
422 'Expected exception'
425 try {
426 $result->addValue( null, 'nan', NAN );
427 $this->fail( 'Expected exception not thrown' );
428 } catch ( InvalidArgumentException $ex ) {
429 $this->assertSame(
430 'Cannot add non-finite floats to ApiResult',
431 $ex->getMessage(),
432 'Expected exception'
435 try {
436 $result->addValue( null, null, NAN );
437 $this->fail( 'Expected exception not thrown' );
438 } catch ( InvalidArgumentException $ex ) {
439 $this->assertSame(
440 'Cannot add non-finite floats to ApiResult',
441 $ex->getMessage(),
442 'Expected exception'
446 $result->addValue( null, null, NAN, ApiResult::NO_VALIDATE );
448 try {
449 $result->addValue( null, null, NAN, ApiResult::NO_SIZE_CHECK );
450 $this->fail( 'Expected exception not thrown' );
451 } catch ( InvalidArgumentException $ex ) {
452 $this->assertSame(
453 'Cannot add non-finite floats to ApiResult',
454 $ex->getMessage(),
455 'Expected exception'
459 $result->reset();
460 $result->addParsedLimit( 'foo', 12 );
461 $this->assertSame( [
462 'limits' => [ 'foo' => 12 ],
463 ApiResult::META_TYPE => 'assoc',
464 ], $result->getResultData() );
465 $result->addParsedLimit( 'foo', 13 );
466 $this->assertSame( [
467 'limits' => [ 'foo' => 13 ],
468 ApiResult::META_TYPE => 'assoc',
469 ], $result->getResultData() );
470 $this->assertSame( null, $result->getResultData( [ 'foo', 'bar', 'baz' ] ) );
471 $this->assertSame( 13, $result->getResultData( [ 'limits', 'foo' ] ) );
472 try {
473 $result->getResultData( [ 'limits', 'foo', 'bar' ] );
474 $this->fail( 'Expected exception not thrown' );
475 } catch ( InvalidArgumentException $ex ) {
476 $this->assertSame(
477 'Path limits.foo is not an array',
478 $ex->getMessage(),
479 'Expected exception'
483 // Add two values and some metadata, but ensure metadata is not counted
484 $result = new ApiResult( 100 );
485 $obj = [ 'attr' => '12345' ];
486 ApiResult::setContentValue( $obj, 'content', '1234567890' );
487 $this->assertTrue( $result->addValue( null, 'foo', $obj ) );
488 $this->assertSame( 15, $result->getSize() );
490 $result = new ApiResult( 10 );
491 $formatter = new ApiErrorFormatter( $result,
492 $this->getServiceContainer()->getLanguageFactory()->getLanguage( 'en' ),
493 'none', false );
494 $result->setErrorFormatter( $formatter );
495 $this->assertFalse( $result->addValue( null, 'foo', '12345678901' ) );
496 $this->assertTrue( $result->addValue( null, 'foo', '12345678901', ApiResult::NO_SIZE_CHECK ) );
497 $this->assertSame( 0, $result->getSize() );
498 $result->reset();
499 $this->assertTrue( $result->addValue( null, 'foo', '1234567890' ) );
500 $this->assertFalse( $result->addValue( null, 'foo', '1' ) );
501 $result->removeValue( null, 'foo' );
502 $this->assertTrue( $result->addValue( null, 'foo', '1' ) );
504 $result = new ApiResult( 10 );
505 $obj = new ApiResultTestSerializableObject( 'ok' );
506 $obj->foobar = 'foobaz';
507 $this->assertTrue( $result->addValue( null, 'foo', $obj ) );
508 $this->assertSame( 2, $result->getSize() );
510 $result = new ApiResult( 8_388_608 );
511 $result2 = new ApiResult( 8_388_608 );
512 $result2->addValue( null, 'foo', 'bar' );
513 $result->addValue( null, 'baz', $result2 );
514 $this->assertSame( [
515 'baz' => [
516 'foo' => 'bar',
517 ApiResult::META_TYPE => 'assoc',
519 ApiResult::META_TYPE => 'assoc',
520 ], $result->getResultData() );
522 $result = new ApiResult( 8_388_608 );
523 $result->addValue( null, 'foo', "foo\x80bar" );
524 $result->addValue( null, 'bar', "a\xcc\x81" );
525 $result->addValue( null, 'baz', 74 );
526 $result->addValue( null, null, "foo\x80bar" );
527 $result->addValue( null, null, "a\xcc\x81" );
528 $this->assertSame( [
529 'foo' => "foo\xef\xbf\xbdbar",
530 'bar' => "\xc3\xa1",
531 'baz' => 74,
532 0 => "foo\xef\xbf\xbdbar",
533 1 => "\xc3\xa1",
534 ApiResult::META_TYPE => 'assoc',
535 ], $result->getResultData() );
537 $result = new ApiResult( 8_388_608 );
538 $obj = (object)[ 1 => 'one' ];
539 $arr = [];
540 $result->addValue( $arr, 'foo', $obj );
541 $this->assertSame( [
542 'foo' => [
543 1 => 'one',
544 ApiResult::META_TYPE => 'assoc',
546 ApiResult::META_TYPE => 'assoc',
547 ], $result->getResultData() );
551 * @covers \MediaWiki\Api\ApiResult
553 public function testMetadata() {
554 $arr = [ 'foo' => [ 'bar' => [] ] ];
555 $result = new ApiResult( 8_388_608 );
556 $result->addValue( null, 'foo', [ 'bar' => [] ] );
558 $expect = [
559 'foo' => [
560 'bar' => [
561 ApiResult::META_INDEXED_TAG_NAME => 'ritn',
562 ApiResult::META_TYPE => 'default',
564 ApiResult::META_INDEXED_TAG_NAME => 'ritn',
565 ApiResult::META_TYPE => 'default',
567 ApiResult::META_SUBELEMENTS => [ 'foo', 'bar' ],
568 ApiResult::META_INDEXED_TAG_NAME => 'itn',
569 ApiResult::META_PRESERVE_KEYS => [ 'foo', 'bar' ],
570 ApiResult::META_TYPE => 'array',
573 ApiResult::setSubelementsList( $arr, 'foo' );
574 ApiResult::setSubelementsList( $arr, [ 'bar', 'baz' ] );
575 ApiResult::unsetSubelementsList( $arr, 'baz' );
576 ApiResult::setIndexedTagNameRecursive( $arr, 'ritn' );
577 ApiResult::setIndexedTagName( $arr, 'itn' );
578 ApiResult::setPreserveKeysList( $arr, 'foo' );
579 ApiResult::setPreserveKeysList( $arr, [ 'bar', 'baz' ] );
580 ApiResult::unsetPreserveKeysList( $arr, 'baz' );
581 ApiResult::setArrayTypeRecursive( $arr, 'default' );
582 ApiResult::setArrayType( $arr, 'array' );
583 $this->assertSame( $expect, $arr );
585 $result->addSubelementsList( null, 'foo' );
586 $result->addSubelementsList( null, [ 'bar', 'baz' ] );
587 $result->removeSubelementsList( null, 'baz' );
588 $result->addIndexedTagNameRecursive( null, 'ritn' );
589 $result->addIndexedTagName( null, 'itn' );
590 $result->addPreserveKeysList( null, 'foo' );
591 $result->addPreserveKeysList( null, [ 'bar', 'baz' ] );
592 $result->removePreserveKeysList( null, 'baz' );
593 $result->addArrayTypeRecursive( null, 'default' );
594 $result->addArrayType( null, 'array' );
595 $this->assertEquals( $expect, $result->getResultData() );
597 $arr = [ 'foo' => [ 'bar' => [] ] ];
598 $expect = [
599 'foo' => [
600 'bar' => [
601 ApiResult::META_TYPE => 'kvp',
602 ApiResult::META_KVP_KEY_NAME => 'key',
604 ApiResult::META_TYPE => 'kvp',
605 ApiResult::META_KVP_KEY_NAME => 'key',
607 ApiResult::META_TYPE => 'BCkvp',
608 ApiResult::META_KVP_KEY_NAME => 'bc',
610 ApiResult::setArrayTypeRecursive( $arr, 'kvp', 'key' );
611 ApiResult::setArrayType( $arr, 'BCkvp', 'bc' );
612 $this->assertSame( $expect, $arr );
616 * @covers \MediaWiki\Api\ApiResult
618 public function testUtilityFunctions() {
619 $arr = [
620 'foo' => [
621 'bar' => [ '_dummy' => 'foobaz' ],
622 'bar2' => (object)[ '_dummy' => 'foobaz' ],
623 'x' => 'ok',
624 '_dummy' => 'foobaz',
626 'foo2' => (object)[
627 'bar' => [ '_dummy' => 'foobaz' ],
628 'bar2' => (object)[ '_dummy' => 'foobaz' ],
629 'x' => 'ok',
630 '_dummy' => 'foobaz',
632 ApiResult::META_SUBELEMENTS => [ 'foo', 'bar' ],
633 ApiResult::META_INDEXED_TAG_NAME => 'itn',
634 ApiResult::META_PRESERVE_KEYS => [ 'foo', 'bar', '_dummy2', 0 ],
635 ApiResult::META_TYPE => 'array',
636 '_dummy' => 'foobaz',
637 '_dummy2' => 'foobaz!',
639 $this->assertEquals( [
640 'foo' => [
641 'bar' => [],
642 'bar2' => (object)[],
643 'x' => 'ok',
645 'foo2' => (object)[
646 'bar' => [],
647 'bar2' => (object)[],
648 'x' => 'ok',
650 '_dummy2' => 'foobaz!',
651 ], ApiResult::stripMetadata( $arr ), 'ApiResult::stripMetadata' );
653 $metadata = [];
654 $data = ApiResult::stripMetadataNonRecursive( $arr, $metadata );
655 $this->assertEquals( [
656 'foo' => [
657 'bar' => [ '_dummy' => 'foobaz' ],
658 'bar2' => (object)[ '_dummy' => 'foobaz' ],
659 'x' => 'ok',
660 '_dummy' => 'foobaz',
662 'foo2' => (object)[
663 'bar' => [ '_dummy' => 'foobaz' ],
664 'bar2' => (object)[ '_dummy' => 'foobaz' ],
665 'x' => 'ok',
666 '_dummy' => 'foobaz',
668 '_dummy2' => 'foobaz!',
669 ], $data, 'ApiResult::stripMetadataNonRecursive ($data)' );
670 $this->assertEquals( [
671 ApiResult::META_SUBELEMENTS => [ 'foo', 'bar' ],
672 ApiResult::META_INDEXED_TAG_NAME => 'itn',
673 ApiResult::META_PRESERVE_KEYS => [ 'foo', 'bar', '_dummy2', 0 ],
674 ApiResult::META_TYPE => 'array',
675 '_dummy' => 'foobaz',
676 ], $metadata, 'ApiResult::stripMetadataNonRecursive ($metadata)' );
678 $metadata = null;
679 $data = ApiResult::stripMetadataNonRecursive( (object)$arr, $metadata );
680 $this->assertEquals( (object)[
681 'foo' => [
682 'bar' => [ '_dummy' => 'foobaz' ],
683 'bar2' => (object)[ '_dummy' => 'foobaz' ],
684 'x' => 'ok',
685 '_dummy' => 'foobaz',
687 'foo2' => (object)[
688 'bar' => [ '_dummy' => 'foobaz' ],
689 'bar2' => (object)[ '_dummy' => 'foobaz' ],
690 'x' => 'ok',
691 '_dummy' => 'foobaz',
693 '_dummy2' => 'foobaz!',
694 ], $data, 'ApiResult::stripMetadataNonRecursive on object ($data)' );
695 $this->assertEquals( [
696 ApiResult::META_SUBELEMENTS => [ 'foo', 'bar' ],
697 ApiResult::META_INDEXED_TAG_NAME => 'itn',
698 ApiResult::META_PRESERVE_KEYS => [ 'foo', 'bar', '_dummy2', 0 ],
699 ApiResult::META_TYPE => 'array',
700 '_dummy' => 'foobaz',
701 ], $metadata, 'ApiResult::stripMetadataNonRecursive on object ($metadata)' );
705 * @covers \MediaWiki\Api\ApiResult
706 * @dataProvider provideTransformations
707 * @param string $label
708 * @param array $input
709 * @param array $transforms
710 * @param array|Exception $expect
712 public function testTransformations( $label, $input, $transforms, $expect ) {
713 $result = new ApiResult( false );
714 $result->addValue( null, 'test', $input );
716 if ( $expect instanceof Exception ) {
717 try {
718 $output = $result->getResultData( 'test', $transforms );
719 $this->fail( 'Expected exception not thrown', $label );
720 } catch ( Exception $ex ) {
721 $this->assertEquals( $ex, $expect, $label );
723 } else {
724 $output = $result->getResultData( 'test', $transforms );
725 $this->assertEquals( $expect, $output, $label );
729 public function provideTransformations() {
730 $kvp = static function ( $keyKey, $key, $valKey, $value ) {
731 return [
732 $keyKey => $key,
733 $valKey => $value,
734 ApiResult::META_PRESERVE_KEYS => [ $keyKey ],
735 ApiResult::META_CONTENT => $valKey,
736 ApiResult::META_TYPE => 'assoc',
739 $typeArr = [
740 'defaultArray' => [ 2 => 'a', 0 => 'b', 1 => 'c' ],
741 'defaultAssoc' => [ 'x' => 'a', 1 => 'b', 0 => 'c' ],
742 'defaultAssoc2' => [ 2 => 'a', 3 => 'b', 0 => 'c' ],
743 'array' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'array' ],
744 'BCarray' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'BCarray' ],
745 'BCassoc' => [ 'a', 'b', 'c', ApiResult::META_TYPE => 'BCassoc' ],
746 'assoc' => [ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ],
747 'kvp' => [ 'x' => 'a', 'y' => 'b', 'z' => [ 'c' ], ApiResult::META_TYPE => 'kvp' ],
748 'BCkvp' => [ 'x' => 'a', 'y' => 'b',
749 ApiResult::META_TYPE => 'BCkvp',
750 ApiResult::META_KVP_KEY_NAME => 'key',
752 'kvpmerge' => [ 'x' => 'a', 'y' => [ 'b' ], 'z' => [ 'c' => 'd' ],
753 ApiResult::META_TYPE => 'kvp',
754 ApiResult::META_KVP_MERGE => true,
756 'emptyDefault' => [ '_dummy' => 1 ],
757 'emptyAssoc' => [ '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ],
758 '_dummy' => 1,
759 ApiResult::META_PRESERVE_KEYS => [ '_dummy' ],
761 $stripArr = [
762 'foo' => [
763 'bar' => [ '_dummy' => 'foobaz' ],
764 'baz' => [
765 ApiResult::META_SUBELEMENTS => [ 'foo', 'bar' ],
766 ApiResult::META_INDEXED_TAG_NAME => 'itn',
767 ApiResult::META_PRESERVE_KEYS => [ 'foo', 'bar', '_dummy2', 0 ],
768 ApiResult::META_TYPE => 'array',
770 'x' => 'ok',
771 '_dummy' => 'foobaz',
773 ApiResult::META_SUBELEMENTS => [ 'foo', 'bar' ],
774 ApiResult::META_INDEXED_TAG_NAME => 'itn',
775 ApiResult::META_PRESERVE_KEYS => [ 'foo', 'bar', '_dummy2', 0 ],
776 ApiResult::META_TYPE => 'array',
777 '_dummy' => 'foobaz',
778 '_dummy2' => 'foobaz!',
781 return [
783 'BC: META_BC_BOOLS',
785 'BCtrue' => true,
786 'BCfalse' => false,
787 'true' => true,
788 'false' => false,
789 ApiResult::META_BC_BOOLS => [ 0, 'true', 'false' ],
791 [ 'BC' => [] ],
793 'BCtrue' => '',
794 'true' => true,
795 'false' => false,
796 ApiResult::META_BC_BOOLS => [ 0, 'true', 'false' ],
800 'BC: META_BC_SUBELEMENTS',
802 'bc' => 'foo',
803 'nobc' => 'bar',
804 ApiResult::META_BC_SUBELEMENTS => [ 'bc' ],
806 [ 'BC' => [] ],
808 'bc' => [
809 '*' => 'foo',
810 ApiResult::META_CONTENT => '*',
811 ApiResult::META_TYPE => 'assoc',
813 'nobc' => 'bar',
814 ApiResult::META_BC_SUBELEMENTS => [ 'bc' ],
818 'BC: META_CONTENT',
820 'content' => '!!!',
821 ApiResult::META_CONTENT => 'content',
823 [ 'BC' => [] ],
825 '*' => '!!!',
826 ApiResult::META_CONTENT => '*',
830 'BC: BCkvp type',
832 'foo' => 'foo value',
833 'bar' => 'bar value',
834 '_baz' => 'baz value',
835 ApiResult::META_TYPE => 'BCkvp',
836 ApiResult::META_KVP_KEY_NAME => 'key',
837 ApiResult::META_PRESERVE_KEYS => [ '_baz' ],
839 [ 'BC' => [] ],
841 $kvp( 'key', 'foo', '*', 'foo value' ),
842 $kvp( 'key', 'bar', '*', 'bar value' ),
843 $kvp( 'key', '_baz', '*', 'baz value' ),
844 ApiResult::META_TYPE => 'array',
845 ApiResult::META_KVP_KEY_NAME => 'key',
846 ApiResult::META_PRESERVE_KEYS => [ '_baz' ],
850 'BC: BCarray type',
852 ApiResult::META_TYPE => 'BCarray',
854 [ 'BC' => [] ],
856 ApiResult::META_TYPE => 'default',
860 'BC: BCassoc type',
862 ApiResult::META_TYPE => 'BCassoc',
864 [ 'BC' => [] ],
866 ApiResult::META_TYPE => 'default',
870 'BC: BCkvp exception',
872 ApiResult::META_TYPE => 'BCkvp',
874 [ 'BC' => [] ],
875 new UnexpectedValueException(
876 'Type "BCkvp" used without setting ApiResult::META_KVP_KEY_NAME metadata item'
880 'BC: nobool, no*, nosub',
882 'true' => true,
883 'false' => false,
884 'content' => 'content',
885 ApiResult::META_CONTENT => 'content',
886 'bc' => 'foo',
887 ApiResult::META_BC_SUBELEMENTS => [ 'bc' ],
888 'BCarray' => [ ApiResult::META_TYPE => 'BCarray' ],
889 'BCassoc' => [ ApiResult::META_TYPE => 'BCassoc' ],
890 'BCkvp' => [
891 'foo' => 'foo value',
892 'bar' => 'bar value',
893 '_baz' => 'baz value',
894 ApiResult::META_TYPE => 'BCkvp',
895 ApiResult::META_KVP_KEY_NAME => 'key',
896 ApiResult::META_PRESERVE_KEYS => [ '_baz' ],
899 [ 'BC' => [ 'nobool', 'no*', 'nosub' ] ],
901 'true' => true,
902 'false' => false,
903 'content' => 'content',
904 'bc' => 'foo',
905 'BCarray' => [ ApiResult::META_TYPE => 'default' ],
906 'BCassoc' => [ ApiResult::META_TYPE => 'default' ],
907 'BCkvp' => [
908 $kvp( 'key', 'foo', '*', 'foo value' ),
909 $kvp( 'key', 'bar', '*', 'bar value' ),
910 $kvp( 'key', '_baz', '*', 'baz value' ),
911 ApiResult::META_TYPE => 'array',
912 ApiResult::META_KVP_KEY_NAME => 'key',
913 ApiResult::META_PRESERVE_KEYS => [ '_baz' ],
915 ApiResult::META_CONTENT => 'content',
916 ApiResult::META_BC_SUBELEMENTS => [ 'bc' ],
921 'Types: Normal transform',
922 $typeArr,
923 [ 'Types' => [] ],
925 'defaultArray' => [ 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ],
926 'defaultAssoc' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ],
927 'defaultAssoc2' => [ 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ],
928 'array' => [ 'c', 'b', 'a', ApiResult::META_TYPE => 'array' ],
929 'BCarray' => [ 'c', 'b', 'a', ApiResult::META_TYPE => 'array' ],
930 'BCassoc' => [ 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ],
931 'assoc' => [ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ],
932 'kvp' => [ 'x' => 'a', 'y' => 'b',
933 'z' => [ 'c', ApiResult::META_TYPE => 'array' ],
934 ApiResult::META_TYPE => 'assoc'
936 'BCkvp' => [ 'x' => 'a', 'y' => 'b',
937 ApiResult::META_TYPE => 'assoc',
938 ApiResult::META_KVP_KEY_NAME => 'key',
940 'kvpmerge' => [
941 'x' => 'a',
942 'y' => [ 'b', ApiResult::META_TYPE => 'array' ],
943 'z' => [ 'c' => 'd', ApiResult::META_TYPE => 'assoc' ],
944 ApiResult::META_TYPE => 'assoc',
945 ApiResult::META_KVP_MERGE => true,
947 'emptyDefault' => [ '_dummy' => 1, ApiResult::META_TYPE => 'array' ],
948 'emptyAssoc' => [ '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ],
949 '_dummy' => 1,
950 ApiResult::META_PRESERVE_KEYS => [ '_dummy' ],
951 ApiResult::META_TYPE => 'assoc',
955 'Types: AssocAsObject',
956 $typeArr,
957 [ 'Types' => [ 'AssocAsObject' => true ] ],
958 (object)[
959 'defaultArray' => [ 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ],
960 'defaultAssoc' => (object)[ 'x' => 'a',
961 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc'
963 'defaultAssoc2' => (object)[ 2 => 'a', 3 => 'b',
964 0 => 'c', ApiResult::META_TYPE => 'assoc'
966 'array' => [ 'c', 'b', 'a', ApiResult::META_TYPE => 'array' ],
967 'BCarray' => [ 'c', 'b', 'a', ApiResult::META_TYPE => 'array' ],
968 'BCassoc' => (object)[ 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ],
969 'assoc' => (object)[ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ],
970 'kvp' => (object)[ 'x' => 'a', 'y' => 'b',
971 'z' => [ 'c', ApiResult::META_TYPE => 'array' ],
972 ApiResult::META_TYPE => 'assoc'
974 'BCkvp' => (object)[ 'x' => 'a', 'y' => 'b',
975 ApiResult::META_TYPE => 'assoc',
976 ApiResult::META_KVP_KEY_NAME => 'key',
978 'kvpmerge' => (object)[
979 'x' => 'a',
980 'y' => [ 'b', ApiResult::META_TYPE => 'array' ],
981 'z' => (object)[ 'c' => 'd', ApiResult::META_TYPE => 'assoc' ],
982 ApiResult::META_TYPE => 'assoc',
983 ApiResult::META_KVP_MERGE => true,
985 'emptyDefault' => [ '_dummy' => 1, ApiResult::META_TYPE => 'array' ],
986 'emptyAssoc' => (object)[ '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ],
987 '_dummy' => 1,
988 ApiResult::META_PRESERVE_KEYS => [ '_dummy' ],
989 ApiResult::META_TYPE => 'assoc',
993 'Types: ArmorKVP',
994 $typeArr,
995 [ 'Types' => [ 'ArmorKVP' => 'name' ] ],
997 'defaultArray' => [ 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ],
998 'defaultAssoc' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ],
999 'defaultAssoc2' => [ 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ],
1000 'array' => [ 'c', 'b', 'a', ApiResult::META_TYPE => 'array' ],
1001 'BCarray' => [ 'c', 'b', 'a', ApiResult::META_TYPE => 'array' ],
1002 'BCassoc' => [ 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ],
1003 'assoc' => [ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ],
1004 'kvp' => [
1005 $kvp( 'name', 'x', 'value', 'a' ),
1006 $kvp( 'name', 'y', 'value', 'b' ),
1007 $kvp( 'name', 'z', 'value', [ 'c', ApiResult::META_TYPE => 'array' ] ),
1008 ApiResult::META_TYPE => 'array'
1010 'BCkvp' => [
1011 $kvp( 'key', 'x', 'value', 'a' ),
1012 $kvp( 'key', 'y', 'value', 'b' ),
1013 ApiResult::META_TYPE => 'array',
1014 ApiResult::META_KVP_KEY_NAME => 'key',
1016 'kvpmerge' => [
1017 $kvp( 'name', 'x', 'value', 'a' ),
1018 $kvp( 'name', 'y', 'value', [ 'b', ApiResult::META_TYPE => 'array' ] ),
1020 'name' => 'z',
1021 'c' => 'd',
1022 ApiResult::META_TYPE => 'assoc',
1023 ApiResult::META_PRESERVE_KEYS => [ 'name' ]
1025 ApiResult::META_TYPE => 'array',
1026 ApiResult::META_KVP_MERGE => true,
1028 'emptyDefault' => [ '_dummy' => 1, ApiResult::META_TYPE => 'array' ],
1029 'emptyAssoc' => [ '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ],
1030 '_dummy' => 1,
1031 ApiResult::META_PRESERVE_KEYS => [ '_dummy' ],
1032 ApiResult::META_TYPE => 'assoc',
1036 'Types: ArmorKVP + BC',
1037 $typeArr,
1038 [ 'BC' => [], 'Types' => [ 'ArmorKVP' => 'name' ] ],
1040 'defaultArray' => [ 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ],
1041 'defaultAssoc' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ],
1042 'defaultAssoc2' => [ 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ],
1043 'array' => [ 'c', 'b', 'a', ApiResult::META_TYPE => 'array' ],
1044 'BCarray' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ],
1045 'BCassoc' => [ 'a', 'b', 'c', ApiResult::META_TYPE => 'array' ],
1046 'assoc' => [ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ],
1047 'kvp' => [
1048 $kvp( 'name', 'x', '*', 'a' ),
1049 $kvp( 'name', 'y', '*', 'b' ),
1050 $kvp( 'name', 'z', '*', [ 'c', ApiResult::META_TYPE => 'array' ] ),
1051 ApiResult::META_TYPE => 'array'
1053 'BCkvp' => [
1054 $kvp( 'key', 'x', '*', 'a' ),
1055 $kvp( 'key', 'y', '*', 'b' ),
1056 ApiResult::META_TYPE => 'array',
1057 ApiResult::META_KVP_KEY_NAME => 'key',
1059 'kvpmerge' => [
1060 $kvp( 'name', 'x', '*', 'a' ),
1061 $kvp( 'name', 'y', '*', [ 'b', ApiResult::META_TYPE => 'array' ] ),
1063 'name' => 'z',
1064 'c' => 'd',
1065 ApiResult::META_TYPE => 'assoc',
1066 ApiResult::META_PRESERVE_KEYS => [ 'name' ] ],
1067 ApiResult::META_TYPE => 'array',
1068 ApiResult::META_KVP_MERGE => true,
1070 'emptyDefault' => [ '_dummy' => 1, ApiResult::META_TYPE => 'array' ],
1071 'emptyAssoc' => [ '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ],
1072 '_dummy' => 1,
1073 ApiResult::META_PRESERVE_KEYS => [ '_dummy' ],
1074 ApiResult::META_TYPE => 'assoc',
1078 'Types: ArmorKVP + AssocAsObject',
1079 $typeArr,
1080 [ 'Types' => [ 'ArmorKVP' => 'name', 'AssocAsObject' => true ] ],
1081 (object)[
1082 'defaultArray' => [ 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ],
1083 'defaultAssoc' => (object)[ 'x' => 'a', 1 => 'b',
1084 0 => 'c', ApiResult::META_TYPE => 'assoc'
1086 'defaultAssoc2' => (object)[ 2 => 'a', 3 => 'b',
1087 0 => 'c', ApiResult::META_TYPE => 'assoc'
1089 'array' => [ 'c', 'b', 'a', ApiResult::META_TYPE => 'array' ],
1090 'BCarray' => [ 'c', 'b', 'a', ApiResult::META_TYPE => 'array' ],
1091 'BCassoc' => (object)[ 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ],
1092 'assoc' => (object)[ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ],
1093 'kvp' => [
1094 (object)$kvp( 'name', 'x', 'value', 'a' ),
1095 (object)$kvp( 'name', 'y', 'value', 'b' ),
1096 (object)$kvp( 'name', 'z', 'value', [ 'c', ApiResult::META_TYPE => 'array' ] ),
1097 ApiResult::META_TYPE => 'array'
1099 'BCkvp' => [
1100 (object)$kvp( 'key', 'x', 'value', 'a' ),
1101 (object)$kvp( 'key', 'y', 'value', 'b' ),
1102 ApiResult::META_TYPE => 'array',
1103 ApiResult::META_KVP_KEY_NAME => 'key',
1105 'kvpmerge' => [
1106 (object)$kvp( 'name', 'x', 'value', 'a' ),
1107 (object)$kvp( 'name', 'y', 'value', [ 'b', ApiResult::META_TYPE => 'array' ] ),
1108 (object)[
1109 'name' => 'z',
1110 'c' => 'd',
1111 ApiResult::META_TYPE => 'assoc',
1112 ApiResult::META_PRESERVE_KEYS => [ 'name' ]
1114 ApiResult::META_TYPE => 'array',
1115 ApiResult::META_KVP_MERGE => true,
1117 'emptyDefault' => [ '_dummy' => 1, ApiResult::META_TYPE => 'array' ],
1118 'emptyAssoc' => (object)[ '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ],
1119 '_dummy' => 1,
1120 ApiResult::META_PRESERVE_KEYS => [ '_dummy' ],
1121 ApiResult::META_TYPE => 'assoc',
1125 'Types: BCkvp exception',
1127 ApiResult::META_TYPE => 'BCkvp',
1129 [ 'Types' => [] ],
1130 new UnexpectedValueException(
1131 'Type "BCkvp" used without setting ApiResult::META_KVP_KEY_NAME metadata item'
1136 'Strip: With ArmorKVP + AssocAsObject transforms',
1137 $typeArr,
1138 [ 'Types' => [ 'ArmorKVP' => 'name', 'AssocAsObject' => true ], 'Strip' => 'all' ],
1139 (object)[
1140 'defaultArray' => [ 'b', 'c', 'a' ],
1141 'defaultAssoc' => (object)[ 'x' => 'a', 1 => 'b', 0 => 'c' ],
1142 'defaultAssoc2' => (object)[ 2 => 'a', 3 => 'b', 0 => 'c' ],
1143 'array' => [ 'c', 'b', 'a' ],
1144 'BCarray' => [ 'c', 'b', 'a' ],
1145 'BCassoc' => (object)[ 'a', 'b', 'c' ],
1146 'assoc' => (object)[ 2 => 'a', 0 => 'b', 1 => 'c' ],
1147 'kvp' => [
1148 (object)[ 'name' => 'x', 'value' => 'a' ],
1149 (object)[ 'name' => 'y', 'value' => 'b' ],
1150 (object)[ 'name' => 'z', 'value' => [ 'c' ] ],
1152 'BCkvp' => [
1153 (object)[ 'key' => 'x', 'value' => 'a' ],
1154 (object)[ 'key' => 'y', 'value' => 'b' ],
1156 'kvpmerge' => [
1157 (object)[ 'name' => 'x', 'value' => 'a' ],
1158 (object)[ 'name' => 'y', 'value' => [ 'b' ] ],
1159 (object)[ 'name' => 'z', 'c' => 'd' ],
1161 'emptyDefault' => [],
1162 'emptyAssoc' => (object)[],
1163 '_dummy' => 1,
1168 'Strip: all',
1169 $stripArr,
1170 [ 'Strip' => 'all' ],
1172 'foo' => [
1173 'bar' => [],
1174 'baz' => [],
1175 'x' => 'ok',
1177 '_dummy2' => 'foobaz!',
1181 'Strip: base',
1182 $stripArr,
1183 [ 'Strip' => 'base' ],
1185 'foo' => [
1186 'bar' => [ '_dummy' => 'foobaz' ],
1187 'baz' => [
1188 ApiResult::META_SUBELEMENTS => [ 'foo', 'bar' ],
1189 ApiResult::META_INDEXED_TAG_NAME => 'itn',
1190 ApiResult::META_PRESERVE_KEYS => [ 'foo', 'bar', '_dummy2', 0 ],
1191 ApiResult::META_TYPE => 'array',
1193 'x' => 'ok',
1194 '_dummy' => 'foobaz',
1196 '_dummy2' => 'foobaz!',
1200 'Strip: bc',
1201 $stripArr,
1202 [ 'Strip' => 'bc' ],
1204 'foo' => [
1205 'bar' => [],
1206 'baz' => [
1207 ApiResult::META_SUBELEMENTS => [ 'foo', 'bar' ],
1208 ApiResult::META_INDEXED_TAG_NAME => 'itn',
1210 'x' => 'ok',
1212 '_dummy2' => 'foobaz!',
1213 ApiResult::META_SUBELEMENTS => [ 'foo', 'bar' ],
1214 ApiResult::META_INDEXED_TAG_NAME => 'itn',
1219 'Custom transform',
1221 'foo' => '?',
1222 'bar' => '?',
1223 '_dummy' => '?',
1224 '_dummy2' => '?',
1225 '_dummy3' => '?',
1226 ApiResult::META_CONTENT => 'foo',
1227 ApiResult::META_PRESERVE_KEYS => [ '_dummy2', '_dummy3' ],
1230 'Custom' => [ $this, 'customTransform' ],
1231 'BC' => [],
1232 'Types' => [],
1233 'Strip' => 'all'
1236 '*' => 'FOO',
1237 'bar' => 'BAR',
1238 'baz' => [ 'a', 'b' ],
1239 '_dummy2' => '_DUMMY2',
1240 '_dummy3' => '_DUMMY3',
1241 ApiResult::META_CONTENT => 'bar',
1246 'Types: Numeric keys in array and BCarray',
1248 'array' => [
1249 0 => 'd',
1250 'x' => 'a',
1251 1 => 'b',
1252 '1.5' => 'c',
1253 '0.5 ' => 'e',
1254 ApiResult::META_TYPE => 'array'
1256 'BCarray' => [
1257 0 => 'd',
1258 'x' => 'a',
1259 1 => 'b',
1260 '1.5' => 'c',
1261 '0.5 ' => 'e',
1262 ApiResult::META_TYPE => 'BCarray'
1265 [ 'Types' => [] ],
1267 'array' => [ 'd', 'e', 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ],
1268 'BCarray' => [ 'd', 'e', 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ],
1269 ApiResult::META_TYPE => 'assoc',
1276 * Custom transformer for testTransformations
1277 * @param array &$data
1278 * @param array &$metadata
1280 public function customTransform( &$data, &$metadata ) {
1281 // Prevent recursion
1282 if ( isset( $metadata['_added'] ) ) {
1283 $metadata[ApiResult::META_TYPE] = 'array';
1284 return;
1287 foreach ( $data as $k => $v ) {
1288 $data[$k] = strtoupper( $k );
1290 $data['baz'] = [ '_added' => 1, 'z' => 'b', 'y' => 'a' ];
1291 $metadata[ApiResult::META_PRESERVE_KEYS][0] = '_dummy';
1292 $data[ApiResult::META_CONTENT] = 'bar';
1296 * @covers \MediaWiki\Api\ApiResult
1298 public function testAddMetadataToResultVars() {
1299 $arr = [
1300 'a' => "foo",
1301 'b' => false,
1302 'c' => 10,
1303 'sequential_numeric_keys' => [ 'a', 'b', 'c' ],
1304 'non_sequential_numeric_keys' => [ 'a', 'b', 4 => 'c' ],
1305 'string_keys' => [
1306 'one' => 1,
1307 'two' => 2
1309 'object_sequential_keys' => (object)[ 'a', 'b', 'c' ],
1310 '_type' => "should be overwritten in result",
1312 $this->assertSame( [
1313 ApiResult::META_TYPE => 'kvp',
1314 ApiResult::META_KVP_KEY_NAME => 'key',
1315 ApiResult::META_PRESERVE_KEYS => [
1316 'a', 'b', 'c',
1317 'sequential_numeric_keys', 'non_sequential_numeric_keys',
1318 'string_keys', 'object_sequential_keys'
1320 ApiResult::META_BC_BOOLS => [ 'b' ],
1321 ApiResult::META_INDEXED_TAG_NAME => 'var',
1322 'a' => "foo",
1323 'b' => false,
1324 'c' => 10,
1325 'sequential_numeric_keys' => [
1326 ApiResult::META_TYPE => 'array',
1327 ApiResult::META_BC_BOOLS => [],
1328 ApiResult::META_INDEXED_TAG_NAME => 'value',
1329 0 => 'a',
1330 1 => 'b',
1331 2 => 'c',
1333 'non_sequential_numeric_keys' => [
1334 ApiResult::META_TYPE => 'kvp',
1335 ApiResult::META_KVP_KEY_NAME => 'key',
1336 ApiResult::META_PRESERVE_KEYS => [ 0, 1, 4 ],
1337 ApiResult::META_BC_BOOLS => [],
1338 ApiResult::META_INDEXED_TAG_NAME => 'var',
1339 0 => 'a',
1340 1 => 'b',
1341 4 => 'c',
1343 'string_keys' => [
1344 ApiResult::META_TYPE => 'kvp',
1345 ApiResult::META_KVP_KEY_NAME => 'key',
1346 ApiResult::META_PRESERVE_KEYS => [ 'one', 'two' ],
1347 ApiResult::META_BC_BOOLS => [],
1348 ApiResult::META_INDEXED_TAG_NAME => 'var',
1349 'one' => 1,
1350 'two' => 2,
1352 'object_sequential_keys' => [
1353 ApiResult::META_TYPE => 'kvp',
1354 ApiResult::META_KVP_KEY_NAME => 'key',
1355 ApiResult::META_PRESERVE_KEYS => [ 0, 1, 2 ],
1356 ApiResult::META_BC_BOOLS => [],
1357 ApiResult::META_INDEXED_TAG_NAME => 'var',
1358 0 => 'a',
1359 1 => 'b',
1360 2 => 'c',
1362 ], ApiResult::addMetadataToResultVars( $arr ) );
1365 public function testObjectSerialization() {
1366 $arr = [];
1367 ApiResult::setValue( $arr, 'foo', (object)[ 'a' => 1, 'b' => 2 ] );
1368 $this->assertSame( [
1369 'a' => 1,
1370 'b' => 2,
1371 ApiResult::META_TYPE => 'assoc',
1372 ], $arr['foo'] );
1374 $arr = [];
1375 ApiResult::setValue( $arr, 'foo', new ApiResultTestStringifiableObject() );
1376 $this->assertSame( 'Ok', $arr['foo'] );
1378 $arr = [];
1379 ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( 'Ok' ) );
1380 $this->assertSame( 'Ok', $arr['foo'] );
1382 try {
1383 $arr = [];
1384 ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
1385 new ApiResultTestStringifiableObject()
1386 ) );
1387 $this->fail( 'Expected exception not thrown' );
1388 } catch ( UnexpectedValueException $ex ) {
1389 $this->assertSame(
1390 'MediaWiki\Tests\Api\ApiResultTestSerializableObject::serializeForApiResult() ' .
1391 'returned an object of class MediaWiki\Tests\Api\ApiResultTestStringifiableObject',
1392 $ex->getMessage(),
1393 'Expected exception'
1397 try {
1398 $arr = [];
1399 ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( NAN ) );
1400 $this->fail( 'Expected exception not thrown' );
1401 } catch ( UnexpectedValueException $ex ) {
1402 $this->assertSame(
1403 'MediaWiki\Tests\Api\ApiResultTestSerializableObject::serializeForApiResult() ' .
1404 'returned an invalid value: Cannot add non-finite floats to ApiResult',
1405 $ex->getMessage(),
1406 'Expected exception'
1410 $arr = [];
1411 ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
1413 'one' => new ApiResultTestStringifiableObject( '1' ),
1414 'two' => new ApiResultTestSerializableObject( 2 ),
1416 ) );
1417 $this->assertSame( [
1418 'one' => '1',
1419 'two' => 2,
1420 ], $arr['foo'] );
1424 class ApiResultTestStringifiableObject implements Stringable {
1425 /** @var string */
1426 private $ret;
1428 public function __construct( $ret = 'Ok' ) {
1429 $this->ret = $ret;
1432 public function __toString() {
1433 return $this->ret;
1437 #[AllowDynamicProperties]
1438 class ApiResultTestSerializableObject implements Stringable {
1439 /** @var string */
1440 private $ret;
1442 public function __construct( $ret ) {
1443 $this->ret = $ret;
1446 public function __toString() {
1447 return "Fail";
1450 public function serializeForApiResult() {
1451 return $this->ret;