Rename JsonUnserial… to JsonDeserial…
[mediawiki.git] / tests / phpunit / includes / api / Validator / ApiParamValidatorTest.php
blob1052f9846b77396a1feafce2cc296e20b287fcee
1 <?php
3 namespace MediaWiki\Tests\Api\Validator;
5 use ApiBase;
6 use ApiMain;
7 use ApiMessage;
8 use ApiUsageException;
9 use MediaWiki\Api\Validator\ApiParamValidator;
10 use MediaWiki\Message\Message;
11 use MediaWiki\Request\FauxRequest;
12 use MediaWiki\Tests\Api\ApiTestCase;
13 use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait;
14 use Wikimedia\Message\DataMessageValue;
15 use Wikimedia\Message\MessageValue;
16 use Wikimedia\ParamValidator\ParamValidator;
17 use Wikimedia\ParamValidator\TypeDef\EnumDef;
18 use Wikimedia\ParamValidator\TypeDef\IntegerDef;
19 use Wikimedia\TestingAccessWrapper;
21 /**
22 * @covers \MediaWiki\Api\Validator\ApiParamValidator
23 * @group API
24 * @group medium
26 class ApiParamValidatorTest extends ApiTestCase {
27 use MockAuthorityTrait;
29 private function getValidator( FauxRequest $request ): array {
30 $context = $this->apiContext->newTestContext( $request, $this->mockRegisteredUltimateAuthority() );
31 $main = new ApiMain( $context );
32 return [
33 new ApiParamValidator( $main, $this->getServiceContainer()->getObjectFactory() ),
34 $main
38 public function testKnownTypes(): void {
39 [ $validator ] = $this->getValidator( new FauxRequest( [] ) );
40 $this->assertSame(
42 'boolean', 'enum', 'expiry', 'integer', 'limit', 'namespace', 'NULL', 'password',
43 'raw', 'string', 'submodule', 'tags', 'text', 'timestamp', 'title', 'user', 'upload',
45 $validator->knownTypes()
49 /**
50 * @dataProvider provideNormalizeSettings
51 * @param array|mixed $settings
52 * @param array $expect
54 public function testNormalizeSettings( $settings, array $expect ): void {
55 [ $validator ] = $this->getValidator( new FauxRequest( [] ) );
56 $this->assertEquals( $expect, $validator->normalizeSettings( $settings ) );
59 public static function provideNormalizeSettings(): array {
60 return [
61 'Basic test' => [
62 [],
64 ParamValidator::PARAM_IGNORE_UNRECOGNIZED_VALUES => true,
65 IntegerDef::PARAM_IGNORE_RANGE => true,
66 ParamValidator::PARAM_TYPE => 'NULL',
69 'Explicit ParamValidator::PARAM_IGNORE_UNRECOGNIZED_VALUES' => [
71 ParamValidator::PARAM_IGNORE_UNRECOGNIZED_VALUES => false,
74 ParamValidator::PARAM_IGNORE_UNRECOGNIZED_VALUES => false,
75 IntegerDef::PARAM_IGNORE_RANGE => true,
76 ParamValidator::PARAM_TYPE => 'NULL',
79 'Explicit IntegerDef::PARAM_IGNORE_RANGE' => [
81 IntegerDef::PARAM_IGNORE_RANGE => false,
84 ParamValidator::PARAM_IGNORE_UNRECOGNIZED_VALUES => true,
85 IntegerDef::PARAM_IGNORE_RANGE => false,
86 ParamValidator::PARAM_TYPE => 'NULL',
89 'Handle ApiBase::PARAM_RANGE_ENFORCE' => [
91 ApiBase::PARAM_RANGE_ENFORCE => true,
94 ApiBase::PARAM_RANGE_ENFORCE => true,
95 ParamValidator::PARAM_IGNORE_UNRECOGNIZED_VALUES => true,
96 IntegerDef::PARAM_IGNORE_RANGE => false,
97 ParamValidator::PARAM_TYPE => 'NULL',
100 'Handle EnumDef::PARAM_DEPRECATED_VALUES, null' => [
102 EnumDef::PARAM_DEPRECATED_VALUES => [
103 'null' => null,
104 'true' => true,
105 'string' => 'some-message',
106 'array' => [ 'some-message', 'with', 'params' ],
107 'Message' => ApiMessage::create(
108 [ 'api-message', 'with', 'params' ], 'somecode', [ 'some-data' ]
110 'MessageValue' => MessageValue::new( 'message-value', [ 'with', 'params' ] ),
111 'DataMessageValue' => DataMessageValue::new(
112 'data-message-value', [ 'with', 'params' ], 'somecode', [ 'some-data' ]
117 ParamValidator::PARAM_IGNORE_UNRECOGNIZED_VALUES => true,
118 IntegerDef::PARAM_IGNORE_RANGE => true,
119 EnumDef::PARAM_DEPRECATED_VALUES => [
120 'null' => null,
121 'true' => true,
122 'string' => DataMessageValue::new( 'some-message', [], 'bogus', [ '💩' => 'back-compat' ] ),
123 'array' => DataMessageValue::new(
124 'some-message', [ 'with', 'params' ], 'bogus', [ '💩' => 'back-compat' ]
126 'Message' => DataMessageValue::new(
127 'api-message', [ 'with', 'params' ], 'bogus', [ '💩' => 'back-compat' ]
129 'MessageValue' => MessageValue::new( 'message-value', [ 'with', 'params' ] ),
130 'DataMessageValue' => DataMessageValue::new(
131 'data-message-value', [ 'with', 'params' ], 'somecode', [ 'some-data' ]
134 ParamValidator::PARAM_TYPE => 'NULL',
141 * @dataProvider provideCheckSettings
142 * @param array $params All module parameters.
143 * @param string $name Parameter to test.
144 * @param array $expect
146 public function testCheckSettings( array $params, string $name, array $expect ): void {
147 [ $validator, $main ] = $this->getValidator( new FauxRequest( [] ) );
148 $module = $main->getModuleFromPath( 'query+allpages' );
150 $mock = $this->getMockBuilder( ParamValidator::class )
151 ->disableOriginalConstructor()
152 ->onlyMethods( [ 'checkSettings' ] )
153 ->getMock();
154 $mock->expects( $this->once() )->method( 'checkSettings' )
155 ->willReturnCallback( function ( $n, $settings, $options ) use ( $name, $module ) {
156 $this->assertSame( "ap$name", $n );
157 $this->assertSame( [ 'module' => $module ], $options );
159 $ret = [ 'issues' => [ 'X' ], 'allowedKeys' => [ 'Y' ], 'messages' => [] ];
160 $stack = is_array( $settings ) ? [ &$settings ] : [];
161 while ( $stack ) {
162 foreach ( $stack[0] as $k => $v ) {
163 if ( $v instanceof MessageValue ) {
164 $ret['messages'][] = $v;
165 } elseif ( is_array( $v ) ) {
166 $stack[] = &$stack[0][$k];
169 array_shift( $stack );
171 return $ret;
172 } );
173 TestingAccessWrapper::newFromObject( $validator )->paramValidator = $mock;
175 $this->assertEquals( $expect, $validator->checkSettings( $module, $params, $name, [] ) );
178 public static function provideCheckSettings() {
179 $keys = [
180 'Y', ApiBase::PARAM_RANGE_ENFORCE, ApiBase::PARAM_HELP_MSG, ApiBase::PARAM_HELP_MSG_APPEND,
181 ApiBase::PARAM_HELP_MSG_INFO, ApiBase::PARAM_HELP_MSG_PER_VALUE, ApiBase::PARAM_TEMPLATE_VARS,
184 return [
185 'Basic test' => [
186 [ 'test' => null ],
187 'test',
189 'issues' => [ 'X' ],
190 'allowedKeys' => $keys,
191 'messages' => [
192 MessageValue::new( 'apihelp-query+allpages-param-test' ),
196 'Message mapping' => [
197 [ 'test' => [
198 EnumDef::PARAM_DEPRECATED_VALUES => [
199 'a' => true,
200 'b' => 'bbb',
201 'c' => [ 'ccc', 'p1', 'p2' ],
202 'd' => Message::newFromKey( 'ddd' )->plaintextParams( 'p1', 'p2' ),
204 ] ],
205 'test',
207 'issues' => [ 'X' ],
208 'allowedKeys' => $keys,
209 'messages' => [
210 DataMessageValue::new( 'bbb', [], 'bogus', [ '💩' => 'back-compat' ] ),
211 DataMessageValue::new( 'ccc', [], 'bogus', [ '💩' => 'back-compat' ] )
212 ->params( 'p1', 'p2' ),
213 DataMessageValue::new( 'ddd', [], 'bogus', [ '💩' => 'back-compat' ] )
214 ->plaintextParams( 'p1', 'p2' ),
215 MessageValue::new( 'apihelp-query+allpages-param-test' ),
219 'Test everything' => [
221 'xxx' => [
222 ParamValidator::PARAM_TYPE => 'not tested here',
223 ParamValidator::PARAM_ISMULTI => true
225 'test-{x}' => [
226 ParamValidator::PARAM_TYPE => [],
227 ApiBase::PARAM_RANGE_ENFORCE => true,
228 ApiBase::PARAM_HELP_MSG => 'foo',
229 ApiBase::PARAM_HELP_MSG_APPEND => [],
230 ApiBase::PARAM_HELP_MSG_INFO => [],
231 ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
232 ApiBase::PARAM_TEMPLATE_VARS => [
233 'x' => 'xxx',
237 'test-{x}',
239 'issues' => [ 'X' ],
240 'allowedKeys' => $keys,
241 'messages' => [
242 MessageValue::new( 'foo' ),
246 'Bad types' => [
247 [ 'test' => [
248 ApiBase::PARAM_RANGE_ENFORCE => 1,
249 ApiBase::PARAM_HELP_MSG => false,
250 ApiBase::PARAM_HELP_MSG_APPEND => 'foo',
251 ApiBase::PARAM_HELP_MSG_INFO => 'bar',
252 ApiBase::PARAM_HELP_MSG_PER_VALUE => true,
253 ApiBase::PARAM_TEMPLATE_VARS => false,
254 ] ],
255 'test',
257 'issues' => [
258 'X',
259 ApiBase::PARAM_RANGE_ENFORCE => 'PARAM_RANGE_ENFORCE must be boolean, got integer',
260 'Message specification for PARAM_HELP_MSG is not valid',
261 ApiBase::PARAM_HELP_MSG_APPEND => 'PARAM_HELP_MSG_APPEND must be an array, got string',
262 ApiBase::PARAM_HELP_MSG_INFO => 'PARAM_HELP_MSG_INFO must be an array, got string',
263 ApiBase::PARAM_HELP_MSG_PER_VALUE => 'PARAM_HELP_MSG_PER_VALUE must be an array, got boolean',
264 ApiBase::PARAM_TEMPLATE_VARS => 'PARAM_TEMPLATE_VARS must be an array, got boolean',
266 'allowedKeys' => $keys,
267 'messages' => [],
270 'PARAM_HELP_MSG (string)' => [
271 [ 'test' => [
272 ApiBase::PARAM_HELP_MSG => 'foo',
273 ] ],
274 'test',
276 'issues' => [ 'X' ],
277 'allowedKeys' => $keys,
278 'messages' => [
279 MessageValue::new( 'foo' ),
283 'PARAM_HELP_MSG (array)' => [
284 [ 'test' => [
285 ApiBase::PARAM_HELP_MSG => [ 'foo', 'bar' ],
286 ] ],
287 'test',
289 'issues' => [ 'X' ],
290 'allowedKeys' => $keys,
291 'messages' => [
292 MessageValue::new( 'foo', [ 'bar' ] ),
296 'PARAM_HELP_MSG (Message)' => [
297 [ 'test' => [
298 ApiBase::PARAM_HELP_MSG => Message::newFromKey( 'foo' )->numParams( 123 ),
299 ] ],
300 'test',
302 'issues' => [ 'X' ],
303 'allowedKeys' => $keys,
304 'messages' => [
305 MessageValue::new( 'foo' )->numParams( 123 ),
309 'PARAM_HELP_MSG_APPEND' => [
310 [ 'test' => [ ApiBase::PARAM_HELP_MSG_APPEND => [
311 'foo',
312 false,
313 [ 'bar', 'p1', 'p2' ],
314 Message::newFromKey( 'baz' )->numParams( 123 ),
315 ] ] ],
316 'test',
318 'issues' => [
319 'X',
320 'Message specification for PARAM_HELP_MSG_APPEND[1] is not valid',
322 'allowedKeys' => $keys,
323 'messages' => [
324 MessageValue::new( 'apihelp-query+allpages-param-test' ),
325 MessageValue::new( 'foo' ),
326 MessageValue::new( 'bar', [ 'p1', 'p2' ] ),
327 MessageValue::new( 'baz' )->numParams( 123 ),
331 'PARAM_HELP_MSG_INFO' => [
332 [ 'test' => [ ApiBase::PARAM_HELP_MSG_INFO => [
333 'foo',
334 [ false ],
335 [ 'foo' ],
336 [ 'bar', 'p1', 'p2' ],
337 ] ] ],
338 'test',
340 'issues' => [
341 'X',
342 'PARAM_HELP_MSG_INFO[0] must be an array, got string',
343 'PARAM_HELP_MSG_INFO[1][0] must be a string, got boolean',
345 'allowedKeys' => $keys,
346 'messages' => [
347 MessageValue::new( 'apihelp-query+allpages-param-test' ),
348 MessageValue::new( 'apihelp-query+allpages-paraminfo-foo' ),
349 MessageValue::new( 'apihelp-query+allpages-paraminfo-bar', [ 'p1', 'p2' ] ),
353 'PARAM_HELP_MSG_PER_VALUE for non-array type' => [
354 [ 'test' => [
355 ParamValidator::PARAM_TYPE => 'namespace',
356 ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
357 ] ],
358 'test',
360 'issues' => [
361 'X',
362 ApiBase::PARAM_HELP_MSG_PER_VALUE
363 => 'PARAM_HELP_MSG_PER_VALUE can only be used with PARAM_TYPE as an array',
365 'allowedKeys' => $keys,
366 'messages' => [
367 MessageValue::new( 'apihelp-query+allpages-param-test' ),
371 'PARAM_HELP_MSG_PER_VALUE' => [
372 [ 'test' => [
373 ParamValidator::PARAM_TYPE => [ 'a', 'b', 'c', 'd' ],
374 ApiBase::PARAM_HELP_MSG_PER_VALUE => [
375 'a' => null,
376 'b' => 'bbb',
377 'c' => [ 'ccc', 'p1', 'p2' ],
378 'd' => Message::newFromKey( 'ddd' )->numParams( 123 ),
379 'e' => 'eee',
381 ] ],
382 'test',
384 'issues' => [
385 'X',
386 'Message specification for PARAM_HELP_MSG_PER_VALUE[a] is not valid',
387 'PARAM_HELP_MSG_PER_VALUE contains "e", which is not in PARAM_TYPE.',
389 'allowedKeys' => $keys,
390 'messages' => [
391 MessageValue::new( 'apihelp-query+allpages-param-test' ),
392 MessageValue::new( 'bbb' ),
393 MessageValue::new( 'ccc', [ 'p1', 'p2' ] ),
394 MessageValue::new( 'ddd' )->numParams( 123 ),
395 MessageValue::new( 'eee' ),
399 'Template-style parameter name without PARAM_TEMPLATE_VARS' => [
400 [ 'test{x}' => null ],
401 'test{x}',
403 'issues' => [
404 'X',
405 "Parameter name may not contain '{' or '}' without PARAM_TEMPLATE_VARS",
407 'allowedKeys' => $keys,
408 'messages' => [
409 MessageValue::new( 'apihelp-query+allpages-param-test{x}' ),
413 'PARAM_TEMPLATE_VARS cannot be empty' => [
414 [ 'test{x}' => [
415 ApiBase::PARAM_TEMPLATE_VARS => [],
416 ] ],
417 'test{x}',
419 'issues' => [
420 'X',
421 ApiBase::PARAM_TEMPLATE_VARS => 'PARAM_TEMPLATE_VARS cannot be the empty array',
423 'allowedKeys' => $keys,
424 'messages' => [
425 MessageValue::new( 'apihelp-query+allpages-param-test{x}' ),
429 'PARAM_TEMPLATE_VARS, ok' => [
431 'ok' => [
432 ParamValidator::PARAM_ISMULTI => true,
434 'ok-templated-{x}' => [
435 ParamValidator::PARAM_ISMULTI => true,
436 ApiBase::PARAM_TEMPLATE_VARS => [
437 'x' => 'ok',
440 'test-{a}-{b}' => [
441 ApiBase::PARAM_TEMPLATE_VARS => [
442 'a' => 'ok',
443 'b' => 'ok-templated-{x}',
447 'test-{a}-{b}',
449 'issues' => [ 'X' ],
450 'allowedKeys' => $keys,
451 'messages' => [
452 MessageValue::new( 'apihelp-query+allpages-param-test-{a}-{b}' ),
456 'PARAM_TEMPLATE_VARS simple errors' => [
458 'ok' => [
459 ParamValidator::PARAM_ISMULTI => true,
461 'not-multi' => false,
462 'test-{a}-{b}-{c}' => [
463 ApiBase::PARAM_TEMPLATE_VARS => [
464 '{x}' => 'ok',
465 'not-in-name' => 'ok',
466 'a' => false,
467 'b' => 'missing',
468 'c' => 'not-multi',
472 'test-{a}-{b}-{c}',
474 'issues' => [
475 'X',
476 "PARAM_TEMPLATE_VARS keys may not contain '{' or '}', got \"{x}\"",
477 'Parameter name must contain PARAM_TEMPLATE_VARS key {not-in-name}',
478 'PARAM_TEMPLATE_VARS[a] has invalid target type boolean',
479 'PARAM_TEMPLATE_VARS[b] target parameter "missing" does not exist',
480 'PARAM_TEMPLATE_VARS[c] target parameter "not-multi" must have PARAM_ISMULTI = true',
482 'allowedKeys' => $keys,
483 'messages' => [
484 MessageValue::new( 'apihelp-query+allpages-param-test-{a}-{b}-{c}' ),
488 'PARAM_TEMPLATE_VARS no recursion' => [
490 'test-{a}' => [
491 ParamValidator::PARAM_ISMULTI => true,
492 ApiBase::PARAM_TEMPLATE_VARS => [
493 'a' => 'test-{a}',
497 'test-{a}',
499 'issues' => [
500 'X',
501 'PARAM_TEMPLATE_VARS[a] cannot target the parameter itself'
503 'allowedKeys' => $keys,
504 'messages' => [
505 MessageValue::new( 'apihelp-query+allpages-param-test-{a}' ),
509 'PARAM_TEMPLATE_VARS targeting another template, target must be a subset' => [
511 'ok1' => [ ParamValidator::PARAM_ISMULTI => true ],
512 'ok2' => [ ParamValidator::PARAM_ISMULTI => true ],
513 'test1-{a}' => [
514 ApiBase::PARAM_TEMPLATE_VARS => [
515 'a' => 'test2-{a}',
518 'test2-{a}' => [
519 ParamValidator::PARAM_ISMULTI => true,
520 ApiBase::PARAM_TEMPLATE_VARS => [
521 'a' => 'ok2',
525 'test1-{a}',
527 'issues' => [
528 'X',
529 'PARAM_TEMPLATE_VARS[a]: Target\'s PARAM_TEMPLATE_VARS must be a subset of the original',
531 'allowedKeys' => $keys,
532 'messages' => [
533 MessageValue::new( 'apihelp-query+allpages-param-test1-{a}' ),
541 * @dataProvider provideGetValue
543 public function testGetValue( ?string $data, $settings, $expect ): void {
544 [ $validator, $main ] = $this->getValidator( new FauxRequest( [ 'aptest' => $data ] ) );
545 $module = $main->getModuleFromPath( 'query+allpages' );
546 $options = [
547 'parse-limit' => false,
548 'raw' => ( $settings[ParamValidator::PARAM_TYPE] ?? '' ) === 'raw',
551 if ( $expect instanceof ApiUsageException ) {
552 try {
553 $validator->getValue( $module, 'test', $settings, $options );
554 $this->fail( 'Expected exception not thrown' );
555 } catch ( ApiUsageException $e ) {
556 $this->assertSame( $module->getModulePath(), $e->getModulePath() );
557 $this->assertEquals( $expect->getStatusValue(), $e->getStatusValue() );
559 } else {
560 $this->assertEquals( $expect, $validator->getValue( $module, 'test', $settings, $options ) );
564 public static function provideGetValue(): array {
565 return [
566 'Basic test' => [
567 '1234',
569 ParamValidator::PARAM_TYPE => 'integer',
571 1234
573 'Test for default' => [
574 null,
575 1234,
576 1234
578 'Test no value' => [
579 null,
581 ParamValidator::PARAM_TYPE => 'integer',
583 null,
585 'Test boolean (false)' => [
586 null,
587 false,
588 null,
590 'Test boolean (true)' => [
592 false,
593 true,
595 // The 'string' type will be NFC normalized (in this case,
596 // U+2001 will be converted to U+2003; see Figure 5 of
597 // of https://unicode.org/reports/tr15 for more examples).
598 'Test string (Unicode NFC)' => [
599 "\u{2001}",
601 ParamValidator::PARAM_TYPE => 'string',
603 "\u{2003}",
605 // The 'raw' type bypasses Unicode NFC normalization.
606 'Test string (raw)' => [
607 "\u{2001}",
609 ParamValidator::PARAM_TYPE => 'raw',
611 "\u{2001}",
613 'Validation failure' => [
614 'xyz',
616 ParamValidator::PARAM_TYPE => 'integer',
618 ApiUsageException::newWithMessage( null, [
619 'paramvalidator-badinteger',
620 Message::plaintextParam( 'aptest' ),
621 Message::plaintextParam( 'xyz' ),
622 ], 'badinteger' ),
628 * @dataProvider provideValidateValue
630 public function testValidateValue( $value, $settings, $expect ): void {
631 [ $validator, $main ] = $this->getValidator( new FauxRequest() );
632 $module = $main->getModuleFromPath( 'query+allpages' );
634 if ( $expect instanceof ApiUsageException ) {
635 try {
636 $validator->validateValue( $module, 'test', $value, $settings, [] );
637 $this->fail( 'Expected exception not thrown' );
638 } catch ( ApiUsageException $e ) {
639 $this->assertSame( $module->getModulePath(), $e->getModulePath() );
640 $this->assertEquals( $expect->getStatusValue(), $e->getStatusValue() );
642 } else {
643 $this->assertEquals(
644 $expect,
645 $validator->validateValue( $module, 'test', $value, $settings, [] )
650 public static function provideValidateValue(): array {
651 return [
652 'Basic test' => [
653 1234,
655 ParamValidator::PARAM_TYPE => 'integer',
657 1234
659 'Validation failure' => [
660 1234,
662 ParamValidator::PARAM_TYPE => 'integer',
663 IntegerDef::PARAM_IGNORE_RANGE => false,
664 IntegerDef::PARAM_MAX => 10,
666 ApiUsageException::newWithMessage( null, [
667 'paramvalidator-outofrange-max',
668 Message::plaintextParam( 'aptest' ),
669 Message::plaintextParam( 1234 ),
670 Message::numParam( '' ),
671 Message::numParam( 10 ),
672 ], 'outofrange', [ 'min' => null, 'curmax' => 10, 'max' => 10, 'highmax' => 10 ] ),
677 public function testGetParamInfo() {
678 [ $validator, $main ] = $this->getValidator( new FauxRequest() );
679 $module = $main->getModuleFromPath( 'query+allpages' );
680 $dummy = (object)[];
682 $settings = [
683 'foo' => (object)[],
685 $options = [
686 'bar' => (object)[],
689 $mock = $this->getMockBuilder( ParamValidator::class )
690 ->disableOriginalConstructor()
691 ->onlyMethods( [ 'getParamInfo' ] )
692 ->getMock();
693 $mock->expects( $this->once() )->method( 'getParamInfo' )
694 ->with(
695 $this->identicalTo( 'aptest' ),
696 $this->identicalTo( $settings ),
697 $this->identicalTo( $options + [ 'module' => $module ] )
699 ->willReturn( [ $dummy ] );
701 TestingAccessWrapper::newFromObject( $validator )->paramValidator = $mock;
702 $this->assertSame( [ $dummy ], $validator->getParamInfo( $module, 'test', $settings, $options ) );
705 public function testGetHelpInfo() {
706 [ $validator, $main ] = $this->getValidator( new FauxRequest() );
707 $module = $main->getModuleFromPath( 'query+allpages' );
709 $settings = [
710 'foo' => (object)[],
712 $options = [
713 'bar' => (object)[],
716 $mock = $this->getMockBuilder( ParamValidator::class )
717 ->disableOriginalConstructor()
718 ->onlyMethods( [ 'getHelpInfo' ] )
719 ->getMock();
720 $mock->expects( $this->once() )->method( 'getHelpInfo' )
721 ->with(
722 $this->identicalTo( 'aptest' ),
723 $this->identicalTo( $settings ),
724 $this->identicalTo( $options + [ 'module' => $module ] )
726 ->willReturn( [
727 'mv1' => MessageValue::new( 'parentheses', [ 'foobar' ] ),
728 'mv2' => MessageValue::new( 'paramvalidator-help-continue' ),
729 ] );
731 TestingAccessWrapper::newFromObject( $validator )->paramValidator = $mock;
732 $ret = $validator->getHelpInfo( $module, 'test', $settings, $options );
733 $this->assertArrayHasKey( 'mv1', $ret );
734 $this->assertInstanceOf( Message::class, $ret['mv1'] );
735 $this->assertEquals( '(parentheses: foobar)', $ret['mv1']->inLanguage( 'qqx' )->plain() );
736 $this->assertArrayHasKey( 'mv2', $ret );
737 $this->assertInstanceOf( Message::class, $ret['mv2'] );
738 $this->assertEquals(
739 [ 'api-help-param-continue', 'paramvalidator-help-continue' ],
740 $ret['mv2']->getKeysToTry()
742 $this->assertCount( 2, $ret );