Localisation updates from https://translatewiki.net.
[mediawiki.git] / tests / phpunit / includes / api / Validator / ApiParamValidatorCallbacksTest.php
blobca74e8590fa21ee6896f2c9bbf8df54c8630fb93
1 <?php
3 namespace MediaWiki\Tests\Api\Validator;
5 use Generator;
6 use MediaWiki\Api\ApiBase;
7 use MediaWiki\Api\ApiMain;
8 use MediaWiki\Api\ApiMessage;
9 use MediaWiki\Api\ApiQueryBase;
10 use MediaWiki\Api\Validator\ApiParamValidatorCallbacks;
11 use MediaWiki\Request\FauxRequest;
12 use MediaWiki\Tests\Api\ApiUploadTestCase;
13 use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait;
14 use Psr\Http\Message\UploadedFileInterface;
15 use Wikimedia\Message\DataMessageValue;
16 use Wikimedia\TestingAccessWrapper;
18 /**
19 * @covers \MediaWiki\Api\Validator\ApiParamValidatorCallbacks
20 * @group API
21 * @group medium
23 class ApiParamValidatorCallbacksTest extends ApiUploadTestCase {
24 use MockAuthorityTrait;
26 private function getCallbacks( FauxRequest $request ): array {
27 $context = $this->apiContext->newTestContext( $request, $this->mockRegisteredUltimateAuthority() );
28 $main = new ApiMain( $context );
29 return [ new ApiParamValidatorCallbacks( $main ), $main ];
32 private function filePath( $fileName ) {
33 return __DIR__ . '/../../../data/media/' . $fileName;
36 public function testHasParam(): void {
37 [ $callbacks, $main ] = $this->getCallbacks( new FauxRequest( [
38 'foo' => '1',
39 'bar' => '',
40 ] ) );
42 $this->assertTrue( $callbacks->hasParam( 'foo', [] ) );
43 $this->assertTrue( $callbacks->hasParam( 'bar', [] ) );
44 $this->assertFalse( $callbacks->hasParam( 'baz', [] ) );
46 $this->assertSame(
47 [ 'foo', 'bar', 'baz' ],
48 TestingAccessWrapper::newFromObject( $main )->getParamsUsed()
52 /**
53 * @dataProvider provideGetValue
54 * @param string|null $data Value from request
55 * @param mixed $default For getValue()
56 * @param mixed $expect Expected return value
57 * @param bool $normalized Whether handleParamNormalization is called
59 public function testGetValue( ?string $data, $default, $expect, bool $normalized = false ): void {
60 [ $callbacks, $main ] = $this->getCallbacks( new FauxRequest( [ 'test' => $data ] ) );
62 $module = $this->getMockBuilder( ApiBase::class )
63 ->setConstructorArgs( [ $main, 'testmodule' ] )
64 ->onlyMethods( [ 'handleParamNormalization' ] )
65 ->getMockForAbstractClass();
66 $options = [ 'module' => $module ];
67 if ( $normalized ) {
68 $module->expects( $this->once() )->method( 'handleParamNormalization' )
69 ->with(
70 $this->identicalTo( 'test' ),
71 $this->identicalTo( $expect ),
72 $this->identicalTo( $data ?? $default )
74 } else {
75 $module->expects( $this->never() )->method( 'handleParamNormalization' );
78 $this->assertSame( $expect, $callbacks->getValue( 'test', $default, $options ) );
79 $this->assertSame( [ 'test' ], TestingAccessWrapper::newFromObject( $main )->getParamsUsed() );
82 public static function provideGetValue() {
83 $obj = (object)[];
84 return [
85 'Basic test' => [ 'foo', 'bar', 'foo', false ],
86 'Default value' => [ null, 1234, 1234, false ],
87 'Default value (2)' => [ null, $obj, $obj, false ],
88 'No default value' => [ null, null, null, false ],
89 'Multi separator' => [ "\x1ffoo\x1fbar", 1234, "\x1ffoo\x1fbar", false ],
90 'Normalized' => [ "\x1ffoo\x1fba\u{0301}r", 1234, "\x1ffoo\x1fbár", true ],
94 private function setupUploads(): void {
95 $fileName = 'TestUploadStash.jpg';
96 $mimeType = 'image/jpeg';
97 $filePath = $this->filePath( 'yuv420.jpg' );
98 $this->fakeUploadFile( 'file', $fileName, $mimeType, $filePath );
100 $this->requestDataFiles['file2'] = [
101 'name' => '',
102 'type' => '',
103 'tmp_name' => '',
104 'size' => 0,
105 'error' => UPLOAD_ERR_NO_FILE,
108 $this->requestDataFiles['file3'] = [
109 'name' => 'xxx.png',
110 'type' => '',
111 'tmp_name' => '',
112 'size' => 0,
113 'error' => UPLOAD_ERR_INI_SIZE,
117 public function testHasUpload(): void {
118 $this->setupUploads();
120 $request = new FauxRequest( [
121 'foo' => '1',
122 'bar' => '',
123 ] );
124 $request->setUploadData( $this->requestDataFiles );
125 [ $callbacks, $main ] = $this->getCallbacks( $request );
127 $this->assertFalse( $callbacks->hasUpload( 'foo', [] ) );
128 $this->assertFalse( $callbacks->hasUpload( 'bar', [] ) );
129 $this->assertFalse( $callbacks->hasUpload( 'baz', [] ) );
130 $this->assertTrue( $callbacks->hasUpload( 'file', [] ) );
131 $this->assertTrue( $callbacks->hasUpload( 'file2', [] ) );
132 $this->assertTrue( $callbacks->hasUpload( 'file3', [] ) );
134 $this->assertSame(
135 [ 'foo', 'bar', 'baz', 'file', 'file2', 'file3' ],
136 TestingAccessWrapper::newFromObject( $main )->getParamsUsed()
140 public function testGetUploadedFile(): void {
141 $this->setupUploads();
143 $request = new FauxRequest( [
144 'foo' => '1',
145 'bar' => '',
146 ] );
147 $request->setUploadData( $this->requestDataFiles );
148 [ $callbacks, $main ] = $this->getCallbacks( $request );
150 $this->assertNull( $callbacks->getUploadedFile( 'foo', [] ) );
151 $this->assertNull( $callbacks->getUploadedFile( 'bar', [] ) );
152 $this->assertNull( $callbacks->getUploadedFile( 'baz', [] ) );
154 $file = $callbacks->getUploadedFile( 'file', [] );
155 $this->assertInstanceOf( UploadedFileInterface::class, $file );
156 $this->assertSame( UPLOAD_ERR_OK, $file->getError() );
157 $this->assertSame( 'TestUploadStash.jpg', $file->getClientFilename() );
159 $file = $callbacks->getUploadedFile( 'file2', [] );
160 $this->assertInstanceOf( UploadedFileInterface::class, $file );
161 $this->assertSame( UPLOAD_ERR_NO_FILE, $file->getError() );
163 $file = $callbacks->getUploadedFile( 'file3', [] );
164 $this->assertInstanceOf( UploadedFileInterface::class, $file );
165 $this->assertSame( UPLOAD_ERR_INI_SIZE, $file->getError() );
169 * @dataProvider provideRecordCondition
170 * @param DataMessageValue $message
171 * @param ApiMessage|null $expect
172 * @param bool $sensitive
174 public function testRecordCondition(
175 DataMessageValue $message, ?ApiMessage $expect, bool $sensitive = false
176 ): void {
177 [ $callbacks, $main ] = $this->getCallbacks( new FauxRequest( [ 'testparam' => 'testvalue' ] ) );
178 $query = $main->getModuleFromPath( 'query' );
179 $warnings = [];
181 $module = $this->getMockBuilder( ApiQueryBase::class )
182 ->setConstructorArgs( [ $query, 'test' ] )
183 ->onlyMethods( [ 'addWarning' ] )
184 ->getMockForAbstractClass();
185 $module->method( 'addWarning' )->willReturnCallback(
186 static function ( $msg, $code, $data ) use ( &$warnings ) {
187 $warnings[] = [ $msg, $code, $data ];
190 $query->getModuleManager()->addModule( 'test', 'meta', [
191 'class' => get_class( $module ),
192 'factory' => static function () use ( $module ) {
193 return $module;
195 ] );
197 $callbacks->recordCondition( $message, 'testparam', 'testvalue', [], [ 'module' => $module ] );
199 if ( $expect ) {
200 $this->assertNotCount( 0, $warnings );
201 $this->assertSame(
202 $expect->inLanguage( 'qqx' )->plain(),
203 $warnings[0][0]->inLanguage( 'qqx' )->plain()
205 $this->assertSame( $expect->getApiCode(), $warnings[0][1] );
206 $this->assertSame( $expect->getApiData(), $warnings[0][2] );
207 } else {
208 $this->assertSame( [], $warnings );
211 $this->assertSame(
212 $sensitive ? [ 'testparam' ] : [],
213 TestingAccessWrapper::newFromObject( $main )->getSensitiveParams()
217 public static function provideRecordCondition(): Generator {
218 yield 'Deprecated param' => [
219 DataMessageValue::new(
220 'paramvalidator-param-deprecated', [],
221 'param-deprecated',
222 [ 'data' => true ]
223 )->plaintextParams( 'XXtestparam', 'XXtestvalue' ),
224 ApiMessage::create(
225 'paramvalidator-param-deprecated',
226 'deprecation',
227 [ 'data' => true, 'feature' => 'action=query&meta=test&testparam' ]
228 )->plaintextParams( 'XXtestparam', 'XXtestvalue' )
231 yield 'Deprecated value' => [
232 DataMessageValue::new(
233 'paramvalidator-deprecated-value', [],
234 'deprecated-value'
235 )->plaintextParams( 'XXtestparam', 'XXtestvalue' ),
236 ApiMessage::create(
237 'paramvalidator-deprecated-value',
238 'deprecation',
239 [ 'feature' => 'action=query&meta=test&testparam=testvalue' ]
240 )->plaintextParams( 'XXtestparam', 'XXtestvalue' )
243 yield 'Deprecated value with custom MessageValue' => [
244 DataMessageValue::new(
245 'some-custom-message-value', [],
246 'deprecated-value',
247 [ 'xyz' => 123 ]
248 )->plaintextParams( 'XXtestparam', 'XXtestvalue', 'foobar' ),
249 ApiMessage::create(
250 'some-custom-message-value',
251 'deprecation',
252 [ 'xyz' => 123, 'feature' => 'action=query&meta=test&testparam=testvalue' ]
253 )->plaintextParams( 'XXtestparam', 'XXtestvalue', 'foobar' )
256 // See ApiParamValidator::normalizeSettings()
257 yield 'Deprecated value with custom Message' => [
258 DataMessageValue::new(
259 'some-custom-message', [],
260 'deprecated-value',
261 [ '💩' => 'back-compat' ]
262 )->plaintextParams( 'XXtestparam', 'XXtestvalue', 'foobar' ),
263 ApiMessage::create(
264 'some-custom-message',
265 'deprecation',
266 [ 'feature' => 'action=query&meta=test&testparam=testvalue' ]
267 )->plaintextParams( 'foobar' )
270 yield 'Sensitive param' => [
271 DataMessageValue::new( 'paramvalidator-param-sensitive', [], 'param-sensitive' )
272 ->plaintextParams( 'XXtestparam', 'XXtestvalue' ),
273 null,
274 true
277 yield 'Arbitrary warning' => [
278 DataMessageValue::new( 'some-warning', [], 'some-code', [ 'some-data' ] )
279 ->plaintextParams( 'XXtestparam', 'XXtestvalue', 'foobar' ),
280 ApiMessage::create( 'some-warning', 'some-code', [ 'some-data' ] )
281 ->plaintextParams( 'XXtestparam', 'XXtestvalue', 'foobar' ),
285 public function testUseHighLimits(): void {
286 $context = $this->apiContext->newTestContext( new FauxRequest, $this->mockRegisteredUltimateAuthority() );
287 $main = $this->getMockBuilder( ApiMain::class )
288 ->setConstructorArgs( [ $context ] )
289 ->onlyMethods( [ 'canApiHighLimits' ] )
290 ->getMock();
292 $main->method( 'canApiHighLimits' )->willReturnOnConsecutiveCalls( true, false );
294 $callbacks = new ApiParamValidatorCallbacks( $main );
295 $this->assertTrue( $callbacks->useHighLimits( [] ) );
296 $this->assertFalse( $callbacks->useHighLimits( [] ) );