MediaWiki  REL1_31
ApiOptionsTest.php
Go to the documentation of this file.
1 <?php
2 
11 
13  private $mUserMock;
15  private $mTested;
16  private $mSession;
18  private $mContext;
19 
20  private static $Success = [ 'options' => 'success' ];
21 
22  protected function setUp() {
23  parent::setUp();
24 
25  $this->mUserMock = $this->getMockBuilder( User::class )
26  ->disableOriginalConstructor()
27  ->getMock();
28 
29  // Set up groups and rights
30  $this->mUserMock->expects( $this->any() )
31  ->method( 'getEffectiveGroups' )->will( $this->returnValue( [ '*', 'user' ] ) );
32  $this->mUserMock->expects( $this->any() )
33  ->method( 'isAllowedAny' )->will( $this->returnValue( true ) );
34 
35  // Set up callback for User::getOptionKinds
36  $this->mUserMock->expects( $this->any() )
37  ->method( 'getOptionKinds' )->will( $this->returnCallback( [ $this, 'getOptionKinds' ] ) );
38 
39  // No actual DB data
40  $this->mUserMock->expects( $this->any() )
41  ->method( 'getInstanceForUpdate' )->will( $this->returnValue( $this->mUserMock ) );
42 
43  // Create a new context
44  $this->mContext = new DerivativeContext( new RequestContext() );
45  $this->mContext->getContext()->setTitle( Title::newFromText( 'Test' ) );
46  $this->mContext->setUser( $this->mUserMock );
47 
48  $main = new ApiMain( $this->mContext );
49 
50  // Empty session
51  $this->mSession = [];
52 
53  $this->mTested = new ApiOptions( $main, 'options' );
54 
55  $this->mergeMwGlobalArrayValue( 'wgHooks', [
56  'GetPreferences' => [
57  [ $this, 'hookGetPreferences' ]
58  ]
59  ] );
60  }
61 
62  public function hookGetPreferences( $user, &$preferences ) {
63  $preferences = [];
64 
65  foreach ( [ 'name', 'willBeNull', 'willBeEmpty', 'willBeHappy' ] as $k ) {
66  $preferences[$k] = [
67  'type' => 'text',
68  'section' => 'test',
69  'label' => '&#160;',
70  ];
71  }
72 
73  $preferences['testmultiselect'] = [
74  'type' => 'multiselect',
75  'options' => [
76  'Test' => [
77  '<span dir="auto">Some HTML here for option 1</span>' => 'opt1',
78  '<span dir="auto">Some HTML here for option 2</span>' => 'opt2',
79  '<span dir="auto">Some HTML here for option 3</span>' => 'opt3',
80  '<span dir="auto">Some HTML here for option 4</span>' => 'opt4',
81  ],
82  ],
83  'section' => 'test',
84  'label' => '&#160;',
85  'prefix' => 'testmultiselect-',
86  'default' => [],
87  ];
88 
89  return true;
90  }
91 
98  public function getOptionKinds( IContextSource $context, $options = null ) {
99  // Match with above.
100  $kinds = [
101  'name' => 'registered',
102  'willBeNull' => 'registered',
103  'willBeEmpty' => 'registered',
104  'willBeHappy' => 'registered',
105  'testmultiselect-opt1' => 'registered-multiselect',
106  'testmultiselect-opt2' => 'registered-multiselect',
107  'testmultiselect-opt3' => 'registered-multiselect',
108  'testmultiselect-opt4' => 'registered-multiselect',
109  'special' => 'special',
110  ];
111 
112  if ( $options === null ) {
113  return $kinds;
114  }
115 
116  $mapping = [];
117  foreach ( $options as $key => $value ) {
118  if ( isset( $kinds[$key] ) ) {
119  $mapping[$key] = $kinds[$key];
120  } elseif ( substr( $key, 0, 7 ) === 'userjs-' ) {
121  $mapping[$key] = 'userjs';
122  } else {
123  $mapping[$key] = 'unused';
124  }
125  }
126 
127  return $mapping;
128  }
129 
130  private function getSampleRequest( $custom = [] ) {
131  $request = [
132  'token' => '123ABC',
133  'change' => null,
134  'optionname' => null,
135  'optionvalue' => null,
136  ];
137 
138  return array_merge( $request, $custom );
139  }
140 
141  private function executeQuery( $request ) {
142  $this->mContext->setRequest( new FauxRequest( $request, true, $this->mSession ) );
143  $this->mTested->execute();
144 
145  return $this->mTested->getResult()->getResultData( null, [ 'Strip' => 'all' ] );
146  }
147 
151  public function testNoToken() {
152  $request = $this->getSampleRequest( [ 'token' => null ] );
153 
154  $this->executeQuery( $request );
155  }
156 
157  public function testAnon() {
158  $this->mUserMock->expects( $this->once() )
159  ->method( 'isAnon' )
160  ->will( $this->returnValue( true ) );
161 
162  try {
163  $request = $this->getSampleRequest();
164 
165  $this->executeQuery( $request );
166  } catch ( ApiUsageException $e ) {
167  $this->assertTrue( ApiTestCase::apiExceptionHasCode( $e, 'notloggedin' ) );
168  return;
169  }
170  $this->fail( "ApiUsageException was not thrown" );
171  }
172 
173  public function testNoOptionname() {
174  try {
175  $request = $this->getSampleRequest( [ 'optionvalue' => '1' ] );
176 
177  $this->executeQuery( $request );
178  } catch ( ApiUsageException $e ) {
179  $this->assertTrue( ApiTestCase::apiExceptionHasCode( $e, 'nooptionname' ) );
180  return;
181  }
182  $this->fail( "ApiUsageException was not thrown" );
183  }
184 
185  public function testNoChanges() {
186  $this->mUserMock->expects( $this->never() )
187  ->method( 'resetOptions' );
188 
189  $this->mUserMock->expects( $this->never() )
190  ->method( 'setOption' );
191 
192  $this->mUserMock->expects( $this->never() )
193  ->method( 'saveSettings' );
194 
195  try {
196  $request = $this->getSampleRequest();
197 
198  $this->executeQuery( $request );
199  } catch ( ApiUsageException $e ) {
200  $this->assertTrue( ApiTestCase::apiExceptionHasCode( $e, 'nochanges' ) );
201  return;
202  }
203  $this->fail( "ApiUsageException was not thrown" );
204  }
205 
206  public function testReset() {
207  $this->mUserMock->expects( $this->once() )
208  ->method( 'resetOptions' )
209  ->with( $this->equalTo( [ 'all' ] ) );
210 
211  $this->mUserMock->expects( $this->never() )
212  ->method( 'setOption' );
213 
214  $this->mUserMock->expects( $this->once() )
215  ->method( 'saveSettings' );
216 
217  $request = $this->getSampleRequest( [ 'reset' => '' ] );
218 
219  $response = $this->executeQuery( $request );
220 
221  $this->assertEquals( self::$Success, $response );
222  }
223 
224  public function testResetKinds() {
225  $this->mUserMock->expects( $this->once() )
226  ->method( 'resetOptions' )
227  ->with( $this->equalTo( [ 'registered' ] ) );
228 
229  $this->mUserMock->expects( $this->never() )
230  ->method( 'setOption' );
231 
232  $this->mUserMock->expects( $this->once() )
233  ->method( 'saveSettings' );
234 
235  $request = $this->getSampleRequest( [ 'reset' => '', 'resetkinds' => 'registered' ] );
236 
237  $response = $this->executeQuery( $request );
238 
239  $this->assertEquals( self::$Success, $response );
240  }
241 
242  public function testOptionWithValue() {
243  $this->mUserMock->expects( $this->never() )
244  ->method( 'resetOptions' );
245 
246  $this->mUserMock->expects( $this->once() )
247  ->method( 'setOption' )
248  ->with( $this->equalTo( 'name' ), $this->equalTo( 'value' ) );
249 
250  $this->mUserMock->expects( $this->once() )
251  ->method( 'saveSettings' );
252 
253  $request = $this->getSampleRequest( [ 'optionname' => 'name', 'optionvalue' => 'value' ] );
254 
255  $response = $this->executeQuery( $request );
256 
257  $this->assertEquals( self::$Success, $response );
258  }
259 
260  public function testOptionResetValue() {
261  $this->mUserMock->expects( $this->never() )
262  ->method( 'resetOptions' );
263 
264  $this->mUserMock->expects( $this->once() )
265  ->method( 'setOption' )
266  ->with( $this->equalTo( 'name' ), $this->identicalTo( null ) );
267 
268  $this->mUserMock->expects( $this->once() )
269  ->method( 'saveSettings' );
270 
271  $request = $this->getSampleRequest( [ 'optionname' => 'name' ] );
272  $response = $this->executeQuery( $request );
273 
274  $this->assertEquals( self::$Success, $response );
275  }
276 
277  public function testChange() {
278  $this->mUserMock->expects( $this->never() )
279  ->method( 'resetOptions' );
280 
281  $this->mUserMock->expects( $this->exactly( 3 ) )
282  ->method( 'setOption' )
283  ->withConsecutive(
284  [ $this->equalTo( 'willBeNull' ), $this->identicalTo( null ) ],
285  [ $this->equalTo( 'willBeEmpty' ), $this->equalTo( '' ) ],
286  [ $this->equalTo( 'willBeHappy' ), $this->equalTo( 'Happy' ) ]
287  );
288 
289  $this->mUserMock->expects( $this->once() )
290  ->method( 'saveSettings' );
291 
292  $request = $this->getSampleRequest( [
293  'change' => 'willBeNull|willBeEmpty=|willBeHappy=Happy'
294  ] );
295 
296  $response = $this->executeQuery( $request );
297 
298  $this->assertEquals( self::$Success, $response );
299  }
300 
301  public function testResetChangeOption() {
302  $this->mUserMock->expects( $this->once() )
303  ->method( 'resetOptions' );
304 
305  $this->mUserMock->expects( $this->exactly( 2 ) )
306  ->method( 'setOption' )
307  ->withConsecutive(
308  [ $this->equalTo( 'willBeHappy' ), $this->equalTo( 'Happy' ) ],
309  [ $this->equalTo( 'name' ), $this->equalTo( 'value' ) ]
310  );
311 
312  $this->mUserMock->expects( $this->once() )
313  ->method( 'saveSettings' );
314 
315  $args = [
316  'reset' => '',
317  'change' => 'willBeHappy=Happy',
318  'optionname' => 'name',
319  'optionvalue' => 'value'
320  ];
321 
322  $response = $this->executeQuery( $this->getSampleRequest( $args ) );
323 
324  $this->assertEquals( self::$Success, $response );
325  }
326 
327  public function testMultiSelect() {
328  $this->mUserMock->expects( $this->never() )
329  ->method( 'resetOptions' );
330 
331  $this->mUserMock->expects( $this->exactly( 4 ) )
332  ->method( 'setOption' )
333  ->withConsecutive(
334  [ $this->equalTo( 'testmultiselect-opt1' ), $this->identicalTo( true ) ],
335  [ $this->equalTo( 'testmultiselect-opt2' ), $this->identicalTo( null ) ],
336  [ $this->equalTo( 'testmultiselect-opt3' ), $this->identicalTo( false ) ],
337  [ $this->equalTo( 'testmultiselect-opt4' ), $this->identicalTo( false ) ]
338  );
339 
340  $this->mUserMock->expects( $this->once() )
341  ->method( 'saveSettings' );
342 
343  $request = $this->getSampleRequest( [
344  'change' => 'testmultiselect-opt1=1|testmultiselect-opt2|'
345  . 'testmultiselect-opt3=|testmultiselect-opt4=0'
346  ] );
347 
348  $response = $this->executeQuery( $request );
349 
350  $this->assertEquals( self::$Success, $response );
351  }
352 
353  public function testSpecialOption() {
354  $this->mUserMock->expects( $this->never() )
355  ->method( 'resetOptions' );
356 
357  $this->mUserMock->expects( $this->never() )
358  ->method( 'saveSettings' );
359 
360  $request = $this->getSampleRequest( [
361  'change' => 'special=1'
362  ] );
363 
364  $response = $this->executeQuery( $request );
365 
366  $this->assertEquals( [
367  'options' => 'success',
368  'warnings' => [
369  'options' => [
370  'warnings' => "Validation error for \"special\": cannot be set by this module."
371  ]
372  ]
373  ], $response );
374  }
375 
376  public function testUnknownOption() {
377  $this->mUserMock->expects( $this->never() )
378  ->method( 'resetOptions' );
379 
380  $this->mUserMock->expects( $this->never() )
381  ->method( 'saveSettings' );
382 
383  $request = $this->getSampleRequest( [
384  'change' => 'unknownOption=1'
385  ] );
386 
387  $response = $this->executeQuery( $request );
388 
389  $this->assertEquals( [
390  'options' => 'success',
391  'warnings' => [
392  'options' => [
393  'warnings' => "Validation error for \"unknownOption\": not a valid preference."
394  ]
395  ]
396  ], $response );
397  }
398 
399  public function testUserjsOption() {
400  $this->mUserMock->expects( $this->never() )
401  ->method( 'resetOptions' );
402 
403  $this->mUserMock->expects( $this->once() )
404  ->method( 'setOption' )
405  ->with( $this->equalTo( 'userjs-option' ), $this->equalTo( '1' ) );
406 
407  $this->mUserMock->expects( $this->once() )
408  ->method( 'saveSettings' );
409 
410  $request = $this->getSampleRequest( [
411  'change' => 'userjs-option=1'
412  ] );
413 
414  $response = $this->executeQuery( $request );
415 
416  $this->assertEquals( self::$Success, $response );
417  }
418 }
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:247
ApiMain
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:43
FauxRequest
WebRequest clone which takes values from a provided array.
Definition: FauxRequest.php:33
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:273
ApiUsageException
Exception used to abort API execution with an error.
Definition: ApiUsageException.php:103
ApiOptionsTest\testReset
testReset()
Definition: ApiOptionsTest.php:206
MediaWikiTestCase\mergeMwGlobalArrayValue
mergeMwGlobalArrayValue( $name, $values)
Merges the given values into a MW global array variable.
Definition: MediaWikiTestCase.php:813
$response
this hook is for auditing only $response
Definition: hooks.txt:783
ApiOptionsTest\testSpecialOption
testSpecialOption()
Definition: ApiOptionsTest.php:353
ApiOptionsTest\hookGetPreferences
hookGetPreferences( $user, &$preferences)
Definition: ApiOptionsTest.php:62
ApiOptionsTest\testResetKinds
testResetKinds()
Definition: ApiOptionsTest.php:224
ApiOptionsTest\setUp
setUp()
Definition: ApiOptionsTest.php:22
ApiOptionsTest\executeQuery
executeQuery( $request)
Definition: ApiOptionsTest.php:141
ApiOptionsTest\testUnknownOption
testUnknownOption()
Definition: ApiOptionsTest.php:376
ApiOptionsTest\getSampleRequest
getSampleRequest( $custom=[])
Definition: ApiOptionsTest.php:130
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:37
ApiOptionsTest\testNoChanges
testNoChanges()
Definition: ApiOptionsTest.php:185
DerivativeContext
An IContextSource implementation which will inherit context from another source but allow individual ...
Definition: DerivativeContext.php:30
ApiOptionsTest\$mTested
ApiOptions $mTested
Definition: ApiOptionsTest.php:15
ApiOptionsTest\$mContext
DerivativeContext $mContext
Definition: ApiOptionsTest.php:18
ApiOptionsTest\testUserjsOption
testUserjsOption()
Definition: ApiOptionsTest.php:399
ApiOptionsTest\$mSession
$mSession
Definition: ApiOptionsTest.php:16
ApiOptionsTest\testMultiSelect
testMultiSelect()
Definition: ApiOptionsTest.php:327
RequestContext
Group all the pieces relevant to the context of a request into one instance.
Definition: RequestContext.php:32
ApiOptionsTest\getOptionKinds
getOptionKinds(IContextSource $context, $options=null)
Definition: ApiOptionsTest.php:98
$options
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 & $options
Definition: hooks.txt:2001
ApiOptions
API module that facilitates the changing of user's preferences.
Definition: ApiOptions.php:31
$value
$value
Definition: styleTest.css.php:45
ApiOptionsTest\testChange
testChange()
Definition: ApiOptionsTest.php:277
ApiOptionsTest\testNoToken
testNoToken()
ApiUsageException.
Definition: ApiOptionsTest.php:151
ApiOptionsTest\$mUserMock
PHPUnit_Framework_MockObject_MockObject $mUserMock
Definition: ApiOptionsTest.php:13
ApiOptionsTest\testOptionWithValue
testOptionWithValue()
Definition: ApiOptionsTest.php:242
MediaWikiLangTestCase
Base class that store and restore the Language objects.
Definition: MediaWikiLangTestCase.php:6
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:53
$args
if( $line===false) $args
Definition: cdb.php:64
ApiOptionsTest\testNoOptionname
testNoOptionname()
Definition: ApiOptionsTest.php:173
ApiTestCase\apiExceptionHasCode
static apiExceptionHasCode(ApiUsageException $ex, $code)
Definition: ApiTestCase.php:225
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:22
ApiOptionsTest\testResetChangeOption
testResetChangeOption()
Definition: ApiOptionsTest.php:301
ApiOptionsTest
API Database medium.
Definition: ApiOptionsTest.php:10
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:56
$request
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2806
$context
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
Definition: hooks.txt:2811
ApiOptionsTest\$Success
static $Success
Definition: ApiOptionsTest.php:20
$e
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:2171
ApiOptionsTest\testOptionResetValue
testOptionResetValue()
Definition: ApiOptionsTest.php:260
ApiOptionsTest\testAnon
testAnon()
Definition: ApiOptionsTest.php:157