Passed
Pull Request — master (#521)
by Alexander
11:59 queued 09:05
created

anonymous//tests/Rule/CompareTest.php$6   A

Complexity

Total Complexity 1

Size/Duplication

Total Lines 4
Duplicated Lines 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
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 stdClass;
9
use Stringable;
10
use Yiisoft\Validator\DataWrapperInterface;
11
use Yiisoft\Validator\Rule\Compare;
12
use Yiisoft\Validator\Rule\CompareType;
13
use Yiisoft\Validator\Tests\Rule\Base\RuleTestCase;
14
use Yiisoft\Validator\Tests\Rule\Base\RuleWithOptionsTestTrait;
15
use Yiisoft\Validator\Tests\Rule\Base\SkipOnErrorTestTrait;
16
use Yiisoft\Validator\Tests\Rule\Base\WhenTestTrait;
17
18
final class CompareTest extends RuleTestCase
19
{
20
    use RuleWithOptionsTestTrait;
21
    use SkipOnErrorTestTrait;
22
    use WhenTestTrait;
23
24
    public function testInitWithWrongType(): void
25
    {
26
        $this->expectException(InvalidArgumentException::class);
27
        $message = 'Type "float" is not supported. The valid types are: "original", "string", "number".';
28
        $this->expectExceptionMessage($message);
29
30
        new Compare(type: 'float');
31
    }
32
33
    public function testInitWithWrongOperator(): void
34
    {
35
        $this->expectException(InvalidArgumentException::class);
36
        $message = 'Operator "=" is not supported. The valid operators are: "==", "===", "!=", "!==", ">", ">=", ' .
37
            '"<", "<=".';
38
        $this->expectExceptionMessage($message);
39
40
        new Compare(1, operator: '=');
41
    }
42
43
    public function testGetName(): void
44
    {
45
        $rule = new Compare();
46
        $this->assertSame('compare', $rule->getName());
47
    }
48
49
    public function dataOptions(): array
50
    {
51
        return [
52
            [
53
                new Compare(1),
54
                [
55
                    'targetValue' => 1,
56
                    'targetAttribute' => null,
57
                    'incorrectInputMessage' => [
58
                        'template' => 'The allowed types are integer, float, string, boolean and null.',
59
                        'parameters' => [
60
                            'targetValue' => 1,
61
                            'targetAttribute' => null,
62
                            'targetValueOrAttribute' => 1,
63
                        ],
64
                    ],
65
                    'incorrectDataSetTypeMessage' => [
66
                        'template' => 'The attribute value returned from a custom data set must have a scalar type or be null.',
67
                        'parameters' => [
68
                            'targetValue' => 1,
69
                            'targetAttribute' => null,
70
                            'targetValueOrAttribute' => 1,
71
                        ],
72
                    ],
73
                    'message' => [
74
                        'template' => 'Value must be equal to "{targetValueOrAttribute}".',
75
                        'parameters' => [
76
                            'targetValue' => 1,
77
                            'targetAttribute' => null,
78
                            'targetValueOrAttribute' => 1,
79
                        ],
80
                    ],
81
                    'type' => 'string',
82
                    'operator' => '==',
83
                    'skipOnEmpty' => false,
84
                    'skipOnError' => false,
85
                ],
86
            ],
87
            [
88
                new Compare(1, type: CompareType::NUMBER),
89
                [
90
                    'targetValue' => 1,
91
                    'targetAttribute' => null,
92
                    'incorrectInputMessage' => [
93
                        'template' => 'The allowed types are integer, float, string, boolean and null.',
94
                        'parameters' => [
95
                            'targetValue' => 1,
96
                            'targetAttribute' => null,
97
                            'targetValueOrAttribute' => 1,
98
                        ],
99
                    ],
100
                    'incorrectDataSetTypeMessage' => [
101
                        'template' => 'The attribute value returned from a custom data set must have a scalar type or be null.',
102
                        'parameters' => [
103
                            'targetValue' => 1,
104
                            'targetAttribute' => null,
105
                            'targetValueOrAttribute' => 1,
106
                        ],
107
                    ],
108
                    'message' => [
109
                        'template' => 'Value must be equal to "{targetValueOrAttribute}".',
110
                        'parameters' => [
111
                            'targetValue' => 1,
112
                            'targetAttribute' => null,
113
                            'targetValueOrAttribute' => 1,
114
                        ],
115
                    ],
116
                    'type' => 'number',
117
                    'operator' => '==',
118
                    'skipOnEmpty' => false,
119
                    'skipOnError' => false,
120
                ],
121
            ],
122
            [
123
                new Compare(1, type: CompareType::NUMBER, operator: '>='),
124
                [
125
                    'targetValue' => 1,
126
                    'targetAttribute' => null,
127
                    'incorrectInputMessage' => [
128
                        'template' => 'The allowed types are integer, float, string, boolean and null.',
129
                        'parameters' => [
130
                            'targetValue' => 1,
131
                            'targetAttribute' => null,
132
                            'targetValueOrAttribute' => 1,
133
                        ],
134
                    ],
135
                    'incorrectDataSetTypeMessage' => [
136
                        'template' => 'The attribute value returned from a custom data set must have a scalar type or be null.',
137
                        'parameters' => [
138
                            'targetValue' => 1,
139
                            'targetAttribute' => null,
140
                            'targetValueOrAttribute' => 1,
141
                        ],
142
                    ],
143
                    'message' => [
144
                        'template' => 'Value must be greater than or equal to "{targetValueOrAttribute}".',
145
                        'parameters' => [
146
                            'targetValue' => 1,
147
                            'targetAttribute' => null,
148
                            'targetValueOrAttribute' => 1,
149
                        ],
150
                    ],
151
                    'type' => 'number',
152
                    'operator' => '>=',
153
                    'skipOnEmpty' => false,
154
                    'skipOnError' => false,
155
                ],
156
            ],
157
            [
158
                new Compare('YES'),
159
                [
160
                    'targetValue' => 'YES',
161
                    'targetAttribute' => null,
162
                    'incorrectInputMessage' => [
163
                        'template' => 'The allowed types are integer, float, string, boolean and null.',
164
                        'parameters' => [
165
                            'targetValue' => 'YES',
166
                            'targetAttribute' => null,
167
                            'targetValueOrAttribute' => 'YES',
168
                        ],
169
                    ],
170
                    'incorrectDataSetTypeMessage' => [
171
                        'template' => 'The attribute value returned from a custom data set must have a scalar type or be null.',
172
                        'parameters' => [
173
                            'targetValue' => 'YES',
174
                            'targetAttribute' => null,
175
                            'targetValueOrAttribute' => 'YES',
176
                        ],
177
                    ],
178
                    'message' => [
179
                        'template' => 'Value must be equal to "{targetValueOrAttribute}".',
180
                        'parameters' => [
181
                            'targetValue' => 'YES',
182
                            'targetAttribute' => null,
183
                            'targetValueOrAttribute' => 'YES',
184
                        ],
185
                    ],
186
                    'type' => 'string',
187
                    'operator' => '==',
188
                    'skipOnEmpty' => false,
189
                    'skipOnError' => false,
190
                ],
191
            ],
192
            [
193
                new Compare('YES', skipOnEmpty: true),
194
                [
195
                    'targetValue' => 'YES',
196
                    'targetAttribute' => null,
197
                    'incorrectInputMessage' => [
198
                        'template' => 'The allowed types are integer, float, string, boolean and null.',
199
                        'parameters' => [
200
                            'targetValue' => 'YES',
201
                            'targetAttribute' => null,
202
                            'targetValueOrAttribute' => 'YES',
203
                        ],
204
                    ],
205
                    'incorrectDataSetTypeMessage' => [
206
                        'template' => 'The attribute value returned from a custom data set must have a scalar type or be null.',
207
                        'parameters' => [
208
                            'targetValue' => 'YES',
209
                            'targetAttribute' => null,
210
                            'targetValueOrAttribute' => 'YES',
211
                        ],
212
                    ],
213
                    'message' => [
214
                        'template' => 'Value must be equal to "{targetValueOrAttribute}".',
215
                        'parameters' => [
216
                            'targetValue' => 'YES',
217
                            'targetAttribute' => null,
218
                            'targetValueOrAttribute' => 'YES',
219
                        ],
220
                    ],
221
                    'type' => 'string',
222
                    'operator' => '==',
223
                    'skipOnEmpty' => true,
224
                    'skipOnError' => false,
225
                ],
226
            ],
227
            [
228
                new Compare('YES', operator: '!=='),
229
                [
230
                    'targetValue' => 'YES',
231
                    'targetAttribute' => null,
232
                    'incorrectInputMessage' => [
233
                        'template' => 'The allowed types are integer, float, string, boolean and null.',
234
                        'parameters' => [
235
                            'targetValue' => 'YES',
236
                            'targetAttribute' => null,
237
                            'targetValueOrAttribute' => 'YES',
238
                        ],
239
                    ],
240
                    'incorrectDataSetTypeMessage' => [
241
                        'template' => 'The attribute value returned from a custom data set must have a scalar type or be null.',
242
                        'parameters' => [
243
                            'targetValue' => 'YES',
244
                            'targetAttribute' => null,
245
                            'targetValueOrAttribute' => 'YES',
246
                        ],
247
                    ],
248
                    'message' => [
249
                        'template' => 'Value must not be equal to "{targetValueOrAttribute}".',
250
                        'parameters' => [
251
                            'targetValue' => 'YES',
252
                            'targetAttribute' => null,
253
                            'targetValueOrAttribute' => 'YES',
254
                        ],
255
                    ],
256
                    'type' => 'string',
257
                    'operator' => '!==',
258
                    'skipOnEmpty' => false,
259
                    'skipOnError' => false,
260
                ],
261
            ],
262
            [
263
                new Compare('YES', message: 'Custom message for {targetValueOrAttribute}.'),
264
                [
265
                    'targetValue' => 'YES',
266
                    'targetAttribute' => null,
267
                    'incorrectInputMessage' => [
268
                        'template' => 'The allowed types are integer, float, string, boolean and null.',
269
                        'parameters' => [
270
                            'targetValue' => 'YES',
271
                            'targetAttribute' => null,
272
                            'targetValueOrAttribute' => 'YES',
273
                        ],
274
                    ],
275
                    'incorrectDataSetTypeMessage' => [
276
                        'template' => 'The attribute value returned from a custom data set must have a scalar type or be null.',
277
                        'parameters' => [
278
                            'targetValue' => 'YES',
279
                            'targetAttribute' => null,
280
                            'targetValueOrAttribute' => 'YES',
281
                        ],
282
                    ],
283
                    'message' => [
284
                        'template' => 'Custom message for {targetValueOrAttribute}.',
285
                        'parameters' => [
286
                            'targetValue' => 'YES',
287
                            'targetAttribute' => null,
288
                            'targetValueOrAttribute' => 'YES',
289
                        ],
290
                    ],
291
                    'type' => 'string',
292
                    'operator' => '==',
293
                    'skipOnEmpty' => false,
294
                    'skipOnError' => false,
295
                ],
296
            ],
297
            [
298
                new Compare(null, 'test'),
299
                [
300
                    'targetValue' => null,
301
                    'targetAttribute' => 'test',
302
                    'incorrectInputMessage' => [
303
                        'template' => 'The allowed types are integer, float, string, boolean and null.',
304
                        'parameters' => [
305
                            'targetValue' => null,
306
                            'targetAttribute' => 'test',
307
                            'targetValueOrAttribute' => 'test',
308
                        ],
309
                    ],
310
                    'incorrectDataSetTypeMessage' => [
311
                        'template' => 'The attribute value returned from a custom data set must have a scalar type or be null.',
312
                        'parameters' => [
313
                            'targetValue' => null,
314
                            'targetAttribute' => 'test',
315
                            'targetValueOrAttribute' => 'test',
316
                        ],
317
                    ],
318
                    'message' => [
319
                        'template' => 'Value must be equal to "{targetValueOrAttribute}".',
320
                        'parameters' => [
321
                            'targetValue' => null,
322
                            'targetAttribute' => 'test',
323
                            'targetValueOrAttribute' => 'test',
324
                        ],
325
                    ],
326
                    'type' => 'string',
327
                    'operator' => '==',
328
                    'skipOnEmpty' => false,
329
                    'skipOnError' => false,
330
                ],
331
            ],
332
            [
333
                new Compare(
334
                    null,
335
                    'test',
336
                    incorrectInputMessage: 'Custom message 1.',
337
                    incorrectDataSetTypeMessage: 'Custom message 2.',
338
                    message: 'Custom message 3.',
339
                ),
340
                [
341
                    'targetValue' => null,
342
                    'targetAttribute' => 'test',
343
                    'incorrectInputMessage' => [
344
                        'template' => 'Custom message 1.',
345
                        'parameters' => [
346
                            'targetValue' => null,
347
                            'targetAttribute' => 'test',
348
                            'targetValueOrAttribute' => 'test',
349
                        ],
350
                    ],
351
                    'incorrectDataSetTypeMessage' => [
352
                        'template' => 'Custom message 2.',
353
                        'parameters' => [
354
                            'targetValue' => null,
355
                            'targetAttribute' => 'test',
356
                            'targetValueOrAttribute' => 'test',
357
                        ],
358
                    ],
359
                    'message' => [
360
                        'template' => 'Custom message 3.',
361
                        'parameters' => [
362
                            'targetValue' => null,
363
                            'targetAttribute' => 'test',
364
                            'targetValueOrAttribute' => 'test',
365
                        ],
366
                    ],
367
                    'type' => 'string',
368
                    'operator' => '==',
369
                    'skipOnEmpty' => false,
370
                    'skipOnError' => false,
371
                ],
372
            ],
373
            [
374
                new Compare(1, 'test'),
375
                [
376
                    'targetValue' => 1,
377
                    'targetAttribute' => 'test',
378
                    'incorrectInputMessage' => [
379
                        'template' => 'The allowed types are integer, float, string, boolean and null.',
380
                        'parameters' => [
381
                            'targetValue' => 1,
382
                            'targetAttribute' => 'test',
383
                            'targetValueOrAttribute' => 1,
384
                        ],
385
                    ],
386
                    'incorrectDataSetTypeMessage' => [
387
                        'template' => 'The attribute value returned from a custom data set must have a scalar type or be null.',
388
                        'parameters' => [
389
                            'targetValue' => 1,
390
                            'targetAttribute' => 'test',
391
                            'targetValueOrAttribute' => 1,
392
                        ],
393
                    ],
394
                    'message' => [
395
                        'template' => 'Value must be equal to "{targetValueOrAttribute}".',
396
                        'parameters' => [
397
                            'targetValue' => 1,
398
                            'targetAttribute' => 'test',
399
                            'targetValueOrAttribute' => 1,
400
                        ],
401
                    ],
402
                    'type' => 'string',
403
                    'operator' => '==',
404
                    'skipOnEmpty' => false,
405
                    'skipOnError' => false,
406
                ],
407
            ],
408
        ];
409
    }
410
411
    public function dataValidationPassed(): array
412
    {
413
        return [
414
            [null, [new Compare('')]],
415
416
            [100, [new Compare(100)]],
417
            [['attribute' => 100, 'number' => 100], ['number' => new Compare(null, 'attribute')]],
418
            ['100', [new Compare(100)]],
419
420
            [100, [new Compare(100, operator: '===')]],
421
422
            [100.00001, [new Compare(100, operator: '!=')]],
423
            [false, [new Compare(100, operator: '!=')]],
424
425
            [101, [new Compare(100, operator: '>')]],
426
427
            [100, [new Compare(100, operator: '>=')]],
428
            [101, [new Compare(100, operator: '>=')]],
429
            [99, [new Compare(100, operator: '<')]],
430
431
            [100, [new Compare(100, operator: '<=')]],
432
            [99, [new Compare(100, operator: '<=')]],
433
            [['attribute' => 100, 'number' => 99], ['number' => new Compare(null, 'attribute', operator: '<=')]],
434
435
            ['100.50', [new Compare('100.5', type: CompareType::NUMBER)]],
436
            ['100.50', [new Compare(100.5, type: CompareType::NUMBER)]],
437
            ['100.50', [new Compare('100.5', type: CompareType::NUMBER, operator: '===')]],
438
439
            'stringable == stringable, number' => [
440
                new class () implements Stringable {
441
                    public function __toString(): string
442
                    {
443
                        return '100.50';
444
                    }
445
                },
446
                [
447
                    new Compare(
448
                        new class () implements Stringable {
449
                            public function __toString(): string
450
                            {
451
                                return '100.5';
452
                            }
453
                        },
454
                        type: CompareType::NUMBER,
455
                    ),
456
                ],
457
            ],
458
459
            'integer !== boolean' => [false, [new Compare(100, operator: '!==')]],
460
            'integer !== string' => ['100', [new Compare(100, operator: '!==')]],
461
            'integer !== float' => [100.0, [new Compare(100, operator: '!==')]],
462
463
            'float == the same float as expression result' => [
464
                1 - 0.83,
465
                [new Compare(0.17, type: CompareType::NUMBER)],
466
            ],
467
            'float === the same float as expression result' => [
468
                1 - 0.83,
469
                [new Compare(0.17, type: CompareType::NUMBER, operator: '===')],
470
            ],
471
        ];
472
    }
473
474
    public function dataValidationFailed(): array
475
    {
476
        $incorrectDataSet = new class () implements DataWrapperInterface {
477
            public function getAttributeValue(string $attribute): mixed
478
            {
479
                return new stdClass();
480
            }
481
482
            public function getData(): ?array
483
            {
484
                return null;
485
            }
486
487
            public function getSource(): mixed
488
            {
489
                return false;
490
            }
491
492
            public function hasAttribute(string $attribute): bool
493
            {
494
                return false;
495
            }
496
        };
497
        $messageEqual = 'Value must be equal to "100".';
498
        $messageNotEqual = 'Value must not be equal to "100".';
499
        $messageGreaterThan = 'Value must be greater than "100".';
500
        $messageGreaterOrEqualThan = 'Value must be greater than or equal to "100".';
501
        $messageLessThan = 'Value must be less than "100".';
502
        $messageLessOrEqualThan = 'Value must be less than or equal to "100".';
503
504
        return [
505
            'incorrect input' => [
506
                [],
507
                [new Compare(false)],
508
                ['' => ['The allowed types are integer, float, string, boolean and null.']],
509
            ],
510
            'custom incorrect input message' => [
511
                [],
512
                [new Compare(false, incorrectInputMessage: 'Custom incorrect input message.')],
513
                ['' => ['Custom incorrect input message.']],
514
            ],
515
            'custom incorrect input message with parameters' => [
516
                [],
517
                [new Compare(false, incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')],
518
                ['' => ['Attribute - , type - array.']],
519
            ],
520
            'custom incorrect input message with parameters, attribute set' => [
521
                ['data' => []],
522
                ['data' => new Compare(false, incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')],
523
                ['data' => ['Attribute - data, type - array.']],
524
            ],
525
526
            'incorrect data set type' => [
527
                $incorrectDataSet,
528
                [new Compare(targetAttribute: 'test')],
529
                ['' => ['The attribute value returned from a custom data set must have a scalar type or be null.']],
530
            ],
531
            'custom incorrect data set type message' => [
532
                $incorrectDataSet,
533
                [
534
                    new Compare(
535
                        targetAttribute: 'test',
536
                        incorrectDataSetTypeMessage: 'Custom incorrect data set type message.',
537
                    ),
538
                ],
539
                ['' => ['Custom incorrect data set type message.']],
540
            ],
541
            'custom incorrect data set type message with parameters' => [
542
                $incorrectDataSet,
543
                [
544
                    new Compare(
545
                        targetAttribute: 'test',
546
                        incorrectDataSetTypeMessage: 'Type - {type}.',
547
                    ),
548
                ],
549
                ['' => ['Type - stdClass.']],
550
            ],
551
552
            'string === null' => [null, [new Compare('', operator: '===')], ['' => ['Value must be equal to "".']]],
553
            'integer === string' => ['100', [new Compare(100, operator: '===')], ['' => [$messageEqual]]],
554
            'integer === float' => [100.0, [new Compare(100, operator: '===')], ['' => [$messageEqual]]],
555
556
            [null, [new Compare(0)], ['' => ['Value must be equal to "0".']]],
557
558
            [101, [new Compare(100)], ['' => [$messageEqual]]],
559
560
            [101, [new Compare(100, operator: '===')], ['' => [$messageEqual]]],
561
            [
562
                ['attribute' => 100, 'number' => 101],
563
                ['number' => new Compare(null, 'attribute', operator: '===')],
564
                ['number' => [$messageEqual]],
565
            ],
566
567
            [100, [new Compare(100, operator: '!=')], ['' => [$messageNotEqual]]],
568
            ['100', [new Compare(100, operator: '!=')], ['' => [$messageNotEqual]]],
569
            [100.0, [new Compare(100, operator: '!=')], ['' => [$messageNotEqual]]],
570
571
            [100, [new Compare(100, operator: '!==')], ['' => [$messageNotEqual]]],
572
573
            [100, [new Compare(100, operator: '>')], ['' => [$messageGreaterThan]]],
574
            [99, [new Compare(100, operator: '>')], ['' => [$messageGreaterThan]]],
575
576
            [99, [new Compare(100, operator: '>=')], ['' => [$messageGreaterOrEqualThan]]],
577
578
            [100, [new Compare(100, operator: '<')], ['' => [$messageLessThan]]],
579
            [101, [new Compare(100, operator: '<')], ['' => [$messageLessThan]]],
580
581
            [101, [new Compare(100, operator: '<=')], ['' => [$messageLessOrEqualThan]]],
582
            [
583
                ['attribute' => 100, 'number' => 101],
584
                ['number' => new Compare(null, 'attribute', operator: '<=')],
585
                ['number' => [$messageLessOrEqualThan]],
586
            ],
587
588
            'custom message' => [101, [new Compare(100, message: 'Custom message.')], ['' => ['Custom message.']]],
589
            'custom message with parameters, target value set' => [
590
                101,
591
                [
592
                    new Compare(
593
                        100,
594
                        message: 'Attribute - {attribute}, target value - {targetValue}, target attribute - ' .
595
                        '{targetAttribute}, target value or attribute - {targetValueOrAttribute}, value - {value}.',
596
                    ),
597
                ],
598
                [
599
                    '' => [
600
                        'Attribute - , target value - 100, target attribute - , target value or attribute - 100, ' .
601
                        'value - 101.',
602
                    ],
603
                ],
604
            ],
605
            'custom message with parameters, attribute and target attribute set' => [
606
                ['attribute' => 100, 'number' => 101],
607
                [
608
                    'number' => new Compare(
609
                        null,
610
                        'attribute',
611
                        message: 'Attribute - {attribute}, target value - {targetValue}, target attribute - ' .
612
                        '{targetAttribute}, target value or attribute - {targetValueOrAttribute}, value - {value}.',
613
                        operator: '===',
614
                    ),
615
                ],
616
                [
617
                    'number' => [
618
                        'Attribute - number, target value - , target attribute - attribute, target value or ' .
619
                        'attribute - 100, value - 101.',
620
                    ],
621
                ],
622
            ],
623
624
            'target value: stringable float, value: stringable float with the same value, but extra decimal place (0), type: string, operator: ==' => [
625
                new class () implements Stringable {
626
                    public function __toString(): string
627
                    {
628
                        return '100.50';
629
                    }
630
                },
631
                [
632
                    new Compare(
633
                        new class () implements Stringable {
634
                            public function __toString(): string
635
                            {
636
                                return '100.5';
637
                            }
638
                        },
639
                    ),
640
                ],
641
                ['' => ['Value must be equal to "100.5".']],
642
            ],
643
            'target value: stringable float, value: stringable float with the same value, but extra decimal place (0), type: string, operator: ===' => [
644
                new class () implements Stringable {
645
                    public function __toString(): string
646
                    {
647
                        return '100.50';
648
                    }
649
                },
650
                [
651
                    new Compare(
652
                        new class () implements Stringable {
653
                            public function __toString(): string
654
                            {
655
                                return '100.51';
656
                            }
657
                        },
658
                        operator: '===',
659
                    ),
660
                ],
661
                ['' => ['Value must be equal to "100.5".']],
662
            ],
663
664
            ['100.50', [new Compare('100.5')], ['' => ['Value must be equal to "100.5".']]],
665
            ['100.50', [new Compare('100.5', operator: '===')], ['' => ['Value must be equal to "100.5".']]],
666
        ];
667
    }
668
669
    public function testSkipOnError(): void
670
    {
671
        $this->testSkipOnErrorInternal(new Compare(), new Compare(skipOnError: true));
672
    }
673
674
    public function testWhen(): void
675
    {
676
        $when = static fn (mixed $value): bool => $value !== null;
677
        $this->testWhenInternal(new Compare(), new Compare(when: $when));
678
    }
679
}
680