+ 'Multi-valued parameter with limits' => [
+ 'a|b|c',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_ISMULTI_LIMIT1 => 3,
+ ],
+ [ 'a', 'b', 'c' ],
+ [],
+ ],
+ 'Multi-valued parameter with exceeded limits' => [
+ 'a|b|c',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_ISMULTI_LIMIT1 => 2,
+ ],
+ [ 'a', 'b' ],
+ [ [ 'apiwarn-toomanyvalues', 'myParam', 2 ] ],
+ ],
+ 'Multi-valued parameter with exceeded limits for non-bot' => [
+ 'a|b|c',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_ISMULTI_LIMIT1 => 2,
+ ApiBase::PARAM_ISMULTI_LIMIT2 => 3,
+ ],
+ [ 'a', 'b' ],
+ [ [ 'apiwarn-toomanyvalues', 'myParam', 2 ] ],
+ ],
+ 'Multi-valued parameter with non-exceeded limits for bot' => [
+ 'a|b|c',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_ISMULTI_LIMIT1 => 2,
+ ApiBase::PARAM_ISMULTI_LIMIT2 => 3,
+ ],
+ [ 'a', 'b', 'c' ],
+ [],
+ [ 'apihighlimits' => true ],
+ ],
+ 'Multi-valued parameter with prohibited duplicates' => [
+ 'a|b|a|c',
+ [ ApiBase::PARAM_ISMULTI => true ],
+ // Note that the keys are not sequential! This matches
+ // array_unique, but might be unexpected.
+ [ 0 => 'a', 1 => 'b', 3 => 'c' ],
+ [],
+ ],
+ 'Multi-valued parameter with allowed duplicates' => [
+ 'a|a',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_ALLOW_DUPLICATES => true,
+ ],
+ [ 'a', 'a' ],
+ [],
+ ],
+ 'Empty boolean param' => [
+ '',
+ [ ApiBase::PARAM_TYPE => 'boolean' ],
+ true,
+ [],
+ ],
+ 'Boolean param 0' => [
+ '0',
+ [ ApiBase::PARAM_TYPE => 'boolean' ],
+ true,
+ [],
+ ],
+ 'Boolean param false' => [
+ 'false',
+ [ ApiBase::PARAM_TYPE => 'boolean' ],
+ true,
+ [],
+ ],
+ 'Boolean multi-param' => [
+ 'true|false',
+ [
+ ApiBase::PARAM_TYPE => 'boolean',
+ ApiBase::PARAM_ISMULTI => true,
+ ],
+ new MWException(
+ 'Internal error in ApiBase::getParameterFromSettings: ' .
+ 'Multi-values not supported for myParam'
+ ),
+ [],
+ ],
+ 'Empty boolean param with non-false default' => [
+ '',
+ [
+ ApiBase::PARAM_TYPE => 'boolean',
+ ApiBase::PARAM_DFLT => true,
+ ],
+ new MWException(
+ 'Internal error in ApiBase::getParameterFromSettings: ' .
+ "Boolean param myParam's default is set to '1'. " .
+ 'Boolean parameters must default to false.' ),
+ [],
+ ],
+ 'Deprecated parameter' => [
+ 'foo',
+ [ ApiBase::PARAM_DEPRECATED => true ],
+ 'foo',
+ [ [ 'apiwarn-deprecation-parameter', 'myParam' ] ],
+ ],
+ 'Deprecated parameter value' => [
+ 'a',
+ [ ApiBase::PARAM_DEPRECATED_VALUES => [ 'a' => true ] ],
+ 'a',
+ [ [ 'apiwarn-deprecation-parameter', 'myParam=a' ] ],
+ ],
+ 'Multiple deprecated parameter values' => [
+ 'a|b|c|d',
+ [ ApiBase::PARAM_DEPRECATED_VALUES =>
+ [ 'b' => true, 'd' => true ],
+ ApiBase::PARAM_ISMULTI => true ],
+ [ 'a', 'b', 'c', 'd' ],
+ [
+ [ 'apiwarn-deprecation-parameter', 'myParam=b' ],
+ [ 'apiwarn-deprecation-parameter', 'myParam=d' ],
+ ],
+ ],
+ 'Deprecated parameter value with custom warning' => [
+ 'a',
+ [ ApiBase::PARAM_DEPRECATED_VALUES => [ 'a' => 'my-msg' ] ],
+ 'a',
+ [ 'my-msg' ],
+ ],
+ '"*" when wildcard not allowed' => [
+ '*',
+ [ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => [ 'a', 'b', 'c' ] ],
+ [],
+ [ [ 'apiwarn-unrecognizedvalues', 'myParam',
+ [ 'list' => [ '*' ], 'type' => 'comma' ], 1 ] ],
+ ],
+ 'Wildcard "*"' => [
+ '*',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => [ 'a', 'b', 'c' ],
+ ApiBase::PARAM_ALL => true,
+ ],
+ [ 'a', 'b', 'c' ],
+ [],
+ ],
+ 'Wildcard "*" with multiples not allowed' => [
+ '*',
+ [
+ ApiBase::PARAM_TYPE => [ 'a', 'b', 'c' ],
+ ApiBase::PARAM_ALL => true,
+ ],
+ ApiUsageException::newWithMessage( null,
+ [ 'apierror-unrecognizedvalue', 'myParam', '*' ],
+ 'unknown_myParam' ),
+ [],
+ ],
+ 'Wildcard "*" with unrestricted type' => [
+ '*',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_ALL => true,
+ ],
+ [ '*' ],
+ [],
+ ],
+ 'Wildcard "x"' => [
+ 'x',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => [ 'a', 'b', 'c' ],
+ ApiBase::PARAM_ALL => 'x',
+ ],
+ [ 'a', 'b', 'c' ],
+ [],
+ ],
+ 'Wildcard conflicting with allowed value' => [
+ 'a',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => [ 'a', 'b', 'c' ],
+ ApiBase::PARAM_ALL => 'a',
+ ],
+ new MWException(
+ 'Internal error in ApiBase::getParameterFromSettings: ' .
+ 'For param myParam, PARAM_ALL collides with a possible ' .
+ 'value' ),
+ [],
+ ],
+ 'Namespace with wildcard' => [
+ '*',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => 'namespace',
+ ],
+ MWNamespace::getValidNamespaces(),
+ [],
+ ],
+ // PARAM_ALL is ignored with namespace types.
+ 'Namespace with wildcard suppressed' => [
+ '*',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => 'namespace',
+ ApiBase::PARAM_ALL => false,
+ ],
+ MWNamespace::getValidNamespaces(),
+ [],
+ ],
+ 'Namespace with wildcard "x"' => [
+ 'x',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => 'namespace',
+ ApiBase::PARAM_ALL => 'x',
+ ],
+ [],
+ [ [ 'apiwarn-unrecognizedvalues', 'myParam',
+ [ 'list' => [ 'x' ], 'type' => 'comma' ], 1 ] ],
+ ],
+ 'Password' => [
+ 'dDy+G?e?txnr.1:(@[Ru',
+ [ ApiBase::PARAM_TYPE => 'password' ],
+ 'dDy+G?e?txnr.1:(@[Ru',
+ [],
+ ],
+ 'Sensitive field' => [
+ 'I am fond of pineapples',
+ [ ApiBase::PARAM_SENSITIVE => true ],
+ 'I am fond of pineapples',
+ [],
+ ],
+ 'Upload with default' => [
+ '',
+ [
+ ApiBase::PARAM_TYPE => 'upload',
+ ApiBase::PARAM_DFLT => '',
+ ],
+ new MWException(
+ 'Internal error in ApiBase::getParameterFromSettings: ' .
+ "File upload param myParam's default is set to ''. " .
+ 'File upload parameters may not have a default.' ),
+ [],
+ ],
+ 'Multiple upload' => [
+ '',
+ [
+ ApiBase::PARAM_TYPE => 'upload',
+ ApiBase::PARAM_ISMULTI => true,
+ ],
+ new MWException(
+ 'Internal error in ApiBase::getParameterFromSettings: ' .
+ 'Multi-values not supported for myParam' ),
+ [],
+ ],
+ // @todo Test actual upload
+ 'Namespace -1' => [
+ '-1',
+ [ ApiBase::PARAM_TYPE => 'namespace' ],
+ ApiUsageException::newWithMessage( null,
+ [ 'apierror-unrecognizedvalue', 'myParam', '-1' ],
+ 'unknown_myParam' ),
+ [],
+ ],
+ 'Extra namespace -1' => [
+ '-1',
+ [
+ ApiBase::PARAM_TYPE => 'namespace',
+ ApiBase::PARAM_EXTRA_NAMESPACES => [ '-1' ],
+ ],
+ '-1',
+ [],
+ ],
+ // @todo Test with PARAM_SUBMODULE_MAP unset, need
+ // getModuleManager() to return something real
+ 'Nonexistent module' => [
+ 'not-a-module-name',
+ [
+ ApiBase::PARAM_TYPE => 'submodule',
+ ApiBase::PARAM_SUBMODULE_MAP =>
+ [ 'foo' => 'foo', 'bar' => 'foo+bar' ],
+ ],
+ ApiUsageException::newWithMessage(
+ null,
+ [
+ 'apierror-unrecognizedvalue',
+ 'myParam',
+ 'not-a-module-name',
+ ],
+ 'unknown_myParam'
+ ),
+ [],
+ ],
+ '\\x1f with multiples not allowed' => [
+ "\x1f",
+ [],
+ ApiUsageException::newWithMessage( null,
+ 'apierror-badvalue-notmultivalue',
+ 'badvalue_notmultivalue' ),
+ [],
+ ],
+ 'Integer with unenforced min' => [
+ '-2',
+ [
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MIN => -1,
+ ],
+ -1,
+ [ [ 'apierror-integeroutofrange-belowminimum', 'myParam', -1,
+ -2 ] ],
+ ],
+ 'Integer with enforced min' => [
+ '-2',
+ [
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MIN => -1,
+ ApiBase::PARAM_RANGE_ENFORCE => true,
+ ],
+ ApiUsageException::newWithMessage( null,
+ [ 'apierror-integeroutofrange-belowminimum', 'myParam',
+ '-1', '-2' ], 'integeroutofrange',
+ [ 'min' => -1, 'max' => null, 'botMax' => null ] ),
+ [],
+ ],
+ 'Integer with unenforced max (internal mode)' => [
+ '8',
+ [
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MAX => 7,
+ ],
+ 8,
+ [],
+ ],
+ 'Integer with enforced max (internal mode)' => [
+ '8',
+ [
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MAX => 7,
+ ApiBase::PARAM_RANGE_ENFORCE => true,
+ ],
+ 8,
+ [],
+ ],
+ 'Integer with unenforced max (non-internal mode)' => [
+ '8',
+ [
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MAX => 7,
+ ],
+ 7,
+ [ [ 'apierror-integeroutofrange-abovemax', 'myParam', 7, 8 ] ],
+ [ 'internalmode' => false ],
+ ],
+ 'Integer with enforced max (non-internal mode)' => [
+ '8',
+ [
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MAX => 7,
+ ApiBase::PARAM_RANGE_ENFORCE => true,
+ ],
+ ApiUsageException::newWithMessage(
+ null,
+ [ 'apierror-integeroutofrange-abovemax', 'myParam', '7', '8' ],
+ 'integeroutofrange',
+ [ 'min' => null, 'max' => 7, 'botMax' => 7 ]
+ ),
+ [],
+ [ 'internalmode' => false ],
+ ],
+ 'Array of integers' => [
+ '3|12|966|-1',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => 'integer',
+ ],
+ [ 3, 12, 966, -1 ],
+ [],
+ ],
+ 'Array of integers with unenforced min/max (internal mode)' => [
+ '3|12|966|-1',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MIN => 0,
+ ApiBase::PARAM_MAX => 100,
+ ],
+ [ 3, 12, 966, 0 ],
+ [ [ 'apierror-integeroutofrange-belowminimum', 'myParam', 0, -1 ] ],
+ ],
+ 'Array of integers with enforced min/max (internal mode)' => [
+ '3|12|966|-1',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MIN => 0,
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_RANGE_ENFORCE => true,
+ ],
+ ApiUsageException::newWithMessage(
+ null,
+ [ 'apierror-integeroutofrange-belowminimum', 'myParam', 0, -1 ],
+ 'integeroutofrange',
+ [ 'min' => 0, 'max' => 100, 'botMax' => 100 ]
+ ),
+ [],
+ ],
+ 'Array of integers with unenforced min/max (non-internal mode)' => [
+ '3|12|966|-1',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MIN => 0,
+ ApiBase::PARAM_MAX => 100,
+ ],
+ [ 3, 12, 100, 0 ],
+ [
+ [ 'apierror-integeroutofrange-abovemax', 'myParam', 100, 966 ],
+ [ 'apierror-integeroutofrange-belowminimum', 'myParam', 0, -1 ]
+ ],
+ [ 'internalmode' => false ],
+ ],
+ 'Array of integers with enforced min/max (non-internal mode)' => [
+ '3|12|966|-1',
+ [
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_TYPE => 'integer',
+ ApiBase::PARAM_MIN => 0,
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_RANGE_ENFORCE => true,
+ ],
+ ApiUsageException::newWithMessage(
+ null,
+ [ 'apierror-integeroutofrange-abovemax', 'myParam', 100, 966 ],
+ 'integeroutofrange',
+ [ 'min' => 0, 'max' => 100, 'botMax' => 100 ]
+ ),
+ [],
+ [ 'internalmode' => false ],
+ ],
+ 'Limit with parseLimits false' => [
+ '100',
+ [ ApiBase::PARAM_TYPE => 'limit' ],
+ '100',
+ [],
+ [ 'parseLimits' => false ],
+ ],
+ 'Limit with no max' => [
+ '100',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX2 => 10,
+ ApiBase::PARAM_ISMULTI => true,
+ ],
+ new MWException(
+ 'Internal error in ApiBase::getParameterFromSettings: ' .
+ 'MAX1 or MAX2 are not defined for the limit myParam' ),
+ [],
+ ],
+ 'Limit with no max2' => [
+ '100',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 10,
+ ApiBase::PARAM_ISMULTI => true,
+ ],
+ new MWException(
+ 'Internal error in ApiBase::getParameterFromSettings: ' .
+ 'MAX1 or MAX2 are not defined for the limit myParam' ),
+ [],
+ ],
+ 'Limit with multi-value' => [
+ '100',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 10,
+ ApiBase::PARAM_MAX2 => 10,
+ ApiBase::PARAM_ISMULTI => true,
+ ],
+ new MWException(
+ 'Internal error in ApiBase::getParameterFromSettings: ' .
+ 'Multi-values not supported for myParam' ),
+ [],
+ ],
+ 'Valid limit' => [
+ '100',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 100,
+ ],
+ 100,
+ [],
+ ],
+ 'Limit max' => [
+ 'max',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 101,
+ ],
+ 100,
+ [],
+ ],
+ 'Limit max for apihighlimits' => [
+ 'max',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 101,
+ ],
+ 101,
+ [],
+ [ 'apihighlimits' => true ],
+ ],
+ 'Limit too large (internal mode)' => [
+ '101',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 101,
+ ],
+ 101,
+ [],
+ ],
+ 'Limit okay for apihighlimits (internal mode)' => [
+ '101',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 101,
+ ],
+ 101,
+ [],
+ [ 'apihighlimits' => true ],
+ ],
+ 'Limit too large for apihighlimits (internal mode)' => [
+ '102',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 101,
+ ],
+ 102,
+ [],
+ [ 'apihighlimits' => true ],
+ ],
+ 'Limit too large (non-internal mode)' => [
+ '101',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 101,
+ ],
+ 100,
+ [ [ 'apierror-integeroutofrange-abovemax', 'myParam', 100, 101 ] ],
+ [ 'internalmode' => false ],
+ ],
+ 'Limit okay for apihighlimits (non-internal mode)' => [
+ '101',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 101,
+ ],
+ 101,
+ [],
+ [ 'internalmode' => false, 'apihighlimits' => true ],
+ ],
+ 'Limit too large for apihighlimits (non-internal mode)' => [
+ '102',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 101,
+ ],
+ 101,
+ [ [ 'apierror-integeroutofrange-abovebotmax', 'myParam', 101, 102 ] ],
+ [ 'internalmode' => false, 'apihighlimits' => true ],
+ ],
+ 'Limit too small' => [
+ '-2',
+ [
+ ApiBase::PARAM_TYPE => 'limit',
+ ApiBase::PARAM_MIN => -1,
+ ApiBase::PARAM_MAX => 100,
+ ApiBase::PARAM_MAX2 => 100,
+ ],
+ -1,
+ [ [ 'apierror-integeroutofrange-belowminimum', 'myParam', -1,
+ -2 ] ],
+ ],
+ 'Timestamp' => [
+ wfTimestamp( TS_UNIX, '20211221122112' ),
+ [ ApiBase::PARAM_TYPE => 'timestamp' ],
+ '20211221122112',
+ [],
+ ],
+ 'Timestamp 0' => [
+ '0',
+ [ ApiBase::PARAM_TYPE => 'timestamp' ],
+ // Magic keyword
+ 'now',
+ [ [ 'apiwarn-unclearnowtimestamp', 'myParam', '0' ] ],
+ ],
+ 'Timestamp empty' => [
+ '',
+ [ ApiBase::PARAM_TYPE => 'timestamp' ],
+ 'now',
+ [ [ 'apiwarn-unclearnowtimestamp', 'myParam', '' ] ],
+ ],
+ // wfTimestamp() interprets this as Unix time
+ 'Timestamp 00' => [
+ '00',
+ [ ApiBase::PARAM_TYPE => 'timestamp' ],
+ '19700101000000',
+ [],
+ ],
+ 'Timestamp now' => [
+ 'now',
+ [ ApiBase::PARAM_TYPE => 'timestamp' ],
+ 'now',
+ [],
+ ],
+ 'Invalid timestamp' => [
+ 'a potato',
+ [ ApiBase::PARAM_TYPE => 'timestamp' ],
+ ApiUsageException::newWithMessage(
+ null,
+ [ 'apierror-badtimestamp', 'myParam', 'a potato' ],
+ 'badtimestamp_myParam'
+ ),
+ [],
+ ],
+ 'Timestamp array' => [
+ '100|101',
+ [
+ ApiBase::PARAM_TYPE => 'timestamp',
+ ApiBase::PARAM_ISMULTI => 1,
+ ],
+ [ wfTimestamp( TS_MW, 100 ), wfTimestamp( TS_MW, 101 ) ],
+ [],
+ ],
+ 'User' => [
+ 'foo_bar',
+ [ ApiBase::PARAM_TYPE => 'user' ],
+ 'Foo bar',
+ [],
+ ],
+ 'Invalid username "|"' => [
+ '|',
+ [ ApiBase::PARAM_TYPE => 'user' ],
+ ApiUsageException::newWithMessage( null,
+ [ 'apierror-baduser', 'myParam', '|' ],
+ 'baduser_myParam' ),
+ [],
+ ],
+ 'Invalid username "300.300.300.300"' => [
+ '300.300.300.300',
+ [ ApiBase::PARAM_TYPE => 'user' ],
+ ApiUsageException::newWithMessage( null,
+ [ 'apierror-baduser', 'myParam', '300.300.300.300' ],
+ 'baduser_myParam' ),
+ [],
+ ],
+ 'IP range as username' => [
+ '10.0.0.0/8',
+ [ ApiBase::PARAM_TYPE => 'user' ],
+ '10.0.0.0/8',
+ [],
+ ],
+ 'IPv6 as username' => [
+ '::1',
+ [ ApiBase::PARAM_TYPE => 'user' ],
+ '0:0:0:0:0:0:0:1',
+ [],
+ ],
+ 'Obsolete cloaked usemod IP address as username' => [
+ '1.2.3.xxx',
+ [ ApiBase::PARAM_TYPE => 'user' ],
+ '1.2.3.xxx',
+ [],
+ ],
+ 'Invalid username containing IP address' => [
+ 'This is [not] valid 1.2.3.xxx, ha!',
+ [ ApiBase::PARAM_TYPE => 'user' ],
+ ApiUsageException::newWithMessage(
+ null,
+ [ 'apierror-baduser', 'myParam', 'This is [not] valid 1.2.3.xxx, ha!' ],
+ 'baduser_myParam'
+ ),
+ [],
+ ],
+ 'External username' => [
+ 'M>Foo bar',
+ [ ApiBase::PARAM_TYPE => 'user' ],
+ 'M>Foo bar',
+ [],
+ ],
+ 'Array of usernames' => [
+ 'foo|bar',
+ [
+ ApiBase::PARAM_TYPE => 'user',
+ ApiBase::PARAM_ISMULTI => true,
+ ],
+ [ 'Foo', 'Bar' ],
+ [],
+ ],
+ 'tag' => [
+ 'tag1',
+ [ ApiBase::PARAM_TYPE => 'tags' ],
+ [ 'tag1' ],
+ [],
+ ],
+ 'Array of one tag' => [
+ 'tag1',
+ [
+ ApiBase::PARAM_TYPE => 'tags',
+ ApiBase::PARAM_ISMULTI => true,
+ ],
+ [ 'tag1' ],
+ [],
+ ],
+ 'Array of tags' => [
+ 'tag1|tag2',
+ [
+ ApiBase::PARAM_TYPE => 'tags',
+ ApiBase::PARAM_ISMULTI => true,
+ ],
+ [ 'tag1', 'tag2' ],
+ [],
+ ],
+ 'Invalid tag' => [
+ 'invalid tag',
+ [ ApiBase::PARAM_TYPE => 'tags' ],
+ new ApiUsageException( null,
+ Status::newFatal( 'tags-apply-not-allowed-one',
+ 'invalid tag', 1 ) ),
+ [],
+ ],
+ 'Unrecognized type' => [
+ 'foo',
+ [ ApiBase::PARAM_TYPE => 'nonexistenttype' ],
+ new MWException(
+ 'Internal error in ApiBase::getParameterFromSettings: ' .
+ "Param myParam's type is unknown - nonexistenttype" ),
+ [],
+ ],
+ 'Too many bytes' => [
+ '1',
+ [
+ ApiBase::PARAM_MAX_BYTES => 0,
+ ApiBase::PARAM_MAX_CHARS => 0,
+ ],
+ ApiUsageException::newWithMessage( null,
+ [ 'apierror-maxbytes', 'myParam', 0 ] ),
+ [],
+ ],
+ 'Too many chars' => [
+ 'ยงยง',
+ [
+ ApiBase::PARAM_MAX_BYTES => 4,
+ ApiBase::PARAM_MAX_CHARS => 1,
+ ],
+ ApiUsageException::newWithMessage( null,
+ [ 'apierror-maxchars', 'myParam', 1 ] ),
+ [],
+ ],
+ 'Omitted required param' => [
+ null,
+ [ ApiBase::PARAM_REQUIRED => true ],
+ ApiUsageException::newWithMessage( null,
+ [ 'apierror-missingparam', 'myParam' ] ),
+ [],
+ ],
+ 'Empty multi-value' => [
+ '',
+ [ ApiBase::PARAM_ISMULTI => true ],
+ [],
+ [],
+ ],
+ 'Multi-value \x1f' => [
+ "\x1f",
+ [ ApiBase::PARAM_ISMULTI => true ],
+ [],
+ [],
+ ],
+ 'Allowed non-multi-value with "|"' => [
+ 'a|b',
+ [ ApiBase::PARAM_TYPE => [ 'a|b' ] ],
+ 'a|b',
+ [],
+ ],
+ 'Prohibited multi-value' => [
+ 'a|b',
+ [ ApiBase::PARAM_TYPE => [ 'a', 'b' ] ],
+ ApiUsageException::newWithMessage( null,
+ [
+ 'apierror-multival-only-one-of',
+ 'myParam',
+ Message::listParam( [ '<kbd>a</kbd>', '<kbd>b</kbd>' ] ),
+ 2
+ ],
+ 'multival_myParam'
+ ),
+ [],
+ ],
+ ];
+
+ // The following really just test PHP's string-to-int conversion.
+ $integerTests = [
+ [ '+1', 1 ],
+ [ '-1', -1 ],
+ [ '1e3', 1 ],
+ [ '1.5', 1 ],
+ [ '-1.5', -1 ],
+ [ '1abc', 1 ],
+ [ ' 1', 1 ],
+ [ "\t1", 1, '\t1' ],
+ [ "\r1", 1, '\r1' ],
+ [ "\f1", 0, '\f1', 'badutf-8' ],
+ [ "\n1", 1, '\n1' ],
+ [ "\v1", 0, '\v1', 'badutf-8' ],
+ [ "\e1", 0, '\e1', 'badutf-8' ],
+ [ "\x001", 0, '\x001', 'badutf-8' ],