Remove usage of codeception/specify and fzaninotto/faker

This commit is contained in:
ErickSkrauch 2019-12-21 02:26:06 +03:00
parent 666213afc7
commit 43a4a58053
19 changed files with 217 additions and 613 deletions

View File

@ -1,4 +1,6 @@
<?php <?php
declare(strict_types=1);
namespace api\models\authentication; namespace api\models\authentication;
use api\aop\annotations\CollectModelMetrics; use api\aop\annotations\CollectModelMetrics;

View File

@ -4,7 +4,7 @@ namespace api\tests\functional\_steps;
use api\rbac\Permissions as P; use api\rbac\Permissions as P;
use api\tests\_pages\SessionServerRoute; use api\tests\_pages\SessionServerRoute;
use api\tests\FunctionalTester; use api\tests\FunctionalTester;
use Faker\Provider\Uuid; use function Ramsey\Uuid\v4 as uuid;
class SessionServerSteps extends FunctionalTester { class SessionServerSteps extends FunctionalTester {
@ -12,7 +12,7 @@ class SessionServerSteps extends FunctionalTester {
$oauthSteps = new OauthSteps($this->scenario); $oauthSteps = new OauthSteps($this->scenario);
$accessToken = $oauthSteps->getAccessToken([P::MINECRAFT_SERVER_SESSION]); $accessToken = $oauthSteps->getAccessToken([P::MINECRAFT_SERVER_SESSION]);
$route = new SessionServerRoute($this); $route = new SessionServerRoute($this);
$serverId = Uuid::uuid(); $serverId = uuid();
$username = 'Admin'; $username = 'Admin';
if ($byLegacy) { if ($byLegacy) {

View File

@ -3,7 +3,7 @@ namespace api\tests\functional\authserver;
use api\tests\_pages\MojangApiRoute; use api\tests\_pages\MojangApiRoute;
use api\tests\FunctionalTester; use api\tests\FunctionalTester;
use Faker\Provider\Uuid; use function Ramsey\Uuid\v4 as uuid;
class UuidToUsernamesHistoryCest { class UuidToUsernamesHistoryCest {
@ -50,7 +50,7 @@ class UuidToUsernamesHistoryCest {
public function passWrongUuid(FunctionalTester $I) { public function passWrongUuid(FunctionalTester $I) {
$I->wantTo('get user username by some wrong uuid'); $I->wantTo('get user username by some wrong uuid');
$this->route->usernamesByUuid(Uuid::uuid()); $this->route->usernamesByUuid(uuid());
$I->canSeeResponseCodeIs(204); $I->canSeeResponseCodeIs(204);
$I->canSeeResponseEquals(''); $I->canSeeResponseEquals('');
} }

View File

@ -4,7 +4,7 @@ namespace api\tests\functional\sessionserver;
use api\tests\_pages\SessionServerRoute; use api\tests\_pages\SessionServerRoute;
use api\tests\functional\_steps\SessionServerSteps; use api\tests\functional\_steps\SessionServerSteps;
use api\tests\FunctionalTester; use api\tests\FunctionalTester;
use Faker\Provider\Uuid; use function Ramsey\Uuid\v4 as uuid;
class HasJoinedCest { class HasJoinedCest {
@ -46,7 +46,7 @@ class HasJoinedCest {
$I->wantTo('hasJoined to some server without join call'); $I->wantTo('hasJoined to some server without join call');
$this->route->hasJoined([ $this->route->hasJoined([
'username' => 'some-username', 'username' => 'some-username',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$I->seeResponseCodeIs(401); $I->seeResponseCodeIs(401);
$I->seeResponseIsJson(); $I->seeResponseIsJson();

View File

@ -4,7 +4,7 @@ namespace api\tests\functional\sessionserver;
use api\tests\_pages\SessionServerRoute; use api\tests\_pages\SessionServerRoute;
use api\tests\functional\_steps\SessionServerSteps; use api\tests\functional\_steps\SessionServerSteps;
use api\tests\FunctionalTester; use api\tests\FunctionalTester;
use Faker\Provider\Uuid; use function Ramsey\Uuid\v4 as uuid;
class HasJoinedLegacyCest { class HasJoinedLegacyCest {
@ -42,7 +42,7 @@ class HasJoinedLegacyCest {
$I->wantTo('hasJoined by legacy version to some server without join call'); $I->wantTo('hasJoined by legacy version to some server without join call');
$this->route->hasJoinedLegacy([ $this->route->hasJoinedLegacy([
'user' => 'random-username', 'user' => 'random-username',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$I->seeResponseCodeIs(200); $I->seeResponseCodeIs(200);
$I->canSeeResponseEquals('NO'); $I->canSeeResponseEquals('NO');

View File

@ -6,7 +6,7 @@ use api\tests\_pages\SessionServerRoute;
use api\tests\functional\_steps\AuthserverSteps; use api\tests\functional\_steps\AuthserverSteps;
use api\tests\functional\_steps\OauthSteps; use api\tests\functional\_steps\OauthSteps;
use api\tests\FunctionalTester; use api\tests\FunctionalTester;
use Faker\Provider\Uuid; use function Ramsey\Uuid\v4 as uuid;
class JoinCest { class JoinCest {
@ -25,7 +25,7 @@ class JoinCest {
$this->route->join([ $this->route->join([
'accessToken' => $accessToken, 'accessToken' => $accessToken,
'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022', 'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$this->expectSuccessResponse($I); $this->expectSuccessResponse($I);
} }
@ -36,7 +36,7 @@ class JoinCest {
$this->route->join(json_encode([ $this->route->join(json_encode([
'accessToken' => $accessToken, 'accessToken' => $accessToken,
'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022', 'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
])); ]));
$this->expectSuccessResponse($I); $this->expectSuccessResponse($I);
} }
@ -47,7 +47,7 @@ class JoinCest {
$this->route->join([ $this->route->join([
'accessToken' => $accessToken, 'accessToken' => $accessToken,
'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022', 'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$this->expectSuccessResponse($I); $this->expectSuccessResponse($I);
} }
@ -58,7 +58,7 @@ class JoinCest {
$this->route->join([ $this->route->join([
'accessToken' => $accessToken, 'accessToken' => $accessToken,
'selectedProfile' => 'df936908b2e1544d96f82977ec213022', 'selectedProfile' => 'df936908b2e1544d96f82977ec213022',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$this->expectSuccessResponse($I); $this->expectSuccessResponse($I);
} }
@ -69,7 +69,7 @@ class JoinCest {
$this->route->join([ $this->route->join([
'accessToken' => $accessToken, 'accessToken' => $accessToken,
'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022', 'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$I->seeResponseCodeIs(401); $I->seeResponseCodeIs(401);
$I->seeResponseIsJson(); $I->seeResponseIsJson();
@ -84,7 +84,7 @@ class JoinCest {
$this->route->join([ $this->route->join([
'accessToken' => '6042634a-a1e2-4aed-866c-c661fe4e63e2', 'accessToken' => '6042634a-a1e2-4aed-866c-c661fe4e63e2',
'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022', 'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$I->seeResponseCodeIs(401); $I->seeResponseCodeIs(401);
$I->seeResponseIsJson(); $I->seeResponseIsJson();
@ -110,9 +110,9 @@ class JoinCest {
public function joinWithWrongAccessToken(FunctionalTester $I) { public function joinWithWrongAccessToken(FunctionalTester $I) {
$I->wantTo('join to some server with wrong accessToken'); $I->wantTo('join to some server with wrong accessToken');
$this->route->join([ $this->route->join([
'accessToken' => Uuid::uuid(), 'accessToken' => uuid(),
'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022', 'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$I->seeResponseCodeIs(401); $I->seeResponseCodeIs(401);
$I->seeResponseIsJson(); $I->seeResponseIsJson();
@ -127,7 +127,7 @@ class JoinCest {
$this->route->join([ $this->route->join([
'accessToken' => '00000000-0000-0000-0000-000000000000', 'accessToken' => '00000000-0000-0000-0000-000000000000',
'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022', 'selectedProfile' => 'df936908-b2e1-544d-96f8-2977ec213022',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$I->canSeeResponseCodeIs(400); $I->canSeeResponseCodeIs(400);
$I->canSeeResponseIsJson(); $I->canSeeResponseIsJson();

View File

@ -6,7 +6,7 @@ use api\tests\_pages\SessionServerRoute;
use api\tests\functional\_steps\AuthserverSteps; use api\tests\functional\_steps\AuthserverSteps;
use api\tests\functional\_steps\OauthSteps; use api\tests\functional\_steps\OauthSteps;
use api\tests\FunctionalTester; use api\tests\FunctionalTester;
use Faker\Provider\Uuid; use function Ramsey\Uuid\v4 as uuid;
class JoinLegacyCest { class JoinLegacyCest {
@ -25,7 +25,7 @@ class JoinLegacyCest {
$this->route->joinLegacy([ $this->route->joinLegacy([
'sessionId' => $accessToken, 'sessionId' => $accessToken,
'user' => 'Admin', 'user' => 'Admin',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$this->expectSuccessResponse($I); $this->expectSuccessResponse($I);
} }
@ -36,7 +36,7 @@ class JoinLegacyCest {
$this->route->joinLegacy([ $this->route->joinLegacy([
'sessionId' => $accessToken, 'sessionId' => $accessToken,
'user' => 'admin', 'user' => 'admin',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$this->expectSuccessResponse($I); $this->expectSuccessResponse($I);
} }
@ -47,7 +47,7 @@ class JoinLegacyCest {
$this->route->joinLegacy([ $this->route->joinLegacy([
'sessionId' => 'token:' . $accessToken . ':' . 'df936908-b2e1-544d-96f8-2977ec213022', 'sessionId' => 'token:' . $accessToken . ':' . 'df936908-b2e1-544d-96f8-2977ec213022',
'user' => 'Admin', 'user' => 'Admin',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$this->expectSuccessResponse($I); $this->expectSuccessResponse($I);
} }
@ -58,7 +58,7 @@ class JoinLegacyCest {
$this->route->joinLegacy([ $this->route->joinLegacy([
'sessionId' => 'token:' . $accessToken . ':' . 'df936908-b2e1-544d-96f8-2977ec213022', 'sessionId' => 'token:' . $accessToken . ':' . 'df936908-b2e1-544d-96f8-2977ec213022',
'user' => 'Admin', 'user' => 'Admin',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$this->expectSuccessResponse($I); $this->expectSuccessResponse($I);
} }
@ -75,9 +75,9 @@ class JoinLegacyCest {
public function joinWithWrongAccessToken(FunctionalTester $I) { public function joinWithWrongAccessToken(FunctionalTester $I) {
$I->wantTo('join to some server with wrong accessToken'); $I->wantTo('join to some server with wrong accessToken');
$this->route->joinLegacy([ $this->route->joinLegacy([
'sessionId' => 'token:' . Uuid::uuid() . ':' . Uuid::uuid(), 'sessionId' => 'token:' . uuid() . ':' . uuid(),
'user' => 'random-username', 'user' => 'random-username',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$I->seeResponseCodeIs(401); $I->seeResponseCodeIs(401);
$I->canSeeResponseContains('Ely.by authorization required'); $I->canSeeResponseContains('Ely.by authorization required');
@ -89,7 +89,7 @@ class JoinLegacyCest {
$this->route->joinLegacy([ $this->route->joinLegacy([
'sessionId' => 'token:' . $accessToken . ':' . 'df936908-b2e1-544d-96f8-2977ec213022', 'sessionId' => 'token:' . $accessToken . ':' . 'df936908-b2e1-544d-96f8-2977ec213022',
'user' => 'Admin', 'user' => 'Admin',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$I->seeResponseCodeIs(401); $I->seeResponseCodeIs(401);
$I->canSeeResponseContains('Ely.by authorization required'); $I->canSeeResponseContains('Ely.by authorization required');
@ -100,7 +100,7 @@ class JoinLegacyCest {
$this->route->joinLegacy([ $this->route->joinLegacy([
'sessionId' => 'token:00000000-0000-0000-0000-000000000000:00000000-0000-0000-0000-000000000000', 'sessionId' => 'token:00000000-0000-0000-0000-000000000000:00000000-0000-0000-0000-000000000000',
'user' => 'SomeUser', 'user' => 'SomeUser',
'serverId' => Uuid::uuid(), 'serverId' => uuid(),
]); ]);
$I->canSeeResponseCodeIs(400); $I->canSeeResponseCodeIs(400);
$I->canSeeResponseContains('credentials can not be null.'); $I->canSeeResponseContains('credentials can not be null.');

View File

@ -4,7 +4,7 @@ namespace api\tests\functional\sessionserver;
use api\tests\_pages\SessionServerRoute; use api\tests\_pages\SessionServerRoute;
use api\tests\functional\_steps\SessionServerSteps; use api\tests\functional\_steps\SessionServerSteps;
use api\tests\FunctionalTester; use api\tests\FunctionalTester;
use Faker\Provider\Uuid; use function Ramsey\Uuid\v4;
class ProfileCest { class ProfileCest {
@ -48,7 +48,7 @@ class ProfileCest {
public function getProfileWithNonexistentUuid(FunctionalTester $I) { public function getProfileWithNonexistentUuid(FunctionalTester $I) {
$I->wantTo('get info about nonexistent uuid'); $I->wantTo('get info about nonexistent uuid');
$this->route->profile(Uuid::uuid()); $this->route->profile(v4());
$I->canSeeResponseCodeIs(401); $I->canSeeResponseCodeIs(401);
$I->canSeeResponseIsJson(); $I->canSeeResponseIsJson();
$I->seeResponseIsJson(); $I->seeResponseIsJson();

View File

@ -5,26 +5,11 @@ namespace api\tests\_support\models\authentication;
use api\models\authentication\LoginForm; use api\models\authentication\LoginForm;
use api\tests\unit\TestCase; use api\tests\unit\TestCase;
use Codeception\Specify;
use common\models\Account; use common\models\Account;
use common\tests\fixtures\AccountFixture; use common\tests\fixtures\AccountFixture;
use OTPHP\TOTP; use OTPHP\TOTP;
class LoginFormTest extends TestCase { class LoginFormTest extends TestCase {
use Specify;
private $originalRemoteAddr;
protected function setUp(): void {
$this->originalRemoteAddr = $_SERVER['REMOTE_ADDR'] ?? null;
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
parent::setUp();
}
protected function tearDown(): void {
parent::tearDown();
$_SERVER['REMOTE_ADDR'] = $this->originalRemoteAddr;
}
public function _fixtures(): array { public function _fixtures(): array {
return [ return [
@ -33,43 +18,31 @@ class LoginFormTest extends TestCase {
} }
public function testValidateLogin() { public function testValidateLogin() {
$this->specify('error.login_not_exist if login not exists', function() { $model = $this->createWithAccount(null);
$model = $this->createModel([ $model->login = 'mock-login';
'login' => 'mr-test', $model->validateLogin('login');
'account' => null, $this->assertSame(['error.login_not_exist'], $model->getErrors('login'));
]);
$model->validateLogin('login');
$this->assertSame(['error.login_not_exist'], $model->getErrors('login'));
});
$this->specify('no errors if login exists', function() { $model = $this->createWithAccount(new Account());
$model = $this->createModel([ $model->login = 'mock-login';
'login' => 'mr-test', $model->validateLogin('login');
'account' => new Account(), $this->assertEmpty($model->getErrors('login'));
]);
$model->validateLogin('login');
$this->assertEmpty($model->getErrors('login'));
});
} }
public function testValidatePassword() { public function testValidatePassword() {
$this->specify('error.password_incorrect if password invalid', function() { $account = new Account();
$model = $this->createModel([ $account->password_hash = '$2y$04$N0q8DaHzlYILCnLYrpZfEeWKEqkPZzbawiS07GbSr/.xbRNweSLU6'; // 12345678
'password' => '87654321', $account->password_hash_strategy = Account::PASS_HASH_STRATEGY_YII2;
'account' => new Account(['password' => '12345678']),
]);
$model->validatePassword('password');
$this->assertSame(['error.password_incorrect'], $model->getErrors('password'));
});
$this->specify('no errors if password valid', function() { $model = $this->createWithAccount($account);
$model = $this->createModel([ $model->password = '87654321';
'password' => '12345678', $model->validatePassword('password');
'account' => new Account(['password' => '12345678']), $this->assertSame(['error.password_incorrect'], $model->getErrors('password'));
]);
$model->validatePassword('password'); $model = $this->createWithAccount($account);
$this->assertEmpty($model->getErrors('password')); $model->password = '12345678';
}); $model->validatePassword('password');
$this->assertEmpty($model->getErrors('password'));
} }
public function testValidateTotp() { public function testValidateTotp() {
@ -78,99 +51,72 @@ class LoginFormTest extends TestCase {
$account->is_otp_enabled = true; $account->is_otp_enabled = true;
$account->otp_secret = 'AAAA'; $account->otp_secret = 'AAAA';
$this->specify('error.totp_incorrect if totp invalid', function() use ($account) { $model = $this->createWithAccount($account);
$model = $this->createModel([ $model->password = '12345678';
'password' => '12345678', $model->totp = '321123';
'totp' => '321123', $model->validateTotp('totp');
'account' => $account, $this->assertSame(['error.totp_incorrect'], $model->getErrors('totp'));
]);
$model->validateTotp('totp');
$this->assertSame(['error.totp_incorrect'], $model->getErrors('totp'));
});
$totp = TOTP::create($account->otp_secret); $totp = TOTP::create($account->otp_secret);
$this->specify('no errors if password valid', function() use ($account, $totp) { $model = $this->createWithAccount($account);
$model = $this->createModel([ $model->password = '12345678';
'password' => '12345678', $model->totp = $totp->now();
'totp' => $totp->now(), $model->validateTotp('totp');
'account' => $account, $this->assertEmpty($model->getErrors('totp'));
]);
$model->validateTotp('totp');
$this->assertEmpty($model->getErrors('totp'));
});
} }
public function testValidateActivity() { public function testValidateActivity() {
$this->specify('error.account_not_activated if account in not activated state', function() { $account = new Account();
$model = $this->createModel([ $account->status = Account::STATUS_REGISTERED;
'account' => new Account(['status' => Account::STATUS_REGISTERED]), $model = $this->createWithAccount($account);
]); $model->validateActivity('login');
$model->validateActivity('login'); $this->assertSame(['error.account_not_activated'], $model->getErrors('login'));
$this->assertSame(['error.account_not_activated'], $model->getErrors('login'));
});
$this->specify('error.account_banned if account has banned status', function() { $account = new Account();
$model = $this->createModel([ $account->status = Account::STATUS_BANNED;
'account' => new Account(['status' => Account::STATUS_BANNED]), $model = $this->createWithAccount($account);
]); $model->validateActivity('login');
$model->validateActivity('login'); $this->assertSame(['error.account_banned'], $model->getErrors('login'));
$this->assertSame(['error.account_banned'], $model->getErrors('login'));
});
$this->specify('no errors if account active', function() { $account = new Account();
$model = $this->createModel([ $account->status = Account::STATUS_ACTIVE;
'account' => new Account(['status' => Account::STATUS_ACTIVE]), $model = $this->createWithAccount($account);
]); $model->validateActivity('login');
$model->validateActivity('login'); $this->assertEmpty($model->getErrors('login'));
$this->assertEmpty($model->getErrors('login'));
});
} }
public function testLogin() { public function testLogin() {
$model = $this->createModel([ $account = new Account();
'login' => 'erickskrauch', $account->id = 1;
'password' => '12345678', $account->username = 'erickskrauch';
'account' => new Account([ $account->password_hash = '$2y$04$N0q8DaHzlYILCnLYrpZfEeWKEqkPZzbawiS07GbSr/.xbRNweSLU6'; // 12345678
'id' => 1, $account->password_hash_strategy = Account::PASS_HASH_STRATEGY_YII2;
'username' => 'erickskrauch', $account->status = Account::STATUS_ACTIVE;
'password' => '12345678',
'status' => Account::STATUS_ACTIVE, $model = $this->createWithAccount($account);
]), $model->login = 'erickskrauch';
]); $model->password = '12345678';
$this->assertNotNull($model->login(), 'model should login user'); $this->assertNotNull($model->login(), 'model should login user');
$this->assertEmpty($model->getErrors(), 'error message should not be set');
} }
public function testLoginWithRehashing() { public function testLoginWithRehashing() {
$model = new LoginForm([ /** @var Account $account */
'login' => $this->tester->grabFixture('accounts', 'user-with-old-password-type')['username'], $account = $this->tester->grabFixture('accounts', 'user-with-old-password-type');
'password' => '12345678', $model = $this->createWithAccount($account);
]); $model->login = $account->username;
$model->password = '12345678';
$this->assertNotNull($model->login()); $this->assertNotNull($model->login());
$this->assertEmpty($model->getErrors()); $this->assertSame(Account::PASS_HASH_STRATEGY_YII2, $account->password_hash_strategy);
$this->assertSame( $this->assertNotSame('133c00c463cbd3e491c28cb653ce4718', $account->password_hash);
Account::PASS_HASH_STRATEGY_YII2,
$model->getAccount()->password_hash_strategy,
'user, that login using account with old pass hash strategy should update it automatically'
);
} }
/** private function createWithAccount(?Account $account): LoginForm {
* @param array $params $model = $this->createPartialMock(LoginForm::class, ['getAccount']);
* @return LoginForm $model->method('getAccount')->willReturn($account);
*/
private function createModel(array $params = []) {
return new class($params) extends LoginForm {
private $_account;
public function setAccount($value) { return $model;
$this->_account = $value;
}
public function getAccount(): ?Account {
return $this->_account;
}
};
} }
} }

View File

@ -6,54 +6,32 @@ namespace api\tests\_support\models\authentication;
use api\components\User\Component; use api\components\User\Component;
use api\models\authentication\LogoutForm; use api\models\authentication\LogoutForm;
use api\tests\unit\TestCase; use api\tests\unit\TestCase;
use Codeception\Specify;
use common\models\AccountSession; use common\models\AccountSession;
use Yii; use Yii;
class LogoutFormTest extends TestCase { class LogoutFormTest extends TestCase {
use Specify;
public function testValidateLogout() { public function testNoActionWhenThereIsNoActiveSession() {
$this->specify('No actions if active session is not exists', function() { $userComp = $this->createPartialMock(Component::class, ['getActiveSession']);
$userComp = $this $userComp->method('getActiveSession')->willReturn(null);
->getMockBuilder(Component::class)
->setMethods(['getActiveSession'])
->getMock();
$userComp
->expects($this->any())
->method('getActiveSession')
->will($this->returnValue(null));
Yii::$app->set('user', $userComp); Yii::$app->set('user', $userComp);
$model = new LogoutForm(); $model = new LogoutForm();
$this->assertTrue($model->logout()); $this->assertTrue($model->logout());
}); }
$this->specify('if active session is presented, then delete should be called', function() { public function testActiveSessionShouldBeDeleted() {
$session = $this $session = $this->createPartialMock(AccountSession::class, ['delete']);
->getMockBuilder(AccountSession::class) $session->expects($this->once())->method('delete')->willReturn(true);
->setMethods(['delete'])
->getMock();
$session
->expects($this->once())
->method('delete')
->willReturn(true);
$userComp = $this $userComp = $this->createPartialMock(Component::class, ['getActiveSession']);
->getMockBuilder(Component::class) $userComp->method('getActiveSession')->willReturn($session);
->setMethods(['getActiveSession'])
->getMock();
$userComp
->expects($this->any())
->method('getActiveSession')
->will($this->returnValue($session));
Yii::$app->set('user', $userComp); Yii::$app->set('user', $userComp);
$model = new LogoutForm(); $model = new LogoutForm();
$model->logout(); $model->logout();
});
} }
} }

View File

@ -6,9 +6,8 @@ namespace api\tests\_support\models\authentication;
use api\components\ReCaptcha\Validator as ReCaptchaValidator; use api\components\ReCaptcha\Validator as ReCaptchaValidator;
use api\models\authentication\RepeatAccountActivationForm; use api\models\authentication\RepeatAccountActivationForm;
use api\tests\unit\TestCase; use api\tests\unit\TestCase;
use Codeception\Specify; use common\models\Account;
use common\models\confirmations\RegistrationConfirmation; use common\models\confirmations\RegistrationConfirmation;
use common\models\EmailActivation;
use common\tasks\SendRegistrationEmail; use common\tasks\SendRegistrationEmail;
use common\tests\fixtures\AccountFixture; use common\tests\fixtures\AccountFixture;
use common\tests\fixtures\EmailActivationFixture; use common\tests\fixtures\EmailActivationFixture;
@ -16,7 +15,6 @@ use GuzzleHttp\ClientInterface;
use Yii; use Yii;
class RepeatAccountActivationFormTest extends TestCase { class RepeatAccountActivationFormTest extends TestCase {
use Specify;
protected function setUp(): void { protected function setUp(): void {
parent::setUp(); parent::setUp();
@ -35,41 +33,35 @@ class RepeatAccountActivationFormTest extends TestCase {
} }
public function testValidateEmailForAccount() { public function testValidateEmailForAccount() {
$this->specify('error.email_not_found if passed valid email, but it don\'t exists in database', function() { $model = $this->createWithAccount(null);
$model = new RepeatAccountActivationForm(['email' => 'me-is-not@exists.net']); $model->validateEmailForAccount('email');
$model->validateEmailForAccount('email'); $this->assertSame(['error.email_not_found'], $model->getErrors('email'));
$this->assertSame(['error.email_not_found'], $model->getErrors('email'));
});
$this->specify('error.account_already_activated if passed valid email, but account already activated', function() { $account = new Account();
$fixture = $this->tester->grabFixture('accounts', 'admin'); $account->status = Account::STATUS_ACTIVE;
$model = new RepeatAccountActivationForm(['email' => $fixture['email']]); $model = $this->createWithAccount($account);
$model->validateEmailForAccount('email'); $model->validateEmailForAccount('email');
$this->assertSame(['error.account_already_activated'], $model->getErrors('email')); $this->assertSame(['error.account_already_activated'], $model->getErrors('email'));
});
$this->specify('no errors if passed valid email for not activated account', function() { $account = new Account();
$fixture = $this->tester->grabFixture('accounts', 'not-activated-account'); $account->status = Account::STATUS_REGISTERED;
$model = new RepeatAccountActivationForm(['email' => $fixture['email']]); $model = $this->createWithAccount($account);
$model->validateEmailForAccount('email'); $model->validateEmailForAccount('email');
$this->assertEmpty($model->getErrors('email')); $this->assertEmpty($model->getErrors('email'));
});
} }
public function testValidateExistsActivation() { public function testValidateExistsActivation() {
$this->specify('error.recently_sent_message if passed email has recently sent message', function() { $activation = new RegistrationConfirmation();
$fixture = $this->tester->grabFixture('activations', 'freshRegistrationConfirmation'); $activation->created_at = time() - 10;
$model = $this->createModel(['emailKey' => $fixture['key']]); $model = $this->createWithActivation($activation);
$model->validateExistsActivation('email'); $model->validateExistsActivation('email');
$this->assertSame(['error.recently_sent_message'], $model->getErrors('email')); $this->assertSame(['error.recently_sent_message'], $model->getErrors('email'));
});
$this->specify('no errors if passed email has expired activation message', function() { $activation = new RegistrationConfirmation();
$fixture = $this->tester->grabFixture('activations', 'oldRegistrationConfirmation'); $activation->created_at = time() - 60 * 60 * 24;
$model = $this->createModel(['emailKey' => $fixture['key']]); $model = $this->createWithActivation($activation);
$model->validateExistsActivation('email'); $model->validateExistsActivation('email');
$this->assertEmpty($model->getErrors('email')); $this->assertEmpty($model->getErrors('email'));
});
} }
public function testSendRepeatMessage() { public function testSendRepeatMessage() {
@ -93,18 +85,18 @@ class RepeatAccountActivationFormTest extends TestCase {
$this->assertSame('http://localhost/activation/' . $activation->key, $job->link); $this->assertSame('http://localhost/activation/' . $activation->key, $job->link);
} }
/** private function createWithAccount(?Account $account): RepeatAccountActivationForm {
* @param array $params $model = $this->createPartialMock(RepeatAccountActivationForm::class, ['getAccount']);
* @return RepeatAccountActivationForm $model->method('getAccount')->willReturn($account);
*/
private function createModel(array $params = []) {
return new class($params) extends RepeatAccountActivationForm {
public $emailKey;
public function getActivation(): ?RegistrationConfirmation { return $model;
return EmailActivation::findOne($this->emailKey); }
}
}; private function createWithActivation(?RegistrationConfirmation $activation): RepeatAccountActivationForm {
$model = $this->createPartialMock(RepeatAccountActivationForm::class, ['getActivation']);
$model->method('getActivation')->willReturn($activation);
return $model;
} }
} }

View File

@ -6,7 +6,6 @@ namespace api\tests\unit\modules\session\filters;
use api\modules\session\filters\RateLimiter; use api\modules\session\filters\RateLimiter;
use api\tests\unit\TestCase; use api\tests\unit\TestCase;
use common\models\OauthClient; use common\models\OauthClient;
use Faker\Provider\Internet;
use Yii; use Yii;
use yii\redis\Connection; use yii\redis\Connection;
use yii\web\Request; use yii\web\Request;
@ -84,7 +83,7 @@ class RateLimiterTest extends TestCase {
->getMock(); ->getMock();
$request->method('getUserIp') $request->method('getUserIp')
->willReturn(Internet::localIpv4()); ->willReturn('10.1.1.17');
/** @var RateLimiter|\PHPUnit\Framework\MockObject\MockObject $filter */ /** @var RateLimiter|\PHPUnit\Framework\MockObject\MockObject $filter */
$filter = $this->getMockBuilder(RateLimiter::class) $filter = $this->getMockBuilder(RateLimiter::class)

View File

@ -1,20 +0,0 @@
<?php
/**
* @var $faker \Faker\Generator
* @var $index integer
*/
$security = Yii::$app->getSecurity();
return [
'uuid' => $faker->uuid,
'username' => $faker->userName,
'email' => $faker->email,
'password_hash' => $security->generatePasswordHash('password_' . $index),
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'auth_key' => $security->generateRandomString(),
'status' => \common\models\Account::STATUS_ACTIVE,
'created_at' => time(),
'updated_at' => time(),
];

View File

@ -1,70 +1,46 @@
<?php <?php
declare(strict_types=1);
namespace common\tests\unit\behaviors; namespace common\tests\unit\behaviors;
use Codeception\Specify;
use common\behaviors\PrimaryKeyValueBehavior; use common\behaviors\PrimaryKeyValueBehavior;
use common\tests\unit\TestCase; use common\tests\unit\TestCase;
use yii\db\ActiveRecord; use yii\db\ActiveRecord;
class PrimaryKeyValueBehaviorTest extends TestCase { class PrimaryKeyValueBehaviorTest extends TestCase {
use Specify;
public function testRefreshPrimaryKeyValue() { public function testGenerateValueForThePrimaryKey() {
$this->specify('method should generate value for primary key field on call', function() { $model = $this->createDummyModel();
$model = new DummyModel(); $behavior = $this->createPartialMock(PrimaryKeyValueBehavior::class, ['isValueExists']);
/** @var PrimaryKeyValueBehavior|\PHPUnit\Framework\MockObject\MockObject $behavior */ $behavior->method('isValueExists')->willReturn(false);
$behavior = $this->getMockBuilder(PrimaryKeyValueBehavior::class) $behavior->value = function() {
->setMethods(['isValueExists']) return 'mock';
->setConstructorArgs([[ };
'value' => function() {
return 'mock';
},
]])
->getMock();
$behavior->expects($this->once()) $model->attachBehavior('primary-key-value-behavior', $behavior);
->method('isValueExists') $behavior->setPrimaryKeyValue();
->will($this->returnValue(false)); $this->assertSame('mock', $model->id);
}
$model->attachBehavior('primary-key-value-behavior', $behavior); public function testShouldRegenerateValueWhenGeneratedAlreadyExists() {
$behavior->setPrimaryKeyValue(); $model = $this->createDummyModel();
$this->assertSame('mock', $model->id); $behavior = $this->createPartialMock(PrimaryKeyValueBehavior::class, ['isValueExists', 'generateValue']);
}); $behavior->expects($this->exactly(3))->method('generateValue')->willReturnOnConsecutiveCalls('1', '2', '3');
$behavior->expects($this->exactly(3))->method('isValueExists')->willReturnOnConsecutiveCalls(true, true, false);
$this->specify('method should repeat value generation if generated value duplicate with exists', function() { $model->attachBehavior('primary-key-value-behavior', $behavior);
$model = new DummyModel(); $behavior->setPrimaryKeyValue();
/** @var PrimaryKeyValueBehavior|\PHPUnit\Framework\MockObject\MockObject $behavior */ $this->assertSame('3', $model->id);
$behavior = $this->getMockBuilder(PrimaryKeyValueBehavior::class) }
->setMethods(['isValueExists', 'generateValue'])
->setConstructorArgs([[
'value' => function() {
return 'this was mocked, but let be passed';
},
]])
->getMock();
$behavior->expects($this->exactly(3)) private function createDummyModel() {
->method('generateValue') return new class extends ActiveRecord {
->will($this->onConsecutiveCalls('1', '2', '3')); public $id;
$behavior->expects($this->exactly(3)) public static function primaryKey() {
->method('isValueExists') return ['id'];
->will($this->onConsecutiveCalls(true, true, false)); }
};
$model->attachBehavior('primary-key-value-behavior', $behavior);
$behavior->setPrimaryKeyValue();
$this->assertSame('3', $model->id);
});
}
}
class DummyModel extends ActiveRecord {
public $id;
public static function primaryKey() {
return ['id'];
} }
} }

View File

@ -3,20 +3,16 @@ declare(strict_types=1);
namespace common\tests\unit\models; namespace common\tests\unit\models;
use Codeception\Specify;
use common\components\UserPass;
use common\models\Account; use common\models\Account;
use common\tasks\CreateWebHooksDeliveries; use common\tasks\CreateWebHooksDeliveries;
use common\tests\fixtures\MojangUsernameFixture; use common\tests\fixtures\MojangUsernameFixture;
use common\tests\unit\TestCase; use common\tests\unit\TestCase;
use Yii;
use const common\LATEST_RULES_VERSION; use const common\LATEST_RULES_VERSION;
/** /**
* @covers \common\models\Account * @covers \common\models\Account
*/ */
class AccountTest extends TestCase { class AccountTest extends TestCase {
use Specify;
public function testSetPassword() { public function testSetPassword() {
$model = new Account(); $model = new Account();
@ -27,57 +23,47 @@ class AccountTest extends TestCase {
} }
public function testValidatePassword() { public function testValidatePassword() {
$this->specify('old Ely password should work', function() { // Use old hashing algorithm
$model = new Account([ $model = new Account();
'email' => 'erick@skrauch.net', $model->email = 'erick@skrauch.net';
'password_hash' => UserPass::make('erick@skrauch.net', '12345678'), $model->password_hash = '2cfdb29eb354af970865a923335d17d9'; // 12345678
]); $model->password_hash_strategy = null; // To be sure it's not set
$this->assertTrue($model->validatePassword('12345678', Account::PASS_HASH_STRATEGY_OLD_ELY), 'valid password should pass'); $this->assertTrue($model->validatePassword('12345678', Account::PASS_HASH_STRATEGY_OLD_ELY), 'valid password should pass');
$this->assertFalse($model->validatePassword('87654321', Account::PASS_HASH_STRATEGY_OLD_ELY), 'invalid password should fail'); $this->assertFalse($model->validatePassword('87654321', Account::PASS_HASH_STRATEGY_OLD_ELY), 'invalid password should fail');
});
$this->specify('modern hash algorithm should work', function() { // Modern hash algorithm should also work
$model = new Account([ $model = new Account();
'password_hash' => Yii::$app->security->generatePasswordHash('12345678'), $model->password_hash = '$2y$04$N0q8DaHzlYILCnLYrpZfEeWKEqkPZzbawiS07GbSr/.xbRNweSLU6'; // 12345678
]); $model->password_hash_strategy = null; // To be sure it's not set
$this->assertTrue($model->validatePassword('12345678', Account::PASS_HASH_STRATEGY_YII2), 'valid password should pass'); $this->assertTrue($model->validatePassword('12345678', Account::PASS_HASH_STRATEGY_YII2), 'valid password should pass');
$this->assertFalse($model->validatePassword('87654321', Account::PASS_HASH_STRATEGY_YII2), 'invalid password should fail'); $this->assertFalse($model->validatePassword('87654321', Account::PASS_HASH_STRATEGY_YII2), 'invalid password should fail');
});
$this->specify('if second argument is not pass model value should be used', function() { // If the second arg isn't passed model's value should be used
$model = new Account([ $model = new Account();
'email' => 'erick@skrauch.net', $model->email = 'erick@skrauch.net';
'password_hash_strategy' => Account::PASS_HASH_STRATEGY_OLD_ELY, $model->password_hash = '2cfdb29eb354af970865a923335d17d9'; // 12345678
'password_hash' => UserPass::make('erick@skrauch.net', '12345678'), $model->password_hash_strategy = Account::PASS_HASH_STRATEGY_OLD_ELY;
]); $this->assertTrue($model->validatePassword('12345678'), 'valid password should pass');
$this->assertTrue($model->validatePassword('12345678'), 'valid password should pass'); $this->assertFalse($model->validatePassword('87654321'), 'invalid password should fail');
$this->assertFalse($model->validatePassword('87654321'), 'invalid password should fail');
$model = new Account([ // The same case for modern algorithm
'password_hash_strategy' => Account::PASS_HASH_STRATEGY_YII2, $model = new Account();
'password_hash' => Yii::$app->security->generatePasswordHash('12345678'), $model->password_hash = '$2y$04$N0q8DaHzlYILCnLYrpZfEeWKEqkPZzbawiS07GbSr/.xbRNweSLU6'; // 12345678
]); $model->password_hash_strategy = Account::PASS_HASH_STRATEGY_YII2;
$this->assertTrue($model->validatePassword('12345678'), 'valid password should pass'); $this->assertTrue($model->validatePassword('12345678'), 'valid password should pass');
$this->assertFalse($model->validatePassword('87654321'), 'invalid password should fail'); $this->assertFalse($model->validatePassword('87654321'), 'invalid password should fail');
});
} }
public function testHasMojangUsernameCollision() { public function testHasMojangUsernameCollision() {
$model = new Account();
$model->username = 'ErickSkrauch';
$this->assertFalse($model->hasMojangUsernameCollision());
$this->tester->haveFixtures([ $this->tester->haveFixtures([
'mojangUsernames' => MojangUsernameFixture::class, 'mojangUsernames' => MojangUsernameFixture::class,
]); ]);
$this->specify('Expect true if collision with current username', function() { $this->assertTrue($model->hasMojangUsernameCollision());
$model = new Account();
$model->username = 'ErickSkrauch';
$this->assertTrue($model->hasMojangUsernameCollision());
});
$this->specify('Expect false if some rare username without any collision on Mojang', function() {
$model = new Account();
$model->username = 'rare-username';
$this->assertFalse($model->hasMojangUsernameCollision());
});
} }
public function testGetProfileLink() { public function testGetProfileLink() {
@ -87,22 +73,14 @@ class AccountTest extends TestCase {
} }
public function testIsAgreedWithActualRules() { public function testIsAgreedWithActualRules() {
$this->specify('get false, if rules field set in null', function() { $model = new Account();
$model = new Account(); $this->assertFalse($model->isAgreedWithActualRules(), 'field is null');
$this->assertFalse($model->isAgreedWithActualRules());
});
$this->specify('get false, if rules field have version less, then actual', function() { $model->rules_agreement_version = 0;
$model = new Account(); $this->assertFalse($model->isAgreedWithActualRules(), 'actual version is greater than zero');
$model->rules_agreement_version = 0;
$this->assertFalse($model->isAgreedWithActualRules());
});
$this->specify('get true, if rules field have equals rules version', function() { $model->rules_agreement_version = LATEST_RULES_VERSION;
$model = new Account(); $this->assertTrue($model->isAgreedWithActualRules());
$model->rules_agreement_version = LATEST_RULES_VERSION;
$this->assertTrue($model->isAgreedWithActualRules());
});
} }
public function testSetRegistrationIp() { public function testSetRegistrationIp() {

View File

@ -1,77 +0,0 @@
<?php
namespace common\tests\unit\validators;
use Codeception\Specify;
use common\tests\unit\TestCase;
use common\validators\UuidValidator;
use Faker\Provider\Uuid;
use yii\base\Model;
class UuidValidatorTest extends TestCase {
use Specify;
public function testValidateAttribute() {
$this->specify('expected error if passed empty value', function() {
$validator = new UuidValidator();
$model = $this->createModel();
$validator->validateAttribute($model, 'attribute');
$this->assertTrue($model->hasErrors());
$this->assertSame(['Attribute must be valid uuid'], $model->getErrors('attribute'));
});
$this->specify('expected error if passed invalid string', function() {
$validator = new UuidValidator();
$model = $this->createModel();
$model->attribute = '123456789';
$validator->validateAttribute($model, 'attribute');
$this->assertTrue($model->hasErrors());
$this->assertSame(['Attribute must be valid uuid'], $model->getErrors('attribute'));
});
$this->specify('no errors if passed nil uuid and allowNil is set to true', function() {
$validator = new UuidValidator();
$model = $this->createModel();
$model->attribute = '00000000-0000-0000-0000-000000000000';
$validator->validateAttribute($model, 'attribute');
$this->assertFalse($model->hasErrors());
});
$this->specify('no errors if passed nil uuid and allowNil is set to false', function() {
$validator = new UuidValidator();
$validator->allowNil = false;
$model = $this->createModel();
$model->attribute = '00000000-0000-0000-0000-000000000000';
$validator->validateAttribute($model, 'attribute');
$this->assertTrue($model->hasErrors());
$this->assertSame(['Attribute must be valid uuid'], $model->getErrors('attribute'));
});
$this->specify('no errors if passed valid uuid', function() {
$validator = new UuidValidator();
$model = $this->createModel();
$model->attribute = Uuid::uuid();
$validator->validateAttribute($model, 'attribute');
$this->assertFalse($model->hasErrors());
});
$this->specify('no errors if passed uuid string without dashes and converted to standart value', function() {
$validator = new UuidValidator();
$model = $this->createModel();
$originalUuid = Uuid::uuid();
$model->attribute = str_replace('-', '', $originalUuid);
$validator->validateAttribute($model, 'attribute');
$this->assertFalse($model->hasErrors());
$this->assertSame($originalUuid, $model->attribute);
});
}
/**
* @return Model
*/
public function createModel() {
return new class extends Model {
public $attribute;
};
}
}

View File

@ -1,29 +0,0 @@
<?php
namespace common\validators;
use InvalidArgumentException;
use Ramsey\Uuid\Uuid;
use yii\validators\Validator;
class UuidValidator extends Validator {
public $allowNil = true;
public $skipOnEmpty = false;
public $message = '{attribute} must be valid uuid';
public function validateAttribute($model, $attribute) {
try {
$uuid = Uuid::fromString($model->$attribute)->toString();
$model->$attribute = $uuid;
} catch (InvalidArgumentException $e) {
$this->addError($model, $attribute, $this->message, []);
}
if (isset($uuid) && $this->allowNil === false && $uuid === Uuid::NIL) {
$this->addError($model, $attribute, $this->message, []);
}
}
}

View File

@ -41,13 +41,10 @@
"codeception/module-asserts": "^1.1.0", "codeception/module-asserts": "^1.1.0",
"codeception/module-rest": "^1.0.0", "codeception/module-rest": "^1.0.0",
"codeception/module-yii2": "^1.0.0", "codeception/module-yii2": "^1.0.0",
"codeception/specify": "^1.0.0",
"cweagans/composer-patches": "^1.6", "cweagans/composer-patches": "^1.6",
"ely/php-code-style": "^0.3.0", "ely/php-code-style": "^0.3.0",
"flow/jsonpath": "^0.4.0", "flow/jsonpath": "^0.4.0",
"fzaninotto/faker": "^1.8",
"php-mock/php-mock-phpunit": "^2.5", "php-mock/php-mock-phpunit": "^2.5",
"predis/predis": "^1.1",
"roave/security-advisories": "dev-master" "roave/security-advisories": "dev-master"
}, },
"replace": { "replace": {

140
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "aece49d205676d4b8150cf622fc5aed8", "content-hash": "0f0f24789cae6267d69fd317a338d634",
"packages": [ "packages": [
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@ -3343,44 +3343,6 @@
"description": "PHPUnit classes used by Codeception", "description": "PHPUnit classes used by Codeception",
"time": "2019-11-24T15:30:35+00:00" "time": "2019-11-24T15:30:35+00:00"
}, },
{
"name": "codeception/specify",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Specify.git",
"reference": "e3fefa22f2304170024b9242b2bd8b01cf5a2ac0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/Specify/zipball/e3fefa22f2304170024b9242b2bd8b01cf5a2ac0",
"reference": "e3fefa22f2304170024b9242b2bd8b01cf5a2ac0",
"shasum": ""
},
"require": {
"myclabs/deep-copy": "~1.1",
"php": ">=7.1.0",
"phpunit/phpunit": ">=7.0 <9.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Codeception\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Bodnarchuk",
"email": "davert@codeception.com"
}
],
"description": "BDD code blocks for PHPUnit and Codeception",
"time": "2019-08-01T20:09:26+00:00"
},
{ {
"name": "codeception/stub", "name": "codeception/stub",
"version": "3.6.0", "version": "3.6.0",
@ -3795,56 +3757,6 @@
"description": "A tool to automatically fix PHP code style", "description": "A tool to automatically fix PHP code style",
"time": "2019-02-17T17:44:13+00:00" "time": "2019-02-17T17:44:13+00:00"
}, },
{
"name": "fzaninotto/faker",
"version": "v1.9.1",
"source": {
"type": "git",
"url": "https://github.com/fzaninotto/Faker.git",
"reference": "fc10d778e4b84d5bd315dad194661e091d307c6f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fzaninotto/Faker/zipball/fc10d778e4b84d5bd315dad194661e091d307c6f",
"reference": "fc10d778e4b84d5bd315dad194661e091d307c6f",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0"
},
"require-dev": {
"ext-intl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7",
"squizlabs/php_codesniffer": "^2.9.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"autoload": {
"psr-4": {
"Faker\\": "src/Faker/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "François Zaninotto"
}
],
"description": "Faker is a PHP library that generates fake data for you.",
"keywords": [
"data",
"faker",
"fixtures"
],
"time": "2019-12-12T13:22:17+00:00"
},
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
"version": "1.9.4", "version": "1.9.4",
@ -4762,56 +4674,6 @@
], ],
"time": "2019-12-06T05:41:38+00:00" "time": "2019-12-06T05:41:38+00:00"
}, },
{
"name": "predis/predis",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/nrk/predis.git",
"reference": "f0210e38881631afeafb56ab43405a92cafd9fd1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nrk/predis/zipball/f0210e38881631afeafb56ab43405a92cafd9fd1",
"reference": "f0210e38881631afeafb56ab43405a92cafd9fd1",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"phpunit/phpunit": "~4.8"
},
"suggest": {
"ext-curl": "Allows access to Webdis when paired with phpiredis",
"ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol"
},
"type": "library",
"autoload": {
"psr-4": {
"Predis\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Daniele Alessandri",
"email": "suppakilla@gmail.com",
"homepage": "http://clorophilla.net"
}
],
"description": "Flexible and feature-complete Redis client for PHP and HHVM",
"homepage": "http://github.com/nrk/predis",
"keywords": [
"nosql",
"predis",
"redis"
],
"time": "2016-06-16T16:22:20+00:00"
},
{ {
"name": "psr/container", "name": "psr/container",
"version": "1.0.0", "version": "1.0.0",