Skip to content

Commit 190ddda

Browse files
authored
Allow use AtLeast rule for arrays + tests refactoring (#334)
1 parent fddb9c6 commit 190ddda

3 files changed

Lines changed: 170 additions & 59 deletions

File tree

src/Rule/AtLeastHandler.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Yiisoft\Validator\Rule;
66

7+
use Yiisoft\Arrays\ArrayHelper;
78
use Yiisoft\Translator\TranslatorInterface;
89
use Yiisoft\Validator\Exception\UnexpectedRuleException;
910
use Yiisoft\Validator\Result;
@@ -29,7 +30,7 @@ public function validate(mixed $value, object $rule, ValidationContext $context)
2930
$filledCount = 0;
3031

3132
foreach ($rule->getAttributes() as $attribute) {
32-
if (!(new SkipOnEmpty())($value->{$attribute}, $context->isAttributeMissing())) {
33+
if (!(new SkipOnEmpty())(ArrayHelper::getValue($value, $attribute), $context->isAttributeMissing())) {
3334
$filledCount++;
3435
}
3536
}

tests/Rule/AtLeastHandlerTest.php

Lines changed: 15 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,65 +4,29 @@
44

55
namespace Yiisoft\Validator\Tests\Rule;
66

7+
use PHPUnit\Framework\TestCase;
78
use stdClass;
8-
use Yiisoft\Validator\Error;
9-
use Yiisoft\Validator\Rule\AtLeast;
109
use Yiisoft\Validator\Rule\AtLeastHandler;
11-
use Yiisoft\Validator\RuleHandlerInterface;
10+
use Yiisoft\Validator\Tests\Stub\FakeValidatorFactory;
11+
use Yiisoft\Validator\Tests\Stub\TranslatorFactory;
12+
use Yiisoft\Validator\ValidationContext;
1213

13-
final class AtLeastHandlerTest extends AbstractRuleValidatorTest
14+
final class AtLeastHandlerTest extends TestCase
1415
{
15-
public function failedValidationProvider(): array
16+
public function testDifferentRule(): void
1617
{
17-
return [
18-
[
19-
new AtLeast(['attr2']),
20-
$this->createObject(1, null),
21-
[new Error('The model is not valid. Must have at least "1" filled attributes.')],
22-
],
23-
[
24-
new AtLeast(['attr1', 'attr2'], min: 2),
25-
$this->createObject(1, null),
26-
[new Error('The model is not valid. Must have at least "2" filled attributes.')],
27-
],
28-
];
29-
}
30-
31-
public function passedValidationProvider(): array
32-
{
33-
return [
34-
[
35-
new AtLeast(['attr1', 'attr2']),
36-
$this->createObject(1, null),
37-
],
38-
[
39-
new AtLeast(['attr2']),
40-
$this->createObject(null, 1),
41-
],
42-
];
43-
}
18+
$handler = $this->createHandler();
19+
$context = new ValidationContext(FakeValidatorFactory::make(), null);
4420

45-
public function customErrorMessagesProvider(): array
46-
{
47-
return [
48-
[
49-
new AtLeast(['attr1', 'attr2'], min: 2, message: 'Custom error'),
50-
$this->createObject(1, null),
51-
[new Error('Custom error')],
52-
],
53-
];
54-
}
55-
56-
protected function getRuleHandler(): RuleHandlerInterface
57-
{
58-
return new AtLeastHandler($this->getTranslator());
21+
$this->expectExceptionMessageMatches('/' . AtLeastHandler::class . '/');
22+
$this->expectExceptionMessageMatches('/' . stdClass::class . '/');
23+
$handler->validate('value', new stdClass(), $context);
5924
}
6025

61-
private function createObject(mixed $attr1, mixed $attr2): stdClass
26+
private function createHandler(): AtLeastHandler
6227
{
63-
$object = new stdClass();
64-
$object->attr1 = $attr1;
65-
$object->attr2 = $attr2;
66-
return $object;
28+
return new AtLeastHandler(
29+
(new TranslatorFactory())->create()
30+
);
6731
}
6832
}

tests/Rule/AtLeastTest.php

Lines changed: 153 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,29 @@
44

55
namespace Yiisoft\Validator\Tests\Rule;
66

7+
use PHPUnit\Framework\TestCase;
8+
use stdClass;
79
use Yiisoft\Validator\Rule\AtLeast;
8-
use Yiisoft\Validator\SerializableRuleInterface;
10+
use Yiisoft\Validator\Tests\Stub\FakeValidatorFactory;
11+
use Yiisoft\Validator\Validator;
912

10-
final class AtLeastTest extends AbstractRuleTest
13+
final class AtLeastTest extends TestCase
1114
{
1215
public function testGetName(): void
1316
{
1417
$rule = new AtLeast([]);
1518
$this->assertSame('atLeast', $rule->getName());
1619
}
1720

18-
public function optionsDataProvider(): array
21+
public function dataOptions(): array
1922
{
2023
return [
2124
[
2225
new AtLeast(['attr1', 'attr2']),
2326
[
2427
'attributes' => [
25-
'attr1', 'attr2',
28+
'attr1',
29+
'attr2',
2630
],
2731
'min' => 1,
2832
'message' => [
@@ -37,7 +41,8 @@ public function optionsDataProvider(): array
3741
new AtLeast(['attr1', 'attr2'], min: 2),
3842
[
3943
'attributes' => [
40-
'attr1', 'attr2',
44+
'attr1',
45+
'attr2',
4146
],
4247
'min' => 2,
4348
'message' => [
@@ -51,8 +56,149 @@ public function optionsDataProvider(): array
5156
];
5257
}
5358

54-
protected function getRule(): SerializableRuleInterface
59+
/**
60+
* @dataProvider dataOptions
61+
*/
62+
public function testOptions(AtLeast $rule, array $expectedOptions): void
5563
{
56-
return new AtLeast([]);
64+
$options = $rule->getOptions();
65+
$this->assertSame($expectedOptions, $options);
66+
}
67+
68+
public function dataValidationPassed(): array
69+
{
70+
return [
71+
[
72+
new class () {
73+
public $attr1 = 1;
74+
public $attr2 = null;
75+
},
76+
[new AtLeast(['attr1', 'attr2'])],
77+
],
78+
[
79+
new class () {
80+
public $attr1 = null;
81+
public $attr2 = 1;
82+
},
83+
[new AtLeast(['attr2'])],
84+
],
85+
[
86+
['attr1' => 1, 'attr2' => null],
87+
[new AtLeast(['attr1', 'attr2'])],
88+
],
89+
[
90+
['attr1' => null, 'attr2' => 1],
91+
[new AtLeast(['attr2'])],
92+
],
93+
[
94+
new class () {
95+
public $obj;
96+
97+
public function __construct()
98+
{
99+
$this->obj = new class () {
100+
public $attr1 = 1;
101+
public $attr2 = null;
102+
};
103+
}
104+
},
105+
['obj' => new AtLeast(['attr1', 'attr2'])],
106+
],
107+
[
108+
new class () {
109+
public $obj;
110+
111+
public function __construct()
112+
{
113+
$this->obj = new class () {
114+
public $attr1 = null;
115+
public $attr2 = 1;
116+
};
117+
}
118+
},
119+
['obj' => new AtLeast(['attr2'])],
120+
],
121+
[
122+
['obj' => ['attr1' => 1, 'attr2' => null]],
123+
['obj' => new AtLeast(['attr1', 'attr2'])],
124+
],
125+
[
126+
['obj' => ['attr1' => null, 'attr2' => 1]],
127+
['obj' => new AtLeast(['attr2'])],
128+
],
129+
];
130+
}
131+
132+
/**
133+
* @dataProvider dataValidationPassed
134+
*/
135+
public function testValidationPassed(mixed $data, array $rules): void
136+
{
137+
$result = $this->createValidator()->validate($data, $rules);
138+
139+
$this->assertTrue($result->isValid());
140+
}
141+
142+
public function dataValidationFailed(): array
143+
{
144+
return [
145+
[
146+
new class () {
147+
public $attr1 = 1;
148+
public $attr2 = null;
149+
},
150+
[new AtLeast(['attr2'])],
151+
['' => ['The model is not valid. Must have at least "1" filled attributes.']],
152+
],
153+
[
154+
new class () {
155+
public $attr1 = 1;
156+
public $attr2 = null;
157+
},
158+
[new AtLeast(['attr1', 'attr2'], min: 2)],
159+
['' => ['The model is not valid. Must have at least "2" filled attributes.']],
160+
],
161+
];
162+
}
163+
164+
/**
165+
* @dataProvider dataValidationFailed
166+
*/
167+
public function testValidationFailed(object $object, array $rules, array $errorMessagesIndexedByPath): void
168+
{
169+
$result = $this->createValidator()->validate($object, $rules);
170+
171+
$this->assertFalse($result->isValid());
172+
$this->assertSame($errorMessagesIndexedByPath, $result->getErrorMessagesIndexedByPath());
173+
}
174+
175+
public function testCustomErrorMessage(): void
176+
{
177+
$object = new class () {
178+
public $attr1 = 1;
179+
public $attr2 = null;
180+
};
181+
$rules = [new AtLeast(['attr1', 'attr2'], min: 2, message: 'Custom error')];
182+
183+
$result = $this->createValidator()->validate($object, $rules);
184+
185+
$this->assertFalse($result->isValid());
186+
$this->assertSame(
187+
['' => ['Custom error']],
188+
$result->getErrorMessagesIndexedByPath()
189+
);
190+
}
191+
192+
private function createValidator(): Validator
193+
{
194+
return FakeValidatorFactory::make();
195+
}
196+
197+
private function createObject(mixed $attr1, mixed $attr2): stdClass
198+
{
199+
$object = new stdClass();
200+
$object->attr1 = $attr1;
201+
$object->attr2 = $attr2;
202+
return $object;
57203
}
58204
}

0 commit comments

Comments
 (0)