wiki.techinc.nl/tests/phpunit/includes/auth/AuthenticationRequestTest.php
Thiemo Kreuz 6aa6d10e86 Replace all call_user_func(_array) in all tests
There is native support for all of this now in PHP, thanks to changes
and additions that have been made in later versions. There should be no
need any more to ever use call_user_func() or call_user_func_array().

Reviewing this should be fairly easy: Because this patch touches
exclusivly tests, but no production code, there is no such thing as
"insufficent test coverage". As long as CI goes green, this should be
fine.

Change-Id: Ib9690103687734bb5a85d3dab0e5642a07087bbc
2020-06-06 18:41:20 +02:00

519 lines
13 KiB
PHP

<?php
namespace MediaWiki\Auth;
/**
* @group AuthManager
* @covers \MediaWiki\Auth\AuthenticationRequest
*/
class AuthenticationRequestTest extends \MediaWikiTestCase {
public function testBasics() {
$mock = $this->getMockForAbstractClass( AuthenticationRequest::class );
$this->assertSame( get_class( $mock ), $mock->getUniqueId() );
$this->assertIsArray( $mock->getMetadata() );
$ret = $mock->describeCredentials();
$this->assertIsArray( $ret );
$this->assertArrayHasKey( 'provider', $ret );
$this->assertInstanceOf( \Message::class, $ret['provider'] );
$this->assertArrayHasKey( 'account', $ret );
$this->assertInstanceOf( \Message::class, $ret['account'] );
}
public function testLoadRequestsFromSubmission() {
$mb = $this->getMockBuilder( AuthenticationRequest::class )
->setMethods( [ 'loadFromSubmission' ] );
$data = [ 'foo', 'bar' ];
$req1 = $mb->getMockForAbstractClass();
$req1->expects( $this->once() )->method( 'loadFromSubmission' )
->with( $this->identicalTo( $data ) )
->will( $this->returnValue( false ) );
$req2 = $mb->getMockForAbstractClass();
$req2->expects( $this->once() )->method( 'loadFromSubmission' )
->with( $this->identicalTo( $data ) )
->will( $this->returnValue( true ) );
$this->assertSame(
[ $req2 ],
AuthenticationRequest::loadRequestsFromSubmission( [ $req1, $req2 ], $data )
);
}
public function testGetRequestByClass() {
$mb = $this->getMockBuilder(
AuthenticationRequest::class, 'AuthenticationRequestTest_AuthenticationRequest2'
);
$reqs = [
$this->getMockForAbstractClass(
AuthenticationRequest::class, [], 'AuthenticationRequestTest_AuthenticationRequest1'
),
$mb->getMockForAbstractClass(),
$mb->getMockForAbstractClass(),
$this->getMockForAbstractClass(
PasswordAuthenticationRequest::class, [],
'AuthenticationRequestTest_PasswordAuthenticationRequest'
),
];
$this->assertNull( AuthenticationRequest::getRequestByClass(
$reqs, 'AuthenticationRequestTest_AuthenticationRequest0'
) );
$this->assertSame( $reqs[0], AuthenticationRequest::getRequestByClass(
$reqs, 'AuthenticationRequestTest_AuthenticationRequest1'
) );
$this->assertNull( AuthenticationRequest::getRequestByClass(
$reqs, 'AuthenticationRequestTest_AuthenticationRequest2'
) );
$this->assertNull( AuthenticationRequest::getRequestByClass(
$reqs, PasswordAuthenticationRequest::class
) );
$this->assertNull( AuthenticationRequest::getRequestByClass(
$reqs, 'ClassThatDoesNotExist'
) );
$this->assertNull( AuthenticationRequest::getRequestByClass(
$reqs, 'AuthenticationRequestTest_AuthenticationRequest0', true
) );
$this->assertSame( $reqs[0], AuthenticationRequest::getRequestByClass(
$reqs, 'AuthenticationRequestTest_AuthenticationRequest1', true
) );
$this->assertNull( AuthenticationRequest::getRequestByClass(
$reqs, 'AuthenticationRequestTest_AuthenticationRequest2', true
) );
$this->assertSame( $reqs[3], AuthenticationRequest::getRequestByClass(
$reqs, PasswordAuthenticationRequest::class, true
) );
$this->assertNull( AuthenticationRequest::getRequestByClass(
$reqs, 'ClassThatDoesNotExist', true
) );
}
public function testGetUsernameFromRequests() {
$mb = $this->getMockBuilder( AuthenticationRequest::class );
for ( $i = 0; $i < 3; $i++ ) {
$req = $mb->getMockForAbstractClass();
$req->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
'username' => [
'type' => 'string',
],
] ) );
$reqs[] = $req;
}
$req = $mb->getMockForAbstractClass();
$req->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [] ) );
$req->username = 'baz';
$reqs[] = $req;
$this->assertNull( AuthenticationRequest::getUsernameFromRequests( $reqs ) );
$reqs[1]->username = 'foo';
$this->assertSame( 'foo', AuthenticationRequest::getUsernameFromRequests( $reqs ) );
$reqs[0]->username = 'foo';
$reqs[2]->username = 'foo';
$this->assertSame( 'foo', AuthenticationRequest::getUsernameFromRequests( $reqs ) );
$reqs[1]->username = 'bar';
try {
AuthenticationRequest::getUsernameFromRequests( $reqs );
$this->fail( 'Expected exception not thrown' );
} catch ( \UnexpectedValueException $ex ) {
$this->assertSame(
'Conflicting username fields: "bar" from ' .
get_class( $reqs[1] ) . '::$username vs. "foo" from ' .
get_class( $reqs[0] ) . '::$username',
$ex->getMessage()
);
}
}
public function testMergeFieldInfo() {
$msg = wfMessage( 'foo' );
$req1 = $this->createMock( AuthenticationRequest::class );
$req1->required = AuthenticationRequest::REQUIRED;
$req1->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
'string1' => [
'type' => 'string',
'label' => $msg,
'help' => $msg,
],
'string2' => [
'type' => 'string',
'label' => $msg,
'help' => $msg,
],
'optional' => [
'type' => 'string',
'label' => $msg,
'help' => $msg,
'optional' => true,
],
'select' => [
'type' => 'select',
'options' => [ 'foo' => $msg, 'baz' => $msg ],
'label' => $msg,
'help' => $msg,
],
] ) );
$req2 = $this->createMock( AuthenticationRequest::class );
$req2->required = AuthenticationRequest::REQUIRED;
$req2->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
'string1' => [
'type' => 'string',
'label' => $msg,
'help' => $msg,
'sensitive' => true,
],
'string3' => [
'type' => 'string',
'label' => $msg,
'help' => $msg,
],
'select' => [
'type' => 'select',
'options' => [ 'bar' => $msg, 'baz' => $msg ],
'label' => $msg,
'help' => $msg,
],
] ) );
$req3 = $this->createMock( AuthenticationRequest::class );
$req3->required = AuthenticationRequest::REQUIRED;
$req3->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
'string1' => [
'type' => 'checkbox',
'label' => $msg,
'help' => $msg,
],
] ) );
$req4 = $this->createMock( AuthenticationRequest::class );
$req4->required = AuthenticationRequest::REQUIRED;
$req4->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [] ) );
// Basic combining
$this->assertEquals( [], AuthenticationRequest::mergeFieldInfo( [] ) );
$fields = AuthenticationRequest::mergeFieldInfo( [ $req1 ] );
$expect = $req1->getFieldInfo();
foreach ( $expect as $name => &$options ) {
$options['optional'] = !empty( $options['optional'] );
$options['sensitive'] = !empty( $options['sensitive'] );
}
unset( $options );
$this->assertEquals( $expect, $fields );
$fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req4 ] );
$this->assertEquals( $expect, $fields );
try {
AuthenticationRequest::mergeFieldInfo( [ $req1, $req3 ] );
$this->fail( 'Expected exception not thrown' );
} catch ( \UnexpectedValueException $ex ) {
$this->assertSame(
'Field type conflict for "string1", "string" vs "checkbox"',
$ex->getMessage()
);
}
$fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
$expect += $req2->getFieldInfo();
$expect['string1']['sensitive'] = true;
$expect['string2']['optional'] = false;
$expect['string3']['optional'] = false;
$expect['string3']['sensitive'] = false;
$expect['select']['options']['bar'] = $msg;
$this->assertEquals( $expect, $fields );
// Combining with something not required
$req1->required = AuthenticationRequest::PRIMARY_REQUIRED;
$fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
$expect += $req2->getFieldInfo();
$expect['string1']['optional'] = false;
$expect['string1']['sensitive'] = true;
$expect['string3']['optional'] = false;
$expect['select']['optional'] = false;
$expect['select']['options']['bar'] = $msg;
$this->assertEquals( $expect, $fields );
$req2->required = AuthenticationRequest::PRIMARY_REQUIRED;
$fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
$expect = $req1->getFieldInfo() + $req2->getFieldInfo();
foreach ( $expect as $name => &$options ) {
$options['sensitive'] = !empty( $options['sensitive'] );
}
$expect['string1']['optional'] = false;
$expect['string1']['sensitive'] = true;
$expect['string2']['optional'] = true;
$expect['string3']['optional'] = true;
$expect['select']['optional'] = false;
$expect['select']['options']['bar'] = $msg;
$this->assertEquals( $expect, $fields );
}
/**
* @dataProvider provideLoadFromSubmission
* @param array $fieldInfo
* @param array $data
* @param array|bool $expectState
*/
public function testLoadFromSubmission( $fieldInfo, $data, $expectState ) {
$mock = $this->getMockForAbstractClass( AuthenticationRequest::class );
$mock->expects( $this->any() )->method( 'getFieldInfo' )
->will( $this->returnValue( $fieldInfo ) );
$ret = $mock->loadFromSubmission( $data );
if ( is_array( $expectState ) ) {
$this->assertTrue( $ret );
$expect = $mock::__set_state( $expectState );
$this->assertEquals( $expect, $mock );
} else {
$this->assertFalse( $ret );
}
}
public static function provideLoadFromSubmission() {
return [
'No fields' => [
[],
$data = [ 'foo' => 'bar' ],
false
],
'Simple field' => [
[
'field' => [
'type' => 'string',
],
],
$data = [ 'field' => 'string!' ],
$data
],
'Simple field, not supplied' => [
[
'field' => [
'type' => 'string',
],
],
[],
false
],
'Simple field, empty' => [
[
'field' => [
'type' => 'string',
],
],
[ 'field' => '' ],
false
],
'Simple field, optional, not supplied' => [
[
'field' => [
'type' => 'string',
'optional' => true,
],
],
[],
false
],
'Simple field, optional, empty' => [
[
'field' => [
'type' => 'string',
'optional' => true,
],
],
$data = [ 'field' => '' ],
$data
],
'Checkbox, checked' => [
[
'check' => [
'type' => 'checkbox',
],
],
[ 'check' => '' ],
[ 'check' => true ]
],
'Checkbox, unchecked' => [
[
'check' => [
'type' => 'checkbox',
],
],
[],
false
],
'Checkbox, optional, unchecked' => [
[
'check' => [
'type' => 'checkbox',
'optional' => true,
],
],
[],
[ 'check' => false ]
],
'Button, used' => [
[
'push' => [
'type' => 'button',
],
],
[ 'push' => '' ],
[ 'push' => true ]
],
'Button, unused' => [
[
'push' => [
'type' => 'button',
],
],
[],
false
],
'Button, optional, unused' => [
[
'push' => [
'type' => 'button',
'optional' => true,
],
],
[],
[ 'push' => false ]
],
'Button, image-style' => [
[
'push' => [
'type' => 'button',
],
],
[ 'push_x' => 0, 'push_y' => 0 ],
[ 'push' => true ]
],
'Select' => [
[
'choose' => [
'type' => 'select',
'options' => [
'foo' => wfMessage( 'mainpage' ),
'bar' => wfMessage( 'mainpage' ),
],
],
],
$data = [ 'choose' => 'foo' ],
$data
],
'Select, invalid choice' => [
[
'choose' => [
'type' => 'select',
'options' => [
'foo' => wfMessage( 'mainpage' ),
'bar' => wfMessage( 'mainpage' ),
],
],
],
$data = [ 'choose' => 'baz' ],
false
],
'Multiselect (2)' => [
[
'choose' => [
'type' => 'multiselect',
'options' => [
'foo' => wfMessage( 'mainpage' ),
'bar' => wfMessage( 'mainpage' ),
],
],
],
$data = [ 'choose' => [ 'foo', 'bar' ] ],
$data
],
'Multiselect (1)' => [
[
'choose' => [
'type' => 'multiselect',
'options' => [
'foo' => wfMessage( 'mainpage' ),
'bar' => wfMessage( 'mainpage' ),
],
],
],
$data = [ 'choose' => [ 'bar' ] ],
$data
],
'Multiselect, string for some reason' => [
[
'choose' => [
'type' => 'multiselect',
'options' => [
'foo' => wfMessage( 'mainpage' ),
'bar' => wfMessage( 'mainpage' ),
],
],
],
[ 'choose' => 'foo' ],
[ 'choose' => [ 'foo' ] ]
],
'Multiselect, invalid choice' => [
[
'choose' => [
'type' => 'multiselect',
'options' => [
'foo' => wfMessage( 'mainpage' ),
'bar' => wfMessage( 'mainpage' ),
],
],
],
[ 'choose' => [ 'foo', 'baz' ] ],
false
],
'Multiselect, empty' => [
[
'choose' => [
'type' => 'multiselect',
'options' => [
'foo' => wfMessage( 'mainpage' ),
'bar' => wfMessage( 'mainpage' ),
],
],
],
[ 'choose' => [] ],
false
],
'Multiselect, optional, nothing submitted' => [
[
'choose' => [
'type' => 'multiselect',
'options' => [
'foo' => wfMessage( 'mainpage' ),
'bar' => wfMessage( 'mainpage' ),
],
'optional' => true,
],
],
[],
[ 'choose' => [] ]
],
];
}
}