Passed
Push — master ( c5e9e9...342519 )
by Sergei
02:35
created

anonymous//tests/Rule/CompositeTest.php$3   A

Complexity

Total Complexity 1

Size/Duplication

Total Lines 4
Duplicated Lines 0 %

Importance

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