Skip to content
This repository has been archived by the owner on Mar 23, 2024. It is now read-only.

Commit

Permalink
:octocat: update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
codemasher committed Mar 22, 2024
1 parent 3cd5c75 commit e8384c6
Show file tree
Hide file tree
Showing 11 changed files with 611 additions and 28 deletions.
2 changes: 1 addition & 1 deletion tests/Providers/Live/OAuthProviderLiveTestAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use function str_contains;

/**
*
* @property \chillerlan\OAuth\Core\OAuthInterface $provider
*/
abstract class OAuthProviderLiveTestAbstract extends ProviderLiveTestAbstract{

Expand Down
13 changes: 8 additions & 5 deletions tests/Providers/ProviderUnitTestAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ protected function setUp():void{

}


/*
* abstract methods
*/
Expand All @@ -75,13 +76,14 @@ protected function setUp():void{
*/
abstract protected function getProviderFQCN():string;


/*
* init provider & dependencies
*/

protected function initOptions():OAuthOptions{
return new OAuthOptions([
'key' => 'testkey',
'key' => 'testclient',
'secret' => 'testsecret',
'callbackURL' => 'https://localhost/callback',
'tokenAutoRefresh' => true,
Expand All @@ -107,25 +109,26 @@ protected function initProvider(string $FQCN):OAuthInterface|OAuth1Interface|OAu
return $this->invokeReflection($FQCN, $args);
}


/*
* Reflection utilities
*/

protected function invokeReflection(string $FQCN, array $args = []):object{
final protected function invokeReflection(string $FQCN, array $args = []):object{
$this->reflection = new ReflectionClass($FQCN);

return $this->reflection->newInstanceArgs($args);
}

protected function setReflectionProperty(string $property, mixed $value):void{
final protected function setReflectionProperty(string $property, mixed $value):void{
$this->reflection->getProperty($property)->setValue($this->provider, $value);
}

protected function getReflectionProperty(string $property):mixed{
final protected function getReflectionProperty(string $property):mixed{
return $this->reflection->getProperty($property)->getValue($this->provider);
}

protected function invokeReflectionMethod(string $method, array $args = []):mixed{
final protected function invokeReflectionMethod(string $method, array $args = []):mixed{
return $this->reflection->getMethod($method)->invokeArgs($this->provider, $args);
}

Expand Down
1 change: 1 addition & 0 deletions tests/Providers/Unit/BattleNetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static function requestTargetProvider():array{
'trailing slash' => ['c/', 'https://eu.api.blizzard.com/c/'],
'full url given' => ['https://oauth.battle.net/other/path/d', 'https://oauth.battle.net/other/path/d'],
'ignore params' => ['https://oauth.battle.net/api/e/?with=param#foo', 'https://oauth.battle.net/api/e/'],
'enforce https' => ['wtf://eu.api.blizzard.com/a/b/c', 'https://eu.api.blizzard.com/a/b/c'],
];
}

Expand Down
84 changes: 84 additions & 0 deletions tests/Providers/Unit/DeezerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,99 @@

namespace chillerlan\OAuthTest\Providers\Unit;

use chillerlan\HTTP\Utils\QueryUtil;
use chillerlan\OAuth\Providers\Deezer;
use chillerlan\OAuth\Providers\ProviderException;
use function implode;

/**
* @property \chillerlan\OAuth\Providers\Deezer $provider
*/
class DeezerTest extends OAuth2ProviderUnitTestAbstract{

protected const TEST_TOKEN = 'access_token=2YotnFZFEjr1zCsicMWpAA&token_type=example&expires=3600&'.
'refresh_token=tGzv3JOkF0XG5Qx2TlKWIA&example_parameter=example_value';

protected function getProviderFQCN():string{
return Deezer::class;
}

public function testParseTokenResponseWithScopes():void{
$this::markTestSkipped('N/A');
}

public function testParseTokenResponseNoDataException():void{
$this->expectException(ProviderException::class);
$this->expectExceptionMessage('unable to parse token response');

$response = $this->responseFactory
->createResponse()
->withBody($this->streamFactory->createStream(''))
;

$this->invokeReflectionMethod('parseTokenResponse', [$response]);
}

public function testParseTokenResponseErrorException():void{
$this->expectException(ProviderException::class);
$this->expectExceptionMessage('error retrieving access token');

// the error variable for deezer is "error_reason" and content type is form-data
$response = $this->responseFactory
->createResponse()
->withBody($this->streamFactory->createStream('error_reason=whatever'))
;

$this->invokeReflectionMethod('parseTokenResponse', [$response]);
}

public function testParseTokenResponseNoTokenException():void{
$this->expectException(ProviderException::class);
$this->expectExceptionMessage('token missing');

$response = $this->responseFactory
->createResponse()
->withBody($this->streamFactory->createStream('foo=bar'))
;

$this->invokeReflectionMethod('parseTokenResponse', [$response]);
}

public function testGetAuthURL():void{
$params = ['response_type' => 'whatever', 'foo' => 'bar']; // response_type shall be overwritten
$scopes = ['scope1', 'scope2', 'scope3'];

$uri = $this->provider->getAuthURL($params, $scopes);
$params = QueryUtil::parse($uri->getQuery());

$this::assertSame($this->getReflectionProperty('authURL'), (string)$uri->withQuery(''));

$this::assertSame($this->options->key, $params['app_id']);
$this::assertSame($this->options->callbackURL, $params['redirect_uri']);
$this::assertSame(implode($this->provider::SCOPE_DELIMITER, $scopes), $params['perms']);
$this::assertSame('bar', $params['foo']);
$this::assertArrayHasKey('state', $params);

}

public function testGetAuthURLRequestParams():void{
$params = ['foo' => 'bar']; // response_type shall be overwritten
$scopes = ['scope1', 'scope2', 'scope3'];

$queryparams = $this->invokeReflectionMethod('getAuthURLRequestParams', [$params, $scopes]);

$this::assertArrayHasKey('app_id', $queryparams);
$this::assertArrayHasKey('redirect_uri', $queryparams);
$this::assertSame(implode($this->provider::SCOPE_DELIMITER, $scopes), $queryparams['perms']);
$this::assertSame('bar', $queryparams['foo']);
}

public function testGetAccessTokenRequestBodyParams():void{
$params = $this->invokeReflectionMethod('getAccessTokenRequestBodyParams', ['*test_code*']);

$this::assertSame('*test_code*', $params['code']);
$this::assertSame($this->options->key, $params['app_id']);
$this::assertSame($this->options->secret, $params['secret']);
}

}
4 changes: 4 additions & 0 deletions tests/Providers/Unit/GuildWars2Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ protected function getProviderFQCN():string{
return GuildWars2::class;
}

public function testGetAuthURL():void{
$this::markTestSkipped('N/A');
}

}
15 changes: 15 additions & 0 deletions tests/Providers/Unit/MusicBrainzTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

namespace chillerlan\OAuthTest\Providers\Unit;

use chillerlan\OAuth\Core\TokenRefresh;
use chillerlan\OAuth\Providers\MusicBrainz;

/**
Expand All @@ -21,4 +22,18 @@ protected function getProviderFQCN():string{
return MusicBrainz::class;
}

public function testGetRefreshAccessTokenRequestBodyParams():void{

if(!$this->provider instanceof TokenRefresh){
$this->markTestSkipped('TokenRefresh N/A');
}

$params = $this->invokeReflectionMethod('getRefreshAccessTokenRequestBodyParams', ['*refresh_token*']);

$this::assertSame('*refresh_token*', $params['refresh_token']);
$this::assertSame($this->options->key, $params['client_id']);
$this::assertSame($this->options->secret, $params['client_secret']);
$this::assertSame('refresh_token', $params['grant_type']);
}

}
132 changes: 129 additions & 3 deletions tests/Providers/Unit/OAuth1ProviderUnitTestAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,145 @@

namespace chillerlan\OAuthTest\Providers\Unit;

use chillerlan\OAuth\Core\{AccessToken, OAuth1Interface, OAuthInterface};
use chillerlan\OAuth\Core\{AccessToken, OAuth1Interface};
use chillerlan\HTTP\Utils\MessageUtil;
use chillerlan\OAuth\Providers\ProviderException;
use function str_starts_with;

/**
* @property \chillerlan\OAuth\Core\OAuth1Interface $provider
*/
abstract class OAuth1ProviderUnitTestAbstract extends OAuthProviderUnitTestAbstract{

protected OAuthInterface|OAuth1Interface $provider;

public function testOAuth1Instance():void{
$this::assertInstanceOf(OAuth1Interface::class, $this->provider);
}

/*
* auth URL
*/

public function testGetRequestTokenRequestParams():void{
$params = $this->invokeReflectionMethod('getRequestTokenRequestParams');

$this::assertSame($this->options->callbackURL, $params['oauth_callback']);
$this::assertSame($this->options->key, $params['oauth_consumer_key']);
$this::assertArrayHasKey('oauth_nonce', $params);
$this::assertSame('HMAC-SHA1', $params['oauth_signature_method']);
$this::assertArrayHasKey('oauth_timestamp', $params);
$this::assertSame('1.0', $params['oauth_version']);
}

public function testSendRequestTokenRequest():void{
$url = 'https://localhost/request_token';
$response = $this->invokeReflectionMethod('sendRequestTokenRequest', [$url]);
$json = MessageUtil::decodeJSON($response);

$this::assertTrue(str_starts_with($json->headers->{'Authorization'}, 'OAuth '));
$this::assertSame('identity', $json->headers->{'Accept-Encoding'});
$this::assertSame('0', $json->headers->{'Content-Length'});
$this::assertSame('POST', $json->request->method);
}


/*
* token response parser
*/

public function testParseTokenResponse():void{
// from https://datatracker.ietf.org/doc/html/rfc5849#section-2.3
$responseBody = 'oauth_token=j49ddk933skd9dks&oauth_token_secret=ll399dj47dskfjdk';

$response = $this->responseFactory
->createResponse()
->withBody($this->streamFactory->createStream($responseBody))
;

/** @var \chillerlan\OAuth\Core\AccessToken $token */
$token = $this->invokeReflectionMethod('parseTokenResponse', [$response]);

$this::assertSame('j49ddk933skd9dks', $token->accessToken);
$this::assertSame('ll399dj47dskfjdk', $token->accessTokenSecret);
}

public function testParseTemporaryCredentialsTokenResponse():void{
// from https://datatracker.ietf.org/doc/html/rfc5849#section-2.1
$responseBody = 'oauth_token=hdk48Djdsa&oauth_token_secret=xyz4992k83j47x0b&oauth_callback_confirmed=true';

$response = $this->responseFactory
->createResponse()
->withBody($this->streamFactory->createStream($responseBody))
;

/** @var \chillerlan\OAuth\Core\AccessToken $token */
$token = $this->invokeReflectionMethod('parseTokenResponse', [$response, true]);

$this::assertSame('hdk48Djdsa', $token->accessToken);
$this::assertSame('xyz4992k83j47x0b', $token->accessTokenSecret);
}

public function testParseTokenResponseNoDataException():void{
$this->expectException(ProviderException::class);
$this->expectExceptionMessage('unable to parse token response');

$response = $this->responseFactory->createResponse();

$this->invokeReflectionMethod('parseTokenResponse', [$response]);
}

public function testParseTokenResponseErrorException():void{
$this->expectException(ProviderException::class);
$this->expectExceptionMessage('error retrieving access token: "whatever"');

$body = $this->streamFactory->createStream('error=whatever');
$response = $this->responseFactory->createResponse()->withBody($body);

$this->invokeReflectionMethod('parseTokenResponse', [$response]);
}

public function testParseTokenResponseNoTokenException():void{
$this->expectException(ProviderException::class);
$this->expectExceptionMessage('invalid token');

$body = $this->streamFactory->createStream('oauth_token=whatever');
$response = $this->responseFactory->createResponse()->withBody($body);

$this->invokeReflectionMethod('parseTokenResponse', [$response]);
}

public function testParseTokenResponseConfirmCallbackException():void{
$this->expectException(ProviderException::class);
$this->expectExceptionMessage('oauth callback unconfirmed');

$body = $this->streamFactory->createStream('oauth_token=whatever&oauth_token_secret=whatever_secret');
$response = $this->responseFactory->createResponse()->withBody($body);

$this->invokeReflectionMethod('parseTokenResponse', [$response, true]);
}


/*
* access token
*/

public function testSendAccessTokenRequest():void{
// we need the request token for the access token request
$requestToken = new AccessToken(['accessToken' => 'hdk48Djdsa', 'accessTokenSecret' => 'xyz4992k83j47x0b']);
$this->provider->storeAccessToken($requestToken);

$response = $this->invokeReflectionMethod('sendAccessTokenRequest', ['*verifier*']);
$json = MessageUtil::decodeJSON($response);

// check if the verifier is set
$this::assertSame('*verifier*', $json->request->params->{'oauth_verifier'});

$this::assertTrue(str_starts_with($json->headers->{'Authorization'}, 'OAuth '));
$this::assertSame('identity', $json->headers->{'Accept-Encoding'});
$this::assertSame('0', $json->headers->{'Content-Length'});
$this::assertSame('POST', $json->request->method);
}


/*
* request authorization
*/
Expand All @@ -42,6 +167,7 @@ public function testGetRequestAuthorization():void{
$this::assertStringContainsString('oauth_token="test_token"', $authHeader);
}


/*
* signature
*/
Expand Down
Loading

0 comments on commit e8384c6

Please sign in to comment.