Passed
Pull Request — master (#550)
by
unknown
02:57
created

CompositeTest::getDifferentRuleInHandlerItems()

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
nc 1
nop 0
dl 0
loc 3
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Tests\Rule;
6
7
use InvalidArgumentException;
8
use Yiisoft\Validator\Result;
9
use Yiisoft\Validator\Rule\Composite;
10
use Yiisoft\Validator\Rule\CompositeHandler;
11
use Yiisoft\Validator\Rule\Equal;
12
use Yiisoft\Validator\Rule\Length;
13
use Yiisoft\Validator\Rule\Number;
14
use Yiisoft\Validator\Rule\Required;
15
use Yiisoft\Validator\Tests\Rule\Base\DifferentRuleInHandlerTestTrait;
16
use Yiisoft\Validator\Tests\Rule\Base\RuleTestCase;
17
use Yiisoft\Validator\Tests\Rule\Base\RuleWithOptionsTestTrait;
18
use Yiisoft\Validator\Tests\Rule\Base\RuleWithProvidedRulesTrait;
19
use Yiisoft\Validator\Tests\Rule\Base\SkipOnErrorTestTrait;
20
use Yiisoft\Validator\Tests\Rule\Base\WhenTestTrait;
21
use Yiisoft\Validator\Tests\Support\Rule\CoordinatesRuleSet;
22
use Yiisoft\Validator\Tests\Support\Rule\RuleWithoutOptions;
23
24
final class CompositeTest extends RuleTestCase
25
{
26
    use DifferentRuleInHandlerTestTrait;
27
    use RuleWithOptionsTestTrait;
28
    use RuleWithProvidedRulesTrait;
29
    use SkipOnErrorTestTrait;
30
    use WhenTestTrait;
31
32
    public function testGetName(): void
33
    {
34
        $rule = new Composite([]);
35
        $this->assertSame('composite', $rule->getName());
36
    }
37
38
    public function dataOptions(): array
39
    {
40
        return [
41
            [
42
                new Composite([
43
                    new Number(max: 13, pattern: '/1/'),
44
                    new Number(max: 14, pattern: '/2/'),
45
                ]),
46
                [
47
                    'skipOnEmpty' => false,
48
                    'skipOnError' => false,
49
                    'rules' => [
50
                        [
51
                            'number',
52
                            'min' => null,
53
                            'max' => 13,
54
                            'incorrectInputMessage' => [
55
                                'template' => 'The allowed types are integer, float and string.',
56
                                'parameters' => [],
57
                            ],
58
                            'notNumberMessage' => [
59
                                'template' => 'Value must be a number.',
60
                                'parameters' => [],
61
                            ],
62
                            'lessThanMinMessage' => [
63
                                'template' => 'Value must be no less than {min}.',
64
                                'parameters' => ['min' => null],
65
                            ],
66
                            'greaterThanMaxMessage' => [
67
                                'template' => 'Value must be no greater than {max}.',
68
                                'parameters' => ['max' => 13],
69
                            ],
70
                            'skipOnEmpty' => false,
71
                            'skipOnError' => false,
72
                            'pattern' => '/1/',
73
                        ],
74
                        [
75
                            'number',
76
                            'min' => null,
77
                            'max' => 14,
78
                            'incorrectInputMessage' => [
79
                                'template' => 'The allowed types are integer, float and string.',
80
                                'parameters' => [],
81
                            ],
82
                            'notNumberMessage' => [
83
                                'template' => 'Value must be a number.',
84
                                'parameters' => [],
85
                            ],
86
                            'lessThanMinMessage' => [
87
                                'template' => 'Value must be no less than {min}.',
88
                                'parameters' => ['min' => null],
89
                            ],
90
                            'greaterThanMaxMessage' => [
91
                                'template' => 'Value must be no greater than {max}.',
92
                                'parameters' => ['max' => 14],
93
                            ],
94
                            'skipOnEmpty' => false,
95
                            'skipOnError' => false,
96
                            'pattern' => '/2/',
97
                        ],
98
                    ],
99
                ],
100
            ],
101
            'rule without options' => [
102
                new Composite([
103
                    new Number(max: 13, pattern: '/1/'),
104
                    new RuleWithoutOptions(),
105
                ]),
106
                [
107
                    'skipOnEmpty' => false,
108
                    'skipOnError' => false,
109
                    'rules' => [
110
                        [
111
                            'number',
112
                            'min' => null,
113
                            'max' => 13,
114
                            'incorrectInputMessage' => [
115
                                'template' => 'The allowed types are integer, float and string.',
116
                                'parameters' => [],
117
                            ],
118
                            'notNumberMessage' => [
119
                                'template' => 'Value must be a number.',
120
                                'parameters' => [],
121
                            ],
122
                            'lessThanMinMessage' => [
123
                                'template' => 'Value must be no less than {min}.',
124
                                'parameters' => [
125
                                    'min' => null,
126
                                ],
127
                            ],
128
                            'greaterThanMaxMessage' => [
129
                                'template' => 'Value must be no greater than {max}.',
130
                                'parameters' => [
131
                                    'max' => 13,
132
                                ],
133
                            ],
134
                            'skipOnEmpty' => false,
135
                            'skipOnError' => false,
136
                            'pattern' => '/1/',
137
                        ],
138
                        [
139
                            'test',
140
                        ],
141
                    ],
142
                ],
143
            ],
144
            'callable' => [
145
                new Composite([
146
                    static fn () => (new Result())->addError('Bad value.'),
147
                ]),
148
                [
149
                    'skipOnEmpty' => false,
150
                    'skipOnError' => false,
151
                    'rules' => [
152
                        [
153
                            'callback',
154
                            'method' => null,
155
                            'skipOnEmpty' => false,
156
                            'skipOnError' => false,
157
                        ],
158
                    ],
159
                ],
160
            ],
161
            'inheritance' => [
162
                new class () extends Composite {
163
                    public function getRules(): iterable
164
                    {
165
                        return [
166
                            new Required(),
167
                        ];
168
                    }
169
170
                    public function getOptions(): array
171
                    {
172
                        return [
173
                            'specific-key' => 42,
174
                            'rules' => $this->dumpRulesAsArray(),
175
                        ];
176
                    }
177
                },
178
                [
179
                    'specific-key' => 42,
180
                    'rules' => [
181
                        [
182
                            'required',
183
                            'message' => [
184
                                'template' => 'Value cannot be blank.',
185
                                'parameters' => [],
186
                            ],
187
                            'notPassedMessage' => [
188
                                'template' => 'Value not passed.',
189
                                'parameters' => [],
190
                            ],
191
                            'skipOnError' => false,
192
                        ],
193
                    ],
194
                ],
195
            ],
196
        ];
197
    }
198
199
    public function testGetOptionsWithNotRule(): void
200
    {
201
        $this->testGetOptionsWithNotRuleInternal(Composite::class);
202
    }
203
204
    public function dataValidationPassed(): array
205
    {
206
        return [
207
            [
208
                20,
209
                [
210
                    new Composite(
211
                        [
212
                            new Number(max: 13),
213
                            new Number(max: 14),
214
                        ],
215
                        when: fn () => false,
216
                    ),
217
                ],
218
            ],
219
            'override constructor' => [
220
                20,
221
                [
222
                    new class () extends Composite {
223
                        public function __construct()
224
                        {
225
                        }
226
                    },
227
                ],
228
            ],
229
            [
230
                null,
231
                [
232
                    new Composite(
233
                        [
234
                            new Number(max: 13),
235
                            new Number(max: 14),
236
                        ],
237
                        skipOnEmpty: true,
238
                    ),
239
                ],
240
            ],
241
            'multiple attributes via subclass' => [
242
                ['latitude' => -90, 'longitude' => 180],
243
                [new CoordinatesRuleSet()],
244
            ],
245
        ];
246
    }
247
248
    public function dataValidationFailed(): array
249
    {
250
        return [
251
            'callable' => [
252
                20,
253
                [
254
                    new Composite([
255
                        static fn () => (new Result())->addError('Bad value.'),
256
                        static fn () => (new Result())->addError('Very bad value.'),
257
                    ]),
258
                ],
259
                [
260
                    '' => [
261
                        'Bad value.',
262
                        'Very bad value.',
263
                    ],
264
                ],
265
            ],
266
            'when true' => [
267
                20,
268
                [
269
                    new Composite(
270
                        [new Number(max: 13), new Number(min: 21)],
271
                        when: fn () => true,
272
                    ),
273
                ],
274
                [
275
                    '' => [
276
                        'Value must be no greater than 13.',
277
                        'Value must be no less than 21.',
278
                    ],
279
                ],
280
            ],
281
            'skip on error with previous error' => [
282
                20,
283
                [
284
                    new Equal(19),
285
                    new Composite(
286
                        [new Number(max: 13)],
287
                        skipOnError: true,
288
                    ),
289
                ],
290
                [
291
                    '' => ['Value must be equal to "19".'],
292
                ],
293
            ],
294
            'skip on error without previous error' => [
295
                20,
296
                [
297
                    new Composite(
298
                        [new Number(max: 13)],
299
                        skipOnError: true,
300
                    ),
301
                ],
302
                [
303
                    '' => ['Value must be no greater than 13.'],
304
                ],
305
            ],
306
            'custom error' => [
307
                20,
308
                [
309
                    new Composite(
310
                        [new Number(max: 13, greaterThanMaxMessage: 'Custom error')],
311
                        when: fn () => true,
312
                    ),
313
                ],
314
                ['' => ['Custom error']],
315
            ],
316
            'override constructor' => [
317
                null,
318
                [
319
                    new class () extends Composite {
320
                        public function __construct()
321
                        {
322
                            $this->rules = [new Required()];
323
                        }
324
                    },
325
                ],
326
                ['' => ['Value cannot be blank.']],
327
            ],
328
            'multiple attributes' => [
329
                ['latitude' => -91, 'longitude' => 181],
330
                [new CoordinatesRuleSet()],
331
                [
332
                    'latitude' => ['Value must be no less than -90.'],
333
                    'longitude' => ['Value must be no greater than 180.'],
334
                ],
335
            ],
336
            'attribute with multiple rules' => [
337
                [],
338
                new class () extends Composite {
339
                    public function getRules(): array
340
                    {
341
                        return [
342
                            'name' => [new Required(), new Length(min: 1)],
343
                        ];
344
                    }
345
                },
346
                [
347
                    'name' => [
348
                        'Value not passed.',
349
                        'The value must be a string.',
350
                    ],
351
                ],
352
            ],
353
            'rules normalization, callable without iterable' => [
354
                [],
355
                new Composite(
356
                    static fn (): Result => (new Result())->addError('Custom error.'),
357
                ),
358
                ['' => ['Custom error.']],
359
            ],
360
            'rules normalization, rule without iterable' => [
361
                [],
362
                new Composite(new Required()),
363
                ['' => ['Value cannot be blank.']],
364
            ],
365
        ];
366
    }
367
368
    public function testSkipOnError(): void
369
    {
370
        $this->testSkipOnErrorInternal(new Composite([]), new Composite([], skipOnError: true));
371
    }
372
373
    public function testWhen(): void
374
    {
375
        $when = static fn (mixed $value): bool => $value !== null;
376
        $this->testWhenInternal(new Composite([]), new Composite([], when: $when));
377
    }
378
379
    protected function getDifferentRuleInHandlerItems(): array
380
    {
381
        return [Composite::class, CompositeHandler::class];
382
    }
383
}
384