Password recovery rebuild, correctly translated Mails and some minor fixes #658
commit
c0e97bfe75
@ -1,6 +1,6 @@
|
||||
{{ __('Hi %s,', [username]) }}
|
||||
{% block title %}{{ __('Hi %s,', [username]) }}{% endblock %}
|
||||
|
||||
{{ __('here is a message for you from the %s:', [config('app_name')]) }}
|
||||
{{ message|raw }}
|
||||
{% block introduction %}{{ __('here is a message for you from the %s:', [config('app_name')]) }}{% endblock %}
|
||||
{% block message %}{{ message|raw }}{% endblock %}
|
||||
|
||||
{{ __('This email is autogenerated and has not been signed. You got this email because you are registered in the %s.', [config('app_name')]) }}
|
||||
{% block footer %}{{ __('This email is autogenerated and has not been signed. You got this email because you are registered in the %s.', [config('app_name')]) }}{% endblock %}
|
||||
|
@ -0,0 +1,3 @@
|
||||
{% extends "emails/mail.twig" %}
|
||||
|
||||
{% block message %}{{ __('Please visit %s to recover your password.', [url('/password/reset/') ~ reset.token]) }}{% endblock %}
|
@ -0,0 +1,18 @@
|
||||
{% macro input(name, label, type, required) %}
|
||||
<div class="form-group">
|
||||
{% if label %}
|
||||
<label for="{{ name }}">{{ label }}</label>
|
||||
{% endif %}
|
||||
<input type="{{ type|default('text') }}" class="form-control" id="{{ name }}" name="{{ name }}"
|
||||
{%- if required|default(false) %} required="required"{% endif -%}
|
||||
>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro hidden(name, value) %}
|
||||
<input type="hidden" id="{{ name }}" name="{{ name }}" value="{{ value }}">
|
||||
{% endmacro %}
|
||||
|
||||
{% macro submit(label) %}
|
||||
<button type="submit" class="btn btn-default">{{ label|default(__('form.submit')) }}</button>
|
||||
{% endmacro %}
|
@ -0,0 +1,18 @@
|
||||
{% extends "pages/password/reset.twig" %}
|
||||
{% import 'macros/base.twig' as m %}
|
||||
{% import 'macros/form.twig' as f %}
|
||||
|
||||
{% block row_content %}
|
||||
<div class="col-md-8">
|
||||
<form action="" enctype="multipart/form-data" method="post">
|
||||
{{ csrf() }}
|
||||
|
||||
{{ f.input('password', __('Password'), 'password', true) }}
|
||||
{{ f.input('password_confirmation', __('Confirm password'), 'password', true) }}
|
||||
|
||||
<div class="form-group">
|
||||
{{ f.submit(__('Save')) }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,12 @@
|
||||
{% extends "pages/password/reset.twig" %}
|
||||
{% import 'macros/base.twig' as m %}
|
||||
|
||||
{% block row_content %}
|
||||
<div class="col-md-12">
|
||||
{% if type == 'email' %}
|
||||
{{ m.alert(__('We sent you an email containing your password recovery link.'), 'info') }}
|
||||
{% elseif type == 'reset' %}
|
||||
{{ m.alert(__('Password saved.'), 'success') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,32 @@
|
||||
{% extends 'layouts/app.twig' %}
|
||||
{% import 'macros/base.twig' as m %}
|
||||
{% import 'macros/form.twig' as f %}
|
||||
|
||||
{% block title %}{{ __('Password recovery') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<h1>{{ __('Password recovery') }}</h1>
|
||||
|
||||
{% for message in errors|default([]) %}
|
||||
{{ m.alert(__(message), 'danger') }}
|
||||
{% endfor %}
|
||||
|
||||
<div class="row">
|
||||
{% block row_content %}
|
||||
<div class="col-md-8">
|
||||
<form action="" enctype="multipart/form-data" method="post">
|
||||
{{ csrf() }}
|
||||
|
||||
{{ __('We will send you an e-mail with a password recovery link. Please use the email address you used for registration.') }}
|
||||
{{ f.input('email', __('E-Mail'), 'email', true) }}
|
||||
|
||||
<div class="form-group">
|
||||
{{ f.submit(__('Recover')) }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Controllers;
|
||||
|
||||
use Engelsystem\Http\Exceptions\HttpNotFound;
|
||||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Mail\EngelsystemMailer;
|
||||
use Engelsystem\Models\User\PasswordReset;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Session\SessionInterface;
|
||||
|
||||
class PasswordResetController extends BaseController
|
||||
{
|
||||
/** @var LoggerInterface */
|
||||
protected $log;
|
||||
|
||||
/** @var EngelsystemMailer */
|
||||
protected $mail;
|
||||
|
||||
/** @var Response */
|
||||
protected $response;
|
||||
|
||||
/** @var SessionInterface */
|
||||
protected $session;
|
||||
|
||||
/** @var array */
|
||||
protected $permissions = [
|
||||
'reset' => 'login',
|
||||
'postReset' => 'login',
|
||||
'resetPassword' => 'login',
|
||||
'postResetPassword' => 'login',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param Response $response
|
||||
* @param SessionInterface $session
|
||||
* @param EngelsystemMailer $mail
|
||||
* @param LoggerInterface $log
|
||||
*/
|
||||
public function __construct(
|
||||
Response $response,
|
||||
SessionInterface $session,
|
||||
EngelsystemMailer $mail,
|
||||
LoggerInterface $log
|
||||
) {
|
||||
$this->log = $log;
|
||||
$this->mail = $mail;
|
||||
$this->response = $response;
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Response
|
||||
*/
|
||||
public function reset(): Response
|
||||
{
|
||||
return $this->showView('pages/password/reset');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function postReset(Request $request): Response
|
||||
{
|
||||
$data = $this->validate($request, [
|
||||
'email' => 'required|email',
|
||||
]);
|
||||
|
||||
/** @var User $user */
|
||||
$user = User::whereEmail($data['email'])->first();
|
||||
if ($user) {
|
||||
$reset = PasswordReset::findOrNew($user->id);
|
||||
$reset->user_id = $user->id;
|
||||
$reset->token = md5(random_bytes(64));
|
||||
$reset->save();
|
||||
|
||||
$this->log->info(
|
||||
sprintf('Password recovery for %s (%u)', $user->name, $user->id),
|
||||
['user' => $user->toJson()]
|
||||
);
|
||||
|
||||
$this->mail->sendViewTranslated(
|
||||
$user,
|
||||
'Password recovery',
|
||||
'emails/password-reset',
|
||||
['username' => $user->name, 'reset' => $reset]
|
||||
);
|
||||
}
|
||||
|
||||
return $this->showView('pages/password/reset-success', ['type' => 'email']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function resetPassword(Request $request): Response
|
||||
{
|
||||
$this->requireToken($request);
|
||||
|
||||
return $this->showView('pages/password/reset-form');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function postResetPassword(Request $request): Response
|
||||
{
|
||||
$reset = $this->requireToken($request);
|
||||
|
||||
$data = $this->validate($request, [
|
||||
'password' => 'required|min:' . config('min_password_length'),
|
||||
'password_confirmation' => 'required',
|
||||
]);
|
||||
|
||||
if ($data['password'] !== $data['password_confirmation']) {
|
||||
$this->session->set('errors',
|
||||
array_merge($this->session->get('errors', []), ['validation.password.confirmed']));
|
||||
|
||||
return $this->showView('pages/password/reset-form');
|
||||
}
|
||||
|
||||
auth()->setPassword($reset->user, $data['password']);
|
||||
$reset->delete();
|
||||
|
||||
return $this->showView('pages/password/reset-success', ['type' => 'reset']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $view
|
||||
* @param array $data
|
||||
* @return Response
|
||||
*/
|
||||
protected function showView($view = 'pages/password/reset', $data = []): Response
|
||||
{
|
||||
$errors = Collection::make(Arr::flatten($this->session->get('errors', [])));
|
||||
$this->session->remove('errors');
|
||||
|
||||
return $this->response->withView(
|
||||
$view,
|
||||
array_merge_recursive(['errors' => $errors], $data)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return PasswordReset
|
||||
*/
|
||||
protected function requireToken(Request $request): PasswordReset
|
||||
{
|
||||
$token = $request->getAttribute('token');
|
||||
/** @var PasswordReset|null $reset */
|
||||
$reset = PasswordReset::whereToken($token)->first();
|
||||
|
||||
if (!$reset) {
|
||||
throw new HttpNotFound();
|
||||
}
|
||||
|
||||
return $reset;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Http\Exceptions;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class HttpNotFound extends HttpException
|
||||
{
|
||||
/**
|
||||
* @param string $message
|
||||
* @param array $headers
|
||||
* @param int $code
|
||||
* @param Throwable|null $previous
|
||||
*/
|
||||
public function __construct(
|
||||
string $message = '',
|
||||
array $headers = [],
|
||||
int $code = 0,
|
||||
Throwable $previous = null
|
||||
) {
|
||||
parent::__construct(404, $message, $headers, $code, $previous);
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Http\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Rules\Between as RespectBetween;
|
||||
|
||||
class Between extends RespectBetween
|
||||
{
|
||||
use StringInputLength;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Http\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Rules\Max as RespectMax;
|
||||
|
||||
class Max extends RespectMax
|
||||
{
|
||||
use StringInputLength;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Http\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Rules\Min as RespectMin;
|
||||
|
||||
class Min extends RespectMin
|
||||
{
|
||||
use StringInputLength;
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Http\Validation\Rules;
|
||||
|
||||
use DateTime;
|
||||
use Illuminate\Support\Str;
|
||||
use Throwable;
|
||||
|
||||
trait StringInputLength
|
||||
{
|
||||
/**
|
||||
* Use the input length of a string
|
||||
*
|
||||
* @param mixed $input
|
||||
* @return bool
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
if (
|
||||
is_string($input)
|
||||
&& !is_numeric($input)
|
||||
&& !$this->isDateTime($input)
|
||||
) {
|
||||
$input = Str::length($input);
|
||||
}
|
||||
|
||||
return parent::validate($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
* @return bool
|
||||
*/
|
||||
protected function isDateTime($input): bool
|
||||
{
|
||||
try {
|
||||
new DateTime($input);
|
||||
} catch (Throwable $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Controllers;
|
||||
|
||||
use Engelsystem\Config\Config;
|
||||
use Engelsystem\Controllers\PasswordResetController;
|
||||
use Engelsystem\Helpers\Authenticator;
|
||||
use Engelsystem\Http\Exceptions\HttpNotFound;
|
||||
use Engelsystem\Http\Exceptions\ValidationException;
|
||||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Http\Validation\Validator;
|
||||
use Engelsystem\Mail\EngelsystemMailer;
|
||||
use Engelsystem\Models\User\PasswordReset;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Renderer\Renderer;
|
||||
use Engelsystem\Test\Unit\HasDatabase;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\Test\TestLogger;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
|
||||
|
||||
class PasswordResetControllerTest extends TestCase
|
||||
{
|
||||
use HasDatabase;
|
||||
|
||||
/** @var array */
|
||||
protected $args = [];
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::reset
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::__construct
|
||||
*/
|
||||
public function testReset(): void
|
||||
{
|
||||
$controller = $this->getController('pages/password/reset');
|
||||
$response = $controller->reset();
|
||||
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::postReset
|
||||
*/
|
||||
public function testPostReset(): void
|
||||
{
|
||||
$this->initDatabase();
|
||||
$request = new Request([], ['email' => 'foo@bar.batz']);
|
||||
$user = $this->createUser();
|
||||
|
||||
$controller = $this->getController(
|
||||
'pages/password/reset-success',
|
||||
['type' => 'email', 'errors' => collect()]
|
||||
);
|
||||
/** @var TestLogger $log */
|
||||
$log = $this->args['log'];
|
||||
/** @var EngelsystemMailer|MockObject $mailer */
|
||||
$mailer = $this->args['mailer'];
|
||||
$this->setExpects($mailer, 'sendViewTranslated');
|
||||
|
||||
$controller->postReset($request);
|
||||
|
||||
$this->assertNotEmpty(PasswordReset::find($user->id)->first());
|
||||
$this->assertTrue($log->hasInfoThatContains($user->name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::postReset
|
||||
*/
|
||||
public function testPostResetInvalidRequest(): void
|
||||
{
|
||||
$request = new Request();
|
||||
|
||||
$controller = $this->getController();
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
$controller->postReset($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::postReset
|
||||
*/
|
||||
public function testPostResetNoUser(): void
|
||||
{
|
||||
$this->initDatabase();
|
||||
$request = new Request([], ['email' => 'foo@bar.batz']);
|
||||
|
||||
$controller = $this->getController(
|
||||
'pages/password/reset-success',
|
||||
['type' => 'email', 'errors' => collect()]
|
||||
);
|
||||
|
||||
$controller->postReset($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::resetPassword
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::requireToken
|
||||
*/
|
||||
public function testResetPassword(): void
|
||||
{
|
||||
$this->initDatabase();
|
||||
|
||||
$user = $this->createUser();
|
||||
$token = $this->createToken($user);
|
||||
$request = new Request([], [], ['token' => $token->token]);
|
||||
|
||||
$controller = $this->getController('pages/password/reset-form');
|
||||
|
||||
$controller->resetPassword($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::resetPassword
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::requireToken
|
||||
*/
|
||||
public function testResetPasswordNoToken(): void
|
||||
{
|
||||
$this->initDatabase();
|
||||
$controller = $this->getController();
|
||||
|
||||
$this->expectException(HttpNotFound::class);
|
||||
$controller->resetPassword(new Request());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::postResetPassword
|
||||
*/
|
||||
public function testPostResetPassword(): void
|
||||
{
|
||||
$this->initDatabase();
|
||||
|
||||
$this->app->instance('config', new Config(['min_password_length' => 3]));
|
||||
$user = $this->createUser();
|
||||
$token = $this->createToken($user);
|
||||
$password = 'SomeRandomPasswordForAmazingSecurity';
|
||||
$request = new Request(
|
||||
[],
|
||||
['password' => $password, 'password_confirmation' => $password],
|
||||
['token' => $token->token]
|
||||
);
|
||||
|
||||
$controller = $this->getController(
|
||||
'pages/password/reset-success',
|
||||
['type' => 'reset', 'errors' => collect()]
|
||||
);
|
||||
|
||||
$auth = new Authenticator($request, $this->args['session'], $user);
|
||||
$this->app->instance('authenticator', $auth);
|
||||
|
||||
$response = $controller->postResetPassword($request);
|
||||
$this->assertEquals(200, $response->getStatusCode());
|
||||
|
||||
$this->assertEmpty(PasswordReset::find($user->id));
|
||||
$this->assertNotNull(auth()->authenticate($user->name, $password));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::postResetPassword
|
||||
* @covers \Engelsystem\Controllers\PasswordResetController::showView
|
||||
*/
|
||||
public function testPostResetPasswordNotMatching(): void
|
||||
{
|
||||
$this->initDatabase();
|
||||
|
||||
$this->app->instance('config', new Config(['min_password_length' => 3]));
|
||||
$user = $this->createUser();
|
||||
$token = $this->createToken($user);
|
||||
$password = 'SomeRandomPasswordForAmazingSecurity';
|
||||
$request = new Request(
|
||||
[],
|
||||
['password' => $password, 'password_confirmation' => $password . 'OrNot'],
|
||||
['token' => $token->token]
|
||||
);
|
||||
|
||||
$controller = $this->getController(
|
||||
'pages/password/reset-form',
|
||||
['errors' => collect(['some.other.error', 'validation.password.confirmed'])]
|
||||
);
|
||||
/** @var Session $session */
|
||||
$session = $this->args['session'];
|
||||
$session->set('errors', ['foo' => ['bar' => 'some.other.error']]);
|
||||
|
||||
$controller->postResetPassword($request);
|
||||
$this->assertEmpty($session->get('errors'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getControllerArgs(): array
|
||||
{
|
||||
$response = new Response();
|
||||
$session = new Session(new MockArraySessionStorage());
|
||||
/** @var EngelsystemMailer|MockObject $mailer */
|
||||
$mailer = $this->createMock(EngelsystemMailer::class);
|
||||
$log = new TestLogger();
|
||||
$renderer = $this->createMock(Renderer::class);
|
||||
$response->setRenderer($renderer);
|
||||
|
||||
return $this->args = [
|
||||
'response' => $response,
|
||||
'session' => $session,
|
||||
'mailer' => $mailer,
|
||||
'log' => $log,
|
||||
'renderer' => $renderer
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $view
|
||||
* @param array $data
|
||||
* @return PasswordResetController
|
||||
*/
|
||||
protected function getController(?string $view = null, ?array $data = null): PasswordResetController
|
||||
{
|
||||
/** @var Response $response */
|
||||
/** @var Session $session */
|
||||
/** @var EngelsystemMailer|MockObject $mailer */
|
||||
/** @var TestLogger $log */
|
||||
/** @var Renderer|MockObject $renderer */
|
||||
list($response, $session, $mailer, $log, $renderer) = array_values($this->getControllerArgs());
|
||||
$controller = new PasswordResetController($response, $session, $mailer, $log);
|
||||
$controller->setValidator(new Validator());
|
||||
|
||||
if ($view) {
|
||||
$args = [$view];
|
||||
if ($data) {
|
||||
$args[] = $data;
|
||||
}
|
||||
|
||||
$this->setExpects($renderer, 'render', $args, 'Foo');
|
||||
}
|
||||
|
||||
return $controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
protected function createUser(): User
|
||||
{
|
||||
$user = new User([
|
||||
'name' => 'foo',
|
||||
'password' => '',
|
||||
'email' => 'foo@bar.batz',
|
||||
'api_key' => '',
|
||||
]);
|
||||
$user->save();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @return PasswordReset
|
||||
*/
|
||||
protected function createToken(User $user): PasswordReset
|
||||
{
|
||||
$reset = new PasswordReset(['user_id' => $user->id, 'token' => 'SomeTestToken123']);
|
||||
$reset->save();
|
||||
|
||||
return $reset;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Http\Exceptions;
|
||||
|
||||
use Engelsystem\Http\Exceptions\HttpNotFound;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HttpNotFoundTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Exceptions\HttpNotFound::__construct
|
||||
*/
|
||||
public function testConstruct()
|
||||
{
|
||||
$exception = new HttpNotFound();
|
||||
$this->assertEquals(404, $exception->getStatusCode());
|
||||
$this->assertEquals('', $exception->getMessage());
|
||||
|
||||
$exception = new HttpNotFound('Nothing to see here!');
|
||||
$this->assertEquals('Nothing to see here!', $exception->getMessage());
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Http\Validation\Rules;
|
||||
|
||||
use Engelsystem\Http\Validation\Rules\Between;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class BetweenTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Validation\Rules\Between
|
||||
*/
|
||||
public function testValidate()
|
||||
{
|
||||
$rule = new Between(3, 10);
|
||||
$this->assertFalse($rule->validate(1));
|
||||
$this->assertFalse($rule->validate('11'));
|
||||
$this->assertTrue($rule->validate(5));
|
||||
$this->assertFalse($rule->validate('AS'));
|
||||
$this->assertFalse($rule->validate('TestContentThatCounts'));
|
||||
$this->assertTrue($rule->validate('TESTING'));
|
||||
|
||||
$rule = new Between('2042-01-01', '2042-10-10');
|
||||
$this->assertFalse($rule->validate('2000-01-01'));
|
||||
$this->assertFalse($rule->validate('3000-01-01'));
|
||||
$this->assertTrue($rule->validate('2042-05-11'));
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Http\Validation\Rules;
|
||||
|
||||
use Engelsystem\Http\Validation\Rules\Max;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class MaxTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Validation\Rules\Max
|
||||
*/
|
||||
public function testValidate()
|
||||
{
|
||||
$rule = new Max(3);
|
||||
$this->assertFalse($rule->validate(10));
|
||||
$this->assertFalse($rule->validate('22'));
|
||||
$this->assertTrue($rule->validate(3));
|
||||
$this->assertFalse($rule->validate('TEST'));
|
||||
$this->assertTrue($rule->validate('AS'));
|
||||
|
||||
$rule = new Max('2042-01-01');
|
||||
$this->assertFalse($rule->validate('2100-01-01'));
|
||||
$this->assertTrue($rule->validate('2000-01-01'));
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Http\Validation\Rules;
|
||||
|
||||
use Engelsystem\Http\Validation\Rules\Min;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class MinTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Validation\Rules\Min
|
||||
*/
|
||||
public function testValidate()
|
||||
{
|
||||
$rule = new Min(3);
|
||||
$this->assertFalse($rule->validate(1));
|
||||
$this->assertFalse($rule->validate('2'));
|
||||
$this->assertTrue($rule->validate(3));
|
||||
$this->assertFalse($rule->validate('AS'));
|
||||
$this->assertTrue($rule->validate('TEST'));
|
||||
|
||||
$rule = new Min('2042-01-01');
|
||||
$this->assertFalse($rule->validate('2000-01-01'));
|
||||
$this->assertTrue($rule->validate('2345-01-01'));
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Http\Validation\Rules;
|
||||
|
||||
use Engelsystem\Test\Unit\Http\Validation\Rules\Stub\UsesStringInputLength;
|
||||
use Engelsystem\Test\Unit\TestCase;
|
||||
|
||||
class StringInputLengthTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Http\Validation\Rules\StringInputLength::validate
|
||||
* @covers \Engelsystem\Http\Validation\Rules\StringInputLength::isDateTime
|
||||
* @dataProvider validateProvider
|
||||
* @param mixed $input
|
||||
* @param mixed $expectedInput
|
||||
*/
|
||||
public function testValidate($input, $expectedInput)
|
||||
{
|
||||
$rule = new UsesStringInputLength();
|
||||
$rule->validate($input);
|
||||
|
||||
$this->assertEquals($expectedInput, $rule->lastInput);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
public function validateProvider()
|
||||
{
|
||||
return [
|
||||
['TEST', 4],
|
||||
['?', 1],
|
||||
['2042-01-01 00:00', '2042-01-01 00:00'],
|
||||
['3', '3'],
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Http\Validation\Rules\Stub;
|
||||
|
||||
class ParentClassImplementation
|
||||
{
|
||||
/** @var bool */
|
||||
public $validateResult = true;
|
||||
|
||||
/** @var mixed */
|
||||
public $lastInput;
|
||||
|
||||
/**
|
||||
* @param mixed $input
|
||||
* @return bool
|
||||
*/
|
||||
public function validate($input): bool
|
||||
{
|
||||
$this->lastInput = $input;
|
||||
|
||||
return $this->validateResult;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Http\Validation\Rules\Stub;
|
||||
|
||||
use Engelsystem\Http\Validation\Rules\StringInputLength;
|
||||
|
||||
class UsesStringInputLength extends ParentClassImplementation
|
||||
{
|
||||
use StringInputLength;
|
||||
}
|
Loading…
Reference in New Issue