293 lines
9.4 KiB
PHP
293 lines
9.4 KiB
PHP
<?php
|
|
|
|
namespace MediaWiki\Api\Validator;
|
|
|
|
use ApiBase;
|
|
use ApiMain;
|
|
use ApiMessage;
|
|
use ApiQueryBase;
|
|
use ApiUploadTestCase;
|
|
use FauxRequest;
|
|
use Wikimedia\Message\DataMessageValue;
|
|
use Wikimedia\TestingAccessWrapper;
|
|
|
|
/**
|
|
* @covers MediaWiki\Api\Validator\ApiParamValidatorCallbacks
|
|
* @group API
|
|
* @group medium
|
|
*/
|
|
class ApiParamValidatorCallbacksTest extends ApiUploadTestCase {
|
|
|
|
private function getCallbacks( FauxRequest $request ) : array {
|
|
$context = $this->apiContext->newTestContext( $request, $this->getTestUser()->getUser() );
|
|
$main = new ApiMain( $context );
|
|
return [ new ApiParamValidatorCallbacks( $main ), $main ];
|
|
}
|
|
|
|
private function filePath( $fileName ) {
|
|
return __DIR__ . '/../../../data/media/' . $fileName;
|
|
}
|
|
|
|
public function testHasParam() : void {
|
|
[ $callbacks, $main ] = $this->getCallbacks( new FauxRequest( [
|
|
'foo' => '1',
|
|
'bar' => '',
|
|
] ) );
|
|
|
|
$this->assertTrue( $callbacks->hasParam( 'foo', [] ) );
|
|
$this->assertTrue( $callbacks->hasParam( 'bar', [] ) );
|
|
$this->assertFalse( $callbacks->hasParam( 'baz', [] ) );
|
|
|
|
$this->assertSame(
|
|
[ 'foo', 'bar', 'baz' ],
|
|
TestingAccessWrapper::newFromObject( $main )->getParamsUsed()
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider provideGetValue
|
|
* @param string|null $data Value from request
|
|
* @param mixed $default For getValue()
|
|
* @param mixed $expect Expected return value
|
|
* @param bool $normalized Whether handleParamNormalization is called
|
|
*/
|
|
public function testGetValue( ?string $data, $default, $expect, bool $normalized = false ) : void {
|
|
[ $callbacks, $main ] = $this->getCallbacks( new FauxRequest( [ 'test' => $data ] ) );
|
|
|
|
$module = $this->getMockBuilder( ApiBase::class )
|
|
->setConstructorArgs( [ $main, 'testmodule' ] )
|
|
->onlyMethods( [ 'handleParamNormalization' ] )
|
|
->getMockForAbstractClass();
|
|
$options = [ 'module' => $module ];
|
|
if ( $normalized ) {
|
|
$module->expects( $this->once() )->method( 'handleParamNormalization' )
|
|
->with(
|
|
$this->identicalTo( 'test' ),
|
|
$this->identicalTo( $expect ),
|
|
$this->identicalTo( $data ?? $default )
|
|
);
|
|
} else {
|
|
$module->expects( $this->never() )->method( 'handleParamNormalization' );
|
|
}
|
|
|
|
$this->assertSame( $expect, $callbacks->getValue( 'test', $default, $options ) );
|
|
$this->assertSame( [ 'test' ], TestingAccessWrapper::newFromObject( $main )->getParamsUsed() );
|
|
}
|
|
|
|
public function provideGetValue() {
|
|
$obj = (object)[];
|
|
return [
|
|
'Basic test' => [ 'foo', 'bar', 'foo', false ],
|
|
'Default value' => [ null, 1234, 1234, false ],
|
|
'Default value (2)' => [ null, $obj, $obj, false ],
|
|
'No default value' => [ null, null, null, false ],
|
|
'Multi separator' => [ "\x1ffoo\x1fbar", 1234, "\x1ffoo\x1fbar", false ],
|
|
'Normalized' => [ "\x1ffoo\x1fba\u{0301}r", 1234, "\x1ffoo\x1fbár", true ],
|
|
];
|
|
}
|
|
|
|
private function setupUploads() : void {
|
|
$fileName = 'TestUploadStash.jpg';
|
|
$mimeType = 'image/jpeg';
|
|
$filePath = $this->filePath( 'yuv420.jpg' );
|
|
$this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath );
|
|
|
|
$this->requestDataFiles['file2'] = [
|
|
'name' => '',
|
|
'type' => '',
|
|
'tmp_name' => '',
|
|
'size' => 0,
|
|
'error' => UPLOAD_ERR_NO_FILE,
|
|
];
|
|
|
|
$this->requestDataFiles['file3'] = [
|
|
'name' => 'xxx.png',
|
|
'type' => '',
|
|
'tmp_name' => '',
|
|
'size' => 0,
|
|
'error' => UPLOAD_ERR_INI_SIZE,
|
|
];
|
|
}
|
|
|
|
public function testHasUpload() : void {
|
|
$this->setupUploads();
|
|
|
|
$request = new FauxRequest( [
|
|
'foo' => '1',
|
|
'bar' => '',
|
|
] );
|
|
$request->setUploadData( $this->requestDataFiles );
|
|
[ $callbacks, $main ] = $this->getCallbacks( $request );
|
|
|
|
$this->assertFalse( $callbacks->hasUpload( 'foo', [] ) );
|
|
$this->assertFalse( $callbacks->hasUpload( 'bar', [] ) );
|
|
$this->assertFalse( $callbacks->hasUpload( 'baz', [] ) );
|
|
$this->assertTrue( $callbacks->hasUpload( 'file', [] ) );
|
|
$this->assertTrue( $callbacks->hasUpload( 'file2', [] ) );
|
|
$this->assertTrue( $callbacks->hasUpload( 'file3', [] ) );
|
|
|
|
$this->assertSame(
|
|
[ 'foo', 'bar', 'baz', 'file', 'file2', 'file3' ],
|
|
TestingAccessWrapper::newFromObject( $main )->getParamsUsed()
|
|
);
|
|
}
|
|
|
|
public function testGetUploadedFile() : void {
|
|
$this->setupUploads();
|
|
|
|
$request = new FauxRequest( [
|
|
'foo' => '1',
|
|
'bar' => '',
|
|
] );
|
|
$request->setUploadData( $this->requestDataFiles );
|
|
[ $callbacks, $main ] = $this->getCallbacks( $request );
|
|
|
|
$this->assertNull( $callbacks->getUploadedFile( 'foo', [] ) );
|
|
$this->assertNull( $callbacks->getUploadedFile( 'bar', [] ) );
|
|
$this->assertNull( $callbacks->getUploadedFile( 'baz', [] ) );
|
|
|
|
$file = $callbacks->getUploadedFile( 'file', [] );
|
|
$this->assertInstanceOf( \Psr\Http\Message\UploadedFileInterface::class, $file );
|
|
$this->assertSame( UPLOAD_ERR_OK, $file->getError() );
|
|
$this->assertSame( 'TestUploadStash.jpg', $file->getClientFilename() );
|
|
|
|
$file = $callbacks->getUploadedFile( 'file2', [] );
|
|
$this->assertInstanceOf( \Psr\Http\Message\UploadedFileInterface::class, $file );
|
|
$this->assertSame( UPLOAD_ERR_NO_FILE, $file->getError() );
|
|
|
|
$file = $callbacks->getUploadedFile( 'file3', [] );
|
|
$this->assertInstanceOf( \Psr\Http\Message\UploadedFileInterface::class, $file );
|
|
$this->assertSame( UPLOAD_ERR_INI_SIZE, $file->getError() );
|
|
}
|
|
|
|
/**
|
|
* @dataProvider provideRecordCondition
|
|
* @param DataMessageValue $message
|
|
* @param ApiMessage|null $expect
|
|
* @param bool $sensitive
|
|
*/
|
|
public function testRecordCondition(
|
|
DataMessageValue $message, ?ApiMessage $expect, bool $sensitive = false
|
|
) : void {
|
|
[ $callbacks, $main ] = $this->getCallbacks( new FauxRequest( [ 'testparam' => 'testvalue' ] ) );
|
|
$query = $main->getModuleFromPath( 'query' );
|
|
$warnings = [];
|
|
|
|
$module = $this->getMockBuilder( ApiQueryBase::class )
|
|
->setConstructorArgs( [ $query, 'test' ] )
|
|
->onlyMethods( [ 'addWarning' ] )
|
|
->getMockForAbstractClass();
|
|
$module->method( 'addWarning' )->willReturnCallback(
|
|
static function ( $msg, $code, $data ) use ( &$warnings ) {
|
|
$warnings[] = [ $msg, $code, $data ];
|
|
}
|
|
);
|
|
$query->getModuleManager()->addModule( 'test', 'meta', [
|
|
'class' => get_class( $module ),
|
|
'factory' => static function () use ( $module ) {
|
|
return $module;
|
|
}
|
|
] );
|
|
|
|
$callbacks->recordCondition( $message, 'testparam', 'testvalue', [], [ 'module' => $module ] );
|
|
|
|
if ( $expect ) {
|
|
$this->assertNotCount( 0, $warnings );
|
|
$this->assertSame(
|
|
$expect->inLanguage( 'qqx' )->plain(),
|
|
$warnings[0][0]->inLanguage( 'qqx' )->plain()
|
|
);
|
|
$this->assertSame( $expect->getApiCode(), $warnings[0][1] );
|
|
$this->assertSame( $expect->getApiData(), $warnings[0][2] );
|
|
} else {
|
|
$this->assertSame( [], $warnings );
|
|
}
|
|
|
|
$this->assertSame(
|
|
$sensitive ? [ 'testparam' ] : [],
|
|
TestingAccessWrapper::newFromObject( $main )->getSensitiveParams()
|
|
);
|
|
}
|
|
|
|
public function provideRecordCondition() : \Generator {
|
|
yield 'Deprecated param' => [
|
|
DataMessageValue::new(
|
|
'paramvalidator-param-deprecated', [],
|
|
'param-deprecated',
|
|
[ 'data' => true ]
|
|
)->plaintextParams( 'XXtestparam', 'XXtestvalue' ),
|
|
ApiMessage::create(
|
|
'paramvalidator-param-deprecated',
|
|
'deprecation',
|
|
[ 'data' => true, 'feature' => 'action=query&meta=test&testparam' ]
|
|
)->plaintextParams( 'XXtestparam', 'XXtestvalue' )
|
|
];
|
|
|
|
yield 'Deprecated value' => [
|
|
DataMessageValue::new(
|
|
'paramvalidator-deprecated-value', [],
|
|
'deprecated-value'
|
|
)->plaintextParams( 'XXtestparam', 'XXtestvalue' ),
|
|
ApiMessage::create(
|
|
'paramvalidator-deprecated-value',
|
|
'deprecation',
|
|
[ 'feature' => 'action=query&meta=test&testparam=testvalue' ]
|
|
)->plaintextParams( 'XXtestparam', 'XXtestvalue' )
|
|
];
|
|
|
|
yield 'Deprecated value with custom MessageValue' => [
|
|
DataMessageValue::new(
|
|
'some-custom-message-value', [],
|
|
'deprecated-value',
|
|
[ 'xyz' => 123 ]
|
|
)->plaintextParams( 'XXtestparam', 'XXtestvalue', 'foobar' ),
|
|
ApiMessage::create(
|
|
'some-custom-message-value',
|
|
'deprecation',
|
|
[ 'xyz' => 123, 'feature' => 'action=query&meta=test&testparam=testvalue' ]
|
|
)->plaintextParams( 'XXtestparam', 'XXtestvalue', 'foobar' )
|
|
];
|
|
|
|
// See ApiParamValidator::normalizeSettings()
|
|
yield 'Deprecated value with custom Message' => [
|
|
DataMessageValue::new(
|
|
'some-custom-message', [],
|
|
'deprecated-value',
|
|
[ '💩' => 'back-compat' ]
|
|
)->plaintextParams( 'XXtestparam', 'XXtestvalue', 'foobar' ),
|
|
ApiMessage::create(
|
|
'some-custom-message',
|
|
'deprecation',
|
|
[ 'feature' => 'action=query&meta=test&testparam=testvalue' ]
|
|
)->plaintextParams( 'foobar' )
|
|
];
|
|
|
|
yield 'Sensitive param' => [
|
|
DataMessageValue::new( 'paramvalidator-param-sensitive', [], 'param-sensitive' )
|
|
->plaintextParams( 'XXtestparam', 'XXtestvalue' ),
|
|
null,
|
|
true
|
|
];
|
|
|
|
yield 'Arbitrary warning' => [
|
|
DataMessageValue::new( 'some-warning', [], 'some-code', [ 'some-data' ] )
|
|
->plaintextParams( 'XXtestparam', 'XXtestvalue', 'foobar' ),
|
|
ApiMessage::create( 'some-warning', 'some-code', [ 'some-data' ] )
|
|
->plaintextParams( 'XXtestparam', 'XXtestvalue', 'foobar' ),
|
|
];
|
|
}
|
|
|
|
public function testUseHighLimits() : void {
|
|
$context = $this->apiContext->newTestContext( new FauxRequest, $this->getTestUser()->getUser() );
|
|
$main = $this->getMockBuilder( ApiMain::class )
|
|
->setConstructorArgs( [ $context ] )
|
|
->onlyMethods( [ 'canApiHighLimits' ] )
|
|
->getMock();
|
|
|
|
$main->method( 'canApiHighLimits' )->will( $this->onConsecutiveCalls( true, false ) );
|
|
|
|
$callbacks = new ApiParamValidatorCallbacks( $main );
|
|
$this->assertTrue( $callbacks->useHighLimits( [] ) );
|
|
$this->assertFalse( $callbacks->useHighLimits( [] ) );
|
|
}
|
|
}
|