From 445623e25619a20a59633eea032c1b5d7c07b17a Mon Sep 17 00:00:00 2001 From: Marcos Antonio Barreche Salguero Date: Fri, 9 Dec 2022 01:48:56 +0100 Subject: [PATCH 1/3] feat: add endpoint to create a user --- apps/mooc/backend/config/routes/users.yaml | 4 ++ .../Controller/Users/UsersPutController.php | 26 ++++++++++ src/Mooc/Users/Application/UserCreator.php | 23 +++++++++ src/Mooc/Users/Domain/User.php | 49 +++++++++++++++++++ src/Mooc/Users/Domain/UserRepository.php | 8 +++ .../Infraestructure/FileUserRepository.php | 26 ++++++++++ .../backend/features/users/users_put.feature | 16 ++++++ tests/apps/mooc/backend/mooc_backend.yml | 6 +++ .../Users/Application/UserCreatorTest.php | 29 +++++++++++ .../Infrastructure/FileUserRepositoryTest.php | 24 +++++++++ 10 files changed, 211 insertions(+) create mode 100644 apps/mooc/backend/config/routes/users.yaml create mode 100644 apps/mooc/backend/src/Controller/Users/UsersPutController.php create mode 100644 src/Mooc/Users/Application/UserCreator.php create mode 100644 src/Mooc/Users/Domain/User.php create mode 100644 src/Mooc/Users/Domain/UserRepository.php create mode 100644 src/Mooc/Users/Infraestructure/FileUserRepository.php create mode 100644 tests/apps/mooc/backend/features/users/users_put.feature create mode 100644 tests/src/Mooc/Users/Application/UserCreatorTest.php create mode 100644 tests/src/Mooc/Users/Infrastructure/FileUserRepositoryTest.php diff --git a/apps/mooc/backend/config/routes/users.yaml b/apps/mooc/backend/config/routes/users.yaml new file mode 100644 index 0000000..61c3741 --- /dev/null +++ b/apps/mooc/backend/config/routes/users.yaml @@ -0,0 +1,4 @@ +users_put: + path: /users/{id} + controller: CodelyTv\Apps\Mooc\Backend\Controller\Users\UsersPutController + methods: [PUT] \ No newline at end of file diff --git a/apps/mooc/backend/src/Controller/Users/UsersPutController.php b/apps/mooc/backend/src/Controller/Users/UsersPutController.php new file mode 100644 index 0000000..4795309 --- /dev/null +++ b/apps/mooc/backend/src/Controller/Users/UsersPutController.php @@ -0,0 +1,26 @@ +creator = $userCreator; + } + + public function __invoke(string $id, Request $request) + { + $name = $request->request->get('name'); + $email = $request->request->get('email'); + $password = $request->request->get('password'); + $this->creator->__invoke($id, $name, $email, $password); + return new Response('', Response::HTTP_CREATED); + } +} \ No newline at end of file diff --git a/src/Mooc/Users/Application/UserCreator.php b/src/Mooc/Users/Application/UserCreator.php new file mode 100644 index 0000000..4fa2187 --- /dev/null +++ b/src/Mooc/Users/Application/UserCreator.php @@ -0,0 +1,23 @@ +repository = $repository; + } + + public function __invoke($id, string $name, string $email, string $password) + { + $user = new User($id, $name, $email, $password); + + $this->repository->saveUser($user); + } +} \ No newline at end of file diff --git a/src/Mooc/Users/Domain/User.php b/src/Mooc/Users/Domain/User.php new file mode 100644 index 0000000..7b557f5 --- /dev/null +++ b/src/Mooc/Users/Domain/User.php @@ -0,0 +1,49 @@ +id = $id; + $this->name = $name; + $this->email = $email; + $this->password = $password; + } + + public function id(): string + { + return $this->id; + } + + public function email(): string + { + return $this->email; + } + + public function name(): string + { + return $this->name; + } + + public function password(): string + { + return $this->password; + } + + public function toString(): string + { + return json_encode([ + 'id' => $this->id(), + 'name' => $this->name(), + 'email' => $this->email(), + 'password' => password_hash($this->password(), PASSWORD_DEFAULT) + ]); + } +} \ No newline at end of file diff --git a/src/Mooc/Users/Domain/UserRepository.php b/src/Mooc/Users/Domain/UserRepository.php new file mode 100644 index 0000000..dba52d5 --- /dev/null +++ b/src/Mooc/Users/Domain/UserRepository.php @@ -0,0 +1,8 @@ +directory = __DIR__ . '/users'; + } + + public function saveUser(User $user): void + { + file_put_contents($this->fileName($user->id()), $user->toString()); + } + + private function fileName(string $id): string + { + return "{$this->directory}.{$id}"; + } +} \ No newline at end of file diff --git a/tests/apps/mooc/backend/features/users/users_put.feature b/tests/apps/mooc/backend/features/users/users_put.feature new file mode 100644 index 0000000..72f5ea7 --- /dev/null +++ b/tests/apps/mooc/backend/features/users/users_put.feature @@ -0,0 +1,16 @@ +Feature: Create a new user + In order to have users on the platform + As a user with admin permissions + I want to create a new user + + Scenario: A valid non existing user + Given I send a PUT request to "/users/1aab45ba-3c7a-4344-8936-78466eca77fa" with body: + """ + { + "name": "John Smith", + "email": "john-smith@gamil.com", + "password": "**password**" + } + """ + Then the response status code should be 201 + And the response should be empty diff --git a/tests/apps/mooc/backend/mooc_backend.yml b/tests/apps/mooc/backend/mooc_backend.yml index 44a5a45..e736865 100644 --- a/tests/apps/mooc/backend/mooc_backend.yml +++ b/tests/apps/mooc/backend/mooc_backend.yml @@ -22,3 +22,9 @@ mooc_backend: contexts: - CodelyTv\Tests\Shared\Infrastructure\Behat\ApiRequestContext - CodelyTv\Tests\Shared\Infrastructure\Behat\ApiResponseContext + + users: + paths: [ tests/apps/mooc/backend/features/users ] + contexts: + - CodelyTv\Tests\Shared\Infrastructure\Behat\ApiRequestContext + - CodelyTv\Tests\Shared\Infrastructure\Behat\ApiResponseContext \ No newline at end of file diff --git a/tests/src/Mooc/Users/Application/UserCreatorTest.php b/tests/src/Mooc/Users/Application/UserCreatorTest.php new file mode 100644 index 0000000..0df2c89 --- /dev/null +++ b/tests/src/Mooc/Users/Application/UserCreatorTest.php @@ -0,0 +1,29 @@ +createMock(UserRepository::class); + $repository->method('saveUser')->with($course); + + // when + $creator = new UserCreator($repository); + $creator->__invoke($id, $name, $email, $password); + } +} diff --git a/tests/src/Mooc/Users/Infrastructure/FileUserRepositoryTest.php b/tests/src/Mooc/Users/Infrastructure/FileUserRepositoryTest.php new file mode 100644 index 0000000..761ba42 --- /dev/null +++ b/tests/src/Mooc/Users/Infrastructure/FileUserRepositoryTest.php @@ -0,0 +1,24 @@ +saveUser($user); + } + + public function tearDown(): void + { + parent::tearDown(); // TODO: Change the autogenerated stub + unlink('/app/src/Mooc/Users/Infraestructure/users.id'); + } +} From 915eaa169924d92f775ea4f53fa4a4bf30f78341 Mon Sep 17 00:00:00 2001 From: Marcos Antonio Barreche Salguero Date: Fri, 9 Dec 2022 03:31:48 +0100 Subject: [PATCH 2/3] feat: create valueobjects --- .../Controller/Users/UsersPutController.php | 12 ++++-- .../Users/Application/CreateUserRequest.php | 39 +++++++++++++++++++ src/Mooc/Users/Application/UserCreator.php | 14 +++++-- src/Mooc/Users/Domain/User.php | 18 ++++----- src/Mooc/Users/Domain/UserEmail.php | 10 +++++ src/Mooc/Users/Domain/UserId.php | 10 +++++ src/Mooc/Users/Domain/UserName.php | 10 +++++ src/Mooc/Users/Domain/UserPassword.php | 10 +++++ .../Infraestructure/FileUserRepository.php | 2 +- .../Application/CreateUserRequestMother.php | 27 +++++++++++++ .../Users/Application/UserCreatorTest.php | 13 ++----- .../Users/Application/UserEmailMother.php | 19 +++++++++ .../Mooc/Users/Application/UserIdMother.php | 18 +++++++++ .../src/Mooc/Users/Application/UserMother.php | 38 ++++++++++++++++++ .../Mooc/Users/Application/UserNameMother.php | 19 +++++++++ .../Users/Application/UserPasswordMother.php | 19 +++++++++ .../Infrastructure/FileUserRepositoryTest.php | 10 +++-- 17 files changed, 259 insertions(+), 29 deletions(-) create mode 100644 src/Mooc/Users/Application/CreateUserRequest.php create mode 100644 src/Mooc/Users/Domain/UserEmail.php create mode 100644 src/Mooc/Users/Domain/UserId.php create mode 100644 src/Mooc/Users/Domain/UserName.php create mode 100644 src/Mooc/Users/Domain/UserPassword.php create mode 100644 tests/src/Mooc/Users/Application/CreateUserRequestMother.php create mode 100644 tests/src/Mooc/Users/Application/UserEmailMother.php create mode 100644 tests/src/Mooc/Users/Application/UserIdMother.php create mode 100644 tests/src/Mooc/Users/Application/UserMother.php create mode 100644 tests/src/Mooc/Users/Application/UserNameMother.php create mode 100644 tests/src/Mooc/Users/Application/UserPasswordMother.php diff --git a/apps/mooc/backend/src/Controller/Users/UsersPutController.php b/apps/mooc/backend/src/Controller/Users/UsersPutController.php index 4795309..0d94fd3 100644 --- a/apps/mooc/backend/src/Controller/Users/UsersPutController.php +++ b/apps/mooc/backend/src/Controller/Users/UsersPutController.php @@ -2,6 +2,7 @@ namespace CodelyTv\Apps\Mooc\Backend\Controller\Users; +use CodelyTv\Mooc\Users\Application\CreateUserRequest; use CodelyTv\Mooc\Users\Application\UserCreator; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -17,10 +18,13 @@ public function __construct(UserCreator $userCreator) public function __invoke(string $id, Request $request) { - $name = $request->request->get('name'); - $email = $request->request->get('email'); - $password = $request->request->get('password'); - $this->creator->__invoke($id, $name, $email, $password); + $request = new CreateUserRequest( + $id, + $request->request->get('name'), + $request->request->get('email'), + $request->request->get('password') + ); + $this->creator->__invoke($request); return new Response('', Response::HTTP_CREATED); } } \ No newline at end of file diff --git a/src/Mooc/Users/Application/CreateUserRequest.php b/src/Mooc/Users/Application/CreateUserRequest.php new file mode 100644 index 0000000..f6eeb77 --- /dev/null +++ b/src/Mooc/Users/Application/CreateUserRequest.php @@ -0,0 +1,39 @@ +id = $id; + $this->name = $name; + $this->email = $email; + $this->password = $password; + } + + public function id(): string + { + return $this->id; + } + + public function name(): string + { + return $this->name; + } + + public function email(): string + { + return $this->email; + } + + public function password(): string + { + return $this->password; + } +} \ No newline at end of file diff --git a/src/Mooc/Users/Application/UserCreator.php b/src/Mooc/Users/Application/UserCreator.php index 4fa2187..8cd7102 100644 --- a/src/Mooc/Users/Application/UserCreator.php +++ b/src/Mooc/Users/Application/UserCreator.php @@ -3,6 +3,10 @@ namespace CodelyTv\Mooc\Users\Application; use CodelyTv\Mooc\Users\Domain\User; +use CodelyTv\Mooc\Users\Domain\UserEmail; +use CodelyTv\Mooc\Users\Domain\UserId; +use CodelyTv\Mooc\Users\Domain\UserName; +use CodelyTv\Mooc\Users\Domain\UserPassword; use CodelyTv\Mooc\Users\Domain\UserRepository; class UserCreator @@ -14,10 +18,14 @@ public function __construct(UserRepository $repository) $this->repository = $repository; } - public function __invoke($id, string $name, string $email, string $password) + public function __invoke(CreateUserRequest $request) { - $user = new User($id, $name, $email, $password); - + $user = new User( + new UserId($request->id()), + new UserName($request->name()), + new UserEmail($request->email()), + new UserPassword($request->password()) + ); $this->repository->saveUser($user); } } \ No newline at end of file diff --git a/src/Mooc/Users/Domain/User.php b/src/Mooc/Users/Domain/User.php index 7b557f5..1f79f3d 100644 --- a/src/Mooc/Users/Domain/User.php +++ b/src/Mooc/Users/Domain/User.php @@ -9,7 +9,7 @@ class User private $email; private $password; - public function __construct(string $id, string $name, string $email, string $password) + public function __construct(UserId $id, UserName $name, UserEmail $email, UserPassword $password) { $this->id = $id; $this->name = $name; @@ -17,22 +17,22 @@ public function __construct(string $id, string $name, string $email, string $pas $this->password = $password; } - public function id(): string + public function id(): UserId { return $this->id; } - public function email(): string + public function email(): UserEmail { return $this->email; } - public function name(): string + public function name(): UserName { return $this->name; } - public function password(): string + public function password(): UserPassword { return $this->password; } @@ -40,10 +40,10 @@ public function password(): string public function toString(): string { return json_encode([ - 'id' => $this->id(), - 'name' => $this->name(), - 'email' => $this->email(), - 'password' => password_hash($this->password(), PASSWORD_DEFAULT) + 'id' => $this->id()->value(), + 'name' => $this->name()->value(), + 'email' => $this->email()->value(), + 'password' => password_hash($this->password()->value(), PASSWORD_DEFAULT) ]); } } \ No newline at end of file diff --git a/src/Mooc/Users/Domain/UserEmail.php b/src/Mooc/Users/Domain/UserEmail.php new file mode 100644 index 0000000..6d79de0 --- /dev/null +++ b/src/Mooc/Users/Domain/UserEmail.php @@ -0,0 +1,10 @@ +fileName($user->id()), $user->toString()); + file_put_contents($this->fileName($user->id()->value()), $user->toString()); } private function fileName(string $id): string diff --git a/tests/src/Mooc/Users/Application/CreateUserRequestMother.php b/tests/src/Mooc/Users/Application/CreateUserRequestMother.php new file mode 100644 index 0000000..34ea5ce --- /dev/null +++ b/tests/src/Mooc/Users/Application/CreateUserRequestMother.php @@ -0,0 +1,27 @@ +value(), $name->value(), $email->value(), $password->value()); + } + + public static function random(): CreateUserRequest + { + return self::create( + UserIdMother::random(), + UserNameMother::random(), + UserEmailMother::random(), + UserPasswordMother::random() + ); + } +} \ No newline at end of file diff --git a/tests/src/Mooc/Users/Application/UserCreatorTest.php b/tests/src/Mooc/Users/Application/UserCreatorTest.php index 0df2c89..dfeea96 100644 --- a/tests/src/Mooc/Users/Application/UserCreatorTest.php +++ b/tests/src/Mooc/Users/Application/UserCreatorTest.php @@ -3,7 +3,6 @@ namespace CodelyTv\Tests\Mooc\Users\Application; use CodelyTv\Mooc\Users\Application\UserCreator; -use CodelyTv\Mooc\Users\Domain\User; use CodelyTv\Mooc\Users\Domain\UserRepository; use PHPUnit\Framework\TestCase; @@ -13,17 +12,13 @@ class UserCreatorTest extends TestCase public function it_should_create_a_valid_user(): void { // given - $id = 'some-id'; - $name = 'some-name'; - $email = 'valid@email.com'; - $password = 'some-password'; - - $course = new User($id, $name, $email, $password); + $request = CreateUserRequestMother::random(); + $user = UserMother::fromRequest($request); $repository = $this->createMock(UserRepository::class); - $repository->method('saveUser')->with($course); + $repository->method('saveUser')->with($user); // when $creator = new UserCreator($repository); - $creator->__invoke($id, $name, $email, $password); + $creator->__invoke($request); } } diff --git a/tests/src/Mooc/Users/Application/UserEmailMother.php b/tests/src/Mooc/Users/Application/UserEmailMother.php new file mode 100644 index 0000000..bd5c441 --- /dev/null +++ b/tests/src/Mooc/Users/Application/UserEmailMother.php @@ -0,0 +1,19 @@ +id()), + UserNameMother::create($request->name()), + UserEmailMother::create($request->email()), + UserPasswordMother::create($request->password()) + ); + } + + public static function random(): User + { + return self::create( + UserIdMother::random(), + UserNameMother::random(), + UserEmailMother::random(), + UserPasswordMother::random(), + ); + } +} \ No newline at end of file diff --git a/tests/src/Mooc/Users/Application/UserNameMother.php b/tests/src/Mooc/Users/Application/UserNameMother.php new file mode 100644 index 0000000..7aed9c7 --- /dev/null +++ b/tests/src/Mooc/Users/Application/UserNameMother.php @@ -0,0 +1,19 @@ +saveUser($user); + $this->userId = $user->id()->value(); } public function tearDown(): void { parent::tearDown(); // TODO: Change the autogenerated stub - unlink('/app/src/Mooc/Users/Infraestructure/users.id'); + $filename = "/app/src/Mooc/Users/Infraestructure/users.{$this->userId}"; + unlink($filename); } } From f5378d2877c1e6ddbcb033ea3ac3e65680345de6 Mon Sep 17 00:00:00 2001 From: Marcos Antonio Barreche Salguero Date: Fri, 9 Dec 2022 17:22:49 +0100 Subject: [PATCH 3/3] feat: validate every value object --- .../Controller/Users/UsersPutController.php | 8 +- src/Mooc/Users/Domain/User.php | 2 +- src/Mooc/Users/Domain/UserEmail.php | 15 +++ src/Mooc/Users/Domain/UserName.php | 17 +++ src/Mooc/Users/Domain/UserPassword.php | 33 +++++ .../backend/features/users/users_put.feature | 2 +- .../Application/Domain/CourseNameMother.php | 2 +- .../Application/CreateUserRequestMother.php | 16 +-- .../Users/Application/UserCreatorTest.php | 115 ++++++++++++++++++ .../Users/Application/UserEmailMother.php | 2 +- .../Mooc/Users/Application/UserNameMother.php | 2 +- .../Users/Application/UserPasswordMother.php | 2 +- tests/src/Shared/Domain/WordMother.php | 23 +++- 13 files changed, 221 insertions(+), 18 deletions(-) diff --git a/apps/mooc/backend/src/Controller/Users/UsersPutController.php b/apps/mooc/backend/src/Controller/Users/UsersPutController.php index 0d94fd3..534db3b 100644 --- a/apps/mooc/backend/src/Controller/Users/UsersPutController.php +++ b/apps/mooc/backend/src/Controller/Users/UsersPutController.php @@ -4,6 +4,7 @@ use CodelyTv\Mooc\Users\Application\CreateUserRequest; use CodelyTv\Mooc\Users\Application\UserCreator; +use InvalidArgumentException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -24,7 +25,12 @@ public function __invoke(string $id, Request $request) $request->request->get('email'), $request->request->get('password') ); - $this->creator->__invoke($request); + + try { + $this->creator->__invoke($request); + } catch (InvalidArgumentException $exception) { + return new Response('', Response::HTTP_BAD_REQUEST); + } return new Response('', Response::HTTP_CREATED); } } \ No newline at end of file diff --git a/src/Mooc/Users/Domain/User.php b/src/Mooc/Users/Domain/User.php index 1f79f3d..164719b 100644 --- a/src/Mooc/Users/Domain/User.php +++ b/src/Mooc/Users/Domain/User.php @@ -43,7 +43,7 @@ public function toString(): string 'id' => $this->id()->value(), 'name' => $this->name()->value(), 'email' => $this->email()->value(), - 'password' => password_hash($this->password()->value(), PASSWORD_DEFAULT) + 'password' => $this->password()->hashValue() ]); } } \ No newline at end of file diff --git a/src/Mooc/Users/Domain/UserEmail.php b/src/Mooc/Users/Domain/UserEmail.php index 6d79de0..4c49476 100644 --- a/src/Mooc/Users/Domain/UserEmail.php +++ b/src/Mooc/Users/Domain/UserEmail.php @@ -3,8 +3,23 @@ namespace CodelyTv\Mooc\Users\Domain; use CodelyTv\Shared\Domain\ValueObject\StringValueObject; +use InvalidArgumentException; class UserEmail extends StringValueObject { + /** @throws InvalidArgumentException */ + public function __construct(string $value) + { + $this->ensureIsValidEmail($value); + parent::__construct($value); + } + /** @throws InvalidArgumentException */ + private function ensureIsValidEmail(string $email): void + { + $validate = filter_var($email, FILTER_VALIDATE_EMAIL); + if ($validate === false) { + throw new InvalidArgumentException(sprintf('<%s> does not allow the value <%s>.', static::class, $email)); + } + } } \ No newline at end of file diff --git a/src/Mooc/Users/Domain/UserName.php b/src/Mooc/Users/Domain/UserName.php index 1aa6e40..0a2d0e9 100644 --- a/src/Mooc/Users/Domain/UserName.php +++ b/src/Mooc/Users/Domain/UserName.php @@ -3,8 +3,25 @@ namespace CodelyTv\Mooc\Users\Domain; use CodelyTv\Shared\Domain\ValueObject\StringValueObject; +use InvalidArgumentException; class UserName extends StringValueObject { + private const LIMIT_MIN = 2; + /** @throws InvalidArgumentException */ + public function __construct(string $value) + { + $this->ensureIsValidName($value); + parent::__construct($value); + } + + /** @throws InvalidArgumentException */ + private function ensureIsValidName(string $name): void + { + $validate = strlen($name) > self::LIMIT_MIN; + if ($validate === false) { + throw new InvalidArgumentException(sprintf('<%s> does not allow the value <%s>.', static::class, $name)); + } + } } \ No newline at end of file diff --git a/src/Mooc/Users/Domain/UserPassword.php b/src/Mooc/Users/Domain/UserPassword.php index c798e8b..42e9dec 100644 --- a/src/Mooc/Users/Domain/UserPassword.php +++ b/src/Mooc/Users/Domain/UserPassword.php @@ -3,8 +3,41 @@ namespace CodelyTv\Mooc\Users\Domain; use CodelyTv\Shared\Domain\ValueObject\StringValueObject; +use InvalidArgumentException; class UserPassword extends StringValueObject { + private const MIN_LENGTH = 8; + /** @throws InvalidArgumentException */ + public function __construct(string $value) + { + $this->ensureIsValidPassword($value); + parent::__construct($value); + } + + /** @throws InvalidArgumentException */ + private function ensureIsValidPassword(string $password): void + { + if (strlen($password) < self::MIN_LENGTH) { + throw new InvalidArgumentException('The password has an invalid length. It must be greater than 8 characters'); + } + if (false === (bool)preg_match('/[a-z]/', $password)) { + throw new InvalidArgumentException('The password is invalid. It must contain a lower case character'); + } + if (false === (bool)preg_match('/[A-Z]/', $password)) { + throw new InvalidArgumentException('The password is invalid. It must contain an upper case character'); + } + if (false === (bool)preg_match('/[0-9]/', $password)) { + throw new InvalidArgumentException('The password is invalid. It must contain a number'); + } + if (false === (bool)preg_match('/[^a-zA-Z0-9]/', $password)) { + throw new InvalidArgumentException('The password is invalid. It must contain a symbol (not a letter nor a number)'); + } + } + + public function hashValue(): string + { + return password_hash($this->value(), PASSWORD_DEFAULT); + } } \ No newline at end of file diff --git a/tests/apps/mooc/backend/features/users/users_put.feature b/tests/apps/mooc/backend/features/users/users_put.feature index 72f5ea7..812c560 100644 --- a/tests/apps/mooc/backend/features/users/users_put.feature +++ b/tests/apps/mooc/backend/features/users/users_put.feature @@ -9,7 +9,7 @@ Feature: Create a new user { "name": "John Smith", "email": "john-smith@gamil.com", - "password": "**password**" + "password": "**-Pa55w0rD-**" } """ Then the response status code should be 201 diff --git a/tests/src/Mooc/Courses/Application/Domain/CourseNameMother.php b/tests/src/Mooc/Courses/Application/Domain/CourseNameMother.php index e8a75b7..9e87749 100644 --- a/tests/src/Mooc/Courses/Application/Domain/CourseNameMother.php +++ b/tests/src/Mooc/Courses/Application/Domain/CourseNameMother.php @@ -16,6 +16,6 @@ public static function create(string $value): CourseName public static function random(): CourseName { - return self::create(WordMother::random()); + return self::create(WordMother::randomWord()); } } diff --git a/tests/src/Mooc/Users/Application/CreateUserRequestMother.php b/tests/src/Mooc/Users/Application/CreateUserRequestMother.php index 34ea5ce..4d8e121 100644 --- a/tests/src/Mooc/Users/Application/CreateUserRequestMother.php +++ b/tests/src/Mooc/Users/Application/CreateUserRequestMother.php @@ -3,25 +3,21 @@ namespace CodelyTv\Tests\Mooc\Users\Application; use CodelyTv\Mooc\Users\Application\CreateUserRequest; -use CodelyTv\Mooc\Users\Domain\UserEmail; -use CodelyTv\Mooc\Users\Domain\UserId; -use CodelyTv\Mooc\Users\Domain\UserName; -use CodelyTv\Mooc\Users\Domain\UserPassword; class CreateUserRequestMother { - public static function create(UserId $id, UserName $name, UserEmail $email, UserPassword $password): CreateUserRequest + public static function create(string $id, string $name, string $email, string $password): CreateUserRequest { - return new CreateUserRequest($id->value(), $name->value(), $email->value(), $password->value()); + return new CreateUserRequest($id, $name, $email, $password); } public static function random(): CreateUserRequest { return self::create( - UserIdMother::random(), - UserNameMother::random(), - UserEmailMother::random(), - UserPasswordMother::random() + UserIdMother::random()->value(), + UserNameMother::random()->value(), + UserEmailMother::random()->value(), + UserPasswordMother::random()->value() ); } } \ No newline at end of file diff --git a/tests/src/Mooc/Users/Application/UserCreatorTest.php b/tests/src/Mooc/Users/Application/UserCreatorTest.php index dfeea96..da2be4d 100644 --- a/tests/src/Mooc/Users/Application/UserCreatorTest.php +++ b/tests/src/Mooc/Users/Application/UserCreatorTest.php @@ -4,6 +4,7 @@ use CodelyTv\Mooc\Users\Application\UserCreator; use CodelyTv\Mooc\Users\Domain\UserRepository; +use InvalidArgumentException; use PHPUnit\Framework\TestCase; class UserCreatorTest extends TestCase @@ -21,4 +22,118 @@ public function it_should_create_a_valid_user(): void $creator = new UserCreator($repository); $creator->__invoke($request); } + + /** @test */ + public function it_is_not_possible_a_very_short_user_name(): void + { + // then + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage(' does not allow the value <>.'); + + // given + $request = CreateUserRequestMother::create( + UserIdMother::random()->value(), + '', + UserEmailMother::random()->value(), + UserPasswordMother::random()->value() + ); + $repository = $this->createMock(UserRepository::class); + $repository + ->expects($this->never()) + ->method('saveUser'); + + // when + $creator = new UserCreator($repository); + $creator->__invoke($request); + } + + public function invalidPasswordsProvider(): array + { + return [ + 'it is missed an upper case letter' => ['_abc_123_', 'The password is invalid. It must contain an upper case character'], + 'it is missed a lower case letter' => ['_ABC_123_', 'The password is invalid. It must contain a lower case character'], + 'it is missed a number' => ['_ABC_abc_', 'The password is invalid. It must contain a number'], + 'it is missed a symbol character' => ['ABC123abc', 'The password is invalid. It must contain a symbol (not a letter nor a number)'], + 'There are not an enough number of characters' => ['Aa1_Bb2', 'The password has an invalid length. It must be greater than 8 characters'] + ]; + } + + /** + * @test + * @dataProvider invalidPasswordsProvider + */ + public function it_is_not_possible_a_invalid_password(string $password, string $errorMessage): void + { + // then + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage($errorMessage); + + // given + $request = CreateUserRequestMother::create( + UserIdMother::random()->value(), + UserNameMother::random()->value(), + UserEmailMother::random()->value(), + $password + ); + $repository = $this->createMock(UserRepository::class); + $repository + ->expects($this->never()) + ->method('saveUser'); + + // when + $creator = new UserCreator($repository); + $creator->__invoke($request); + } + + /** + * @test + */ + public function it_is_not_possible_an_invalid_id(): void + { + // then + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage(' does not allow the value <123>.'); + + // given + $request = CreateUserRequestMother::create( + '123', + UserNameMother::random()->value(), + UserEmailMother::random()->value(), + UserPasswordMother::random()->value() + ); + $repository = $this->createMock(UserRepository::class); + $repository + ->expects($this->never()) + ->method('saveUser'); + + // when + $creator = new UserCreator($repository); + $creator->__invoke($request); + } + + /** + * @test + */ + public function it_is_not_possible_an_invalid_email(): void + { + // then + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage(' does not allow the value .'); + + // given + $request = CreateUserRequestMother::create( + UserIdMother::random()->value(), + UserNameMother::random()->value(), + 'abc', + UserPasswordMother::random()->value() + ); + $repository = $this->createMock(UserRepository::class); + $repository + ->expects($this->never()) + ->method('saveUser'); + + // when + $creator = new UserCreator($repository); + $creator->__invoke($request); + } } diff --git a/tests/src/Mooc/Users/Application/UserEmailMother.php b/tests/src/Mooc/Users/Application/UserEmailMother.php index bd5c441..f5146d4 100644 --- a/tests/src/Mooc/Users/Application/UserEmailMother.php +++ b/tests/src/Mooc/Users/Application/UserEmailMother.php @@ -14,6 +14,6 @@ public static function create(string $value): UserEmail public static function random(): UserEmail { - return self::create(WordMother::random()); + return self::create(WordMother::randomUserEmail()); } } \ No newline at end of file diff --git a/tests/src/Mooc/Users/Application/UserNameMother.php b/tests/src/Mooc/Users/Application/UserNameMother.php index 7aed9c7..7961b73 100644 --- a/tests/src/Mooc/Users/Application/UserNameMother.php +++ b/tests/src/Mooc/Users/Application/UserNameMother.php @@ -14,6 +14,6 @@ public static function create(string $value): UserName public static function random(): UserName { - return self::create(WordMother::random()); + return self::create(WordMother::randomUserName()); } } \ No newline at end of file diff --git a/tests/src/Mooc/Users/Application/UserPasswordMother.php b/tests/src/Mooc/Users/Application/UserPasswordMother.php index 75a97ff..90fd9ad 100644 --- a/tests/src/Mooc/Users/Application/UserPasswordMother.php +++ b/tests/src/Mooc/Users/Application/UserPasswordMother.php @@ -14,6 +14,6 @@ public static function create(string $value): UserPassword public static function random(): UserPassword { - return self::create(WordMother::random()); + return self::create(WordMother::randomUserPassword()); } } \ No newline at end of file diff --git a/tests/src/Shared/Domain/WordMother.php b/tests/src/Shared/Domain/WordMother.php index 6dfaf08..b3df93d 100644 --- a/tests/src/Shared/Domain/WordMother.php +++ b/tests/src/Shared/Domain/WordMother.php @@ -6,8 +6,29 @@ final class WordMother { - public static function random(): string + public static function randomWord(): string { return MotherCreator::random()->word; } + + public static function randomUserEmail(): string + { + return MotherCreator::random()->email; + } + + public static function randomUserPassword(): string + { + $minChunk = [ + substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 1), + substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'), 0, 1), + substr(str_shuffle('0123456789'), 0, 1), + substr(str_shuffle('`-=~!@#$%^&*()_+,./<>?;:[]{}\|'), 0, 1), + ]; + return str_shuffle(MotherCreator::random()->password(4, 16) . implode('', $minChunk)); + } + + public static function randomUserName(): string + { + return MotherCreator::random()->name; + } }