7 class ApiResultTest
extends MediaWikiTestCase
{
12 public function testStaticDataMethods() {
15 ApiResult
::setValue( $arr, 'setValue', '1' );
17 ApiResult
::setValue( $arr, null, 'unnamed 1' );
18 ApiResult
::setValue( $arr, null, 'unnamed 2' );
20 ApiResult
::setValue( $arr, 'deleteValue', '2' );
21 ApiResult
::unsetValue( $arr, 'deleteValue' );
23 ApiResult
::setContentValue( $arr, 'setContentValue', '3' );
29 ApiResult
::META_CONTENT
=> 'setContentValue',
30 'setContentValue' => '3',
34 ApiResult
::setValue( $arr, 'setValue', '99' );
35 $this->fail( 'Expected exception not thrown' );
36 } catch ( RuntimeException
$ex ) {
38 'Attempting to add element setValue=99, existing value is 1',
45 ApiResult
::setContentValue( $arr, 'setContentValue2', '99' );
46 $this->fail( 'Expected exception not thrown' );
47 } catch ( RuntimeException
$ex ) {
49 'Attempting to set content element as setContentValue2 when setContentValue ' .
50 'is already set as the content element',
56 ApiResult
::setValue( $arr, 'setValue', '99', ApiResult
::OVERRIDE
);
57 $this->assertSame( '99', $arr['setValue'] );
59 ApiResult
::setContentValue( $arr, 'setContentValue2', '99', ApiResult
::OVERRIDE
);
60 $this->assertSame( 'setContentValue2', $arr[ApiResult
::META_CONTENT
] );
62 $arr = [ 'foo' => 1, 'bar' => 1 ];
63 ApiResult
::setValue( $arr, 'top', '2', ApiResult
::ADD_ON_TOP
);
64 ApiResult
::setValue( $arr, null, '2', ApiResult
::ADD_ON_TOP
);
65 ApiResult
::setValue( $arr, 'bottom', '2' );
66 ApiResult
::setValue( $arr, 'foo', '2', ApiResult
::OVERRIDE
);
67 ApiResult
::setValue( $arr, 'bar', '2', ApiResult
::OVERRIDE | ApiResult
::ADD_ON_TOP
);
68 $this->assertSame( [ 0, 'top', 'foo', 'bar', 'bottom' ], array_keys( $arr ) );
71 ApiResult
::setValue( $arr, 'sub', [ 'foo' => 1 ] );
72 ApiResult
::setValue( $arr, 'sub', [ 'bar' => 1 ] );
73 $this->assertSame( [ 'sub' => [ 'foo' => 1, 'bar' => 1 ] ], $arr );
76 ApiResult
::setValue( $arr, 'sub', [ 'foo' => 2, 'baz' => 2 ] );
77 $this->fail( 'Expected exception not thrown' );
78 } catch ( RuntimeException
$ex ) {
80 'Conflicting keys (foo) when attempting to merge element sub',
87 $title = Title
::newFromText( "MediaWiki:Foobar" );
91 ApiResult
::setValue( $arr, 'title', $title );
92 ApiResult
::setValue( $arr, 'obj', $obj );
94 'title' => (string)$title,
95 'obj' => [ 'foo' => 1, 'bar' => 2, ApiResult
::META_TYPE
=> 'assoc' ],
100 ApiResult
::setValue( $arr, 'file', $fh );
101 $this->fail( 'Expected exception not thrown' );
102 } catch ( InvalidArgumentException
$ex ) {
104 'Cannot add resource(stream) to ApiResult',
110 ApiResult
::setValue( $arr, null, $fh );
111 $this->fail( 'Expected exception not thrown' );
112 } catch ( InvalidArgumentException
$ex ) {
114 'Cannot add resource(stream) to ApiResult',
121 ApiResult
::setValue( $arr, 'sub', $obj );
122 $this->fail( 'Expected exception not thrown' );
123 } catch ( InvalidArgumentException
$ex ) {
125 'Cannot add resource(stream) to ApiResult',
132 ApiResult
::setValue( $arr, null, $obj );
133 $this->fail( 'Expected exception not thrown' );
134 } catch ( InvalidArgumentException
$ex ) {
136 'Cannot add resource(stream) to ApiResult',
144 ApiResult
::setValue( $arr, 'inf', INF
);
145 $this->fail( 'Expected exception not thrown' );
146 } catch ( InvalidArgumentException
$ex ) {
148 'Cannot add non-finite floats to ApiResult',
154 ApiResult
::setValue( $arr, null, INF
);
155 $this->fail( 'Expected exception not thrown' );
156 } catch ( InvalidArgumentException
$ex ) {
158 'Cannot add non-finite floats to ApiResult',
164 ApiResult
::setValue( $arr, 'nan', NAN
);
165 $this->fail( 'Expected exception not thrown' );
166 } catch ( InvalidArgumentException
$ex ) {
168 'Cannot add non-finite floats to ApiResult',
174 ApiResult
::setValue( $arr, null, NAN
);
175 $this->fail( 'Expected exception not thrown' );
176 } catch ( InvalidArgumentException
$ex ) {
178 'Cannot add non-finite floats to ApiResult',
184 ApiResult
::setValue( $arr, null, NAN
, ApiResult
::NO_VALIDATE
);
187 ApiResult
::setValue( $arr, null, NAN
, ApiResult
::NO_SIZE_CHECK
);
188 $this->fail( 'Expected exception not thrown' );
189 } catch ( InvalidArgumentException
$ex ) {
191 'Cannot add non-finite floats to ApiResult',
198 $result2 = new ApiResult( 8388608 );
199 $result2->addValue( null, 'foo', 'bar' );
200 ApiResult
::setValue( $arr, 'baz', $result2 );
203 ApiResult
::META_TYPE
=> 'assoc',
209 ApiResult
::setValue( $arr, 'foo', "foo\x80bar" );
210 ApiResult
::setValue( $arr, 'bar', "a\xcc\x81" );
211 ApiResult
::setValue( $arr, 'baz', 74 );
212 ApiResult
::setValue( $arr, null, "foo\x80bar" );
213 ApiResult
::setValue( $arr, null, "a\xcc\x81" );
215 'foo' => "foo\xef\xbf\xbdbar",
218 0 => "foo\xef\xbf\xbdbar",
225 ApiResult
::setValue( $arr, 'foo', $obj );
229 ApiResult
::META_TYPE
=> 'assoc',
237 public function testInstanceDataMethods() {
238 $result = new ApiResult( 8388608 );
240 $result->addValue( null, 'setValue', '1' );
242 $result->addValue( null, null, 'unnamed 1' );
243 $result->addValue( null, null, 'unnamed 2' );
245 $result->addValue( null, 'deleteValue', '2' );
246 $result->removeValue( null, 'deleteValue' );
248 $result->addValue( [ 'a', 'b' ], 'deleteValue', '3' );
249 $result->removeValue( [ 'a', 'b', 'deleteValue' ], null, '3' );
251 $result->addContentValue( null, 'setContentValue', '3' );
257 'a' => [ 'b' => [] ],
258 'setContentValue' => '3',
259 ApiResult
::META_TYPE
=> 'assoc',
260 ApiResult
::META_CONTENT
=> 'setContentValue',
261 ], $result->getResultData() );
262 $this->assertSame( 20, $result->getSize() );
265 $result->addValue( null, 'setValue', '99' );
266 $this->fail( 'Expected exception not thrown' );
267 } catch ( RuntimeException
$ex ) {
269 'Attempting to add element setValue=99, existing value is 1',
276 $result->addContentValue( null, 'setContentValue2', '99' );
277 $this->fail( 'Expected exception not thrown' );
278 } catch ( RuntimeException
$ex ) {
280 'Attempting to set content element as setContentValue2 when setContentValue ' .
281 'is already set as the content element',
287 $result->addValue( null, 'setValue', '99', ApiResult
::OVERRIDE
);
288 $this->assertSame( '99', $result->getResultData( [ 'setValue' ] ) );
290 $result->addContentValue( null, 'setContentValue2', '99', ApiResult
::OVERRIDE
);
291 $this->assertSame( 'setContentValue2',
292 $result->getResultData( [ ApiResult
::META_CONTENT
] ) );
296 ApiResult
::META_TYPE
=> 'assoc',
297 ], $result->getResultData() );
298 $this->assertSame( 0, $result->getSize() );
300 $result->addValue( null, 'foo', 1 );
301 $result->addValue( null, 'bar', 1 );
302 $result->addValue( null, 'top', '2', ApiResult
::ADD_ON_TOP
);
303 $result->addValue( null, null, '2', ApiResult
::ADD_ON_TOP
);
304 $result->addValue( null, 'bottom', '2' );
305 $result->addValue( null, 'foo', '2', ApiResult
::OVERRIDE
);
306 $result->addValue( null, 'bar', '2', ApiResult
::OVERRIDE | ApiResult
::ADD_ON_TOP
);
307 $this->assertSame( [ 0, 'top', 'foo', 'bar', 'bottom', ApiResult
::META_TYPE
],
308 array_keys( $result->getResultData() ) );
311 $result->addValue( null, 'foo', [ 'bar' => 1 ] );
312 $result->addValue( [ 'foo', 'top' ], 'x', 2, ApiResult
::ADD_ON_TOP
);
313 $result->addValue( [ 'foo', 'bottom' ], 'x', 2 );
314 $this->assertSame( [ 'top', 'bar', 'bottom' ],
315 array_keys( $result->getResultData( [ 'foo' ] ) ) );
318 $result->addValue( null, 'sub', [ 'foo' => 1 ] );
319 $result->addValue( null, 'sub', [ 'bar' => 1 ] );
321 'sub' => [ 'foo' => 1, 'bar' => 1 ],
322 ApiResult
::META_TYPE
=> 'assoc',
323 ], $result->getResultData() );
326 $result->addValue( null, 'sub', [ 'foo' => 2, 'baz' => 2 ] );
327 $this->fail( 'Expected exception not thrown' );
328 } catch ( RuntimeException
$ex ) {
330 'Conflicting keys (foo) when attempting to merge element sub',
337 $title = Title
::newFromText( "MediaWiki:Foobar" );
341 $result->addValue( null, 'title', $title );
342 $result->addValue( null, 'obj', $obj );
344 'title' => (string)$title,
345 'obj' => [ 'foo' => 1, 'bar' => 2, ApiResult
::META_TYPE
=> 'assoc' ],
346 ApiResult
::META_TYPE
=> 'assoc',
347 ], $result->getResultData() );
351 $result->addValue( null, 'file', $fh );
352 $this->fail( 'Expected exception not thrown' );
353 } catch ( InvalidArgumentException
$ex ) {
355 'Cannot add resource(stream) to ApiResult',
361 $result->addValue( null, null, $fh );
362 $this->fail( 'Expected exception not thrown' );
363 } catch ( InvalidArgumentException
$ex ) {
365 'Cannot add resource(stream) to ApiResult',
372 $result->addValue( null, 'sub', $obj );
373 $this->fail( 'Expected exception not thrown' );
374 } catch ( InvalidArgumentException
$ex ) {
376 'Cannot add resource(stream) to ApiResult',
383 $result->addValue( null, null, $obj );
384 $this->fail( 'Expected exception not thrown' );
385 } catch ( InvalidArgumentException
$ex ) {
387 'Cannot add resource(stream) to ApiResult',
395 $result->addValue( null, 'inf', INF
);
396 $this->fail( 'Expected exception not thrown' );
397 } catch ( InvalidArgumentException
$ex ) {
399 'Cannot add non-finite floats to ApiResult',
405 $result->addValue( null, null, INF
);
406 $this->fail( 'Expected exception not thrown' );
407 } catch ( InvalidArgumentException
$ex ) {
409 'Cannot add non-finite floats to ApiResult',
415 $result->addValue( null, 'nan', NAN
);
416 $this->fail( 'Expected exception not thrown' );
417 } catch ( InvalidArgumentException
$ex ) {
419 'Cannot add non-finite floats to ApiResult',
425 $result->addValue( null, null, NAN
);
426 $this->fail( 'Expected exception not thrown' );
427 } catch ( InvalidArgumentException
$ex ) {
429 'Cannot add non-finite floats to ApiResult',
435 $result->addValue( null, null, NAN
, ApiResult
::NO_VALIDATE
);
438 $result->addValue( null, null, NAN
, ApiResult
::NO_SIZE_CHECK
);
439 $this->fail( 'Expected exception not thrown' );
440 } catch ( InvalidArgumentException
$ex ) {
442 'Cannot add non-finite floats to ApiResult',
449 $result->addParsedLimit( 'foo', 12 );
451 'limits' => [ 'foo' => 12 ],
452 ApiResult
::META_TYPE
=> 'assoc',
453 ], $result->getResultData() );
454 $result->addParsedLimit( 'foo', 13 );
456 'limits' => [ 'foo' => 13 ],
457 ApiResult
::META_TYPE
=> 'assoc',
458 ], $result->getResultData() );
459 $this->assertSame( null, $result->getResultData( [ 'foo', 'bar', 'baz' ] ) );
460 $this->assertSame( 13, $result->getResultData( [ 'limits', 'foo' ] ) );
462 $result->getResultData( [ 'limits', 'foo', 'bar' ] );
463 $this->fail( 'Expected exception not thrown' );
464 } catch ( InvalidArgumentException
$ex ) {
466 'Path limits.foo is not an array',
472 // Add two values and some metadata, but ensure metadata is not counted
473 $result = new ApiResult( 100 );
474 $obj = [ 'attr' => '12345' ];
475 ApiResult
::setContentValue( $obj, 'content', '1234567890' );
476 $this->assertTrue( $result->addValue( null, 'foo', $obj ) );
477 $this->assertSame( 15, $result->getSize() );
479 $result = new ApiResult( 10 );
480 $formatter = new ApiErrorFormatter( $result, Language
::factory( 'en' ), 'none', false );
481 $result->setErrorFormatter( $formatter );
482 $this->assertFalse( $result->addValue( null, 'foo', '12345678901' ) );
483 $this->assertTrue( $result->addValue( null, 'foo', '12345678901', ApiResult
::NO_SIZE_CHECK
) );
484 $this->assertSame( 0, $result->getSize() );
486 $this->assertTrue( $result->addValue( null, 'foo', '1234567890' ) );
487 $this->assertFalse( $result->addValue( null, 'foo', '1' ) );
488 $result->removeValue( null, 'foo' );
489 $this->assertTrue( $result->addValue( null, 'foo', '1' ) );
491 $result = new ApiResult( 10 );
492 $obj = new ApiResultTestSerializableObject( 'ok' );
493 $obj->foobar
= 'foobaz';
494 $this->assertTrue( $result->addValue( null, 'foo', $obj ) );
495 $this->assertSame( 2, $result->getSize() );
497 $result = new ApiResult( 8388608 );
498 $result2 = new ApiResult( 8388608 );
499 $result2->addValue( null, 'foo', 'bar' );
500 $result->addValue( null, 'baz', $result2 );
504 ApiResult
::META_TYPE
=> 'assoc',
506 ApiResult
::META_TYPE
=> 'assoc',
507 ], $result->getResultData() );
509 $result = new ApiResult( 8388608 );
510 $result->addValue( null, 'foo', "foo\x80bar" );
511 $result->addValue( null, 'bar', "a\xcc\x81" );
512 $result->addValue( null, 'baz', 74 );
513 $result->addValue( null, null, "foo\x80bar" );
514 $result->addValue( null, null, "a\xcc\x81" );
516 'foo' => "foo\xef\xbf\xbdbar",
519 0 => "foo\xef\xbf\xbdbar",
521 ApiResult
::META_TYPE
=> 'assoc',
522 ], $result->getResultData() );
524 $result = new ApiResult( 8388608 );
528 $result->addValue( $arr, 'foo', $obj );
532 ApiResult
::META_TYPE
=> 'assoc',
534 ApiResult
::META_TYPE
=> 'assoc',
535 ], $result->getResultData() );
541 public function testMetadata() {
542 $arr = [ 'foo' => [ 'bar' => [] ] ];
543 $result = new ApiResult( 8388608 );
544 $result->addValue( null, 'foo', [ 'bar' => [] ] );
549 ApiResult
::META_INDEXED_TAG_NAME
=> 'ritn',
550 ApiResult
::META_TYPE
=> 'default',
552 ApiResult
::META_INDEXED_TAG_NAME
=> 'ritn',
553 ApiResult
::META_TYPE
=> 'default',
555 ApiResult
::META_SUBELEMENTS
=> [ 'foo', 'bar' ],
556 ApiResult
::META_INDEXED_TAG_NAME
=> 'itn',
557 ApiResult
::META_PRESERVE_KEYS
=> [ 'foo', 'bar' ],
558 ApiResult
::META_TYPE
=> 'array',
561 ApiResult
::setSubelementsList( $arr, 'foo' );
562 ApiResult
::setSubelementsList( $arr, [ 'bar', 'baz' ] );
563 ApiResult
::unsetSubelementsList( $arr, 'baz' );
564 ApiResult
::setIndexedTagNameRecursive( $arr, 'ritn' );
565 ApiResult
::setIndexedTagName( $arr, 'itn' );
566 ApiResult
::setPreserveKeysList( $arr, 'foo' );
567 ApiResult
::setPreserveKeysList( $arr, [ 'bar', 'baz' ] );
568 ApiResult
::unsetPreserveKeysList( $arr, 'baz' );
569 ApiResult
::setArrayTypeRecursive( $arr, 'default' );
570 ApiResult
::setArrayType( $arr, 'array' );
571 $this->assertSame( $expect, $arr );
573 $result->addSubelementsList( null, 'foo' );
574 $result->addSubelementsList( null, [ 'bar', 'baz' ] );
575 $result->removeSubelementsList( null, 'baz' );
576 $result->addIndexedTagNameRecursive( null, 'ritn' );
577 $result->addIndexedTagName( null, 'itn' );
578 $result->addPreserveKeysList( null, 'foo' );
579 $result->addPreserveKeysList( null, [ 'bar', 'baz' ] );
580 $result->removePreserveKeysList( null, 'baz' );
581 $result->addArrayTypeRecursive( null, 'default' );
582 $result->addArrayType( null, 'array' );
583 $this->assertEquals( $expect, $result->getResultData() );
585 $arr = [ 'foo' => [ 'bar' => [] ] ];
589 ApiResult
::META_TYPE
=> 'kvp',
590 ApiResult
::META_KVP_KEY_NAME
=> 'key',
592 ApiResult
::META_TYPE
=> 'kvp',
593 ApiResult
::META_KVP_KEY_NAME
=> 'key',
595 ApiResult
::META_TYPE
=> 'BCkvp',
596 ApiResult
::META_KVP_KEY_NAME
=> 'bc',
598 ApiResult
::setArrayTypeRecursive( $arr, 'kvp', 'key' );
599 ApiResult
::setArrayType( $arr, 'BCkvp', 'bc' );
600 $this->assertSame( $expect, $arr );
606 public function testUtilityFunctions() {
609 'bar' => [ '_dummy' => 'foobaz' ],
610 'bar2' => (object)[ '_dummy' => 'foobaz' ],
612 '_dummy' => 'foobaz',
615 'bar' => [ '_dummy' => 'foobaz' ],
616 'bar2' => (object)[ '_dummy' => 'foobaz' ],
618 '_dummy' => 'foobaz',
620 ApiResult
::META_SUBELEMENTS
=> [ 'foo', 'bar' ],
621 ApiResult
::META_INDEXED_TAG_NAME
=> 'itn',
622 ApiResult
::META_PRESERVE_KEYS
=> [ 'foo', 'bar', '_dummy2', 0 ],
623 ApiResult
::META_TYPE
=> 'array',
624 '_dummy' => 'foobaz',
625 '_dummy2' => 'foobaz!',
627 $this->assertEquals( [
630 'bar2' => (object)[],
635 'bar2' => (object)[],
638 '_dummy2' => 'foobaz!',
639 ], ApiResult
::stripMetadata( $arr ), 'ApiResult::stripMetadata' );
642 $data = ApiResult
::stripMetadataNonRecursive( $arr, $metadata );
643 $this->assertEquals( [
645 'bar' => [ '_dummy' => 'foobaz' ],
646 'bar2' => (object)[ '_dummy' => 'foobaz' ],
648 '_dummy' => 'foobaz',
651 'bar' => [ '_dummy' => 'foobaz' ],
652 'bar2' => (object)[ '_dummy' => 'foobaz' ],
654 '_dummy' => 'foobaz',
656 '_dummy2' => 'foobaz!',
657 ], $data, 'ApiResult::stripMetadataNonRecursive ($data)' );
658 $this->assertEquals( [
659 ApiResult
::META_SUBELEMENTS
=> [ 'foo', 'bar' ],
660 ApiResult
::META_INDEXED_TAG_NAME
=> 'itn',
661 ApiResult
::META_PRESERVE_KEYS
=> [ 'foo', 'bar', '_dummy2', 0 ],
662 ApiResult
::META_TYPE
=> 'array',
663 '_dummy' => 'foobaz',
664 ], $metadata, 'ApiResult::stripMetadataNonRecursive ($metadata)' );
667 $data = ApiResult
::stripMetadataNonRecursive( (object)$arr, $metadata );
668 $this->assertEquals( (object)[
670 'bar' => [ '_dummy' => 'foobaz' ],
671 'bar2' => (object)[ '_dummy' => 'foobaz' ],
673 '_dummy' => 'foobaz',
676 'bar' => [ '_dummy' => 'foobaz' ],
677 'bar2' => (object)[ '_dummy' => 'foobaz' ],
679 '_dummy' => 'foobaz',
681 '_dummy2' => 'foobaz!',
682 ], $data, 'ApiResult::stripMetadataNonRecursive on object ($data)' );
683 $this->assertEquals( [
684 ApiResult
::META_SUBELEMENTS
=> [ 'foo', 'bar' ],
685 ApiResult
::META_INDEXED_TAG_NAME
=> 'itn',
686 ApiResult
::META_PRESERVE_KEYS
=> [ 'foo', 'bar', '_dummy2', 0 ],
687 ApiResult
::META_TYPE
=> 'array',
688 '_dummy' => 'foobaz',
689 ], $metadata, 'ApiResult::stripMetadataNonRecursive on object ($metadata)' );
694 * @dataProvider provideTransformations
695 * @param string $label
696 * @param array $input
697 * @param array $transforms
698 * @param array|Exception $expect
700 public function testTransformations( $label, $input, $transforms, $expect ) {
701 $result = new ApiResult( false );
702 $result->addValue( null, 'test', $input );
704 if ( $expect instanceof Exception
) {
706 $output = $result->getResultData( 'test', $transforms );
707 $this->fail( 'Expected exception not thrown', $label );
708 } catch ( Exception
$ex ) {
709 $this->assertEquals( $ex, $expect, $label );
712 $output = $result->getResultData( 'test', $transforms );
713 $this->assertEquals( $expect, $output, $label );
717 public function provideTransformations() {
718 $kvp = function ( $keyKey, $key, $valKey, $value ) {
722 ApiResult
::META_PRESERVE_KEYS
=> [ $keyKey ],
723 ApiResult
::META_CONTENT
=> $valKey,
724 ApiResult
::META_TYPE
=> 'assoc',
728 'defaultArray' => [ 2 => 'a', 0 => 'b', 1 => 'c' ],
729 'defaultAssoc' => [ 'x' => 'a', 1 => 'b', 0 => 'c' ],
730 'defaultAssoc2' => [ 2 => 'a', 3 => 'b', 0 => 'c' ],
731 'array' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult
::META_TYPE
=> 'array' ],
732 'BCarray' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult
::META_TYPE
=> 'BCarray' ],
733 'BCassoc' => [ 'a', 'b', 'c', ApiResult
::META_TYPE
=> 'BCassoc' ],
734 'assoc' => [ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
735 'kvp' => [ 'x' => 'a', 'y' => 'b', 'z' => [ 'c' ], ApiResult
::META_TYPE
=> 'kvp' ],
736 'BCkvp' => [ 'x' => 'a', 'y' => 'b',
737 ApiResult
::META_TYPE
=> 'BCkvp',
738 ApiResult
::META_KVP_KEY_NAME
=> 'key',
740 'kvpmerge' => [ 'x' => 'a', 'y' => [ 'b' ], 'z' => [ 'c' => 'd' ],
741 ApiResult
::META_TYPE
=> 'kvp',
742 ApiResult
::META_KVP_MERGE
=> true,
744 'emptyDefault' => [ '_dummy' => 1 ],
745 'emptyAssoc' => [ '_dummy' => 1, ApiResult
::META_TYPE
=> 'assoc' ],
747 ApiResult
::META_PRESERVE_KEYS
=> [ '_dummy' ],
751 'bar' => [ '_dummy' => 'foobaz' ],
753 ApiResult
::META_SUBELEMENTS
=> [ 'foo', 'bar' ],
754 ApiResult
::META_INDEXED_TAG_NAME
=> 'itn',
755 ApiResult
::META_PRESERVE_KEYS
=> [ 'foo', 'bar', '_dummy2', 0 ],
756 ApiResult
::META_TYPE
=> 'array',
759 '_dummy' => 'foobaz',
761 ApiResult
::META_SUBELEMENTS
=> [ 'foo', 'bar' ],
762 ApiResult
::META_INDEXED_TAG_NAME
=> 'itn',
763 ApiResult
::META_PRESERVE_KEYS
=> [ 'foo', 'bar', '_dummy2', 0 ],
764 ApiResult
::META_TYPE
=> 'array',
765 '_dummy' => 'foobaz',
766 '_dummy2' => 'foobaz!',
777 ApiResult
::META_BC_BOOLS
=> [ 0, 'true', 'false' ],
784 ApiResult
::META_BC_BOOLS
=> [ 0, 'true', 'false' ],
788 'BC: META_BC_SUBELEMENTS',
792 ApiResult
::META_BC_SUBELEMENTS
=> [ 'bc' ],
798 ApiResult
::META_CONTENT
=> '*',
799 ApiResult
::META_TYPE
=> 'assoc',
802 ApiResult
::META_BC_SUBELEMENTS
=> [ 'bc' ],
809 ApiResult
::META_CONTENT
=> 'content',
814 ApiResult
::META_CONTENT
=> '*',
820 'foo' => 'foo value',
821 'bar' => 'bar value',
822 '_baz' => 'baz value',
823 ApiResult
::META_TYPE
=> 'BCkvp',
824 ApiResult
::META_KVP_KEY_NAME
=> 'key',
825 ApiResult
::META_PRESERVE_KEYS
=> [ '_baz' ],
829 $kvp( 'key', 'foo', '*', 'foo value' ),
830 $kvp( 'key', 'bar', '*', 'bar value' ),
831 $kvp( 'key', '_baz', '*', 'baz value' ),
832 ApiResult
::META_TYPE
=> 'array',
833 ApiResult
::META_KVP_KEY_NAME
=> 'key',
834 ApiResult
::META_PRESERVE_KEYS
=> [ '_baz' ],
840 ApiResult
::META_TYPE
=> 'BCarray',
844 ApiResult
::META_TYPE
=> 'default',
850 ApiResult
::META_TYPE
=> 'BCassoc',
854 ApiResult
::META_TYPE
=> 'default',
858 'BC: BCkvp exception',
860 ApiResult
::META_TYPE
=> 'BCkvp',
863 new UnexpectedValueException(
864 'Type "BCkvp" used without setting ApiResult::META_KVP_KEY_NAME metadata item'
868 'BC: nobool, no*, nosub',
872 'content' => 'content',
873 ApiResult
::META_CONTENT
=> 'content',
875 ApiResult
::META_BC_SUBELEMENTS
=> [ 'bc' ],
876 'BCarray' => [ ApiResult
::META_TYPE
=> 'BCarray' ],
877 'BCassoc' => [ ApiResult
::META_TYPE
=> 'BCassoc' ],
879 'foo' => 'foo value',
880 'bar' => 'bar value',
881 '_baz' => 'baz value',
882 ApiResult
::META_TYPE
=> 'BCkvp',
883 ApiResult
::META_KVP_KEY_NAME
=> 'key',
884 ApiResult
::META_PRESERVE_KEYS
=> [ '_baz' ],
887 [ 'BC' => [ 'nobool', 'no*', 'nosub' ] ],
891 'content' => 'content',
893 'BCarray' => [ ApiResult
::META_TYPE
=> 'default' ],
894 'BCassoc' => [ ApiResult
::META_TYPE
=> 'default' ],
896 $kvp( 'key', 'foo', '*', 'foo value' ),
897 $kvp( 'key', 'bar', '*', 'bar value' ),
898 $kvp( 'key', '_baz', '*', 'baz value' ),
899 ApiResult
::META_TYPE
=> 'array',
900 ApiResult
::META_KVP_KEY_NAME
=> 'key',
901 ApiResult
::META_PRESERVE_KEYS
=> [ '_baz' ],
903 ApiResult
::META_CONTENT
=> 'content',
904 ApiResult
::META_BC_SUBELEMENTS
=> [ 'bc' ],
909 'Types: Normal transform',
913 'defaultArray' => [ 'b', 'c', 'a', ApiResult
::META_TYPE
=> 'array' ],
914 'defaultAssoc' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
915 'defaultAssoc2' => [ 2 => 'a', 3 => 'b', 0 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
916 'array' => [ 'a', 'c', 'b', ApiResult
::META_TYPE
=> 'array' ],
917 'BCarray' => [ 'a', 'c', 'b', ApiResult
::META_TYPE
=> 'array' ],
918 'BCassoc' => [ 'a', 'b', 'c', ApiResult
::META_TYPE
=> 'assoc' ],
919 'assoc' => [ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
920 'kvp' => [ 'x' => 'a', 'y' => 'b',
921 'z' => [ 'c', ApiResult
::META_TYPE
=> 'array' ],
922 ApiResult
::META_TYPE
=> 'assoc'
924 'BCkvp' => [ 'x' => 'a', 'y' => 'b',
925 ApiResult
::META_TYPE
=> 'assoc',
926 ApiResult
::META_KVP_KEY_NAME
=> 'key',
930 'y' => [ 'b', ApiResult
::META_TYPE
=> 'array' ],
931 'z' => [ 'c' => 'd', ApiResult
::META_TYPE
=> 'assoc' ],
932 ApiResult
::META_TYPE
=> 'assoc',
933 ApiResult
::META_KVP_MERGE
=> true,
935 'emptyDefault' => [ '_dummy' => 1, ApiResult
::META_TYPE
=> 'array' ],
936 'emptyAssoc' => [ '_dummy' => 1, ApiResult
::META_TYPE
=> 'assoc' ],
938 ApiResult
::META_PRESERVE_KEYS
=> [ '_dummy' ],
939 ApiResult
::META_TYPE
=> 'assoc',
943 'Types: AssocAsObject',
945 [ 'Types' => [ 'AssocAsObject' => true ] ],
947 'defaultArray' => [ 'b', 'c', 'a', ApiResult
::META_TYPE
=> 'array' ],
948 'defaultAssoc' => (object)[ 'x' => 'a',
949 1 => 'b', 0 => 'c', ApiResult
::META_TYPE
=> 'assoc'
951 'defaultAssoc2' => (object)[ 2 => 'a', 3 => 'b',
952 0 => 'c', ApiResult
::META_TYPE
=> 'assoc'
954 'array' => [ 'a', 'c', 'b', ApiResult
::META_TYPE
=> 'array' ],
955 'BCarray' => [ 'a', 'c', 'b', ApiResult
::META_TYPE
=> 'array' ],
956 'BCassoc' => (object)[ 'a', 'b', 'c', ApiResult
::META_TYPE
=> 'assoc' ],
957 'assoc' => (object)[ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
958 'kvp' => (object)[ 'x' => 'a', 'y' => 'b',
959 'z' => [ 'c', ApiResult
::META_TYPE
=> 'array' ],
960 ApiResult
::META_TYPE
=> 'assoc'
962 'BCkvp' => (object)[ 'x' => 'a', 'y' => 'b',
963 ApiResult
::META_TYPE
=> 'assoc',
964 ApiResult
::META_KVP_KEY_NAME
=> 'key',
966 'kvpmerge' => (object)[
968 'y' => [ 'b', ApiResult
::META_TYPE
=> 'array' ],
969 'z' => (object)[ 'c' => 'd', ApiResult
::META_TYPE
=> 'assoc' ],
970 ApiResult
::META_TYPE
=> 'assoc',
971 ApiResult
::META_KVP_MERGE
=> true,
973 'emptyDefault' => [ '_dummy' => 1, ApiResult
::META_TYPE
=> 'array' ],
974 'emptyAssoc' => (object)[ '_dummy' => 1, ApiResult
::META_TYPE
=> 'assoc' ],
976 ApiResult
::META_PRESERVE_KEYS
=> [ '_dummy' ],
977 ApiResult
::META_TYPE
=> 'assoc',
983 [ 'Types' => [ 'ArmorKVP' => 'name' ] ],
985 'defaultArray' => [ 'b', 'c', 'a', ApiResult
::META_TYPE
=> 'array' ],
986 'defaultAssoc' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
987 'defaultAssoc2' => [ 2 => 'a', 3 => 'b', 0 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
988 'array' => [ 'a', 'c', 'b', ApiResult
::META_TYPE
=> 'array' ],
989 'BCarray' => [ 'a', 'c', 'b', ApiResult
::META_TYPE
=> 'array' ],
990 'BCassoc' => [ 'a', 'b', 'c', ApiResult
::META_TYPE
=> 'assoc' ],
991 'assoc' => [ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
993 $kvp( 'name', 'x', 'value', 'a' ),
994 $kvp( 'name', 'y', 'value', 'b' ),
995 $kvp( 'name', 'z', 'value', [ 'c', ApiResult
::META_TYPE
=> 'array' ] ),
996 ApiResult
::META_TYPE
=> 'array'
999 $kvp( 'key', 'x', 'value', 'a' ),
1000 $kvp( 'key', 'y', 'value', 'b' ),
1001 ApiResult
::META_TYPE
=> 'array',
1002 ApiResult
::META_KVP_KEY_NAME
=> 'key',
1005 $kvp( 'name', 'x', 'value', 'a' ),
1006 $kvp( 'name', 'y', 'value', [ 'b', ApiResult
::META_TYPE
=> 'array' ] ),
1010 ApiResult
::META_TYPE
=> 'assoc',
1011 ApiResult
::META_PRESERVE_KEYS
=> [ 'name' ]
1013 ApiResult
::META_TYPE
=> 'array',
1014 ApiResult
::META_KVP_MERGE
=> true,
1016 'emptyDefault' => [ '_dummy' => 1, ApiResult
::META_TYPE
=> 'array' ],
1017 'emptyAssoc' => [ '_dummy' => 1, ApiResult
::META_TYPE
=> 'assoc' ],
1019 ApiResult
::META_PRESERVE_KEYS
=> [ '_dummy' ],
1020 ApiResult
::META_TYPE
=> 'assoc',
1024 'Types: ArmorKVP + BC',
1026 [ 'BC' => [], 'Types' => [ 'ArmorKVP' => 'name' ] ],
1028 'defaultArray' => [ 'b', 'c', 'a', ApiResult
::META_TYPE
=> 'array' ],
1029 'defaultAssoc' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
1030 'defaultAssoc2' => [ 2 => 'a', 3 => 'b', 0 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
1031 'array' => [ 'a', 'c', 'b', ApiResult
::META_TYPE
=> 'array' ],
1032 'BCarray' => [ 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
1033 'BCassoc' => [ 'a', 'b', 'c', ApiResult
::META_TYPE
=> 'array' ],
1034 'assoc' => [ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
1036 $kvp( 'name', 'x', '*', 'a' ),
1037 $kvp( 'name', 'y', '*', 'b' ),
1038 $kvp( 'name', 'z', '*', [ 'c', ApiResult
::META_TYPE
=> 'array' ] ),
1039 ApiResult
::META_TYPE
=> 'array'
1042 $kvp( 'key', 'x', '*', 'a' ),
1043 $kvp( 'key', 'y', '*', 'b' ),
1044 ApiResult
::META_TYPE
=> 'array',
1045 ApiResult
::META_KVP_KEY_NAME
=> 'key',
1048 $kvp( 'name', 'x', '*', 'a' ),
1049 $kvp( 'name', 'y', '*', [ 'b', ApiResult
::META_TYPE
=> 'array' ] ),
1053 ApiResult
::META_TYPE
=> 'assoc',
1054 ApiResult
::META_PRESERVE_KEYS
=> [ 'name' ] ],
1055 ApiResult
::META_TYPE
=> 'array',
1056 ApiResult
::META_KVP_MERGE
=> true,
1058 'emptyDefault' => [ '_dummy' => 1, ApiResult
::META_TYPE
=> 'array' ],
1059 'emptyAssoc' => [ '_dummy' => 1, ApiResult
::META_TYPE
=> 'assoc' ],
1061 ApiResult
::META_PRESERVE_KEYS
=> [ '_dummy' ],
1062 ApiResult
::META_TYPE
=> 'assoc',
1066 'Types: ArmorKVP + AssocAsObject',
1068 [ 'Types' => [ 'ArmorKVP' => 'name', 'AssocAsObject' => true ] ],
1070 'defaultArray' => [ 'b', 'c', 'a', ApiResult
::META_TYPE
=> 'array' ],
1071 'defaultAssoc' => (object)[ 'x' => 'a', 1 => 'b',
1072 0 => 'c', ApiResult
::META_TYPE
=> 'assoc'
1074 'defaultAssoc2' => (object)[ 2 => 'a', 3 => 'b',
1075 0 => 'c', ApiResult
::META_TYPE
=> 'assoc'
1077 'array' => [ 'a', 'c', 'b', ApiResult
::META_TYPE
=> 'array' ],
1078 'BCarray' => [ 'a', 'c', 'b', ApiResult
::META_TYPE
=> 'array' ],
1079 'BCassoc' => (object)[ 'a', 'b', 'c', ApiResult
::META_TYPE
=> 'assoc' ],
1080 'assoc' => (object)[ 2 => 'a', 0 => 'b', 1 => 'c', ApiResult
::META_TYPE
=> 'assoc' ],
1082 (object)$kvp( 'name', 'x', 'value', 'a' ),
1083 (object)$kvp( 'name', 'y', 'value', 'b' ),
1084 (object)$kvp( 'name', 'z', 'value', [ 'c', ApiResult
::META_TYPE
=> 'array' ] ),
1085 ApiResult
::META_TYPE
=> 'array'
1088 (object)$kvp( 'key', 'x', 'value', 'a' ),
1089 (object)$kvp( 'key', 'y', 'value', 'b' ),
1090 ApiResult
::META_TYPE
=> 'array',
1091 ApiResult
::META_KVP_KEY_NAME
=> 'key',
1094 (object)$kvp( 'name', 'x', 'value', 'a' ),
1095 (object)$kvp( 'name', 'y', 'value', [ 'b', ApiResult
::META_TYPE
=> 'array' ] ),
1099 ApiResult
::META_TYPE
=> 'assoc',
1100 ApiResult
::META_PRESERVE_KEYS
=> [ 'name' ]
1102 ApiResult
::META_TYPE
=> 'array',
1103 ApiResult
::META_KVP_MERGE
=> true,
1105 'emptyDefault' => [ '_dummy' => 1, ApiResult
::META_TYPE
=> 'array' ],
1106 'emptyAssoc' => (object)[ '_dummy' => 1, ApiResult
::META_TYPE
=> 'assoc' ],
1108 ApiResult
::META_PRESERVE_KEYS
=> [ '_dummy' ],
1109 ApiResult
::META_TYPE
=> 'assoc',
1113 'Types: BCkvp exception',
1115 ApiResult
::META_TYPE
=> 'BCkvp',
1118 new UnexpectedValueException(
1119 'Type "BCkvp" used without setting ApiResult::META_KVP_KEY_NAME metadata item'
1124 'Strip: With ArmorKVP + AssocAsObject transforms',
1126 [ 'Types' => [ 'ArmorKVP' => 'name', 'AssocAsObject' => true ], 'Strip' => 'all' ],
1128 'defaultArray' => [ 'b', 'c', 'a' ],
1129 'defaultAssoc' => (object)[ 'x' => 'a', 1 => 'b', 0 => 'c' ],
1130 'defaultAssoc2' => (object)[ 2 => 'a', 3 => 'b', 0 => 'c' ],
1131 'array' => [ 'a', 'c', 'b' ],
1132 'BCarray' => [ 'a', 'c', 'b' ],
1133 'BCassoc' => (object)[ 'a', 'b', 'c' ],
1134 'assoc' => (object)[ 2 => 'a', 0 => 'b', 1 => 'c' ],
1136 (object)[ 'name' => 'x', 'value' => 'a' ],
1137 (object)[ 'name' => 'y', 'value' => 'b' ],
1138 (object)[ 'name' => 'z', 'value' => [ 'c' ] ],
1141 (object)[ 'key' => 'x', 'value' => 'a' ],
1142 (object)[ 'key' => 'y', 'value' => 'b' ],
1145 (object)[ 'name' => 'x', 'value' => 'a' ],
1146 (object)[ 'name' => 'y', 'value' => [ 'b' ] ],
1147 (object)[ 'name' => 'z', 'c' => 'd' ],
1149 'emptyDefault' => [],
1150 'emptyAssoc' => (object)[],
1158 [ 'Strip' => 'all' ],
1165 '_dummy2' => 'foobaz!',
1171 [ 'Strip' => 'base' ],
1174 'bar' => [ '_dummy' => 'foobaz' ],
1176 ApiResult
::META_SUBELEMENTS
=> [ 'foo', 'bar' ],
1177 ApiResult
::META_INDEXED_TAG_NAME
=> 'itn',
1178 ApiResult
::META_PRESERVE_KEYS
=> [ 'foo', 'bar', '_dummy2', 0 ],
1179 ApiResult
::META_TYPE
=> 'array',
1182 '_dummy' => 'foobaz',
1184 '_dummy2' => 'foobaz!',
1190 [ 'Strip' => 'bc' ],
1195 ApiResult
::META_SUBELEMENTS
=> [ 'foo', 'bar' ],
1196 ApiResult
::META_INDEXED_TAG_NAME
=> 'itn',
1200 '_dummy2' => 'foobaz!',
1201 ApiResult
::META_SUBELEMENTS
=> [ 'foo', 'bar' ],
1202 ApiResult
::META_INDEXED_TAG_NAME
=> 'itn',
1214 ApiResult
::META_CONTENT
=> 'foo',
1215 ApiResult
::META_PRESERVE_KEYS
=> [ '_dummy2', '_dummy3' ],
1218 'Custom' => [ $this, 'customTransform' ],
1226 'baz' => [ 'a', 'b' ],
1227 '_dummy2' => '_DUMMY2',
1228 '_dummy3' => '_DUMMY3',
1229 ApiResult
::META_CONTENT
=> 'bar',
1237 * Custom transformer for testTransformations
1238 * @param array &$data
1239 * @param array &$metadata
1241 public function customTransform( &$data, &$metadata ) {
1242 // Prevent recursion
1243 if ( isset( $metadata['_added'] ) ) {
1244 $metadata[ApiResult
::META_TYPE
] = 'array';
1248 foreach ( $data as $k => $v ) {
1249 $data[$k] = strtoupper( $k );
1251 $data['baz'] = [ '_added' => 1, 'z' => 'b', 'y' => 'a' ];
1252 $metadata[ApiResult
::META_PRESERVE_KEYS
][0] = '_dummy';
1253 $data[ApiResult
::META_CONTENT
] = 'bar';
1259 public function testAddMetadataToResultVars() {
1264 'sequential_numeric_keys' => [ 'a', 'b', 'c' ],
1265 'non_sequential_numeric_keys' => [ 'a', 'b', 4 => 'c' ],
1270 'object_sequential_keys' => (object)[ 'a', 'b', 'c' ],
1271 '_type' => "should be overwritten in result",
1273 $this->assertSame( [
1274 ApiResult
::META_TYPE
=> 'kvp',
1275 ApiResult
::META_KVP_KEY_NAME
=> 'key',
1276 ApiResult
::META_PRESERVE_KEYS
=> [
1278 'sequential_numeric_keys', 'non_sequential_numeric_keys',
1279 'string_keys', 'object_sequential_keys'
1281 ApiResult
::META_BC_BOOLS
=> [ 'b' ],
1282 ApiResult
::META_INDEXED_TAG_NAME
=> 'var',
1286 'sequential_numeric_keys' => [
1287 ApiResult
::META_TYPE
=> 'array',
1288 ApiResult
::META_BC_BOOLS
=> [],
1289 ApiResult
::META_INDEXED_TAG_NAME
=> 'value',
1294 'non_sequential_numeric_keys' => [
1295 ApiResult
::META_TYPE
=> 'kvp',
1296 ApiResult
::META_KVP_KEY_NAME
=> 'key',
1297 ApiResult
::META_PRESERVE_KEYS
=> [ 0, 1, 4 ],
1298 ApiResult
::META_BC_BOOLS
=> [],
1299 ApiResult
::META_INDEXED_TAG_NAME
=> 'var',
1305 ApiResult
::META_TYPE
=> 'kvp',
1306 ApiResult
::META_KVP_KEY_NAME
=> 'key',
1307 ApiResult
::META_PRESERVE_KEYS
=> [ 'one', 'two' ],
1308 ApiResult
::META_BC_BOOLS
=> [],
1309 ApiResult
::META_INDEXED_TAG_NAME
=> 'var',
1313 'object_sequential_keys' => [
1314 ApiResult
::META_TYPE
=> 'kvp',
1315 ApiResult
::META_KVP_KEY_NAME
=> 'key',
1316 ApiResult
::META_PRESERVE_KEYS
=> [ 0, 1, 2 ],
1317 ApiResult
::META_BC_BOOLS
=> [],
1318 ApiResult
::META_INDEXED_TAG_NAME
=> 'var',
1323 ], ApiResult
::addMetadataToResultVars( $arr ) );
1329 public function testDeprecatedFunctions() {
1330 // Ignore ApiResult deprecation warnings during this test
1331 set_error_handler( function ( $errno, $errstr ) use ( &$warnings ) {
1332 if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
1335 if ( preg_match( '/Use of ApiMain to ApiResult::__construct ' .
1336 'was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
1341 $reset = new ScopedCallback( 'restore_error_handler' );
1343 $context = new DerivativeContext( RequestContext
::getMain() );
1344 $context->setConfig( new HashConfig( [
1346 'APIFormatModules' => [],
1347 'APIMaxResultSize' => 42,
1349 $main = new ApiMain( $context );
1350 $result = TestingAccessWrapper
::newFromObject( new ApiResult( $main ) );
1351 $this->assertSame( 42, $result->maxSize
);
1352 $this->assertSame( $main->getErrorFormatter(), $result->errorFormatter
);
1353 $this->assertSame( $main, $result->mainForContinuation
);
1355 $result = new ApiResult( 8388608 );
1357 $result->addContentValue( null, 'test', 'content' );
1358 $result->addContentValue( [ 'foo', 'bar' ], 'test', 'content' );
1359 $result->addIndexedTagName( null, 'itn' );
1360 $result->addSubelementsList( null, [ 'sub' ] );
1361 $this->assertSame( [
1368 ], $result->getData() );
1371 ApiResult
::setContent( $arr, 'value' );
1372 ApiResult
::setContent( $arr, 'value2', 'foobar' );
1373 $this->assertSame( [
1374 ApiResult
::META_CONTENT
=> 'content',
1375 'content' => 'value',
1377 ApiResult
::META_CONTENT
=> 'content',
1378 'content' => 'value2',
1382 $result = new ApiResult( 3 );
1383 $formatter = new ApiErrorFormatter_BackCompat( $result );
1384 $result->setErrorFormatter( $formatter );
1385 $result->disableSizeCheck();
1386 $this->assertTrue( $result->addValue( null, 'foo', '1234567890' ) );
1387 $result->enableSizeCheck();
1388 $this->assertSame( 0, $result->getSize() );
1389 $this->assertFalse( $result->addValue( null, 'foo', '1234567890' ) );
1391 $arr = [ 'foo' => [ 'bar' => 1 ] ];
1392 $result->setIndexedTagName_recursive( $arr, 'itn' );
1393 $this->assertSame( [
1396 ApiResult
::META_INDEXED_TAG_NAME
=> 'itn'
1400 $status = Status
::newGood();
1401 $status->fatal( 'parentheses', '1' );
1402 $status->fatal( 'parentheses', '2' );
1403 $status->warning( 'parentheses', '3' );
1404 $status->warning( 'parentheses', '4' );
1405 $this->assertSame( [
1408 'message' => 'parentheses',
1411 ApiResult
::META_INDEXED_TAG_NAME
=> 'param',
1416 'message' => 'parentheses',
1419 ApiResult
::META_INDEXED_TAG_NAME
=> 'param',
1422 ApiResult
::META_INDEXED_TAG_NAME
=> 'error',
1423 ], $result->convertStatusToArray( $status, 'error' ) );
1424 $this->assertSame( [
1426 'type' => 'warning',
1427 'message' => 'parentheses',
1430 ApiResult
::META_INDEXED_TAG_NAME
=> 'param',
1434 'type' => 'warning',
1435 'message' => 'parentheses',
1438 ApiResult
::META_INDEXED_TAG_NAME
=> 'param',
1441 ApiResult
::META_INDEXED_TAG_NAME
=> 'warning',
1442 ], $result->convertStatusToArray( $status, 'warning' ) );
1448 public function testDeprecatedContinuation() {
1449 // Ignore ApiResult deprecation warnings during this test
1450 set_error_handler( function ( $errno, $errstr ) use ( &$warnings ) {
1451 if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
1457 $reset = new ScopedCallback( 'restore_error_handler' );
1459 new MockApiQueryBase( 'mock1' ),
1460 new MockApiQueryBase( 'mock2' ),
1461 new MockApiQueryBase( 'mocklist' ),
1463 $generator = new MockApiQueryBase( 'generator' );
1465 $main = new ApiMain( RequestContext
::getMain() );
1466 $result = new ApiResult( 8388608 );
1467 $result->setMainForContinuation( $main );
1468 $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
1469 $this->assertSame( [ false, $allModules ], $ret );
1470 $result->setContinueParam( $allModules[0], 'm1continue', [ 1, 2 ] );
1471 $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
1472 $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
1473 $result->endContinuation( 'raw' );
1474 $result->endContinuation( 'standard' );
1475 $this->assertSame( [
1477 'm1continue' => '1|2',
1478 'continue' => '||mock2',
1479 ], $result->getResultData( 'continue' ) );
1480 $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
1481 $this->assertSame( [
1482 'mock1' => [ 'm1continue' => '1|2' ],
1483 'mocklist' => [ 'mlcontinue' => 2 ],
1484 'generator' => [ 'gcontinue' => 3 ],
1485 ], $result->getResultData( 'query-continue' ) );
1486 $main->setContinuationManager( null );
1488 $result = new ApiResult( 8388608 );
1489 $result->setMainForContinuation( $main );
1490 $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
1491 $this->assertSame( [ false, $allModules ], $ret );
1492 $result->setContinueParam( $allModules[0], 'm1continue', [ 1, 2 ] );
1493 $result->setGeneratorContinueParam( $generator, 'gcontinue', [ 3, 4 ] );
1494 $result->endContinuation( 'raw' );
1495 $result->endContinuation( 'standard' );
1496 $this->assertSame( [
1497 'm1continue' => '1|2',
1498 'continue' => '||mock2|mocklist',
1499 ], $result->getResultData( 'continue' ) );
1500 $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
1501 $this->assertSame( [
1502 'mock1' => [ 'm1continue' => '1|2' ],
1503 'generator' => [ 'gcontinue' => '3|4' ],
1504 ], $result->getResultData( 'query-continue' ) );
1505 $main->setContinuationManager( null );
1507 $result = new ApiResult( 8388608 );
1508 $result->setMainForContinuation( $main );
1509 $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
1510 $this->assertSame( [ false, $allModules ], $ret );
1511 $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
1512 $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
1513 $result->endContinuation( 'raw' );
1514 $result->endContinuation( 'standard' );
1515 $this->assertSame( [
1518 'continue' => 'gcontinue||',
1519 ], $result->getResultData( 'continue' ) );
1520 $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
1521 $this->assertSame( [
1522 'mocklist' => [ 'mlcontinue' => 2 ],
1523 'generator' => [ 'gcontinue' => 3 ],
1524 ], $result->getResultData( 'query-continue' ) );
1525 $main->setContinuationManager( null );
1527 $result = new ApiResult( 8388608 );
1528 $result->setMainForContinuation( $main );
1529 $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
1530 $this->assertSame( [ false, $allModules ], $ret );
1531 $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
1532 $result->endContinuation( 'raw' );
1533 $result->endContinuation( 'standard' );
1534 $this->assertSame( [
1536 'continue' => 'gcontinue||mocklist',
1537 ], $result->getResultData( 'continue' ) );
1538 $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
1539 $this->assertSame( [
1540 'generator' => [ 'gcontinue' => 3 ],
1541 ], $result->getResultData( 'query-continue' ) );
1542 $main->setContinuationManager( null );
1544 $result = new ApiResult( 8388608 );
1545 $result->setMainForContinuation( $main );
1546 $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
1547 $this->assertSame( [ false, $allModules ], $ret );
1548 $result->setContinueParam( $allModules[0], 'm1continue', [ 1, 2 ] );
1549 $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
1550 $result->endContinuation( 'raw' );
1551 $result->endContinuation( 'standard' );
1552 $this->assertSame( [
1554 'm1continue' => '1|2',
1555 'continue' => '||mock2',
1556 ], $result->getResultData( 'continue' ) );
1557 $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
1558 $this->assertSame( [
1559 'mock1' => [ 'm1continue' => '1|2' ],
1560 'mocklist' => [ 'mlcontinue' => 2 ],
1561 ], $result->getResultData( 'query-continue' ) );
1562 $main->setContinuationManager( null );
1564 $result = new ApiResult( 8388608 );
1565 $result->setMainForContinuation( $main );
1566 $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
1567 $this->assertSame( [ false, $allModules ], $ret );
1568 $result->setContinueParam( $allModules[0], 'm1continue', [ 1, 2 ] );
1569 $result->endContinuation( 'raw' );
1570 $result->endContinuation( 'standard' );
1571 $this->assertSame( [
1572 'm1continue' => '1|2',
1573 'continue' => '||mock2|mocklist',
1574 ], $result->getResultData( 'continue' ) );
1575 $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
1576 $this->assertSame( [
1577 'mock1' => [ 'm1continue' => '1|2' ],
1578 ], $result->getResultData( 'query-continue' ) );
1579 $main->setContinuationManager( null );
1581 $result = new ApiResult( 8388608 );
1582 $result->setMainForContinuation( $main );
1583 $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
1584 $this->assertSame( [ false, $allModules ], $ret );
1585 $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
1586 $result->endContinuation( 'raw' );
1587 $result->endContinuation( 'standard' );
1588 $this->assertSame( [
1590 'continue' => '-||mock1|mock2',
1591 ], $result->getResultData( 'continue' ) );
1592 $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
1593 $this->assertSame( [
1594 'mocklist' => [ 'mlcontinue' => 2 ],
1595 ], $result->getResultData( 'query-continue' ) );
1596 $main->setContinuationManager( null );
1598 $result = new ApiResult( 8388608 );
1599 $result->setMainForContinuation( $main );
1600 $ret = $result->beginContinuation( null, $allModules, [ 'mock1', 'mock2' ] );
1601 $this->assertSame( [ false, $allModules ], $ret );
1602 $result->endContinuation( 'raw' );
1603 $result->endContinuation( 'standard' );
1604 $this->assertSame( null, $result->getResultData( 'continue' ) );
1605 $this->assertSame( true, $result->getResultData( 'batchcomplete' ) );
1606 $this->assertSame( null, $result->getResultData( 'query-continue' ) );
1607 $main->setContinuationManager( null );
1609 $result = new ApiResult( 8388608 );
1610 $result->setMainForContinuation( $main );
1611 $ret = $result->beginContinuation( '||mock2', $allModules, [ 'mock1', 'mock2' ] );
1613 [ false, array_values( array_diff_key( $allModules, [ 1 => 1 ] ) ) ],
1616 $main->setContinuationManager( null );
1618 $result = new ApiResult( 8388608 );
1619 $result->setMainForContinuation( $main );
1620 $ret = $result->beginContinuation( '-||', $allModules, [ 'mock1', 'mock2' ] );
1622 [ true, array_values( array_diff_key( $allModules, [ 0 => 0, 1 => 1 ] ) ) ],
1625 $main->setContinuationManager( null );
1627 $result = new ApiResult( 8388608 );
1628 $result->setMainForContinuation( $main );
1630 $result->beginContinuation( 'foo', $allModules, [ 'mock1', 'mock2' ] );
1631 $this->fail( 'Expected exception not thrown' );
1632 } catch ( UsageException
$ex ) {
1634 'Invalid continue param. You should pass the original value returned by the previous query',
1636 'Expected exception'
1639 $main->setContinuationManager( null );
1641 $result = new ApiResult( 8388608 );
1642 $result->setMainForContinuation( $main );
1643 $result->beginContinuation( '||mock2', array_slice( $allModules, 0, 2 ),
1644 [ 'mock1', 'mock2' ] );
1646 $result->setContinueParam( $allModules[1], 'm2continue', 1 );
1647 $this->fail( 'Expected exception not thrown' );
1648 } catch ( UnexpectedValueException
$ex ) {
1650 'Module \'mock2\' was not supposed to have been executed, but it was executed anyway',
1652 'Expected exception'
1656 $result->setContinueParam( $allModules[2], 'mlcontinue', 1 );
1657 $this->fail( 'Expected exception not thrown' );
1658 } catch ( UnexpectedValueException
$ex ) {
1660 'Module \'mocklist\' called ApiContinuationManager::addContinueParam ' .
1661 'but was not passed to ApiContinuationManager::__construct',
1663 'Expected exception'
1666 $main->setContinuationManager( null );
1670 public function testObjectSerialization() {
1672 ApiResult
::setValue( $arr, 'foo', (object)[ 'a' => 1, 'b' => 2 ] );
1673 $this->assertSame( [
1676 ApiResult
::META_TYPE
=> 'assoc',
1680 ApiResult
::setValue( $arr, 'foo', new ApiResultTestStringifiableObject() );
1681 $this->assertSame( 'Ok', $arr['foo'] );
1684 ApiResult
::setValue( $arr, 'foo', new ApiResultTestSerializableObject( 'Ok' ) );
1685 $this->assertSame( 'Ok', $arr['foo'] );
1689 ApiResult
::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
1690 new ApiResultTestStringifiableObject()
1692 $this->fail( 'Expected exception not thrown' );
1693 } catch ( UnexpectedValueException
$ex ) {
1695 'ApiResultTestSerializableObject::serializeForApiResult() ' .
1696 'returned an object of class ApiResultTestStringifiableObject',
1698 'Expected exception'
1704 ApiResult
::setValue( $arr, 'foo', new ApiResultTestSerializableObject( NAN
) );
1705 $this->fail( 'Expected exception not thrown' );
1706 } catch ( UnexpectedValueException
$ex ) {
1708 'ApiResultTestSerializableObject::serializeForApiResult() ' .
1709 'returned an invalid value: Cannot add non-finite floats to ApiResult',
1711 'Expected exception'
1716 ApiResult
::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
1718 'one' => new ApiResultTestStringifiableObject( '1' ),
1719 'two' => new ApiResultTestSerializableObject( 2 ),
1722 $this->assertSame( [
1730 class ApiResultTestStringifiableObject
{
1733 public function __construct( $ret = 'Ok' ) {
1737 public function __toString() {
1742 class ApiResultTestSerializableObject
{
1745 public function __construct( $ret ) {
1749 public function __toString() {
1753 public function serializeForApiResult() {