3 namespace MediaWiki\Auth
;
7 * @covers MediaWiki\Auth\AuthenticationRequest
9 class AuthenticationRequestTest
extends \MediaWikiTestCase
{
10 protected function setUp() {
11 global $wgDisableAuthManager;
14 if ( $wgDisableAuthManager ) {
15 $this->markTestSkipped( '$wgDisableAuthManager is set' );
19 public function testBasics() {
20 $mock = $this->getMockForAbstractClass( AuthenticationRequest
::class );
22 $this->assertSame( get_class( $mock ), $mock->getUniqueId() );
24 $this->assertType( 'array', $mock->getMetadata() );
26 $ret = $mock->describeCredentials();
27 $this->assertInternalType( 'array', $ret );
28 $this->assertArrayHasKey( 'provider', $ret );
29 $this->assertInstanceOf( 'Message', $ret['provider'] );
30 $this->assertArrayHasKey( 'account', $ret );
31 $this->assertInstanceOf( 'Message', $ret['account'] );
34 public function testLoadRequestsFromSubmission() {
35 $mb = $this->getMockBuilder( AuthenticationRequest
::class )
36 ->setMethods( [ 'loadFromSubmission' ] );
38 $data = [ 'foo', 'bar' ];
40 $req1 = $mb->getMockForAbstractClass();
41 $req1->expects( $this->once() )->method( 'loadFromSubmission' )
42 ->with( $this->identicalTo( $data ) )
43 ->will( $this->returnValue( false ) );
45 $req2 = $mb->getMockForAbstractClass();
46 $req2->expects( $this->once() )->method( 'loadFromSubmission' )
47 ->with( $this->identicalTo( $data ) )
48 ->will( $this->returnValue( true ) );
52 AuthenticationRequest
::loadRequestsFromSubmission( [ $req1, $req2 ], $data )
56 public function testGetRequestByClass() {
57 $mb = $this->getMockBuilder(
58 AuthenticationRequest
::class, 'AuthenticationRequestTest_AuthenticationRequest2'
62 $this->getMockForAbstractClass(
63 AuthenticationRequest
::class, [], 'AuthenticationRequestTest_AuthenticationRequest1'
65 $mb->getMockForAbstractClass(),
66 $mb->getMockForAbstractClass(),
67 $this->getMockForAbstractClass(
68 PasswordAuthenticationRequest
::class, [],
69 'AuthenticationRequestTest_PasswordAuthenticationRequest'
73 $this->assertNull( AuthenticationRequest
::getRequestByClass(
74 $reqs, 'AuthenticationRequestTest_AuthenticationRequest0'
76 $this->assertSame( $reqs[0], AuthenticationRequest
::getRequestByClass(
77 $reqs, 'AuthenticationRequestTest_AuthenticationRequest1'
79 $this->assertNull( AuthenticationRequest
::getRequestByClass(
80 $reqs, 'AuthenticationRequestTest_AuthenticationRequest2'
82 $this->assertNull( AuthenticationRequest
::getRequestByClass(
83 $reqs, PasswordAuthenticationRequest
::class
85 $this->assertNull( AuthenticationRequest
::getRequestByClass(
86 $reqs, 'ClassThatDoesNotExist'
89 $this->assertNull( AuthenticationRequest
::getRequestByClass(
90 $reqs, 'AuthenticationRequestTest_AuthenticationRequest0', true
92 $this->assertSame( $reqs[0], AuthenticationRequest
::getRequestByClass(
93 $reqs, 'AuthenticationRequestTest_AuthenticationRequest1', true
95 $this->assertNull( AuthenticationRequest
::getRequestByClass(
96 $reqs, 'AuthenticationRequestTest_AuthenticationRequest2', true
98 $this->assertSame( $reqs[3], AuthenticationRequest
::getRequestByClass(
99 $reqs, PasswordAuthenticationRequest
::class, true
101 $this->assertNull( AuthenticationRequest
::getRequestByClass(
102 $reqs, 'ClassThatDoesNotExist', true
106 public function testGetUsernameFromRequests() {
107 $mb = $this->getMockBuilder( AuthenticationRequest
::class );
109 for ( $i = 0; $i < 3; $i++
) {
110 $req = $mb->getMockForAbstractClass();
111 $req->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
119 $req = $mb->getMockForAbstractClass();
120 $req->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [] ) );
121 $req->username
= 'baz';
124 $this->assertNull( AuthenticationRequest
::getUsernameFromRequests( $reqs ) );
126 $reqs[1]->username
= 'foo';
127 $this->assertSame( 'foo', AuthenticationRequest
::getUsernameFromRequests( $reqs ) );
129 $reqs[0]->username
= 'foo';
130 $reqs[2]->username
= 'foo';
131 $this->assertSame( 'foo', AuthenticationRequest
::getUsernameFromRequests( $reqs ) );
133 $reqs[1]->username
= 'bar';
135 AuthenticationRequest
::getUsernameFromRequests( $reqs );
136 $this->fail( 'Expected exception not thrown' );
137 } catch ( \UnexpectedValueException
$ex ) {
139 'Conflicting username fields: "bar" from ' .
140 get_class( $reqs[1] ) . '::$username vs. "foo" from ' .
141 get_class( $reqs[0] ) . '::$username',
147 public function testMergeFieldInfo() {
148 $msg = wfMessage( 'foo' );
150 $req1 = $this->getMock( AuthenticationRequest
::class );
151 $req1->required
= AuthenticationRequest
::REQUIRED
;
152 $req1->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
171 'options' => [ 'foo' => $msg, 'baz' => $msg ],
177 $req2 = $this->getMock( AuthenticationRequest
::class );
178 $req2->required
= AuthenticationRequest
::REQUIRED
;
179 $req2->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
192 'options' => [ 'bar' => $msg, 'baz' => $msg ],
198 $req3 = $this->getMock( AuthenticationRequest
::class );
199 $req3->required
= AuthenticationRequest
::REQUIRED
;
200 $req3->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
202 'type' => 'checkbox',
208 $req4 = $this->getMock( AuthenticationRequest
::class );
209 $req4->required
= AuthenticationRequest
::REQUIRED
;
210 $req4->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [] ) );
214 $fields = AuthenticationRequest
::mergeFieldInfo( [ $req1 ] );
215 $expect = $req1->getFieldInfo();
216 foreach ( $expect as $name => &$options ) {
217 $options['optional'] = !empty( $options['optional'] );
220 $this->assertEquals( $expect, $fields );
222 $fields = AuthenticationRequest
::mergeFieldInfo( [ $req1, $req4 ] );
223 $this->assertEquals( $expect, $fields );
226 AuthenticationRequest
::mergeFieldInfo( [ $req1, $req3 ] );
227 $this->fail( 'Expected exception not thrown' );
228 } catch ( \UnexpectedValueException
$ex ) {
230 'Field type conflict for "string1", "string" vs "checkbox"',
235 $fields = AuthenticationRequest
::mergeFieldInfo( [ $req1, $req2 ] );
236 $expect +
= $req2->getFieldInfo();
237 $expect['string2']['optional'] = false;
238 $expect['string3']['optional'] = false;
239 $expect['select']['options']['bar'] = $msg;
240 $this->assertEquals( $expect, $fields );
242 // Combining with something not required
244 $req1->required
= AuthenticationRequest
::PRIMARY_REQUIRED
;
246 $fields = AuthenticationRequest
::mergeFieldInfo( [ $req1, $req2 ] );
247 $expect +
= $req2->getFieldInfo();
248 $expect['string1']['optional'] = false;
249 $expect['string3']['optional'] = false;
250 $expect['select']['optional'] = false;
251 $expect['select']['options']['bar'] = $msg;
252 $this->assertEquals( $expect, $fields );
254 $req2->required
= AuthenticationRequest
::PRIMARY_REQUIRED
;
256 $fields = AuthenticationRequest
::mergeFieldInfo( [ $req1, $req2 ] );
257 $expect = $req1->getFieldInfo() +
$req2->getFieldInfo();
258 $expect['string1']['optional'] = false;
259 $expect['string2']['optional'] = true;
260 $expect['string3']['optional'] = true;
261 $expect['select']['optional'] = false;
262 $expect['select']['options']['bar'] = $msg;
263 $this->assertEquals( $expect, $fields );
267 * @dataProvider provideLoadFromSubmission
268 * @param array $fieldInfo
270 * @param array|bool $expectState
272 public function testLoadFromSubmission( $fieldInfo, $data, $expectState ) {
273 $mock = $this->getMockForAbstractClass( AuthenticationRequest
::class );
274 $mock->expects( $this->any() )->method( 'getFieldInfo' )
275 ->will( $this->returnValue( $fieldInfo ) );
277 $ret = $mock->loadFromSubmission( $data );
278 if ( is_array( $expectState ) ) {
279 $this->assertTrue( $ret );
280 $expect = call_user_func( [ get_class( $mock ), '__set_state' ], $expectState );
281 $this->assertEquals( $expect, $mock );
283 $this->assertFalse( $ret );
287 public static function provideLoadFromSubmission() {
291 $data = [ 'foo' => 'bar' ],
301 $data = [ 'field' => 'string!' ],
304 'Simple field, not supplied' => [
313 'Simple field, empty' => [
322 'Simple field, optional, not supplied' => [
332 'Simple field, optional, empty' => [
339 $data = [ 'field' => '' ],
343 'Checkbox, checked' => [
346 'type' => 'checkbox',
352 'Checkbox, unchecked' => [
355 'type' => 'checkbox',
361 'Checkbox, optional, unchecked' => [
364 'type' => 'checkbox',
381 'Button, unused' => [
390 'Button, optional, unused' => [
400 'Button, image-style' => [
406 [ 'push_x' => 0, 'push_y' => 0 ],
415 'foo' => wfMessage( 'mainpage' ),
416 'bar' => wfMessage( 'mainpage' ),
420 $data = [ 'choose' => 'foo' ],
423 'Select, invalid choice' => [
428 'foo' => wfMessage( 'mainpage' ),
429 'bar' => wfMessage( 'mainpage' ),
433 $data = [ 'choose' => 'baz' ],
436 'Multiselect (2)' => [
439 'type' => 'multiselect',
441 'foo' => wfMessage( 'mainpage' ),
442 'bar' => wfMessage( 'mainpage' ),
446 $data = [ 'choose' => [ 'foo', 'bar' ] ],
449 'Multiselect (1)' => [
452 'type' => 'multiselect',
454 'foo' => wfMessage( 'mainpage' ),
455 'bar' => wfMessage( 'mainpage' ),
459 $data = [ 'choose' => [ 'bar' ] ],
462 'Multiselect, string for some reason' => [
465 'type' => 'multiselect',
467 'foo' => wfMessage( 'mainpage' ),
468 'bar' => wfMessage( 'mainpage' ),
472 [ 'choose' => 'foo' ],
473 [ 'choose' => [ 'foo' ] ]
475 'Multiselect, invalid choice' => [
478 'type' => 'multiselect',
480 'foo' => wfMessage( 'mainpage' ),
481 'bar' => wfMessage( 'mainpage' ),
485 [ 'choose' => [ 'foo', 'baz' ] ],
488 'Multiselect, empty' => [
491 'type' => 'multiselect',
493 'foo' => wfMessage( 'mainpage' ),
494 'bar' => wfMessage( 'mainpage' ),
501 'Multiselect, optional, nothing submitted' => [
504 'type' => 'multiselect',
506 'foo' => wfMessage( 'mainpage' ),
507 'bar' => wfMessage( 'mainpage' ),