Merge "Add $linkTrail for Western Baluchi (bgn)"
[lhc/web/wiklou.git] / tests / phpunit / includes / api / ApiResultTest.php
1 <?php
2
3 /**
4 * @covers ApiResult
5 * @group API
6 */
7 class ApiResultTest extends MediaWikiTestCase {
8
9 /**
10 * @covers ApiResult
11 */
12 public function testStaticDataMethods() {
13 $arr = array();
14
15 ApiResult::setValue( $arr, 'setValue', '1' );
16
17 ApiResult::setValue( $arr, null, 'unnamed 1' );
18 ApiResult::setValue( $arr, null, 'unnamed 2' );
19
20 ApiResult::setValue( $arr, 'deleteValue', '2' );
21 ApiResult::unsetValue( $arr, 'deleteValue' );
22
23 ApiResult::setContentValue( $arr, 'setContentValue', '3' );
24
25 $this->assertSame( array(
26 'setValue' => '1',
27 'unnamed 1',
28 'unnamed 2',
29 ApiResult::META_CONTENT => 'setContentValue',
30 'setContentValue' => '3',
31 ), $arr );
32
33 try {
34 ApiResult::setValue( $arr, 'setValue', '99' );
35 $this->fail( 'Expected exception not thrown' );
36 } catch ( RuntimeException $ex ) {
37 $this->assertSame(
38 'Attempting to add element setValue=99, existing value is 1',
39 $ex->getMessage(),
40 'Expected exception'
41 );
42 }
43
44 try {
45 ApiResult::setContentValue( $arr, 'setContentValue2', '99' );
46 $this->fail( 'Expected exception not thrown' );
47 } catch ( RuntimeException $ex ) {
48 $this->assertSame(
49 'Attempting to set content element as setContentValue2 when setContentValue ' .
50 'is already set as the content element',
51 $ex->getMessage(),
52 'Expected exception'
53 );
54 }
55
56 ApiResult::setValue( $arr, 'setValue', '99', ApiResult::OVERRIDE );
57 $this->assertSame( '99', $arr['setValue'] );
58
59 ApiResult::setContentValue( $arr, 'setContentValue2', '99', ApiResult::OVERRIDE );
60 $this->assertSame( 'setContentValue2', $arr[ApiResult::META_CONTENT] );
61
62 $arr = array( '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( array( 0, 'top', 'foo', 'bar', 'bottom' ), array_keys( $arr ) );
69
70 $arr = array();
71 ApiResult::setValue( $arr, 'sub', array( 'foo' => 1 ) );
72 ApiResult::setValue( $arr, 'sub', array( 'bar' => 1 ) );
73 $this->assertSame( array( 'sub' => array( 'foo' => 1, 'bar' => 1 ) ), $arr );
74
75 try {
76 ApiResult::setValue( $arr, 'sub', array( 'foo' => 2, 'baz' => 2 ) );
77 $this->fail( 'Expected exception not thrown' );
78 } catch ( RuntimeException $ex ) {
79 $this->assertSame(
80 'Conflicting keys (foo) when attempting to merge element sub',
81 $ex->getMessage(),
82 'Expected exception'
83 );
84 }
85
86 $arr = array();
87 $title = Title::newFromText( "MediaWiki:Foobar" );
88 $obj = new stdClass;
89 $obj->foo = 1;
90 $obj->bar = 2;
91 ApiResult::setValue( $arr, 'title', $title );
92 ApiResult::setValue( $arr, 'obj', $obj );
93 $this->assertSame( array(
94 'title' => (string)$title,
95 'obj' => array( 'foo' => 1, 'bar' => 2, ApiResult::META_TYPE => 'assoc' ),
96 ), $arr );
97
98 $fh = tmpfile();
99 try {
100 ApiResult::setValue( $arr, 'file', $fh );
101 $this->fail( 'Expected exception not thrown' );
102 } catch ( InvalidArgumentException $ex ) {
103 $this->assertSame(
104 'Cannot add resource(stream) to ApiResult',
105 $ex->getMessage(),
106 'Expected exception'
107 );
108 }
109 try {
110 $obj->file = $fh;
111 ApiResult::setValue( $arr, 'sub', $obj );
112 $this->fail( 'Expected exception not thrown' );
113 } catch ( InvalidArgumentException $ex ) {
114 $this->assertSame(
115 'Cannot add resource(stream) to ApiResult',
116 $ex->getMessage(),
117 'Expected exception'
118 );
119 }
120 fclose( $fh );
121
122 try {
123 ApiResult::setValue( $arr, 'inf', INF );
124 $this->fail( 'Expected exception not thrown' );
125 } catch ( InvalidArgumentException $ex ) {
126 $this->assertSame(
127 'Cannot add non-finite floats to ApiResult',
128 $ex->getMessage(),
129 'Expected exception'
130 );
131 }
132 try {
133 ApiResult::setValue( $arr, 'nan', NAN );
134 $this->fail( 'Expected exception not thrown' );
135 } catch ( InvalidArgumentException $ex ) {
136 $this->assertSame(
137 'Cannot add non-finite floats to ApiResult',
138 $ex->getMessage(),
139 'Expected exception'
140 );
141 }
142
143 $arr = array();
144 $result2 = new ApiResult( 8388608 );
145 $result2->addValue( null, 'foo', 'bar' );
146 ApiResult::setValue( $arr, 'baz', $result2 );
147 $this->assertSame( array( 'baz' => array( 'foo' => 'bar' ) ), $arr );
148
149 $arr = array();
150 ApiResult::setValue( $arr, 'foo', "foo\x80bar" );
151 ApiResult::setValue( $arr, 'bar', "a\xcc\x81" );
152 ApiResult::setValue( $arr, 'baz', 74 );
153 $this->assertSame( array(
154 'foo' => "foo\xef\xbf\xbdbar",
155 'bar' => "\xc3\xa1",
156 'baz' => 74,
157 ), $arr );
158 }
159
160 /**
161 * @covers ApiResult
162 */
163 public function testInstanceDataMethods() {
164 $result = new ApiResult( 8388608 );
165
166 $result->addValue( null, 'setValue', '1' );
167
168 $result->addValue( null, null, 'unnamed 1' );
169 $result->addValue( null, null, 'unnamed 2' );
170
171 $result->addValue( null, 'deleteValue', '2' );
172 $result->removeValue( null, 'deleteValue' );
173
174 $result->addValue( array( 'a', 'b' ), 'deleteValue', '3' );
175 $result->removeValue( array( 'a', 'b', 'deleteValue' ), null, '3' );
176
177 $result->addContentValue( null, 'setContentValue', '3' );
178
179 $this->assertSame( array(
180 'setValue' => '1',
181 'unnamed 1',
182 'unnamed 2',
183 'a' => array( 'b' => array() ),
184 'setContentValue' => '3',
185 ApiResult::META_CONTENT => 'setContentValue',
186 ), $result->getResultData() );
187 $this->assertSame( 20, $result->getSize() );
188
189 try {
190 $result->addValue( null, 'setValue', '99' );
191 $this->fail( 'Expected exception not thrown' );
192 } catch ( RuntimeException $ex ) {
193 $this->assertSame(
194 'Attempting to add element setValue=99, existing value is 1',
195 $ex->getMessage(),
196 'Expected exception'
197 );
198 }
199
200 try {
201 $result->addContentValue( null, 'setContentValue2', '99' );
202 $this->fail( 'Expected exception not thrown' );
203 } catch ( RuntimeException $ex ) {
204 $this->assertSame(
205 'Attempting to set content element as setContentValue2 when setContentValue ' .
206 'is already set as the content element',
207 $ex->getMessage(),
208 'Expected exception'
209 );
210 }
211
212 $result->addValue( null, 'setValue', '99', ApiResult::OVERRIDE );
213 $this->assertSame( '99', $result->getResultData( array( 'setValue' ) ) );
214
215 $result->addContentValue( null, 'setContentValue2', '99', ApiResult::OVERRIDE );
216 $this->assertSame( 'setContentValue2',
217 $result->getResultData( array( ApiResult::META_CONTENT ) ) );
218
219 $result->reset();
220 $this->assertSame( array(), $result->getResultData() );
221 $this->assertSame( 0, $result->getSize() );
222
223 $result->addValue( null, 'foo', 1 );
224 $result->addValue( null, 'bar', 1 );
225 $result->addValue( null, 'top', '2', ApiResult::ADD_ON_TOP );
226 $result->addValue( null, null, '2', ApiResult::ADD_ON_TOP );
227 $result->addValue( null, 'bottom', '2' );
228 $result->addValue( null, 'foo', '2', ApiResult::OVERRIDE );
229 $result->addValue( null, 'bar', '2', ApiResult::OVERRIDE | ApiResult::ADD_ON_TOP );
230 $this->assertSame( array( 0, 'top', 'foo', 'bar', 'bottom' ),
231 array_keys( $result->getResultData() ) );
232
233 $result->reset();
234 $result->addValue( null, 'foo', array( 'bar' => 1 ) );
235 $result->addValue( array( 'foo', 'top' ), 'x', 2, ApiResult::ADD_ON_TOP );
236 $result->addValue( array( 'foo', 'bottom' ), 'x', 2 );
237 $this->assertSame( array( 'top', 'bar', 'bottom' ),
238 array_keys( $result->getResultData( array( 'foo' ) ) ) );
239
240 $result->reset();
241 $result->addValue( null, 'sub', array( 'foo' => 1 ) );
242 $result->addValue( null, 'sub', array( 'bar' => 1 ) );
243 $this->assertSame( array( 'sub' => array( 'foo' => 1, 'bar' => 1 ) ),
244 $result->getResultData() );
245
246 try {
247 $result->addValue( null, 'sub', array( 'foo' => 2, 'baz' => 2 ) );
248 $this->fail( 'Expected exception not thrown' );
249 } catch ( RuntimeException $ex ) {
250 $this->assertSame(
251 'Conflicting keys (foo) when attempting to merge element sub',
252 $ex->getMessage(),
253 'Expected exception'
254 );
255 }
256
257 $result->reset();
258 $title = Title::newFromText( "MediaWiki:Foobar" );
259 $obj = new stdClass;
260 $obj->foo = 1;
261 $obj->bar = 2;
262 $result->addValue( null, 'title', $title );
263 $result->addValue( null, 'obj', $obj );
264 $this->assertSame( array(
265 'title' => (string)$title,
266 'obj' => array( 'foo' => 1, 'bar' => 2, ApiResult::META_TYPE => 'assoc' ),
267 ), $result->getResultData() );
268
269 $fh = tmpfile();
270 try {
271 $result->addValue( null, 'file', $fh );
272 $this->fail( 'Expected exception not thrown' );
273 } catch ( InvalidArgumentException $ex ) {
274 $this->assertSame(
275 'Cannot add resource(stream) to ApiResult',
276 $ex->getMessage(),
277 'Expected exception'
278 );
279 }
280 try {
281 $obj->file = $fh;
282 $result->addValue( null, 'sub', $obj );
283 $this->fail( 'Expected exception not thrown' );
284 } catch ( InvalidArgumentException $ex ) {
285 $this->assertSame(
286 'Cannot add resource(stream) to ApiResult',
287 $ex->getMessage(),
288 'Expected exception'
289 );
290 }
291 fclose( $fh );
292
293 try {
294 $result->addValue( null, 'inf', INF );
295 $this->fail( 'Expected exception not thrown' );
296 } catch ( InvalidArgumentException $ex ) {
297 $this->assertSame(
298 'Cannot add non-finite floats to ApiResult',
299 $ex->getMessage(),
300 'Expected exception'
301 );
302 }
303 try {
304 $result->addValue( null, 'nan', NAN );
305 $this->fail( 'Expected exception not thrown' );
306 } catch ( InvalidArgumentException $ex ) {
307 $this->assertSame(
308 'Cannot add non-finite floats to ApiResult',
309 $ex->getMessage(),
310 'Expected exception'
311 );
312 }
313
314 $result->reset();
315 $result->addParsedLimit( 'foo', 12 );
316 $this->assertSame( array( 'limits' => array( 'foo' => 12 ) ), $result->getResultData() );
317 $result->addParsedLimit( 'foo', 13 );
318 $this->assertSame( array( 'limits' => array( 'foo' => 13 ) ), $result->getResultData() );
319 $this->assertSame( null, $result->getResultData( array( 'foo', 'bar', 'baz' ) ) );
320 $this->assertSame( 13, $result->getResultData( array( 'limits', 'foo' ) ) );
321 try {
322 $result->getResultData( array( 'limits', 'foo', 'bar' ) );
323 $this->fail( 'Expected exception not thrown' );
324 } catch ( InvalidArgumentException $ex ) {
325 $this->assertSame(
326 'Path limits.foo is not an array',
327 $ex->getMessage(),
328 'Expected exception'
329 );
330 }
331
332 $result = new ApiResult( 10 );
333 $formatter = new ApiErrorFormatter( $result, Language::factory( 'en' ), 'none', false );
334 $result->setErrorFormatter( $formatter );
335 $this->assertFalse( $result->addValue( null, 'foo', '12345678901' ) );
336 $this->assertTrue( $result->addValue( null, 'foo', '12345678901', ApiResult::NO_SIZE_CHECK ) );
337 $this->assertSame( 0, $result->getSize() );
338 $result->reset();
339 $this->assertTrue( $result->addValue( null, 'foo', '1234567890' ) );
340 $this->assertFalse( $result->addValue( null, 'foo', '1' ) );
341 $result->removeValue( null, 'foo' );
342 $this->assertTrue( $result->addValue( null, 'foo', '1' ) );
343
344 $result = new ApiResult( 8388608 );
345 $result2 = new ApiResult( 8388608 );
346 $result2->addValue( null, 'foo', 'bar' );
347 $result->addValue( null, 'baz', $result2 );
348 $this->assertSame( array( 'baz' => array( 'foo' => 'bar' ) ), $result->getResultData() );
349
350 $result = new ApiResult( 8388608 );
351 $result->addValue( null, 'foo', "foo\x80bar" );
352 $result->addValue( null, 'bar', "a\xcc\x81" );
353 $result->addValue( null, 'baz', 74 );
354 $this->assertSame( array(
355 'foo' => "foo\xef\xbf\xbdbar",
356 'bar' => "\xc3\xa1",
357 'baz' => 74,
358 ), $result->getResultData() );
359 }
360
361 /**
362 * @covers ApiResult
363 */
364 public function testMetadata() {
365 $arr = array( 'foo' => array( 'bar' => array() ) );
366 $result = new ApiResult( 8388608 );
367 $result->addValue( null, 'foo', array( 'bar' => array() ) );
368
369 $expect = array(
370 'foo' => array(
371 'bar' => array(
372 ApiResult::META_INDEXED_TAG_NAME => 'ritn',
373 ApiResult::META_TYPE => 'default',
374 ),
375 ApiResult::META_INDEXED_TAG_NAME => 'ritn',
376 ApiResult::META_TYPE => 'default',
377 ),
378 ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
379 ApiResult::META_INDEXED_TAG_NAME => 'itn',
380 ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar' ),
381 ApiResult::META_TYPE => 'array',
382 );
383
384 ApiResult::setSubelementsList( $arr, 'foo' );
385 ApiResult::setSubelementsList( $arr, array( 'bar', 'baz' ) );
386 ApiResult::unsetSubelementsList( $arr, 'baz' );
387 ApiResult::setIndexedTagNameRecursive( $arr, 'ritn' );
388 ApiResult::setIndexedTagName( $arr, 'itn' );
389 ApiResult::setPreserveKeysList( $arr, 'foo' );
390 ApiResult::setPreserveKeysList( $arr, array( 'bar', 'baz' ) );
391 ApiResult::unsetPreserveKeysList( $arr, 'baz' );
392 ApiResult::setArrayTypeRecursive( $arr, 'default' );
393 ApiResult::setArrayType( $arr, 'array' );
394 $this->assertSame( $expect, $arr );
395
396 $result->addSubelementsList( null, 'foo' );
397 $result->addSubelementsList( null, array( 'bar', 'baz' ) );
398 $result->removeSubelementsList( null, 'baz' );
399 $result->addIndexedTagNameRecursive( null, 'ritn' );
400 $result->addIndexedTagName( null, 'itn' );
401 $result->addPreserveKeysList( null, 'foo' );
402 $result->addPreserveKeysList( null, array( 'bar', 'baz' ) );
403 $result->removePreserveKeysList( null, 'baz' );
404 $result->addArrayTypeRecursive( null, 'default' );
405 $result->addArrayType( null, 'array' );
406 $this->assertSame( $expect, $result->getResultData() );
407
408 $arr = array( 'foo' => array( 'bar' => array() ) );
409 $expect = array(
410 'foo' => array(
411 'bar' => array(
412 ApiResult::META_TYPE => 'kvp',
413 ApiResult::META_KVP_KEY_NAME => 'key',
414 ),
415 ApiResult::META_TYPE => 'kvp',
416 ApiResult::META_KVP_KEY_NAME => 'key',
417 ),
418 ApiResult::META_TYPE => 'BCkvp',
419 ApiResult::META_KVP_KEY_NAME => 'bc',
420 );
421 ApiResult::setArrayTypeRecursive( $arr, 'kvp', 'key' );
422 ApiResult::setArrayType( $arr, 'BCkvp', 'bc' );
423 $this->assertSame( $expect, $arr );
424 }
425
426 /**
427 * @covers ApiResult
428 */
429 public function testUtilityFunctions() {
430 $arr = array(
431 'foo' => array(
432 'bar' => array( '_dummy' => 'foobaz' ),
433 'bar2' => (object)array( '_dummy' => 'foobaz' ),
434 'x' => 'ok',
435 '_dummy' => 'foobaz',
436 ),
437 'foo2' => (object)array(
438 'bar' => array( '_dummy' => 'foobaz' ),
439 'bar2' => (object)array( '_dummy' => 'foobaz' ),
440 'x' => 'ok',
441 '_dummy' => 'foobaz',
442 ),
443 ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
444 ApiResult::META_INDEXED_TAG_NAME => 'itn',
445 ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
446 ApiResult::META_TYPE => 'array',
447 '_dummy' => 'foobaz',
448 '_dummy2' => 'foobaz!',
449 );
450 $this->assertEquals( array(
451 'foo' => array(
452 'bar' => array(),
453 'bar2' => (object)array(),
454 'x' => 'ok',
455 ),
456 'foo2' => (object)array(
457 'bar' => array(),
458 'bar2' => (object)array(),
459 'x' => 'ok',
460 ),
461 '_dummy2' => 'foobaz!',
462 ), ApiResult::stripMetadata( $arr ), 'ApiResult::stripMetadata' );
463
464 $metadata = array();
465 $data = ApiResult::stripMetadataNonRecursive( $arr, $metadata );
466 $this->assertEquals( array(
467 'foo' => array(
468 'bar' => array( '_dummy' => 'foobaz' ),
469 'bar2' => (object)array( '_dummy' => 'foobaz' ),
470 'x' => 'ok',
471 '_dummy' => 'foobaz',
472 ),
473 'foo2' => (object)array(
474 'bar' => array( '_dummy' => 'foobaz' ),
475 'bar2' => (object)array( '_dummy' => 'foobaz' ),
476 'x' => 'ok',
477 '_dummy' => 'foobaz',
478 ),
479 '_dummy2' => 'foobaz!',
480 ), $data, 'ApiResult::stripMetadataNonRecursive ($data)' );
481 $this->assertEquals( array(
482 ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
483 ApiResult::META_INDEXED_TAG_NAME => 'itn',
484 ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
485 ApiResult::META_TYPE => 'array',
486 '_dummy' => 'foobaz',
487 ), $metadata, 'ApiResult::stripMetadataNonRecursive ($metadata)' );
488
489 $metadata = null;
490 $data = ApiResult::stripMetadataNonRecursive( (object)$arr, $metadata );
491 $this->assertEquals( (object)array(
492 'foo' => array(
493 'bar' => array( '_dummy' => 'foobaz' ),
494 'bar2' => (object)array( '_dummy' => 'foobaz' ),
495 'x' => 'ok',
496 '_dummy' => 'foobaz',
497 ),
498 'foo2' => (object)array(
499 'bar' => array( '_dummy' => 'foobaz' ),
500 'bar2' => (object)array( '_dummy' => 'foobaz' ),
501 'x' => 'ok',
502 '_dummy' => 'foobaz',
503 ),
504 '_dummy2' => 'foobaz!',
505 ), $data, 'ApiResult::stripMetadataNonRecursive on object ($data)' );
506 $this->assertEquals( array(
507 ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
508 ApiResult::META_INDEXED_TAG_NAME => 'itn',
509 ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
510 ApiResult::META_TYPE => 'array',
511 '_dummy' => 'foobaz',
512 ), $metadata, 'ApiResult::stripMetadataNonRecursive on object ($metadata)' );
513 }
514
515 /**
516 * @covers ApiResult
517 * @dataProvider provideTransformations
518 * @param string $label
519 * @param array $input
520 * @param array $transforms
521 * @param array|Exception $expect
522 */
523 public function testTransformations( $label, $input, $transforms, $expect ) {
524 $result = new ApiResult( false );
525 $result->addValue( null, 'test', $input );
526
527 if ( $expect instanceof Exception ) {
528 try {
529 $output = $result->getResultData( 'test', $transforms );
530 $this->fail( 'Expected exception not thrown', $label );
531 } catch ( Exception $ex ) {
532 $this->assertEquals( $ex, $expect, $label );
533 }
534 } else {
535 $output = $result->getResultData( 'test', $transforms );
536 $this->assertEquals( $expect, $output, $label );
537 }
538 }
539
540 public function provideTransformations() {
541 $kvp = function ( $keyKey, $key, $valKey, $value ) {
542 return array(
543 $keyKey => $key,
544 $valKey => $value,
545 ApiResult::META_PRESERVE_KEYS => array( $keyKey ),
546 ApiResult::META_CONTENT => $valKey,
547 ApiResult::META_TYPE => 'assoc',
548 );
549 };
550 $typeArr = array(
551 'defaultArray' => array( 2 => 'a', 0 => 'b', 1 => 'c' ),
552 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c' ),
553 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c' ),
554 'array' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'array' ),
555 'BCarray' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'BCarray' ),
556 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'BCassoc' ),
557 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
558 'kvp' => array( 'x' => 'a', 'y' => 'b', 'z' => array( 'c' ), ApiResult::META_TYPE => 'kvp' ),
559 'BCkvp' => array( 'x' => 'a', 'y' => 'b',
560 ApiResult::META_TYPE => 'BCkvp',
561 ApiResult::META_KVP_KEY_NAME => 'key',
562 ),
563 'emptyDefault' => array( '_dummy' => 1 ),
564 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
565 '_dummy' => 1,
566 ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
567 );
568 $stripArr = array(
569 'foo' => array(
570 'bar' => array( '_dummy' => 'foobaz' ),
571 'baz' => array(
572 ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
573 ApiResult::META_INDEXED_TAG_NAME => 'itn',
574 ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
575 ApiResult::META_TYPE => 'array',
576 ),
577 'x' => 'ok',
578 '_dummy' => 'foobaz',
579 ),
580 ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
581 ApiResult::META_INDEXED_TAG_NAME => 'itn',
582 ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
583 ApiResult::META_TYPE => 'array',
584 '_dummy' => 'foobaz',
585 '_dummy2' => 'foobaz!',
586 );
587
588 return array(
589 array(
590 'BC: META_BC_BOOLS',
591 array(
592 'BCtrue' => true,
593 'BCfalse' => false,
594 'true' => true,
595 'false' => false,
596 ApiResult::META_BC_BOOLS => array( 0, 'true', 'false' ),
597 ),
598 array( 'BC' => array() ),
599 array(
600 'BCtrue' => '',
601 'true' => true,
602 'false' => false,
603 ApiResult::META_BC_BOOLS => array( 0, 'true', 'false' ),
604 )
605 ),
606 array(
607 'BC: META_BC_SUBELEMENTS',
608 array(
609 'bc' => 'foo',
610 'nobc' => 'bar',
611 ApiResult::META_BC_SUBELEMENTS => array( 'bc' ),
612 ),
613 array( 'BC' => array() ),
614 array(
615 'bc' => array(
616 '*' => 'foo',
617 ApiResult::META_CONTENT => '*',
618 ApiResult::META_TYPE => 'assoc',
619 ),
620 'nobc' => 'bar',
621 ApiResult::META_BC_SUBELEMENTS => array( 'bc' ),
622 ),
623 ),
624 array(
625 'BC: META_CONTENT',
626 array(
627 'content' => '!!!',
628 ApiResult::META_CONTENT => 'content',
629 ),
630 array( 'BC' => array() ),
631 array(
632 '*' => '!!!',
633 ApiResult::META_CONTENT => '*',
634 ),
635 ),
636 array(
637 'BC: BCkvp type',
638 array(
639 'foo' => 'foo value',
640 'bar' => 'bar value',
641 '_baz' => 'baz value',
642 ApiResult::META_TYPE => 'BCkvp',
643 ApiResult::META_KVP_KEY_NAME => 'key',
644 ApiResult::META_PRESERVE_KEYS => array( '_baz' ),
645 ),
646 array( 'BC' => array() ),
647 array(
648 $kvp( 'key', 'foo', '*', 'foo value' ),
649 $kvp( 'key', 'bar', '*', 'bar value' ),
650 $kvp( 'key', '_baz', '*', 'baz value' ),
651 ApiResult::META_TYPE => 'array',
652 ApiResult::META_KVP_KEY_NAME => 'key',
653 ApiResult::META_PRESERVE_KEYS => array( '_baz' ),
654 ),
655 ),
656 array(
657 'BC: BCarray type',
658 array(
659 ApiResult::META_TYPE => 'BCarray',
660 ),
661 array( 'BC' => array() ),
662 array(
663 ApiResult::META_TYPE => 'default',
664 ),
665 ),
666 array(
667 'BC: BCassoc type',
668 array(
669 ApiResult::META_TYPE => 'BCassoc',
670 ),
671 array( 'BC' => array() ),
672 array(
673 ApiResult::META_TYPE => 'default',
674 ),
675 ),
676 array(
677 'BC: BCkvp exception',
678 array(
679 ApiResult::META_TYPE => 'BCkvp',
680 ),
681 array( 'BC' => array() ),
682 new UnexpectedValueException(
683 'Type "BCkvp" used without setting ApiResult::META_KVP_KEY_NAME metadata item'
684 ),
685 ),
686 array(
687 'BC: nobool, no*, nosub',
688 array(
689 'true' => true,
690 'false' => false,
691 'content' => 'content',
692 ApiResult::META_CONTENT => 'content',
693 'bc' => 'foo',
694 ApiResult::META_BC_SUBELEMENTS => array( 'bc' ),
695 'BCarray' => array( ApiResult::META_TYPE => 'BCarray' ),
696 'BCassoc' => array( ApiResult::META_TYPE => 'BCassoc' ),
697 'BCkvp' => array(
698 'foo' => 'foo value',
699 'bar' => 'bar value',
700 '_baz' => 'baz value',
701 ApiResult::META_TYPE => 'BCkvp',
702 ApiResult::META_KVP_KEY_NAME => 'key',
703 ApiResult::META_PRESERVE_KEYS => array( '_baz' ),
704 ),
705 ),
706 array( 'BC' => array( 'nobool', 'no*', 'nosub' ) ),
707 array(
708 'true' => true,
709 'false' => false,
710 'content' => 'content',
711 'bc' => 'foo',
712 'BCarray' => array( ApiResult::META_TYPE => 'default' ),
713 'BCassoc' => array( ApiResult::META_TYPE => 'default' ),
714 'BCkvp' => array(
715 $kvp( 'key', 'foo', '*', 'foo value' ),
716 $kvp( 'key', 'bar', '*', 'bar value' ),
717 $kvp( 'key', '_baz', '*', 'baz value' ),
718 ApiResult::META_TYPE => 'array',
719 ApiResult::META_KVP_KEY_NAME => 'key',
720 ApiResult::META_PRESERVE_KEYS => array( '_baz' ),
721 ),
722 ApiResult::META_CONTENT => 'content',
723 ApiResult::META_BC_SUBELEMENTS => array( 'bc' ),
724 ),
725 ),
726
727 array(
728 'Types: Normal transform',
729 $typeArr,
730 array( 'Types' => array() ),
731 array(
732 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
733 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
734 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
735 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
736 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
737 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ),
738 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
739 'kvp' => array( 'x' => 'a', 'y' => 'b',
740 'z' => array( 'c', ApiResult::META_TYPE => 'array' ),
741 ApiResult::META_TYPE => 'assoc'
742 ),
743 'BCkvp' => array( 'x' => 'a', 'y' => 'b',
744 ApiResult::META_TYPE => 'assoc',
745 ApiResult::META_KVP_KEY_NAME => 'key',
746 ),
747 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
748 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
749 '_dummy' => 1,
750 ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
751 ApiResult::META_TYPE => 'assoc',
752 ),
753 ),
754 array(
755 'Types: AssocAsObject',
756 $typeArr,
757 array( 'Types' => array( 'AssocAsObject' => true ) ),
758 (object)array(
759 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
760 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
761 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
762 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
763 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
764 'BCassoc' => (object)array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ),
765 'assoc' => (object)array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
766 'kvp' => (object)array( 'x' => 'a', 'y' => 'b',
767 'z' => array( 'c', ApiResult::META_TYPE => 'array' ),
768 ApiResult::META_TYPE => 'assoc'
769 ),
770 'BCkvp' => (object)array( 'x' => 'a', 'y' => 'b',
771 ApiResult::META_TYPE => 'assoc',
772 ApiResult::META_KVP_KEY_NAME => 'key',
773 ),
774 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
775 'emptyAssoc' => (object)array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
776 '_dummy' => 1,
777 ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
778 ApiResult::META_TYPE => 'assoc',
779 ),
780 ),
781 array(
782 'Types: ArmorKVP',
783 $typeArr,
784 array( 'Types' => array( 'ArmorKVP' => 'name' ) ),
785 array(
786 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
787 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
788 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
789 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
790 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
791 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ),
792 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
793 'kvp' => array(
794 $kvp( 'name', 'x', 'value', 'a' ),
795 $kvp( 'name', 'y', 'value', 'b' ),
796 $kvp( 'name', 'z', 'value', array( 'c', ApiResult::META_TYPE => 'array' ) ),
797 ApiResult::META_TYPE => 'array'
798 ),
799 'BCkvp' => array(
800 $kvp( 'key', 'x', 'value', 'a' ),
801 $kvp( 'key', 'y', 'value', 'b' ),
802 ApiResult::META_TYPE => 'array',
803 ApiResult::META_KVP_KEY_NAME => 'key',
804 ),
805 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
806 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
807 '_dummy' => 1,
808 ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
809 ApiResult::META_TYPE => 'assoc',
810 ),
811 ),
812 array(
813 'Types: ArmorKVP + BC',
814 $typeArr,
815 array( 'BC' => array(), 'Types' => array( 'ArmorKVP' => 'name' ) ),
816 array(
817 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
818 'defaultAssoc' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
819 'defaultAssoc2' => array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
820 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
821 'BCarray' => array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
822 'BCassoc' => array( 'a', 'b', 'c', ApiResult::META_TYPE => 'array' ),
823 'assoc' => array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
824 'kvp' => array(
825 $kvp( 'name', 'x', '*', 'a' ),
826 $kvp( 'name', 'y', '*', 'b' ),
827 $kvp( 'name', 'z', '*', array( 'c', ApiResult::META_TYPE => 'array' ) ),
828 ApiResult::META_TYPE => 'array'
829 ),
830 'BCkvp' => array(
831 $kvp( 'key', 'x', '*', 'a' ),
832 $kvp( 'key', 'y', '*', 'b' ),
833 ApiResult::META_TYPE => 'array',
834 ApiResult::META_KVP_KEY_NAME => 'key',
835 ),
836 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
837 'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
838 '_dummy' => 1,
839 ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
840 ApiResult::META_TYPE => 'assoc',
841 ),
842 ),
843 array(
844 'Types: ArmorKVP + AssocAsObject',
845 $typeArr,
846 array( 'Types' => array( 'ArmorKVP' => 'name', 'AssocAsObject' => true ) ),
847 (object)array(
848 'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
849 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
850 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
851 'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
852 'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
853 'BCassoc' => (object)array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ),
854 'assoc' => (object)array( 2 => 'a', 0 => 'b', 1 => 'c', ApiResult::META_TYPE => 'assoc' ),
855 'kvp' => array(
856 (object)$kvp( 'name', 'x', 'value', 'a' ),
857 (object)$kvp( 'name', 'y', 'value', 'b' ),
858 (object)$kvp( 'name', 'z', 'value', array( 'c', ApiResult::META_TYPE => 'array' ) ),
859 ApiResult::META_TYPE => 'array'
860 ),
861 'BCkvp' => array(
862 (object)$kvp( 'key', 'x', 'value', 'a' ),
863 (object)$kvp( 'key', 'y', 'value', 'b' ),
864 ApiResult::META_TYPE => 'array',
865 ApiResult::META_KVP_KEY_NAME => 'key',
866 ),
867 'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
868 'emptyAssoc' => (object)array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
869 '_dummy' => 1,
870 ApiResult::META_PRESERVE_KEYS => array( '_dummy' ),
871 ApiResult::META_TYPE => 'assoc',
872 ),
873 ),
874 array(
875 'Types: BCkvp exception',
876 array(
877 ApiResult::META_TYPE => 'BCkvp',
878 ),
879 array( 'Types' => array() ),
880 new UnexpectedValueException(
881 'Type "BCkvp" used without setting ApiResult::META_KVP_KEY_NAME metadata item'
882 ),
883 ),
884
885 array(
886 'Strip: With ArmorKVP + AssocAsObject transforms',
887 $typeArr,
888 array( 'Types' => array( 'ArmorKVP' => 'name', 'AssocAsObject' => true ), 'Strip' => 'all' ),
889 (object)array(
890 'defaultArray' => array( 'b', 'c', 'a' ),
891 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c' ),
892 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c' ),
893 'array' => array( 'a', 'c', 'b' ),
894 'BCarray' => array( 'a', 'c', 'b' ),
895 'BCassoc' => (object)array( 'a', 'b', 'c' ),
896 'assoc' => (object)array( 2 => 'a', 0 => 'b', 1 => 'c' ),
897 'kvp' => array(
898 (object)array( 'name' => 'x', 'value' => 'a' ),
899 (object)array( 'name' => 'y', 'value' => 'b' ),
900 (object)array( 'name' => 'z', 'value' => array( 'c' ) ),
901 ),
902 'BCkvp' => array(
903 (object)array( 'key' => 'x', 'value' => 'a' ),
904 (object)array( 'key' => 'y', 'value' => 'b' ),
905 ),
906 'emptyDefault' => array(),
907 'emptyAssoc' => (object)array(),
908 '_dummy' => 1,
909 ),
910 ),
911
912 array(
913 'Strip: all',
914 $stripArr,
915 array( 'Strip' => 'all' ),
916 array(
917 'foo' => array(
918 'bar' => array(),
919 'baz' => array(),
920 'x' => 'ok',
921 ),
922 '_dummy2' => 'foobaz!',
923 ),
924 ),
925 array(
926 'Strip: base',
927 $stripArr,
928 array( 'Strip' => 'base' ),
929 array(
930 'foo' => array(
931 'bar' => array( '_dummy' => 'foobaz' ),
932 'baz' => array(
933 ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
934 ApiResult::META_INDEXED_TAG_NAME => 'itn',
935 ApiResult::META_PRESERVE_KEYS => array( 'foo', 'bar', '_dummy2', 0 ),
936 ApiResult::META_TYPE => 'array',
937 ),
938 'x' => 'ok',
939 '_dummy' => 'foobaz',
940 ),
941 '_dummy2' => 'foobaz!',
942 ),
943 ),
944 array(
945 'Strip: bc',
946 $stripArr,
947 array( 'Strip' => 'bc' ),
948 array(
949 'foo' => array(
950 'bar' => array(),
951 'baz' => array(
952 ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
953 ApiResult::META_INDEXED_TAG_NAME => 'itn',
954 ),
955 'x' => 'ok',
956 ),
957 '_dummy2' => 'foobaz!',
958 ApiResult::META_SUBELEMENTS => array( 'foo', 'bar' ),
959 ApiResult::META_INDEXED_TAG_NAME => 'itn',
960 ),
961 ),
962
963 array(
964 'Custom transform',
965 array(
966 'foo' => '?',
967 'bar' => '?',
968 '_dummy' => '?',
969 '_dummy2' => '?',
970 '_dummy3' => '?',
971 ApiResult::META_CONTENT => 'foo',
972 ApiResult::META_PRESERVE_KEYS => array( '_dummy2', '_dummy3' ),
973 ),
974 array(
975 'Custom' => array( $this, 'customTransform' ),
976 'BC' => array(),
977 'Types' => array(),
978 'Strip' => 'all'
979 ),
980 array(
981 '*' => 'FOO',
982 'bar' => 'BAR',
983 'baz' => array( 'a', 'b' ),
984 '_dummy2' => '_DUMMY2',
985 '_dummy3' => '_DUMMY3',
986 ApiResult::META_CONTENT => 'bar',
987 ),
988 ),
989 );
990
991 }
992
993 /**
994 * Custom transformer for testTransformations
995 * @param array &$data
996 * @param array &$metadata
997 */
998 public function customTransform( &$data, &$metadata ) {
999 // Prevent recursion
1000 if ( isset( $metadata['_added'] ) ) {
1001 $metadata[ApiResult::META_TYPE] = 'array';
1002 return;
1003 }
1004
1005 foreach ( $data as $k => $v ) {
1006 $data[$k] = strtoupper( $k );
1007 }
1008 $data['baz'] = array( '_added' => 1, 'z' => 'b', 'y' => 'a' );
1009 $metadata[ApiResult::META_PRESERVE_KEYS][0] = '_dummy';
1010 $data[ApiResult::META_CONTENT] = 'bar';
1011 }
1012
1013 /**
1014 * @covers ApiResult
1015 */
1016 public function testDeprecatedFunctions() {
1017 // Ignore ApiResult deprecation warnings during this test
1018 set_error_handler( function ( $errno, $errstr ) use ( &$warnings ) {
1019 if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
1020 return true;
1021 }
1022 return false;
1023 } );
1024 $reset = new ScopedCallback( 'restore_error_handler' );
1025
1026 $context = new DerivativeContext( RequestContext::getMain() );
1027 $context->setConfig( new HashConfig( array(
1028 'APIModules' => array(),
1029 'APIFormatModules' => array(),
1030 'APIMaxResultSize' => 42,
1031 ) ) );
1032 $main = new ApiMain( $context );
1033 $result = TestingAccessWrapper::newFromObject( new ApiResult( $main ) );
1034 $this->assertSame( 42, $result->maxSize );
1035 $this->assertSame( $main->getErrorFormatter(), $result->errorFormatter );
1036 $this->assertSame( $main, $result->mainForContinuation );
1037
1038 $result = new ApiResult( 8388608 );
1039
1040 $result->addContentValue( null, 'test', 'content' );
1041 $result->addContentValue( array( 'foo', 'bar' ), 'test', 'content' );
1042 $result->addIndexedTagName( null, 'itn' );
1043 $result->addSubelementsList( null, array( 'sub' ) );
1044 $this->assertSame( array(
1045 'foo' => array(
1046 'bar' => array(
1047 '*' => 'content',
1048 ),
1049 ),
1050 '*' => 'content',
1051 ), $result->getData() );
1052 $result->setRawMode();
1053 $this->assertSame( array(
1054 'foo' => array(
1055 'bar' => array(
1056 '*' => 'content',
1057 ),
1058 ),
1059 '*' => 'content',
1060 '_element' => 'itn',
1061 '_subelements' => array( 'sub' ),
1062 ), $result->getData() );
1063
1064 $arr = array();
1065 ApiResult::setContent( $arr, 'value' );
1066 ApiResult::setContent( $arr, 'value2', 'foobar' );
1067 $this->assertSame( array(
1068 ApiResult::META_CONTENT => 'content',
1069 'content' => 'value',
1070 'foobar' => array(
1071 ApiResult::META_CONTENT => 'content',
1072 'content' => 'value2',
1073 ),
1074 ), $arr );
1075
1076 $result = new ApiResult( 3 );
1077 $formatter = new ApiErrorFormatter_BackCompat( $result );
1078 $result->setErrorFormatter( $formatter );
1079 $result->disableSizeCheck();
1080 $this->assertTrue( $result->addValue( null, 'foo', '1234567890' ) );
1081 $result->enableSizeCheck();
1082 $this->assertSame( 0, $result->getSize() );
1083 $this->assertFalse( $result->addValue( null, 'foo', '1234567890' ) );
1084
1085 $arr = array( 'foo' => array( 'bar' => 1 ) );
1086 $result->setIndexedTagName_recursive( $arr, 'itn' );
1087 $this->assertSame( array(
1088 'foo' => array(
1089 'bar' => 1,
1090 ApiResult::META_INDEXED_TAG_NAME => 'itn'
1091 ),
1092 ), $arr );
1093
1094 $status = Status::newGood();
1095 $status->fatal( 'parentheses', '1' );
1096 $status->fatal( 'parentheses', '2' );
1097 $status->warning( 'parentheses', '3' );
1098 $status->warning( 'parentheses', '4' );
1099 $this->assertSame( array(
1100 array(
1101 'type' => 'error',
1102 'message' => 'parentheses',
1103 'params' => array(
1104 0 => '1',
1105 ApiResult::META_INDEXED_TAG_NAME => 'param',
1106 ),
1107 ),
1108 array(
1109 'type' => 'error',
1110 'message' => 'parentheses',
1111 'params' => array(
1112 0 => '2',
1113 ApiResult::META_INDEXED_TAG_NAME => 'param',
1114 ),
1115 ),
1116 ApiResult::META_INDEXED_TAG_NAME => 'error',
1117 ), $result->convertStatusToArray( $status, 'error' ) );
1118 $this->assertSame( array(
1119 array(
1120 'type' => 'warning',
1121 'message' => 'parentheses',
1122 'params' => array(
1123 0 => '3',
1124 ApiResult::META_INDEXED_TAG_NAME => 'param',
1125 ),
1126 ),
1127 array(
1128 'type' => 'warning',
1129 'message' => 'parentheses',
1130 'params' => array(
1131 0 => '4',
1132 ApiResult::META_INDEXED_TAG_NAME => 'param',
1133 ),
1134 ),
1135 ApiResult::META_INDEXED_TAG_NAME => 'warning',
1136 ), $result->convertStatusToArray( $status, 'warning' ) );
1137 }
1138
1139 /**
1140 * @covers ApiResult
1141 */
1142 public function testDeprecatedContinuation() {
1143 // Ignore ApiResult deprecation warnings during this test
1144 set_error_handler( function ( $errno, $errstr ) use ( &$warnings ) {
1145 if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
1146 return true;
1147 }
1148 return false;
1149 } );
1150
1151 $reset = new ScopedCallback( 'restore_error_handler' );
1152 $allModules = array(
1153 new MockApiQueryBase( 'mock1' ),
1154 new MockApiQueryBase( 'mock2' ),
1155 new MockApiQueryBase( 'mocklist' ),
1156 );
1157 $generator = new MockApiQueryBase( 'generator' );
1158
1159 $main = new ApiMain( RequestContext::getMain() );
1160 $result = new ApiResult( 8388608 );
1161 $result->setMainForContinuation( $main );
1162 $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
1163 $this->assertSame( array( false, $allModules ), $ret );
1164 $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
1165 $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
1166 $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
1167 $result->endContinuation( 'raw' );
1168 $result->endContinuation( 'standard' );
1169 $this->assertSame( array(
1170 'mlcontinue' => 2,
1171 'm1continue' => '1|2',
1172 'continue' => '||mock2',
1173 ), $result->getResultData( 'continue' ) );
1174 $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
1175 $this->assertSame( array(
1176 'mock1' => array( 'm1continue' => '1|2' ),
1177 'mocklist' => array( 'mlcontinue' => 2 ),
1178 'generator' => array( 'gcontinue' => 3 ),
1179 ), $result->getResultData( 'query-continue' ) );
1180 $main->setContinuationManager( null );
1181
1182 $result = new ApiResult( 8388608 );
1183 $result->setMainForContinuation( $main );
1184 $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
1185 $this->assertSame( array( false, $allModules ), $ret );
1186 $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
1187 $result->setGeneratorContinueParam( $generator, 'gcontinue', array( 3, 4 ) );
1188 $result->endContinuation( 'raw' );
1189 $result->endContinuation( 'standard' );
1190 $this->assertSame( array(
1191 'm1continue' => '1|2',
1192 'continue' => '||mock2|mocklist',
1193 ), $result->getResultData( 'continue' ) );
1194 $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
1195 $this->assertSame( array(
1196 'mock1' => array( 'm1continue' => '1|2' ),
1197 'generator' => array( 'gcontinue' => '3|4' ),
1198 ), $result->getResultData( 'query-continue' ) );
1199 $main->setContinuationManager( null );
1200
1201 $result = new ApiResult( 8388608 );
1202 $result->setMainForContinuation( $main );
1203 $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
1204 $this->assertSame( array( false, $allModules ), $ret );
1205 $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
1206 $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
1207 $result->endContinuation( 'raw' );
1208 $result->endContinuation( 'standard' );
1209 $this->assertSame( array(
1210 'mlcontinue' => 2,
1211 'gcontinue' => 3,
1212 'continue' => 'gcontinue||',
1213 ), $result->getResultData( 'continue' ) );
1214 $this->assertSame( '', $result->getResultData( 'batchcomplete' ) );
1215 $this->assertSame( array(
1216 'mocklist' => array( 'mlcontinue' => 2 ),
1217 'generator' => array( 'gcontinue' => 3 ),
1218 ), $result->getResultData( 'query-continue' ) );
1219 $main->setContinuationManager( null );
1220
1221 $result = new ApiResult( 8388608 );
1222 $result->setMainForContinuation( $main );
1223 $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
1224 $this->assertSame( array( false, $allModules ), $ret );
1225 $result->setGeneratorContinueParam( $generator, 'gcontinue', 3 );
1226 $result->endContinuation( 'raw' );
1227 $result->endContinuation( 'standard' );
1228 $this->assertSame( array(
1229 'gcontinue' => 3,
1230 'continue' => 'gcontinue||mocklist',
1231 ), $result->getResultData( 'continue' ) );
1232 $this->assertSame( '', $result->getResultData( 'batchcomplete' ) );
1233 $this->assertSame( array(
1234 'generator' => array( 'gcontinue' => 3 ),
1235 ), $result->getResultData( 'query-continue' ) );
1236 $main->setContinuationManager( null );
1237
1238 $result = new ApiResult( 8388608 );
1239 $result->setMainForContinuation( $main );
1240 $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
1241 $this->assertSame( array( false, $allModules ), $ret );
1242 $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
1243 $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
1244 $result->endContinuation( 'raw' );
1245 $result->endContinuation( 'standard' );
1246 $this->assertSame( array(
1247 'mlcontinue' => 2,
1248 'm1continue' => '1|2',
1249 'continue' => '||mock2',
1250 ), $result->getResultData( 'continue' ) );
1251 $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
1252 $this->assertSame( array(
1253 'mock1' => array( 'm1continue' => '1|2' ),
1254 'mocklist' => array( 'mlcontinue' => 2 ),
1255 ), $result->getResultData( 'query-continue' ) );
1256 $main->setContinuationManager( null );
1257
1258 $result = new ApiResult( 8388608 );
1259 $result->setMainForContinuation( $main );
1260 $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
1261 $this->assertSame( array( false, $allModules ), $ret );
1262 $result->setContinueParam( $allModules[0], 'm1continue', array( 1, 2 ) );
1263 $result->endContinuation( 'raw' );
1264 $result->endContinuation( 'standard' );
1265 $this->assertSame( array(
1266 'm1continue' => '1|2',
1267 'continue' => '||mock2|mocklist',
1268 ), $result->getResultData( 'continue' ) );
1269 $this->assertSame( null, $result->getResultData( 'batchcomplete' ) );
1270 $this->assertSame( array(
1271 'mock1' => array( 'm1continue' => '1|2' ),
1272 ), $result->getResultData( 'query-continue' ) );
1273 $main->setContinuationManager( null );
1274
1275 $result = new ApiResult( 8388608 );
1276 $result->setMainForContinuation( $main );
1277 $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
1278 $this->assertSame( array( false, $allModules ), $ret );
1279 $result->setContinueParam( $allModules[2], 'mlcontinue', 2 );
1280 $result->endContinuation( 'raw' );
1281 $result->endContinuation( 'standard' );
1282 $this->assertSame( array(
1283 'mlcontinue' => 2,
1284 'continue' => '-||mock1|mock2',
1285 ), $result->getResultData( 'continue' ) );
1286 $this->assertSame( '', $result->getResultData( 'batchcomplete' ) );
1287 $this->assertSame( array(
1288 'mocklist' => array( 'mlcontinue' => 2 ),
1289 ), $result->getResultData( 'query-continue' ) );
1290 $main->setContinuationManager( null );
1291
1292 $result = new ApiResult( 8388608 );
1293 $result->setMainForContinuation( $main );
1294 $ret = $result->beginContinuation( null, $allModules, array( 'mock1', 'mock2' ) );
1295 $this->assertSame( array( false, $allModules ), $ret );
1296 $result->endContinuation( 'raw' );
1297 $result->endContinuation( 'standard' );
1298 $this->assertSame( null, $result->getResultData( 'continue' ) );
1299 $this->assertSame( '', $result->getResultData( 'batchcomplete' ) );
1300 $this->assertSame( null, $result->getResultData( 'query-continue' ) );
1301 $main->setContinuationManager( null );
1302
1303 $result = new ApiResult( 8388608 );
1304 $result->setMainForContinuation( $main );
1305 $ret = $result->beginContinuation( '||mock2', $allModules, array( 'mock1', 'mock2' ) );
1306 $this->assertSame(
1307 array( false, array_values( array_diff_key( $allModules, array( 1 => 1 ) ) ) ),
1308 $ret
1309 );
1310 $main->setContinuationManager( null );
1311
1312 $result = new ApiResult( 8388608 );
1313 $result->setMainForContinuation( $main );
1314 $ret = $result->beginContinuation( '-||', $allModules, array( 'mock1', 'mock2' ) );
1315 $this->assertSame(
1316 array( true, array_values( array_diff_key( $allModules, array( 0 => 0, 1 => 1 ) ) ) ),
1317 $ret
1318 );
1319 $main->setContinuationManager( null );
1320
1321 $result = new ApiResult( 8388608 );
1322 $result->setMainForContinuation( $main );
1323 try {
1324 $result->beginContinuation( 'foo', $allModules, array( 'mock1', 'mock2' ) );
1325 $this->fail( 'Expected exception not thrown' );
1326 } catch ( UsageException $ex ) {
1327 $this->assertSame(
1328 'Invalid continue param. You should pass the original value returned by the previous query',
1329 $ex->getMessage(),
1330 'Expected exception'
1331 );
1332 }
1333 $main->setContinuationManager( null );
1334
1335 $result = new ApiResult( 8388608 );
1336 $result->setMainForContinuation( $main );
1337 $result->beginContinuation( '||mock2', array_slice( $allModules, 0, 2 ), array( 'mock1', 'mock2' ) );
1338 try {
1339 $result->setContinueParam( $allModules[1], 'm2continue', 1 );
1340 $this->fail( 'Expected exception not thrown' );
1341 } catch ( UnexpectedValueException $ex ) {
1342 $this->assertSame(
1343 'Module \'mock2\' was not supposed to have been executed, but it was executed anyway',
1344 $ex->getMessage(),
1345 'Expected exception'
1346 );
1347 }
1348 try {
1349 $result->setContinueParam( $allModules[2], 'mlcontinue', 1 );
1350 $this->fail( 'Expected exception not thrown' );
1351 } catch ( UnexpectedValueException $ex ) {
1352 $this->assertSame(
1353 'Module \'mocklist\' called ApiContinuationManager::addContinueParam but was not passed to ApiContinuationManager::__construct',
1354 $ex->getMessage(),
1355 'Expected exception'
1356 );
1357 }
1358 $main->setContinuationManager( null );
1359
1360 }
1361
1362 public function testObjectSerialization() {
1363 $arr = array();
1364 ApiResult::setValue( $arr, 'foo', (object)array( 'a' => 1, 'b' => 2 ) );
1365 $this->assertSame( array(
1366 'a' => 1,
1367 'b' => 2,
1368 ApiResult::META_TYPE => 'assoc',
1369 ), $arr['foo'] );
1370
1371 $arr = array();
1372 ApiResult::setValue( $arr, 'foo', new ApiResultTestStringifiableObject() );
1373 $this->assertSame( 'Ok', $arr['foo'] );
1374
1375 $arr = array();
1376 ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( 'Ok' ) );
1377 $this->assertSame( 'Ok', $arr['foo'] );
1378
1379 try {
1380 $arr = array();
1381 ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
1382 new ApiResultTestStringifiableObject()
1383 ) );
1384 $this->fail( 'Expected exception not thrown' );
1385 } catch ( UnexpectedValueException $ex ) {
1386 $this->assertSame(
1387 'ApiResultTestSerializableObject::serializeForApiResult() returned an object of class ApiResultTestStringifiableObject',
1388 $ex->getMessage(),
1389 'Expected exception'
1390 );
1391 }
1392
1393 try {
1394 $arr = array();
1395 ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( NAN ) );
1396 $this->fail( 'Expected exception not thrown' );
1397 } catch ( UnexpectedValueException $ex ) {
1398 $this->assertSame(
1399 'ApiResultTestSerializableObject::serializeForApiResult() returned an invalid value: Cannot add non-finite floats to ApiResult',
1400 $ex->getMessage(),
1401 'Expected exception'
1402 );
1403 }
1404
1405 $arr = array();
1406 ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
1407 array(
1408 'one' => new ApiResultTestStringifiableObject( '1' ),
1409 'two' => new ApiResultTestSerializableObject( 2 ),
1410 )
1411 ) );
1412 $this->assertSame( array(
1413 'one' => '1',
1414 'two' => 2,
1415 ), $arr['foo'] );
1416 }
1417
1418 }
1419
1420 class ApiResultTestStringifiableObject {
1421 private $ret;
1422
1423 public function __construct( $ret = 'Ok' ) {
1424 $this->ret = $ret;
1425 }
1426
1427 public function __toString() {
1428 return $this->ret;
1429 }
1430 }
1431
1432 class ApiResultTestSerializableObject {
1433 private $ret;
1434
1435 public function __construct( $ret ) {
1436 $this->ret = $ret;
1437 }
1438
1439 public function __toString() {
1440 return "Fail";
1441 }
1442
1443 public function serializeForApiResult() {
1444 return $this->ret;
1445 }
1446 }