Merge "HTML escape parameter 'text' of hook 'SkinEditSectionLinks'"
[lhc/web/wiklou.git] / tests / phpunit / includes / preferences / DefaultPreferencesFactoryTest.php
1 <?php
2
3 use MediaWiki\Auth\AuthManager;
4 use MediaWiki\Config\ServiceOptions;
5 use MediaWiki\MediaWikiServices;
6 use MediaWiki\Preferences\DefaultPreferencesFactory;
7 use Wikimedia\TestingAccessWrapper;
8
9 /**
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.
14 *
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.
19 *
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
24 *
25 * @file
26 */
27
28 /**
29 * @group Preferences
30 */
31 class DefaultPreferencesFactoryTest extends \MediaWikiTestCase {
32
33 /** @var IContextSource */
34 protected $context;
35
36 /** @var Config */
37 protected $config;
38
39 public function setUp() {
40 parent::setUp();
41 $this->context = new RequestContext();
42 $this->context->setTitle( Title::newFromText( self::class ) );
43
44 $services = MediaWikiServices::getInstance();
45
46 $this->setMwGlobals( 'wgParser', $services->getParserFactory()->create() );
47 $this->config = $services->getMainConfig();
48 }
49
50 /**
51 * Get a basic PreferencesFactory for testing with.
52 * @return DefaultPreferencesFactory
53 */
54 protected function getPreferencesFactory() {
55 $mockNsInfo = $this->createMock( NamespaceInfo::class );
56 $mockNsInfo->method( 'getValidNamespaces' )->willReturn( [
57 NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK
58 ] );
59 $mockNsInfo->expects( $this->never() )
60 ->method( $this->anythingBut( 'getValidNamespaces', '__destruct' ) );
61
62 return new DefaultPreferencesFactory(
63 new ServiceOptions( DefaultPreferencesFactory::$constructorOptions, $this->config ),
64 new Language(),
65 AuthManager::singleton(),
66 MediaWikiServices::getInstance()->getLinkRenderer(),
67 $mockNsInfo
68 );
69 }
70
71 /**
72 * @covers MediaWiki\Preferences\DefaultPreferencesFactory::getForm()
73 */
74 public function testGetForm() {
75 $this->setTemporaryHook( 'GetPreferences', null );
76
77 $testUser = $this->getTestUser();
78 $form = $this->getPreferencesFactory()->getForm( $testUser->getUser(), $this->context );
79 $this->assertInstanceOf( PreferencesFormOOUI::class, $form );
80 $this->assertCount( 5, $form->getPreferenceSections() );
81 }
82
83 /**
84 * CSS classes for emailauthentication preference field when there's no email.
85 * @see https://phabricator.wikimedia.org/T36302
86 * @covers MediaWiki\Preferences\DefaultPreferencesFactory::profilePreferences()
87 * @dataProvider emailAuthenticationProvider
88 */
89 public function testEmailAuthentication( $user, $cssClass ) {
90 $prefs = $this->getPreferencesFactory()->getFormDescriptor( $user, $this->context );
91 $this->assertArrayHasKey( 'cssclass', $prefs['emailauthentication'] );
92 $this->assertEquals( $cssClass, $prefs['emailauthentication']['cssclass'] );
93 }
94
95 /**
96 * @covers MediaWiki\Preferences\DefaultPreferencesFactory::renderingPreferences()
97 */
98 public function testShowRollbackConfIsHiddenForUsersWithoutRollbackRights() {
99 $userMock = $this->getMockBuilder( User::class )
100 ->disableOriginalConstructor()
101 ->getMock();
102 $userMock->method( 'isAllowed' )
103 ->willReturn( false );
104 $userMock->method( 'getEffectiveGroups' )
105 ->willReturn( [] );
106 $userMock->method( 'getGroupMemberships' )
107 ->willReturn( [] );
108 $userMock->method( 'getOptions' )
109 ->willReturn( [ 'test' => 'yes' ] );
110
111 $prefs = $this->getPreferencesFactory()->getFormDescriptor( $userMock, $this->context );
112 $this->assertArrayNotHasKey( 'showrollbackconfirmation', $prefs );
113 }
114
115 /**
116 * @covers MediaWiki\Preferences\DefaultPreferencesFactory::renderingPreferences()
117 */
118 public function testShowRollbackConfIsShownForUsersWithRollbackRights() {
119 $userMock = $this->getMockBuilder( User::class )
120 ->disableOriginalConstructor()
121 ->getMock();
122 $userMock->method( 'isAllowed' )
123 ->willReturn( true );
124 $userMock->method( 'getEffectiveGroups' )
125 ->willReturn( [] );
126 $userMock->method( 'getGroupMemberships' )
127 ->willReturn( [] );
128 $userMock->method( 'getOptions' )
129 ->willReturn( [ 'test' => 'yes' ] );
130
131 $prefs = $this->getPreferencesFactory()->getFormDescriptor( $userMock, $this->context );
132 $this->assertArrayHasKey( 'showrollbackconfirmation', $prefs );
133 $this->assertEquals(
134 'rendering/advancedrendering',
135 $prefs['showrollbackconfirmation']['section']
136 );
137 }
138
139 public function emailAuthenticationProvider() {
140 $userNoEmail = new User;
141 $userEmailUnauthed = new User;
142 $userEmailUnauthed->setEmail( 'noauth@example.org' );
143 $userEmailAuthed = new User;
144 $userEmailAuthed->setEmail( 'noauth@example.org' );
145 $userEmailAuthed->setEmailAuthenticationTimestamp( wfTimestamp() );
146 return [
147 [ $userNoEmail, 'mw-email-none' ],
148 [ $userEmailUnauthed, 'mw-email-not-authenticated' ],
149 [ $userEmailAuthed, 'mw-email-authenticated' ],
150 ];
151 }
152
153 /**
154 * Test that PreferencesFormPreSave hook has correct data:
155 * - user Object is passed
156 * - oldUserOptions contains previous user options (before save)
157 * - formData and User object have set up new properties
158 *
159 * @see https://phabricator.wikimedia.org/T169365
160 * @covers MediaWiki\Preferences\DefaultPreferencesFactory::submitForm()
161 */
162 public function testPreferencesFormPreSaveHookHasCorrectData() {
163 $oldOptions = [
164 'test' => 'abc',
165 'option' => 'old'
166 ];
167 $newOptions = [
168 'test' => 'abc',
169 'option' => 'new'
170 ];
171 $configMock = new HashConfig( [
172 'HiddenPrefs' => []
173 ] );
174 $form = $this->getMockBuilder( PreferencesFormOOUI::class )
175 ->disableOriginalConstructor()
176 ->getMock();
177
178 $userMock = $this->getMockBuilder( User::class )
179 ->disableOriginalConstructor()
180 ->getMock();
181 $userMock->method( 'getOptions' )
182 ->willReturn( $oldOptions );
183 $userMock->method( 'isAllowedAny' )
184 ->willReturn( true );
185 $userMock->method( 'isAllowed' )
186 ->willReturn( true );
187
188 $userMock->expects( $this->exactly( 2 ) )
189 ->method( 'setOption' )
190 ->withConsecutive(
191 [ $this->equalTo( 'test' ), $this->equalTo( $newOptions[ 'test' ] ) ],
192 [ $this->equalTo( 'option' ), $this->equalTo( $newOptions[ 'option' ] ) ]
193 );
194
195 $form->expects( $this->any() )
196 ->method( 'getModifiedUser' )
197 ->willReturn( $userMock );
198
199 $form->expects( $this->any() )
200 ->method( 'getContext' )
201 ->willReturn( $this->context );
202
203 $form->expects( $this->any() )
204 ->method( 'getConfig' )
205 ->willReturn( $configMock );
206
207 $this->setTemporaryHook( 'PreferencesFormPreSave',
208 function ( $formData, $form, $user, &$result, $oldUserOptions )
209 use ( $newOptions, $oldOptions, $userMock ) {
210 $this->assertSame( $userMock, $user );
211 foreach ( $newOptions as $option => $value ) {
212 $this->assertSame( $value, $formData[ $option ] );
213 }
214 foreach ( $oldOptions as $option => $value ) {
215 $this->assertSame( $value, $oldUserOptions[ $option ] );
216 }
217 $this->assertEquals( true, $result );
218 }
219 );
220
221 /** @var DefaultPreferencesFactory $factory */
222 $factory = TestingAccessWrapper::newFromObject( $this->getPreferencesFactory() );
223 $factory->saveFormData( $newOptions, $form, [] );
224 }
225
226 /**
227 * The rclimit preference should accept non-integer input and filter it to become an integer.
228 *
229 * @covers \MediaWiki\Preferences\DefaultPreferencesFactory::saveFormData
230 */
231 public function testIntvalFilter() {
232 // Test a string with leading zeros (i.e. not octal) and spaces.
233 $this->context->getRequest()->setVal( 'wprclimit', ' 0012 ' );
234 $user = new User;
235 $form = $this->getPreferencesFactory()->getForm( $user, $this->context );
236 $form->show();
237 $form->trySubmit();
238 $this->assertEquals( 12, $user->getOption( 'rclimit' ) );
239 }
240 }