X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/tests/phpunit/includes/api/ApiOptionsTest.php diff --git a/tests/phpunit/includes/api/ApiOptionsTest.php b/tests/phpunit/includes/api/ApiOptionsTest.php new file mode 100644 index 00000000..ef706261 --- /dev/null +++ b/tests/phpunit/includes/api/ApiOptionsTest.php @@ -0,0 +1,445 @@ + 'success' ]; + + protected function setUp() { + parent::setUp(); + + $this->mUserMock = $this->getMockBuilder( 'User' ) + ->disableOriginalConstructor() + ->getMock(); + + // Set up groups and rights + $this->mUserMock->expects( $this->any() ) + ->method( 'getEffectiveGroups' )->will( $this->returnValue( [ '*', 'user' ] ) ); + $this->mUserMock->expects( $this->any() ) + ->method( 'isAllowedAny' )->will( $this->returnValue( true ) ); + + // Set up callback for User::getOptionKinds + $this->mUserMock->expects( $this->any() ) + ->method( 'getOptionKinds' )->will( $this->returnCallback( [ $this, 'getOptionKinds' ] ) ); + + // No actual DB data + $this->mUserMock->expects( $this->any() ) + ->method( 'getInstanceForUpdate' )->will( $this->returnValue( $this->mUserMock ) ); + + // Create a new context + $this->mContext = new DerivativeContext( new RequestContext() ); + $this->mContext->getContext()->setTitle( Title::newFromText( 'Test' ) ); + $this->mContext->setUser( $this->mUserMock ); + + $main = new ApiMain( $this->mContext ); + + // Empty session + $this->mSession = []; + + $this->mTested = new ApiOptions( $main, 'options' ); + + $this->mergeMwGlobalArrayValue( 'wgHooks', [ + 'GetPreferences' => [ + [ $this, 'hookGetPreferences' ] + ] + ] ); + } + + public function hookGetPreferences( $user, &$preferences ) { + $preferences = []; + + foreach ( [ 'name', 'willBeNull', 'willBeEmpty', 'willBeHappy' ] as $k ) { + $preferences[$k] = [ + 'type' => 'text', + 'section' => 'test', + 'label' => ' ', + ]; + } + + $preferences['testmultiselect'] = [ + 'type' => 'multiselect', + 'options' => [ + 'Test' => [ + 'Some HTML here for option 1' => 'opt1', + 'Some HTML here for option 2' => 'opt2', + 'Some HTML here for option 3' => 'opt3', + 'Some HTML here for option 4' => 'opt4', + ], + ], + 'section' => 'test', + 'label' => ' ', + 'prefix' => 'testmultiselect-', + 'default' => [], + ]; + + return true; + } + + /** + * @param IContextSource $context + * @param array|null $options + * + * @return array + */ + public function getOptionKinds( IContextSource $context, $options = null ) { + // Match with above. + $kinds = [ + 'name' => 'registered', + 'willBeNull' => 'registered', + 'willBeEmpty' => 'registered', + 'willBeHappy' => 'registered', + 'testmultiselect-opt1' => 'registered-multiselect', + 'testmultiselect-opt2' => 'registered-multiselect', + 'testmultiselect-opt3' => 'registered-multiselect', + 'testmultiselect-opt4' => 'registered-multiselect', + 'special' => 'special', + ]; + + if ( $options === null ) { + return $kinds; + } + + $mapping = []; + foreach ( $options as $key => $value ) { + if ( isset( $kinds[$key] ) ) { + $mapping[$key] = $kinds[$key]; + } elseif ( substr( $key, 0, 7 ) === 'userjs-' ) { + $mapping[$key] = 'userjs'; + } else { + $mapping[$key] = 'unused'; + } + } + + return $mapping; + } + + private function getSampleRequest( $custom = [] ) { + $request = [ + 'token' => '123ABC', + 'change' => null, + 'optionname' => null, + 'optionvalue' => null, + ]; + + return array_merge( $request, $custom ); + } + + private function executeQuery( $request ) { + $this->mContext->setRequest( new FauxRequest( $request, true, $this->mSession ) ); + $this->mTested->execute(); + + return $this->mTested->getResult()->getResultData( null, [ 'Strip' => 'all' ] ); + } + + /** + * @expectedException ApiUsageException + */ + public function testNoToken() { + $request = $this->getSampleRequest( [ 'token' => null ] ); + + $this->executeQuery( $request ); + } + + public function testAnon() { + $this->mUserMock->expects( $this->once() ) + ->method( 'isAnon' ) + ->will( $this->returnValue( true ) ); + + try { + $request = $this->getSampleRequest(); + + $this->executeQuery( $request ); + } catch ( ApiUsageException $e ) { + $this->assertTrue( ApiTestCase::apiExceptionHasCode( $e, 'notloggedin' ) ); + return; + } + $this->fail( "ApiUsageException was not thrown" ); + } + + public function testNoOptionname() { + try { + $request = $this->getSampleRequest( [ 'optionvalue' => '1' ] ); + + $this->executeQuery( $request ); + } catch ( ApiUsageException $e ) { + $this->assertTrue( ApiTestCase::apiExceptionHasCode( $e, 'nooptionname' ) ); + return; + } + $this->fail( "ApiUsageException was not thrown" ); + } + + public function testNoChanges() { + $this->mUserMock->expects( $this->never() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->never() ) + ->method( 'setOption' ); + + $this->mUserMock->expects( $this->never() ) + ->method( 'saveSettings' ); + + try { + $request = $this->getSampleRequest(); + + $this->executeQuery( $request ); + } catch ( ApiUsageException $e ) { + $this->assertTrue( ApiTestCase::apiExceptionHasCode( $e, 'nochanges' ) ); + return; + } + $this->fail( "ApiUsageException was not thrown" ); + } + + public function testReset() { + $this->mUserMock->expects( $this->once() ) + ->method( 'resetOptions' ) + ->with( $this->equalTo( [ 'all' ] ) ); + + $this->mUserMock->expects( $this->never() ) + ->method( 'setOption' ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( [ 'reset' => '' ] ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( self::$Success, $response ); + } + + public function testResetKinds() { + $this->mUserMock->expects( $this->once() ) + ->method( 'resetOptions' ) + ->with( $this->equalTo( [ 'registered' ] ) ); + + $this->mUserMock->expects( $this->never() ) + ->method( 'setOption' ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( [ 'reset' => '', 'resetkinds' => 'registered' ] ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( self::$Success, $response ); + } + + public function testOptionWithValue() { + $this->mUserMock->expects( $this->never() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'name' ), $this->equalTo( 'value' ) ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( [ 'optionname' => 'name', 'optionvalue' => 'value' ] ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( self::$Success, $response ); + } + + public function testOptionResetValue() { + $this->mUserMock->expects( $this->never() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'name' ), $this->identicalTo( null ) ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( [ 'optionname' => 'name' ] ); + $response = $this->executeQuery( $request ); + + $this->assertEquals( self::$Success, $response ); + } + + public function testChange() { + $this->mUserMock->expects( $this->never() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->at( 2 ) ) + ->method( 'getOptions' ); + + $this->mUserMock->expects( $this->at( 5 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'willBeNull' ), $this->identicalTo( null ) ); + + $this->mUserMock->expects( $this->at( 6 ) ) + ->method( 'getOptions' ); + + $this->mUserMock->expects( $this->at( 7 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'willBeEmpty' ), $this->equalTo( '' ) ); + + $this->mUserMock->expects( $this->at( 8 ) ) + ->method( 'getOptions' ); + + $this->mUserMock->expects( $this->at( 9 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'willBeHappy' ), $this->equalTo( 'Happy' ) ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( [ + 'change' => 'willBeNull|willBeEmpty=|willBeHappy=Happy' + ] ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( self::$Success, $response ); + } + + public function testResetChangeOption() { + $this->mUserMock->expects( $this->once() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->at( 5 ) ) + ->method( 'getOptions' ); + + $this->mUserMock->expects( $this->at( 6 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'willBeHappy' ), $this->equalTo( 'Happy' ) ); + + $this->mUserMock->expects( $this->at( 7 ) ) + ->method( 'getOptions' ); + + $this->mUserMock->expects( $this->at( 8 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'name' ), $this->equalTo( 'value' ) ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'saveSettings' ); + + $args = [ + 'reset' => '', + 'change' => 'willBeHappy=Happy', + 'optionname' => 'name', + 'optionvalue' => 'value' + ]; + + $response = $this->executeQuery( $this->getSampleRequest( $args ) ); + + $this->assertEquals( self::$Success, $response ); + } + + public function testMultiSelect() { + $this->mUserMock->expects( $this->never() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->at( 4 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'testmultiselect-opt1' ), $this->identicalTo( true ) ); + + $this->mUserMock->expects( $this->at( 5 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'testmultiselect-opt2' ), $this->identicalTo( null ) ); + + $this->mUserMock->expects( $this->at( 6 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'testmultiselect-opt3' ), $this->identicalTo( false ) ); + + $this->mUserMock->expects( $this->at( 7 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'testmultiselect-opt4' ), $this->identicalTo( false ) ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( [ + 'change' => 'testmultiselect-opt1=1|testmultiselect-opt2|' + . 'testmultiselect-opt3=|testmultiselect-opt4=0' + ] ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( self::$Success, $response ); + } + + public function testSpecialOption() { + $this->mUserMock->expects( $this->never() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->never() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( [ + 'change' => 'special=1' + ] ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( [ + 'options' => 'success', + 'warnings' => [ + 'options' => [ + 'warnings' => "Validation error for \"special\": cannot be set by this module." + ] + ] + ], $response ); + } + + public function testUnknownOption() { + $this->mUserMock->expects( $this->never() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->never() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( [ + 'change' => 'unknownOption=1' + ] ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( [ + 'options' => 'success', + 'warnings' => [ + 'options' => [ + 'warnings' => "Validation error for \"unknownOption\": not a valid preference." + ] + ] + ], $response ); + } + + public function testUserjsOption() { + $this->mUserMock->expects( $this->never() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'userjs-option' ), $this->equalTo( '1' ) ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( [ + 'change' => 'userjs-option=1' + ] ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( self::$Success, $response ); + } +}