3 use MediaWiki\Auth\AuthManager
;
4 use MediaWiki\MediaWikiServices
;
5 use MediaWiki\Permissions\PermissionManager
;
6 use MediaWiki\Preferences\DefaultPreferencesFactory
;
7 use Wikimedia\TestingAccessWrapper
;
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 * http://www.gnu.org/copyleft/gpl.html
31 class DefaultPreferencesFactoryTest
extends \MediaWikiTestCase
{
32 use TestAllServiceOptionsUsed
;
34 /** @var IContextSource */
40 public function setUp() {
42 $this->context
= new RequestContext();
43 $this->context
->setTitle( Title
::newFromText( self
::class ) );
45 $services = MediaWikiServices
::getInstance();
47 $this->setMwGlobals( 'wgParser', $services->getParserFactory()->create() );
48 $this->config
= $services->getMainConfig();
52 * Get a basic PreferencesFactory for testing with.
53 * @param PermissionManager|null $manager
54 * @return DefaultPreferencesFactory
56 protected function getPreferencesFactory( PermissionManager
$manager = null ) {
57 $mockNsInfo = $this->createMock( NamespaceInfo
::class );
58 $mockNsInfo->method( 'getValidNamespaces' )->willReturn( [
59 NS_MAIN
, NS_TALK
, NS_USER
, NS_USER_TALK
61 $mockNsInfo->expects( $this->never() )
62 ->method( $this->anythingBut( 'getValidNamespaces', '__destruct' ) );
64 $mockPermissionManager = $manager ??
$this->createMock( PermissionManager
::class );
66 return new DefaultPreferencesFactory(
67 new LoggedServiceOptions( self
::$serviceOptionsAccessLog,
68 DefaultPreferencesFactory
::$constructorOptions, $this->config
),
70 AuthManager
::singleton(),
71 MediaWikiServices
::getInstance()->getLinkRenderer(),
73 $mockPermissionManager
78 * @covers MediaWiki\Preferences\DefaultPreferencesFactory::getForm()
80 public function testGetForm() {
81 $this->setTemporaryHook( 'GetPreferences', null );
83 $testUser = $this->getTestUser();
84 $form = $this->getPreferencesFactory()->getForm( $testUser->getUser(), $this->context
);
85 $this->assertInstanceOf( PreferencesFormOOUI
::class, $form );
86 $this->assertCount( 5, $form->getPreferenceSections() );
90 * CSS classes for emailauthentication preference field when there's no email.
91 * @see https://phabricator.wikimedia.org/T36302
92 * @covers MediaWiki\Preferences\DefaultPreferencesFactory::profilePreferences()
93 * @dataProvider emailAuthenticationProvider
95 public function testEmailAuthentication( $user, $cssClass ) {
96 $pm = $this->createMock( PermissionManager
::class );
97 $pm->method( 'userHasRight' )->willReturn( true );
98 $prefs = $this->getPreferencesFactory( $pm )->getFormDescriptor( $user, $this->context
);
99 $this->assertArrayHasKey( 'cssclass', $prefs['emailauthentication'] );
100 $this->assertEquals( $cssClass, $prefs['emailauthentication']['cssclass'] );
104 * @covers MediaWiki\Preferences\DefaultPreferencesFactory::renderingPreferences()
106 public function testShowRollbackConfIsHiddenForUsersWithoutRollbackRights() {
107 $userMock = $this->getMockBuilder( User
::class )
108 ->disableOriginalConstructor()
110 $userMock->method( 'getEffectiveGroups' )
112 $userMock->method( 'getGroupMemberships' )
114 $userMock->method( 'getOptions' )
115 ->willReturn( [ 'test' => 'yes' ] );
116 $pm = $this->createMock( PermissionManager
::class );
117 $pm->method( 'userHasRight' )
118 ->will( $this->returnValueMap( [
119 [ $userMock, 'editmyoptions', true ]
121 $prefs = $this->getPreferencesFactory( $pm )->getFormDescriptor( $userMock, $this->context
);
122 $this->assertArrayNotHasKey( 'showrollbackconfirmation', $prefs );
126 * @covers MediaWiki\Preferences\DefaultPreferencesFactory::renderingPreferences()
128 public function testShowRollbackConfIsShownForUsersWithRollbackRights() {
129 $userMock = $this->getMockBuilder( User
::class )
130 ->disableOriginalConstructor()
132 $userMock->method( 'getEffectiveGroups' )
134 $userMock->method( 'getGroupMemberships' )
136 $userMock->method( 'getOptions' )
137 ->willReturn( [ 'test' => 'yes' ] );
138 $pm = $this->createMock( PermissionManager
::class );
139 $pm->method( 'userHasRight' )
140 ->will( $this->returnValueMap( [
141 [ $userMock, 'editmyoptions', true ],
142 [ $userMock, 'rollback', true ]
144 $prefs = $this->getPreferencesFactory( $pm )->getFormDescriptor( $userMock, $this->context
);
145 $this->assertArrayHasKey( 'showrollbackconfirmation', $prefs );
147 'rendering/advancedrendering',
148 $prefs['showrollbackconfirmation']['section']
152 public function emailAuthenticationProvider() {
153 $userNoEmail = new User
;
154 $userEmailUnauthed = new User
;
155 $userEmailUnauthed->setEmail( 'noauth@example.org' );
156 $userEmailAuthed = new User
;
157 $userEmailAuthed->setEmail( 'noauth@example.org' );
158 $userEmailAuthed->setEmailAuthenticationTimestamp( wfTimestamp() );
160 [ $userNoEmail, 'mw-email-none' ],
161 [ $userEmailUnauthed, 'mw-email-not-authenticated' ],
162 [ $userEmailAuthed, 'mw-email-authenticated' ],
167 * Test that PreferencesFormPreSave hook has correct data:
168 * - user Object is passed
169 * - oldUserOptions contains previous user options (before save)
170 * - formData and User object have set up new properties
172 * @see https://phabricator.wikimedia.org/T169365
173 * @covers MediaWiki\Preferences\DefaultPreferencesFactory::submitForm()
175 public function testPreferencesFormPreSaveHookHasCorrectData() {
184 $configMock = new HashConfig( [
187 $form = $this->getMockBuilder( PreferencesFormOOUI
::class )
188 ->disableOriginalConstructor()
191 $userMock = $this->getMockBuilder( User
::class )
192 ->disableOriginalConstructor()
194 $userMock->method( 'getOptions' )
195 ->willReturn( $oldOptions );
197 $userMock->expects( $this->exactly( 2 ) )
198 ->method( 'setOption' )
200 [ $this->equalTo( 'test' ), $this->equalTo( $newOptions[ 'test' ] ) ],
201 [ $this->equalTo( 'option' ), $this->equalTo( $newOptions[ 'option' ] ) ]
204 $form->method( 'getModifiedUser' )
205 ->willReturn( $userMock );
207 $form->method( 'getContext' )
208 ->willReturn( $this->context
);
210 $form->method( 'getConfig' )
211 ->willReturn( $configMock );
213 $pm = $this->createMock( PermissionManager
::class );
214 $pm->method( 'userHasAnyRight' )
215 ->will( $this->returnValueMap( [
216 [ $userMock, 'editmyprivateinfo', 'editmyoptions', true ]
218 $pm->method( 'userHasRight' )
219 ->will( $this->returnValueMap( [
220 [ $userMock, 'editmyoptions', true ]
223 $this->setTemporaryHook( 'PreferencesFormPreSave',
224 function ( $formData, $form, $user, &$result, $oldUserOptions )
225 use ( $newOptions, $oldOptions, $userMock ) {
226 $this->assertSame( $userMock, $user );
227 foreach ( $newOptions as $option => $value ) {
228 $this->assertSame( $value, $formData[ $option ] );
230 foreach ( $oldOptions as $option => $value ) {
231 $this->assertSame( $value, $oldUserOptions[ $option ] );
233 $this->assertEquals( true, $result );
237 /** @var DefaultPreferencesFactory $factory */
238 $factory = TestingAccessWrapper
::newFromObject( $this->getPreferencesFactory( $pm ) );
239 $factory->saveFormData( $newOptions, $form, [] );
243 * The rclimit preference should accept non-integer input and filter it to become an integer.
245 * @covers \MediaWiki\Preferences\DefaultPreferencesFactory::saveFormData
247 public function testIntvalFilter() {
248 // Test a string with leading zeros (i.e. not octal) and spaces.
249 $this->context
->getRequest()->setVal( 'wprclimit', ' 0012 ' );
251 $pm = $this->createMock( PermissionManager
::class );
252 $pm->method( 'userHasAnyRight' )
253 ->willReturn( true );
254 $pm->method( 'userHasRight' )
255 ->will( $this->returnValueMap( [
256 [ $user, 'editmyoptions', true ]
258 $form = $this->getPreferencesFactory( $pm )->getForm( $user, $this->context
);
261 $this->assertEquals( 12, $user->getOption( 'rclimit' ) );
267 public function testAllServiceOptionsUsed() {
268 $this->assertAllServiceOptionsUsed( [ 'EnotifMinorEdits', 'EnotifRevealEditorAddress' ] );