212 lines
7.2 KiB
PHP
212 lines
7.2 KiB
PHP
<?php
|
||
|
||
namespace Tests\Unit;
|
||
|
||
use PHPUnit\Framework\TestCase;
|
||
use System\Classes\MyException;
|
||
use System\Classes\Validation;
|
||
|
||
class ValidationTest extends TestCase
|
||
{
|
||
public function testValidDataPasses(): void
|
||
{
|
||
$v = Validation::factory(['email' => 'a@b.com', 'age' => '20'])
|
||
->rule('email', 'email')
|
||
->rule('age', 'digit');
|
||
|
||
$this->assertTrue($v->check());
|
||
$this->assertSame([], $v->errors());
|
||
}
|
||
|
||
public function testRequiredFailsOnEmpty(): void
|
||
{
|
||
$v = Validation::factory(['name' => ''])->rule('name', 'required');
|
||
|
||
$this->assertFalse($v->check());
|
||
$this->assertArrayHasKey('name', $v->errors());
|
||
}
|
||
|
||
public function testRequiredFailsOnMissingKey(): void
|
||
{
|
||
$v = Validation::factory([])->rule('name', 'required');
|
||
|
||
$this->assertFalse($v->check());
|
||
$this->assertArrayHasKey('name', $v->errors());
|
||
}
|
||
|
||
public function testEmptyOptionalFieldSkipsOtherRules(): void
|
||
{
|
||
// Поле пустое, но required нет — email-правило не должно срабатывать.
|
||
$v = Validation::factory(['email' => ''])->rule('email', 'email');
|
||
|
||
$this->assertTrue($v->check());
|
||
$this->assertSame([], $v->errors());
|
||
}
|
||
|
||
public function testStopsAtFirstErrorPerField(): void
|
||
{
|
||
// required и email оба провалились бы, но сообщение должно быть от required.
|
||
$v = Validation::factory(['email' => ''])
|
||
->rule('email', 'required')
|
||
->rule('email', 'email');
|
||
|
||
$this->assertFalse($v->check());
|
||
$this->assertStringContainsString('обязательно', $v->error('email'));
|
||
}
|
||
|
||
public function testEmailRule(): void
|
||
{
|
||
$bad = Validation::factory(['email' => 'not-an-email'])->rule('email', 'email');
|
||
$this->assertFalse($bad->check());
|
||
|
||
$ok = Validation::factory(['email' => 'user@example.com'])->rule('email', 'email');
|
||
$this->assertTrue($ok->check());
|
||
}
|
||
|
||
public function testUrlRule(): void
|
||
{
|
||
$bad = Validation::factory(['site' => 'example'])->rule('site', 'url');
|
||
$this->assertFalse($bad->check());
|
||
|
||
$ok = Validation::factory(['site' => 'https://example.com'])->rule('site', 'url');
|
||
$this->assertTrue($ok->check());
|
||
}
|
||
|
||
public function testNumericRule(): void
|
||
{
|
||
$this->assertTrue(Validation::factory(['n' => '3.14'])->rule('n', 'numeric')->check());
|
||
$this->assertFalse(Validation::factory(['n' => '12abc'])->rule('n', 'numeric')->check());
|
||
}
|
||
|
||
public function testDigitRule(): void
|
||
{
|
||
$this->assertTrue(Validation::factory(['n' => '42'])->rule('n', 'digit')->check());
|
||
$this->assertFalse(Validation::factory(['n' => '3.14'])->rule('n', 'digit')->check());
|
||
}
|
||
|
||
public function testMinLengthRule(): void
|
||
{
|
||
$this->assertFalse(Validation::factory(['p' => '123'])->rule('p', 'min_length', [8])->check());
|
||
$this->assertTrue(Validation::factory(['p' => '12345678'])->rule('p', 'min_length', [8])->check());
|
||
}
|
||
|
||
public function testMaxLengthRule(): void
|
||
{
|
||
$this->assertFalse(Validation::factory(['p' => '123456'])->rule('p', 'max_length', [4])->check());
|
||
$this->assertTrue(Validation::factory(['p' => '1234'])->rule('p', 'max_length', [4])->check());
|
||
}
|
||
|
||
public function testExactLengthRule(): void
|
||
{
|
||
$this->assertTrue(Validation::factory(['code' => '1234'])->rule('code', 'exact_length', [4])->check());
|
||
$this->assertFalse(Validation::factory(['code' => '12345'])->rule('code', 'exact_length', [4])->check());
|
||
}
|
||
|
||
public function testMinLengthCountsMultibyte(): void
|
||
{
|
||
// 4 кириллических символа — должно проходить min_length(4).
|
||
$this->assertTrue(Validation::factory(['p' => 'тест'])->rule('p', 'min_length', [4])->check());
|
||
}
|
||
|
||
public function testMatchesRule(): void
|
||
{
|
||
$ok = Validation::factory(['pass' => 'secret', 'confirm' => 'secret'])
|
||
->rule('confirm', 'matches', ['pass']);
|
||
$this->assertTrue($ok->check());
|
||
|
||
$bad = Validation::factory(['pass' => 'secret', 'confirm' => 'other'])
|
||
->rule('confirm', 'matches', ['pass']);
|
||
$this->assertFalse($bad->check());
|
||
}
|
||
|
||
public function testInRule(): void
|
||
{
|
||
$ok = Validation::factory(['role' => 'admin'])
|
||
->rule('role', 'in', [['admin', 'user']]);
|
||
$this->assertTrue($ok->check());
|
||
|
||
$bad = Validation::factory(['role' => 'root'])
|
||
->rule('role', 'in', [['admin', 'user']]);
|
||
$this->assertFalse($bad->check());
|
||
}
|
||
|
||
public function testRegexRule(): void
|
||
{
|
||
$ok = Validation::factory(['slug' => 'hello-world'])
|
||
->rule('slug', 'regex', ['/^[a-z\-]+$/']);
|
||
$this->assertTrue($ok->check());
|
||
|
||
$bad = Validation::factory(['slug' => 'Hello World'])
|
||
->rule('slug', 'regex', ['/^[a-z\-]+$/']);
|
||
$this->assertFalse($bad->check());
|
||
}
|
||
|
||
public function testLabelAppearsInMessage(): void
|
||
{
|
||
$v = Validation::factory(['email' => 'bad'])
|
||
->label('email', 'E-mail')
|
||
->rule('email', 'email');
|
||
|
||
$v->check();
|
||
$this->assertStringContainsString('E-mail', $v->error('email'));
|
||
}
|
||
|
||
public function testMatchesMessageUsesParamLabel(): void
|
||
{
|
||
$v = Validation::factory(['pass' => 'a', 'confirm' => 'b'])
|
||
->label('pass', 'Пароль')
|
||
->rule('confirm', 'matches', ['pass']);
|
||
|
||
$v->check();
|
||
$this->assertStringContainsString('Пароль', $v->error('confirm'));
|
||
}
|
||
|
||
public function testParamPlaceholderInMessage(): void
|
||
{
|
||
$v = Validation::factory(['p' => '1'])->rule('p', 'min_length', [8]);
|
||
$v->check();
|
||
$this->assertStringContainsString('8', $v->error('p'));
|
||
}
|
||
|
||
public function testErrorReturnsNullForValidField(): void
|
||
{
|
||
$v = Validation::factory(['email' => 'a@b.com'])->rule('email', 'email');
|
||
$v->check();
|
||
$this->assertNull($v->error('email'));
|
||
}
|
||
|
||
public function testMultipleFieldsCollectErrors(): void
|
||
{
|
||
$v = Validation::factory(['email' => 'bad', 'age' => 'x'])
|
||
->rule('email', 'email')
|
||
->rule('age', 'digit');
|
||
|
||
$this->assertFalse($v->check());
|
||
$this->assertCount(2, $v->errors());
|
||
}
|
||
|
||
public function testFluentReturnsStatic(): void
|
||
{
|
||
$v = Validation::factory([]);
|
||
$this->assertSame($v, $v->rule('a', 'required'));
|
||
$this->assertSame($v, $v->label('a', 'A'));
|
||
}
|
||
|
||
public function testUnknownRuleThrows(): void
|
||
{
|
||
$this->expectException(MyException::class);
|
||
Validation::factory(['a' => 'x'])->rule('a', 'no_such_rule')->check();
|
||
}
|
||
|
||
public function testCheckIsRepeatableAndResetsErrors(): void
|
||
{
|
||
$v = Validation::factory(['email' => 'bad'])->rule('email', 'email');
|
||
$this->assertFalse($v->check());
|
||
$this->assertCount(1, $v->errors());
|
||
|
||
// Повторный вызов не накапливает ошибки.
|
||
$this->assertFalse($v->check());
|
||
$this->assertCount(1, $v->errors());
|
||
}
|
||
}
|