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