3use Wikimedia\TestingAccessWrapper;
109 if ( !self::$main ) {
111 self::$main->getContext()->setLanguage(
'en' );
112 self::$main->getContext()->setTitle(
113 Title::makeTitle(
NS_SPECIAL,
'Badtitle/dummy title for ApiStructureTest' )
126 $this->assertInstanceOf( Message::class, $msg,
"$what message" );
127 $this->assertTrue( $msg->exists(),
"$what message {$msg->getKey()} exists" );
143 foreach ( $globals as $k => $v ) {
148 $module = TestingAccessWrapper::newFromObject(
$main->getModuleFromPath( $path ) );
151 foreach ( $module->getHelpFlags() as $flag ) {
152 $this->
checkMessage(
"api-help-flag-$flag",
"Flag $flag" );
156 $this->
checkMessage( $module->getSummaryMessage(),
'Module summary' );
157 $this->
checkMessage( $module->getExtendedDescription(),
'Module help top text' );
162 foreach (
$params as $name => $settings ) {
163 if ( !is_array( $settings ) ) {
171 $msg =
"apihelp-{$path}-param-{$name}";
173 $this->
checkMessage( $msg,
"Parameter $name description" );
178 "Parameter $name PARAM_HELP_MSG_PER_VALUE is array" );
180 "Parameter $name PARAM_TYPE is array for msg-per-value mode" );
183 if ( isset( $valueMsgs[
$value] ) ) {
184 $msg = $valueMsgs[
$value];
186 $msg =
"apihelp-{$path}-paramvalue-{$name}-{$value}";
188 $this->
checkMessage( $msg,
"Parameter $name value $value" );
195 "Parameter $name PARAM_HELP_MSG_APPEND is array" );
197 $this->
checkMessage( $msg,
"Parameter $name HELP_MSG_APPEND #$i" );
205 $tags[array_shift( $i )] = 1;
211 foreach ( $tags as $tag => $dummy ) {
212 $this->
checkMessage(
"apihelp-{$path}-paraminfo-{$tag}",
"HELP_MSG_INFO tag $tag" );
216 foreach ( $module->getExamplesMessages() as $qs => $msg ) {
217 $this->assertStringStartsNotWith(
'api.php?', $qs,
218 "Query string must not begin with 'api.php?'" );
226 array_unshift( $paths,
$main->getModulePath() );
229 foreach ( $paths as $path ) {
230 foreach ( self::$testGlobals as $globals ) {
232 foreach ( $globals as $k => $v ) {
233 $g[] =
"$k=" . var_export( $v, 1 );
235 $k =
"Module $path with " . implode(
', ', $g );
248 $module = TestingAccessWrapper::newFromObject(
$main->getModuleFromPath( $path ) );
250 $paramsPlain = $module->getFinalParams();
254 $this->assertTrue(
true );
256 if ( self::$constantNames ===
null ) {
257 self::$constantNames = [];
259 foreach ( (
new ReflectionClass(
'ApiBase' ) )->getConstants() as $key => $val ) {
260 if ( substr( $key, 0, 6 ) ===
'PARAM_' ) {
261 self::$constantNames[$val] = $key;
266 foreach ( [ $paramsPlain, $paramsForHelp ] as
$params ) {
267 foreach (
$params as $param => $config ) {
268 if ( !is_array( $config ) ) {
277 foreach ( self::$paramTypes as $key => $types ) {
278 if ( !isset( $config[$key] ) ) {
281 $keyName = self::$constantNames[$key];
282 $this->
validateType( $types, $config[$key], $param, $keyName );
285 foreach ( self::$paramRequirements as $key => $required ) {
286 if ( !isset( $config[$key] ) ) {
289 foreach ( $required as $requireKey => $requireVal ) {
290 $this->assertArrayHasKey( $requireKey, $config,
291 "$param: When " . self::$constantNames[$key] .
" is set, " .
292 self::$constantNames[$requireKey] .
" must also be set" );
293 if ( $requireVal !==
null ) {
294 $this->assertSame( $requireVal, $config[$requireKey],
295 "$param: When " . self::$constantNames[$key] .
" is set, " .
296 self::$constantNames[$requireKey] .
" must equal " .
297 var_export( $requireVal,
true ) );
302 foreach ( self::$paramAllowedTypes as $key => $allowedTypes ) {
303 if ( !isset( $config[$key] ) ) {
310 $this->assertContains(
312 (array)$allowedTypes,
313 "$param: " . self::$constantNames[$key] .
314 " can only be used with PARAM_TYPE " .
315 implode(
', ', (array)$allowedTypes )
319 foreach ( self::$paramProhibitedTypes as $key => $prohibitedTypes ) {
320 if ( !isset( $config[$key] ) ) {
327 $this->assertNotContains(
329 (array)$prohibitedTypes,
330 "$param: " . self::$constantNames[$key] .
331 " cannot be used with PARAM_TYPE " .
332 implode(
', ', (array)$prohibitedTypes )
340 "$param: A required parameter cannot have a default" );
349 "$param: PARAM_MAX and PARAM_MAX2 are required for limits"
351 $this->assertGreaterThanOrEqual(
354 "$param: PARAM_MAX cannot be greater than PARAM_MAX2"
362 $this->assertGreaterThanOrEqual(
365 "$param: PARAM_MIN cannot be greater than PARAM_MAX"
373 "$param: PARAM_RANGE_ENFORCE can only be set together with " .
374 "PARAM_MIN or PARAM_MAX"
381 "$param: Deprecated value \"$key\" is not allowed, " .
382 "how can it be deprecated?" );
391 "$param: PARAM_ISMULTI_LIMIT1 cannot be negative" );
395 "$param: PARAM_ISMULTI_LIMIT2 cannot be negative or zero" );
396 $this->assertGreaterThanOrEqual(
399 "$param: PARAM_ISMULTI limit cannot be smaller for users with " .
400 "apihighlimits rights" );
405 "$param: PARAM_MAX_BYTES cannot be negative or zero" );
410 "$param: PARAM_MAX_CHARS cannot be negative or zero" );
419 $this->assertGreaterThanOrEqual(
422 "$param: PARAM_MAX_BYTES cannot be less than PARAM_MAX_CHARS"
438 if ( count( $types ) === 1 ) {
440 if ( is_string( $types[0] ) ) {
444 $this->assertInternalType(
'array',
$value,
"$param: $desc type" );
445 foreach (
$value as $subvalue ) {
446 $this->
validateType( $types[0], $subvalue, $param,
"$desc value" );
451 foreach ( $types as
$type ) {
452 if ( is_string(
$type ) ) {
453 if ( class_exists(
$type ) || interface_exists(
$type ) ) {
468 }
catch ( Exception $unused ) {
473 $this->fail(
"$param: $desc has incorrect type" );
488 if ( $default ===
'' ) {
492 $defaults = explode(
'|', $default );
494 foreach ( $defaults as $defaultValue ) {
497 if (
$type ===
'integer' && $defaultValue === (
string)(
int)$defaultValue ) {
498 $defaultValue = (int)$defaultValue;
507 $this->assertFalse( $default,
508 "$param: Boolean params may only default to false" );
512 $this->assertInternalType(
'integer', $default,
513 "$param: Default $default is not an integer" );
517 if ( $default ===
'max' ) {
520 $this->assertInternalType(
'integer', $default,
521 "$param: Default $default is neither an integer nor \"max\"" );
525 $validValues = MWNamespace::getValidNamespaces();
530 $validValues = array_merge(
535 $this->assertContains( $default, $validValues,
536 "$param: Default $default is not a valid namespace" );
545 $this->assertInternalType(
'string', $default,
546 "$param: Default $default is not a string" );
550 if ( $default ===
'now' ) {
553 $this->assertNotFalse(
wfTimestamp( TS_MW, $default ),
554 "$param: Default $default is not a valid timestamp" );
561 $wrapper = TestingAccessWrapper::newFromObject(
new ApiMain() );
563 $wrapper->validateUser( $default,
'' );
565 $this->fail(
"$param: Default $default is not a valid username/IP address" );
570 if ( is_array(
$type ) ) {
571 $this->assertContains( $default,
$type,
572 "$param: Default $default is not any of " .
573 implode(
', ',
$type ) );
575 $this->fail(
"Unrecognized type $type" );
586 array_unshift( $paths,
$main->getModulePath() );
589 foreach ( $paths as $path ) {
602 foreach ( $manager->
getNames() as $name ) {
604 $paths[] = $module->getModulePath();
605 $subManager = $module->getModuleManager();
607 $paths = array_merge( $paths, self::getSubModulePaths( $subManager ) );
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
const PARAM_REQUIRED
(boolean) Is the parameter required?
const PARAM_MAX2
(integer) Max value allowed for the parameter for users with the apihighlimits right,...
const PARAM_SUBMODULE_MAP
(string[]) When PARAM_TYPE is 'submodule', map parameter values to submodule paths.
const PARAM_DEPRECATED
(boolean) Is the parameter deprecated (will show a warning)?
static makeMessage( $msg, IContextSource $context, array $params=null)
Create a Message from a string or array.
const PARAM_MAX
(integer) Max value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'.
const PARAM_DEPRECATED_VALUES
(array) When PARAM_TYPE is an array, this indicates which of the values are deprecated.
const PARAM_ISMULTI_LIMIT1
(integer) Maximum number of values, for normal users.
const PARAM_TYPE
(string|string[]) Either an array of allowed value strings, or a string type as described below.
const PARAM_SENSITIVE
(boolean) Is the parameter sensitive? Note 'password'-type fields are always sensitive regardless of ...
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
const PARAM_DFLT
(null|boolean|integer|string) Default value of the parameter.
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
const PARAM_ALLOW_DUPLICATES
(boolean) Allow the same value to be set more than once when PARAM_ISMULTI is true?
const PARAM_VALUE_LINKS
(string[]) When PARAM_TYPE is an array, this may be an array mapping those values to page titles whic...
const PARAM_ISMULTI_LIMIT2
(integer) Maximum number of values, for users with the apihighimits right.
const PARAM_MAX_CHARS
(integer) Maximum length of a string in characters (unicode codepoints).
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
const PARAM_SUBMODULE_PARAM_PREFIX
(string) When PARAM_TYPE is 'submodule', used to indicate the 'g' prefix added by ApiQueryGeneratorBa...
const PARAM_MIN
(integer) Lowest value allowed for the parameter, for PARAM_TYPE 'integer' and 'limit'.
const PARAM_MAX_BYTES
(integer) Maximum length of a string in bytes (in UTF-8 encoding).
const PARAM_RANGE_ENFORCE
(boolean) For PARAM_TYPE 'integer', enforce PARAM_MIN and PARAM_MAX?
const PARAM_EXTRA_NAMESPACES
(int[]) When PARAM_TYPE is 'namespace', include these as additional possible values.
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
const PARAM_ALL
(boolean|string) When PARAM_TYPE has a defined set of values and PARAM_ISMULTI is true,...
const GET_VALUES_FOR_HELP
getAllowedParams() flag: When set, the result could take longer to generate, but should be more thoro...
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
This is the main API class, used for both external and internal processing.
This class holds a list of modules and handles instantiation.
getModule( $moduleName, $group=null, $ignoreCache=false)
Get module instance by name, or instantiate it if it does not exist.
getNames( $group=null)
Get an array of modules in a specific group or all if no group is set.
Checks that all API modules, core and extensions, conform to the conventions:
static provideDocumentationExists()
static $paramAllowedTypes
static array $testGlobals
Sets of globals to test.
static $paramTypes
Values are an array, where each array value is a permitted type.
static provideParameterConsistency()
static getSubModulePaths(ApiModuleManager $manager)
Return paths of all submodules in an ApiModuleManager, recursively.
testDocumentationExists( $path, array $globals)
provideDocumentationExists
static $paramProhibitedTypes
testParameterConsistency( $path)
provideParameterConsistency
validateDefault( $param, $config)
Asserts that $default is a valid default for $type.
checkMessage( $msg, $what)
Test a message.
validateType( $types, $value, $param, $desc)
Throws if $value does not match one of the types specified in $types.
static $paramRequirements
static getMain()
Initialize/fetch the ApiMain instance for testing.
Exception used to abort API execution with an error.
A Config instance which stores all settings as a member variable.
Provides a fallback sequence for Config objects.
static getMain()
Get the RequestContext object associated with the main request.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
returning false will NOT prevent logging $e