EachTest   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 300
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 169
c 3
b 0
f 0
dl 0
loc 300
rs 10
wmc 8

8 Methods

Rating   Name   Duplication   Size   Complexity  
B dataOptions() 0 121 1
A getDifferentRuleInHandlerItems() 0 3 1
A testGetOptionsWithNotRule() 0 3 1
A testGetName() 0 4 1
A testSkipOnError() 0 3 1
A testWhen() 0 4 1
A dataValidationPassed() 0 6 1
B dataValidationFailed() 0 123 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Tests\Rule;
6
7
use Generator;
8
use Yiisoft\Validator\Result;
9
use Yiisoft\Validator\Rule\Each;
10
use Yiisoft\Validator\Rule\EachHandler;
11
use Yiisoft\Validator\Rule\Length;
12
use Yiisoft\Validator\Rule\Number;
13
use Yiisoft\Validator\Rule\Required;
14
use Yiisoft\Validator\Tests\Rule\Base\DifferentRuleInHandlerTestTrait;
15
use Yiisoft\Validator\Tests\Rule\Base\RuleTestCase;
16
use Yiisoft\Validator\Tests\Rule\Base\RuleWithOptionsTestTrait;
17
use Yiisoft\Validator\Tests\Rule\Base\RuleWithProvidedRulesTrait;
18
use Yiisoft\Validator\Tests\Rule\Base\SkipOnErrorTestTrait;
19
use Yiisoft\Validator\Tests\Rule\Base\WhenTestTrait;
20
use Yiisoft\Validator\Tests\Support\Rule\RuleWithoutOptions;
21
22
final class EachTest extends RuleTestCase
23
{
24
    use DifferentRuleInHandlerTestTrait;
25
    use RuleWithOptionsTestTrait;
26
    use RuleWithProvidedRulesTrait;
27
    use SkipOnErrorTestTrait;
28
    use WhenTestTrait;
29
30
    public function testGetName(): void
31
    {
32
        $rule = new Each();
33
        $this->assertSame(Each::class, $rule->getName());
34
    }
35
36
    public function dataOptions(): array
37
    {
38
        return [
39
            [
40
                new Each([
41
                    new Number(max: 13, pattern: '/1/'),
42
                    new Number(max: 14, pattern: '/2/'),
43
                ]),
44
                [
45
                    'incorrectInputMessage' => [
46
                        'template' => 'Value must be array or iterable.',
47
                        'parameters' => [],
48
                    ],
49
                    'incorrectInputKeyMessage' => [
50
                        'template' => 'Every iterable key must have an integer or a string type.',
51
                        'parameters' => [],
52
                    ],
53
                    'skipOnEmpty' => false,
54
                    'skipOnError' => false,
55
                    'rules' => [
56
                        [
57
                            [
58
                                Number::class,
59
                                'min' => null,
60
                                'max' => 13,
61
                                'incorrectInputMessage' => [
62
                                    'template' => 'The allowed types are integer, float and string.',
63
                                    'parameters' => [],
64
                                ],
65
                                'notNumberMessage' => [
66
                                    'template' => 'Value must be a number.',
67
                                    'parameters' => [],
68
                                ],
69
                                'lessThanMinMessage' => [
70
                                    'template' => 'Value must be no less than {min}.',
71
                                    'parameters' => ['min' => null],
72
                                ],
73
                                'greaterThanMaxMessage' => [
74
                                    'template' => 'Value must be no greater than {max}.',
75
                                    'parameters' => ['max' => 13],
76
                                ],
77
                                'skipOnEmpty' => false,
78
                                'skipOnError' => false,
79
                                'pattern' => '/1/',
80
                            ],
81
                        ],
82
                        [
83
                            [
84
                                Number::class,
85
                                'min' => null,
86
                                'max' => 14,
87
                                'incorrectInputMessage' => [
88
                                    'template' => 'The allowed types are integer, float and string.',
89
                                    'parameters' => [],
90
                                ],
91
                                'notNumberMessage' => [
92
                                    'template' => 'Value must be a number.',
93
                                    'parameters' => [],
94
                                ],
95
                                'lessThanMinMessage' => [
96
                                    'template' => 'Value must be no less than {min}.',
97
                                    'parameters' => ['min' => null],
98
                                ],
99
                                'greaterThanMaxMessage' => [
100
                                    'template' => 'Value must be no greater than {max}.',
101
                                    'parameters' => ['max' => 14],
102
                                ],
103
                                'skipOnEmpty' => false,
104
                                'skipOnError' => false,
105
                                'pattern' => '/2/',
106
                            ],
107
                        ],
108
                    ],
109
                ],
110
            ],
111
            'rule without options' => [
112
                new Each([
113
                    new Number(max: 13, pattern: '/1/'),
114
                    new RuleWithoutOptions(),
115
                ]),
116
                [
117
                    'incorrectInputMessage' => [
118
                        'template' => 'Value must be array or iterable.',
119
                        'parameters' => [],
120
                    ],
121
                    'incorrectInputKeyMessage' => [
122
                        'template' => 'Every iterable key must have an integer or a string type.',
123
                        'parameters' => [],
124
                    ],
125
                    'skipOnEmpty' => false,
126
                    'skipOnError' => false,
127
                    'rules' => [
128
                        [
129
                            [
130
                                Number::class,
131
                                'min' => null,
132
                                'max' => 13,
133
                                'incorrectInputMessage' => [
134
                                    'template' => 'The allowed types are integer, float and string.',
135
                                    'parameters' => [],
136
                                ],
137
                                'notNumberMessage' => [
138
                                    'template' => 'Value must be a number.',
139
                                    'parameters' => [],
140
                                ],
141
                                'lessThanMinMessage' => [
142
                                    'template' => 'Value must be no less than {min}.',
143
                                    'parameters' => ['min' => null],
144
                                ],
145
                                'greaterThanMaxMessage' => [
146
                                    'template' => 'Value must be no greater than {max}.',
147
                                    'parameters' => ['max' => 13],
148
                                ],
149
                                'skipOnEmpty' => false,
150
                                'skipOnError' => false,
151
                                'pattern' => '/1/',
152
                            ],
153
                        ],
154
                        [
155
                            [
156
                                RuleWithoutOptions::class,
157
                            ],
158
                        ],
159
                    ],
160
                ],
161
            ],
162
        ];
163
    }
164
165
    public function testGetOptionsWithNotRule(): void
166
    {
167
        $this->testGetOptionsWithNotRuleInternal(Each::class);
168
    }
169
170
    public function dataValidationPassed(): array
171
    {
172
        return [
173
            [
174
                [10, 11],
175
                [new Each([new Number(max: 20)])],
176
            ],
177
        ];
178
    }
179
180
    public function dataValidationFailed(): array
181
    {
182
        $getGeneratorWithIncorrectKey = static function (): Generator {
183
            yield false => 0;
184
        };
185
186
        return [
187
            'incorrect input' => [1, [new Each([new Number(max: 13)])], ['' => ['Value must be array or iterable.']]],
188
            'custom incorrect input message' => [
189
                1,
190
                [new Each([new Number(max: 13)], incorrectInputMessage: 'Custom incorrect input message.')],
191
                ['' => ['Custom incorrect input message.']],
192
            ],
193
            'custom incorrect input message, plain Each rule' => [
194
                1,
195
                new Each([new Number(max: 13)], incorrectInputMessage: 'Custom incorrect input message.'),
196
                ['' => ['Custom incorrect input message.']],
197
            ],
198
            'custom incorrect input message with parameters' => [
199
                1,
200
                [new Each([new Number(max: 13)], incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')],
201
                ['' => ['Attribute - , type - int.']],
202
            ],
203
            'custom incorrect input message with parameters, attribute set' => [
204
                ['data' => 1],
205
                [
206
                    'data' => new Each(
207
                        [new Number(max: 13)],
208
                        incorrectInputMessage: 'Attribute - {attribute}, type - {type}.',
209
                    ),
210
                ],
211
                ['data' => ['Attribute - data, type - int.']],
212
            ],
213
214
            'incorrect input key' => [
215
                ['attribute' => $getGeneratorWithIncorrectKey()],
216
                ['attribute' => new Each([new Number(max: 13)])],
217
                ['attribute' => ['Every iterable key must have an integer or a string type.']],
218
            ],
219
            'custom incorrect input key message' => [
220
                ['attribute' => $getGeneratorWithIncorrectKey()],
221
                [
222
                    'attribute' => new Each(
223
                        [new Number(max: 13)],
224
                        incorrectInputKeyMessage: 'Custom incorrect input key message.',
225
                    ),
226
                ],
227
                ['attribute' => ['Custom incorrect input key message.']],
228
            ],
229
            'custom incorrect input key message with parameters' => [
230
                ['attribute' => $getGeneratorWithIncorrectKey()],
231
                [
232
                    'attribute' => new Each(
233
                        [new Number(max: 13)],
234
                        incorrectInputKeyMessage: 'Attribute - {attribute}, type - {type}.',
235
                    ),
236
                ],
237
                ['attribute' => ['Attribute - attribute, type - Generator.']],
238
            ],
239
240
            [
241
                [10, 20, 30],
242
                [new Each([new Number(max: 13)])],
243
                [
244
                    '1' => ['Value must be no greater than 13.'],
245
                    '2' => ['Value must be no greater than 13.'],
246
                ],
247
            ],
248
249
            'single rule' => [
250
                [10, 20, 30],
251
                [new Each(new Number(max: 13))],
252
                [
253
                    '1' => ['Value must be no greater than 13.'],
254
                    '2' => ['Value must be no greater than 13.'],
255
                ],
256
            ],
257
            'single callable rule' => [
258
                [10, 20],
259
                [new Each(static fn (): Result => (new Result())->addError('error'))],
260
                [
261
                    0 => ['error'],
262
                    1 => ['error'],
263
                ],
264
            ],
265
            'rules array with callable' => [
266
                [10, 20],
267
                [new Each([static fn (): Result => (new Result())->addError('error')])],
268
                [
269
                    0 => ['error'],
270
                    1 => ['error'],
271
                ],
272
            ],
273
274
            'custom message' => [
275
                [10, 20, 30],
276
                [new Each([new Number(max: 13, greaterThanMaxMessage: 'Custom too big message.')])],
277
                [
278
                    '1' => ['Custom too big message.'],
279
                    '2' => ['Custom too big message.'],
280
                ],
281
            ],
282
            'custom message with parameters' => [
283
                [10, 20, 30],
284
                [
285
                    new Each(
286
                        [new Number(max: 13, greaterThanMaxMessage: 'Max - {max}, value - {value}.')],
287
                    ),
288
                ],
289
                [
290
                    '1' => ['Max - 13, value - 20.'],
291
                    '2' => ['Max - 13, value - 30.'],
292
                ],
293
            ],
294
            'validate arrays' => [
295
                [['name' => 'Mi', 'age' => 31], ['name' => 'SuHo', 'age' => 17]],
296
                new Each([
297
                    'name' => [new Required(), new Length(min: 3)],
298
                    'age' => new Number(min: 18),
299
                ]),
300
                [
301
                    '0.name' => ['This value must contain at least 3 characters.'],
302
                    '1.age' => ['Value must be no less than 18.'],
303
                ],
304
            ],
305
        ];
306
    }
307
308
    public function testSkipOnError(): void
309
    {
310
        $this->testSkipOnErrorInternal(new Each(), new Each(skipOnError: true));
311
    }
312
313
    public function testWhen(): void
314
    {
315
        $when = static fn (mixed $value): bool => $value !== null;
316
        $this->testWhenInternal(new Each(), new Each(when: $when));
317
    }
318
319
    protected function getDifferentRuleInHandlerItems(): array
320
    {
321
        return [Each::class, EachHandler::class];
322
    }
323
}
324