3 use Wikimedia\TestingAccessWrapper;
20 private static $testGlobals = [
37 private static $paramTypes = [
67 private static $paramRequirements = [
81 private static $paramAllowedTypes = [
97 private static $paramProhibitedTypes = [
103 private static $constantNames =
null;
109 private static function getMain() {
110 if ( !self::$main ) {
112 self::$main->getContext()->setLanguage(
'en' );
113 self::$main->getContext()->setTitle(
125 private function checkMessage( $msg, $what ) {
128 $this->assertTrue( $msg->exists(),
"$what message {$msg->getKey()} exists" );
136 public function testDocumentationExists(
$path,
array $globals ) {
137 $main = self::getMain();
144 foreach ( $globals
as $k => $v ) {
152 foreach ( $module->getHelpFlags()
as $flag ) {
153 $this->checkMessage(
"api-help-flag-$flag",
"Flag $flag" );
157 $this->checkMessage( $module->getSummaryMessage(),
'Module summary' );
158 $this->checkMessage( $module->getExtendedDescription(),
'Module help top text' );
164 if ( !is_array( $settings ) ) {
172 $msg =
"apihelp-{$path}-param-{$name}";
174 $this->checkMessage( $msg,
"Parameter $name description" );
179 "Parameter $name PARAM_HELP_MSG_PER_VALUE is array" );
181 "Parameter $name PARAM_TYPE is array for msg-per-value mode" );
184 if ( isset( $valueMsgs[
$value] ) ) {
185 $msg = $valueMsgs[
$value];
187 $msg =
"apihelp-{$path}-paramvalue-{$name}-{$value}";
189 $this->checkMessage( $msg,
"Parameter $name value $value" );
196 "Parameter $name PARAM_HELP_MSG_APPEND is array" );
198 $this->checkMessage( $msg,
"Parameter $name HELP_MSG_APPEND #$i" );
206 $tags[array_shift( $i )] = 1;
212 foreach ( $tags
as $tag => $dummy ) {
213 $this->checkMessage(
"apihelp-{$path}-paraminfo-{$tag}",
"HELP_MSG_INFO tag $tag" );
217 foreach ( $module->getExamplesMessages()
as $qs => $msg ) {
218 $this->assertStringStartsNotWith(
'api.php?', $qs,
219 "Query string must not begin with 'api.php?'" );
220 $this->checkMessage( $msg,
"Example $qs" );
224 public static function provideDocumentationExists() {
225 $main = self::getMain();
231 foreach ( self::$testGlobals
as $globals ) {
233 foreach ( $globals
as $k => $v ) {
234 $g[] =
"$k=" . var_export( $v, 1 );
236 $k =
"Module $path with " . implode(
', ', $g );
247 public function testParameterConsistency(
$path ) {
248 $main = self::getMain();
251 $paramsPlain = $module->getFinalParams();
255 $this->assertTrue(
true );
257 if ( self::$constantNames ===
null ) {
258 self::$constantNames = [];
260 foreach ( (
new ReflectionClass(
'ApiBase' ) )->getConstants()
as $key => $val ) {
261 if ( substr( $key, 0, 6 ) ===
'PARAM_' ) {
262 self::$constantNames[$val] = $key;
267 foreach ( [ $paramsPlain, $paramsForHelp ]
as $params ) {
268 foreach (
$params as $param => $config ) {
269 if ( !is_array( $config ) ) {
278 foreach ( self::$paramTypes
as $key => $types ) {
279 if ( !isset( $config[$key] ) ) {
282 $keyName = self::$constantNames[$key];
283 $this->validateType( $types, $config[$key], $param, $keyName );
286 foreach ( self::$paramRequirements
as $key => $required ) {
287 if ( !isset( $config[$key] ) ) {
290 foreach ( $required
as $requireKey => $requireVal ) {
291 $this->assertArrayHasKey( $requireKey, $config,
292 "$param: When " . self::$constantNames[$key] .
" is set, " .
293 self::$constantNames[$requireKey] .
" must also be set" );
294 if ( $requireVal !==
null ) {
295 $this->assertSame( $requireVal, $config[$requireKey],
296 "$param: When " . self::$constantNames[$key] .
" is set, " .
297 self::$constantNames[$requireKey] .
" must equal " .
298 var_export( $requireVal,
true ) );
303 foreach ( self::$paramAllowedTypes
as $key => $allowedTypes ) {
304 if ( !isset( $config[$key] ) ) {
311 $this->assertContains(
313 (
array)$allowedTypes,
314 "$param: " . self::$constantNames[$key] .
315 " can only be used with PARAM_TYPE " .
316 implode(
', ', (
array)$allowedTypes )
320 foreach ( self::$paramProhibitedTypes
as $key => $prohibitedTypes ) {
321 if ( !isset( $config[$key] ) ) {
328 $this->assertNotContains(
330 (
array)$prohibitedTypes,
331 "$param: " . self::$constantNames[$key] .
332 " cannot be used with PARAM_TYPE " .
333 implode(
', ', (
array)$prohibitedTypes )
341 "$param: A required parameter cannot have a default" );
343 $this->validateDefault( $param, $config );
350 "$param: PARAM_MAX and PARAM_MAX2 are required for limits"
352 $this->assertGreaterThanOrEqual(
355 "$param: PARAM_MAX cannot be greater than PARAM_MAX2"
363 $this->assertGreaterThanOrEqual(
366 "$param: PARAM_MIN cannot be greater than PARAM_MAX"
374 "$param: PARAM_RANGE_ENFORCE can only be set together with " .
375 "PARAM_MIN or PARAM_MAX"
382 "$param: Deprecated value \"$key\" is not allowed, " .
383 "how can it be deprecated?" );
392 "$param: PARAM_ISMULTI_LIMIT1 cannot be negative" );
396 "$param: PARAM_ISMULTI_LIMIT2 cannot be negative or zero" );
397 $this->assertGreaterThanOrEqual(
400 "$param: PARAM_ISMULTI limit cannot be smaller for users with " .
401 "apihighlimits rights" );
406 "$param: PARAM_MAX_BYTES cannot be negative or zero" );
411 "$param: PARAM_MAX_CHARS cannot be negative or zero" );
420 $this->assertGreaterThanOrEqual(
423 "$param: PARAM_MAX_BYTES cannot be less than PARAM_MAX_CHARS"
429 "$param: PARAM_TEMPLATE_VARS cannot be empty" );
431 $this->assertRegExp(
'/^[^{}]+$/', $key,
432 "$param: PARAM_TEMPLATE_VARS key may not contain '{' or '}'" );
434 $this->assertContains(
'{' . $key .
'}', $param,
435 "$param: Name must contain PARAM_TEMPLATE_VARS key {" . $key .
"}" );
436 $this->assertArrayHasKey( $target,
$params,
437 "$param: PARAM_TEMPLATE_VARS target parameter '$target' does not exist" );
440 "$param: PARAM_TEMPLATE_VARS target parameter '$target' must have PARAM_ISMULTI = true" );
443 $this->assertNotSame( $param, $target,
444 "$param: PARAM_TEMPLATE_VARS cannot target itself" );
446 $this->assertArraySubset(
450 "$param: PARAM_TEMPLATE_VARS target parameter '$target': "
451 .
"the target's PARAM_TEMPLATE_VARS must be a subset of the original."
456 $keys = implode(
'|',
459 return preg_quote( $key,
'/' );
464 $this->assertRegExp(
'/^(?>[^{}]+|\{(?:' .
$keys .
')\})+$/', $param,
465 "$param: Name may not contain '{' or '}' other than as defined by PARAM_TEMPLATE_VARS" );
467 $this->assertRegExp(
'/^[^{}]+$/', $param,
468 "$param: Name may not contain '{' or '}' without PARAM_TEMPLATE_VARS" );
482 private function validateType( $types,
$value, $param, $desc ) {
483 if (
count( $types ) === 1 ) {
485 if ( is_string( $types[0] ) ) {
489 $this->assertInternalType(
'array',
$value,
"$param: $desc type" );
491 $this->validateType( $types[0], $subvalue, $param,
"$desc value" );
497 if ( is_string(
$type ) ) {
498 if ( class_exists(
$type ) || interface_exists(
$type ) ) {
510 $this->validateType( [
$type ],
$value, $param,
"$desc type" );
513 }
catch ( Exception $unused ) {
518 $this->fail(
"$param: $desc has incorrect type" );
528 private function validateDefault( $param, $config ) {
533 if ( $default ===
'' ) {
537 $defaults = explode(
'|', $default );
539 foreach ( $defaults
as $defaultValue ) {
542 if (
$type ===
'integer' && $defaultValue === (
string)(
int)$defaultValue ) {
543 $defaultValue = (int)$defaultValue;
546 $this->validateDefault( $param, $config );
552 $this->assertFalse( $default,
553 "$param: Boolean params may only default to false" );
557 $this->assertInternalType(
'integer', $default,
558 "$param: Default $default is not an integer" );
562 if ( $default ===
'max' ) {
565 $this->assertInternalType(
'integer', $default,
566 "$param: Default $default is neither an integer nor \"max\"" );
575 $validValues = array_merge(
580 $this->assertContains( $default, $validValues,
581 "$param: Default $default is not a valid namespace" );
590 $this->assertInternalType(
'string', $default,
591 "$param: Default $default is not a string" );
595 if ( $default ===
'now' ) {
598 $this->assertNotFalse(
wfTimestamp( TS_MW, $default ),
599 "$param: Default $default is not a valid timestamp" );
606 $wrapper = TestingAccessWrapper::newFromObject(
new ApiMain() );
608 $wrapper->validateUser( $default,
'' );
610 $this->fail(
"$param: Default $default is not a valid username/IP address" );
615 if ( is_array(
$type ) ) {
616 $this->assertContains( $default,
$type,
617 "$param: Default $default is not any of " .
618 implode(
', ',
$type ) );
620 $this->fail(
"Unrecognized type $type" );
628 public static function provideParameterConsistency() {
629 $main = self::getMain();
649 $paths[] = $module->getModulePath();
650 $subManager = $module->getModuleManager();
652 $paths = array_merge( $paths, self::getSubModulePaths( $subManager ) );