Failed Conditions
Pull Request — master (#199)
by Tomasz
02:52
created

Assert::contains()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10

Duplication

Lines 10
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 10
loc 10
ccs 7
cts 7
cp 1
rs 9.9332
c 0
b 0
f 0
cc 3
nc 2
nop 3
crap 3
1
<?php
2
3
/*
4
 * This file is part of the webmozart/assert package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webmozart\Assert;
13
14
use ArrayAccess;
15
use BadMethodCallException;
16
use Closure;
17
use Countable;
18
use DateTime;
19
use DateTimeImmutable;
20
use Exception;
21
use InvalidArgumentException;
22
use ResourceBundle;
23
use SimpleXMLElement;
24
use Throwable;
25
use Traversable;
26
27
/**
28
 * Efficient assertions to validate the input/output of your methods.
29
 *
30
 * @mixin Mixin
31
 *
32
 * @since  1.0
33
 *
34
 * @author Bernhard Schussek <[email protected]>
35
 */
36
class Assert
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
37
{
38
    /**
39
     * @psalm-pure
40
     * @psalm-assert string $value
41
     *
42
     * @param mixed  $value
43
     * @param string $message
44
     *
45
     * @throws InvalidArgumentException
46
     */
47 241
    public static function string($value, $message = '')
48
    {
49 241
        if (!\is_string($value)) {
50 45
            static::reportInvalidArgument(\sprintf(
51 45
                $message ?: 'Expected a string. Got: %s',
52 45
                static::typeToString($value)
53
            ));
54
        }
55 196
    }
56
57
    /**
58
     * @psalm-pure
59
     * @psalm-assert non-empty-string $value
60
     *
61
     * @param mixed  $value
62
     * @param string $message
63
     *
64
     * @throws InvalidArgumentException
65
     */
66 16
    public static function stringNotEmpty($value, $message = '')
67
    {
68 16
        static::string($value, $message);
69 12
        static::notEq($value, '', $message);
70 8
    }
71
72
    /**
73
     * @psalm-pure
74
     * @psalm-assert int $value
75
     *
76
     * @param mixed  $value
77
     * @param string $message
78
     *
79
     * @throws InvalidArgumentException
80
     */
81 17
    public static function integer($value, $message = '')
82
    {
83 17
        if (!\is_int($value)) {
84 13
            static::reportInvalidArgument(\sprintf(
85 13
                $message ?: 'Expected an integer. Got: %s',
86 13
                static::typeToString($value)
87
            ));
88
        }
89 4
    }
90
91
    /**
92
     * @psalm-pure
93
     * @psalm-assert numeric $value
94
     *
95
     * @param mixed  $value
96
     * @param string $message
97
     *
98
     * @throws InvalidArgumentException
99
     */
100 16
    public static function integerish($value, $message = '')
101
    {
102 16
        if (!\is_numeric($value) || $value != (int) $value) {
103 4
            static::reportInvalidArgument(\sprintf(
104 4
                $message ?: 'Expected an integerish value. Got: %s',
105 4
                static::typeToString($value)
106
            ));
107
        }
108 12
    }
109
110
    /**
111
     * @psalm-pure
112
     * @psalm-assert float $value
113
     *
114
     * @param mixed  $value
115
     * @param string $message
116
     *
117
     * @throws InvalidArgumentException
118
     */
119 16
    public static function float($value, $message = '')
120
    {
121 16
        if (!\is_float($value)) {
122 8
            static::reportInvalidArgument(\sprintf(
123 8
                $message ?: 'Expected a float. Got: %s',
124 8
                static::typeToString($value)
125
            ));
126
        }
127 8
    }
128
129
    /**
130
     * @psalm-pure
131
     * @psalm-assert numeric $value
132
     *
133
     * @param mixed  $value
134
     * @param string $message
135
     *
136
     * @throws InvalidArgumentException
137
     */
138 20
    public static function numeric($value, $message = '')
139
    {
140 20
        if (!\is_numeric($value)) {
141 4
            static::reportInvalidArgument(\sprintf(
142 4
                $message ?: 'Expected a numeric. Got: %s',
143 4
                static::typeToString($value)
144
            ));
145
        }
146 16
    }
147
148
    /**
149
     * @psalm-pure
150
     * @psalm-assert int $value
151
     *
152
     * @param mixed  $value
153
     * @param string $message
154
     *
155
     * @throws InvalidArgumentException
156
     */
157 24
    public static function natural($value, $message = '')
158
    {
159 24
        if (!\is_int($value) || $value < 0) {
160 16
            static::reportInvalidArgument(\sprintf(
161 16
                $message ?: 'Expected a non-negative integer. Got: %s',
162 16
                static::valueToString($value)
163
            ));
164
        }
165 8
    }
166
167
    /**
168
     * @psalm-pure
169
     * @psalm-assert bool $value
170
     *
171
     * @param mixed  $value
172
     * @param string $message
173
     *
174
     * @throws InvalidArgumentException
175
     */
176 16
    public static function boolean($value, $message = '')
177
    {
178 16
        if (!\is_bool($value)) {
179 8
            static::reportInvalidArgument(\sprintf(
180 8
                $message ?: 'Expected a boolean. Got: %s',
181 8
                static::typeToString($value)
182
            ));
183
        }
184 8
    }
185
186
    /**
187
     * @psalm-pure
188
     * @psalm-assert scalar $value
189
     *
190
     * @param mixed  $value
191
     * @param string $message
192
     *
193
     * @throws InvalidArgumentException
194
     */
195 23
    public static function scalar($value, $message = '')
196
    {
197 23
        if (!\is_scalar($value)) {
198 11
            static::reportInvalidArgument(\sprintf(
199 11
                $message ?: 'Expected a scalar. Got: %s',
200 11
                static::typeToString($value)
201
            ));
202
        }
203 12
    }
204
205
    /**
206
     * @psalm-pure
207
     * @psalm-assert object $value
208
     *
209
     * @param mixed  $value
210
     * @param string $message
211
     *
212
     * @throws InvalidArgumentException
213
     */
214 23
    public static function object($value, $message = '')
215
    {
216 23
        if (!\is_object($value)) {
217 15
            static::reportInvalidArgument(\sprintf(
218 15
                $message ?: 'Expected an object. Got: %s',
219 15
                static::typeToString($value)
220
            ));
221
        }
222 8
    }
223
224
    /**
225
     * @psalm-pure
226
     * @psalm-assert resource $value
227
     *
228
     * @param mixed       $value
229
     * @param string|null $type    type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php
230
     * @param string      $message
231
     *
232
     * @throws InvalidArgumentException
233
     */
234 16
    public static function resource($value, $type = null, $message = '')
235
    {
236 16
        if (!\is_resource($value)) {
237 4
            static::reportInvalidArgument(\sprintf(
238 4
                $message ?: 'Expected a resource. Got: %s',
239 4
                static::typeToString($value)
240
            ));
241
        }
242
243 12
        if ($type && $type !== \get_resource_type($value)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $type of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
244 4
            static::reportInvalidArgument(\sprintf(
245 4
                $message ?: 'Expected a resource of type %2$s. Got: %s',
246 4
                static::typeToString($value),
247 4
                $type
248
            ));
249
        }
250 8
    }
251
252
    /**
253
     * @psalm-pure
254
     * @psalm-assert callable $value
255
     *
256
     * @param mixed  $value
257
     * @param string $message
258
     *
259
     * @throws InvalidArgumentException
260
     */
261 20
    public static function isCallable($value, $message = '')
262
    {
263 20
        if (!\is_callable($value)) {
264 8
            static::reportInvalidArgument(\sprintf(
265 8
                $message ?: 'Expected a callable. Got: %s',
266 8
                static::typeToString($value)
267
            ));
268
        }
269 12
    }
270
271
    /**
272
     * @psalm-pure
273
     * @psalm-assert array $value
274
     *
275
     * @param mixed  $value
276
     * @param string $message
277
     *
278
     * @throws InvalidArgumentException
279
     */
280 20
    public static function isArray($value, $message = '')
281
    {
282 20
        if (!\is_array($value)) {
283 12
            static::reportInvalidArgument(\sprintf(
284 12
                $message ?: 'Expected an array. Got: %s',
285 12
                static::typeToString($value)
286
            ));
287
        }
288 8
    }
289
290
    /**
291
     * @psalm-pure
292
     * @psalm-assert iterable $value
293
     *
294
     * @deprecated use "isIterable" or "isInstanceOf" instead
295
     *
296
     * @param mixed  $value
297
     * @param string $message
298
     *
299
     * @throws InvalidArgumentException
300
     */
301 20
    public static function isTraversable($value, $message = '')
302
    {
303 20
        @\trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
304 20
            \sprintf(
305 20
                'The "%s" assertion is deprecated. You should stop using it, as it will soon be removed in 2.0 version. Use "isIterable" or "isInstanceOf" instead.',
306 20
                __METHOD__
307
            ),
308 20
            \E_USER_DEPRECATED
309
        );
310
311 20
        if (!\is_array($value) && !($value instanceof Traversable)) {
312 8
            static::reportInvalidArgument(\sprintf(
313 8
                $message ?: 'Expected a traversable. Got: %s',
314 8
                static::typeToString($value)
315
            ));
316
        }
317 12
    }
318
319
    /**
320
     * @psalm-pure
321
     * @psalm-assert array|ArrayAccess $value
322
     *
323
     * @param mixed  $value
324
     * @param string $message
325
     *
326
     * @throws InvalidArgumentException
327
     */
328 20 View Code Duplication
    public static function isArrayAccessible($value, $message = '')
329
    {
330 20
        if (!\is_array($value) && !($value instanceof ArrayAccess)) {
331 8
            static::reportInvalidArgument(\sprintf(
332 8
                $message ?: 'Expected an array accessible. Got: %s',
333 8
                static::typeToString($value)
334
            ));
335
        }
336 12
    }
337
338
    /**
339
     * @psalm-pure
340
     * @psalm-assert countable $value
341
     *
342
     * @param mixed  $value
343
     * @param string $message
344
     *
345
     * @throws InvalidArgumentException
346
     */
347 28
    public static function isCountable($value, $message = '')
348
    {
349
        if (
350 28
            !\is_array($value)
351 28
            && !($value instanceof Countable)
352 28
            && !($value instanceof ResourceBundle)
0 ignored issues
show
Bug introduced by
The class ResourceBundle does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
353 28
            && !($value instanceof SimpleXMLElement)
354
        ) {
355 12
            static::reportInvalidArgument(\sprintf(
356 12
                $message ?: 'Expected a countable. Got: %s',
357 12
                static::typeToString($value)
358
            ));
359
        }
360 16
    }
361
362
    /**
363
     * @psalm-pure
364
     * @psalm-assert iterable $value
365
     *
366
     * @param mixed  $value
367
     * @param string $message
368
     *
369
     * @throws InvalidArgumentException
370
     */
371 1074 View Code Duplication
    public static function isIterable($value, $message = '')
372
    {
373 1074
        if (!\is_array($value) && !($value instanceof Traversable)) {
374 8
            static::reportInvalidArgument(\sprintf(
375 8
                $message ?: 'Expected an iterable. Got: %s',
376 8
                static::typeToString($value)
377
            ));
378
        }
379 1070
    }
380
381
    /**
382
     * @psalm-pure
383
     * @psalm-template ExpectedType of object
384
     * @psalm-param class-string<ExpectedType> $class
385
     * @psalm-assert ExpectedType $value
386
     *
387
     * @param mixed         $value
388
     * @param string|object $class
389
     * @param string        $message
390
     *
391
     * @throws InvalidArgumentException
392
     */
393 19
    public static function isInstanceOf($value, $class, $message = '')
394
    {
395 19
        if (!($value instanceof $class)) {
396 15
            static::reportInvalidArgument(\sprintf(
397 15
                $message ?: 'Expected an instance of %2$s. Got: %s',
398 15
                static::typeToString($value),
399 15
                $class
400
            ));
401
        }
402 4
    }
403
404
    /**
405
     * @psalm-pure
406
     * @psalm-template ExpectedType of object
407
     * @psalm-param class-string<ExpectedType> $class
408
     * @psalm-assert !ExpectedType $value
409
     *
410
     * @param mixed         $value
411
     * @param string|object $class
412
     * @param string        $message
413
     *
414
     * @throws InvalidArgumentException
415
     */
416 16
    public static function notInstanceOf($value, $class, $message = '')
417
    {
418 16
        if ($value instanceof $class) {
419 4
            static::reportInvalidArgument(\sprintf(
420 4
                $message ?: 'Expected an instance other than %2$s. Got: %s',
421 4
                static::typeToString($value),
422 4
                $class
423
            ));
424
        }
425 12
    }
426
427
    /**
428
     * @psalm-pure
429
     * @psalm-param array<class-string> $classes
430
     *
431
     * @param mixed                $value
432
     * @param array<object|string> $classes
433
     * @param string               $message
434
     *
435
     * @throws InvalidArgumentException
436
     */
437 20
    public static function isInstanceOfAny($value, array $classes, $message = '')
438
    {
439 20
        foreach ($classes as $class) {
440 20
            if ($value instanceof $class) {
441 8
                return;
442
            }
443
        }
444
445 12
        static::reportInvalidArgument(\sprintf(
446 12
            $message ?: 'Expected an instance of any of %2$s. Got: %s',
447 12
            static::typeToString($value),
448 12
            \implode(', ', \array_map(array('static', 'valueToString'), $classes))
449
        ));
450
    }
451
452
    /**
453
     * @psalm-pure
454
     * @psalm-template ExpectedType of object
455
     * @psalm-param class-string<ExpectedType> $class
456
     * @psalm-assert ExpectedType|class-string<ExpectedType> $value
457
     *
458
     * @param object|string $value
459
     * @param string        $class
460
     * @param string        $message
461
     *
462
     * @throws InvalidArgumentException
463
     */
464 20 View Code Duplication
    public static function isAOf($value, $class, $message = '')
465
    {
466 20
        static::string($class, 'Expected class as a string. Got: %s');
467
468 16
        if (!\is_a($value, $class, \is_string($value))) {
469 12
            static::reportInvalidArgument(sprintf(
470 12
                $message ?: 'Expected an instance of this class or to this class among his parents %2$s. Got: %s',
471 12
                static::typeToString($value),
472
                $class
473
            ));
474
        }
475 4
    }
476
477
    /**
478
     * @psalm-pure
479
     * @psalm-template UnexpectedType of object
480
     * @psalm-param class-string<UnexpectedType> $class
481
     * @psalm-assert !UnexpectedType $value
482
     * @psalm-assert !class-string<UnexpectedType> $value
483
     *
484
     * @param object|string $value
485
     * @param string        $class
486
     * @param string        $message
487
     *
488
     * @throws InvalidArgumentException
489
     */
490 20 View Code Duplication
    public static function isNotA($value, $class, $message = '')
491
    {
492 20
        static::string($class, 'Expected class as a string. Got: %s');
493
494 16
        if (\is_a($value, $class, \is_string($value))) {
495 4
            static::reportInvalidArgument(sprintf(
496 4
                $message ?: 'Expected an instance of this class or to this class among his parents other than %2$s. Got: %s',
497 4
                static::typeToString($value),
498
                $class
499
            ));
500
        }
501 12
    }
502
503
    /**
504
     * @psalm-pure
505
     * @psalm-param array<class-string> $classes
506
     *
507
     * @param object|string $value
508
     * @param string[]      $classes
509
     * @param string        $message
510
     *
511
     * @throws InvalidArgumentException
512
     */
513 24
    public static function isAnyOf($value, array $classes, $message = '')
514
    {
515 24
        foreach ($classes as $class) {
516 24
            static::string($class, 'Expected class as a string. Got: %s');
517
518 20
            if (\is_a($value, $class, \is_string($value))) {
519 8
                return;
520
            }
521
        }
522
523 12
        static::reportInvalidArgument(sprintf(
524 12
            $message ?: 'Expected an any of instance of this class or to this class among his parents other than %2$s. Got: %s',
525 12
            static::typeToString($value),
526 12
            \implode(', ', \array_map(array('static', 'valueToString'), $classes))
527
        ));
528
    }
529
530
    /**
531
     * @psalm-pure
532
     * @psalm-assert empty $value
533
     *
534
     * @param mixed  $value
535
     * @param string $message
536
     *
537
     * @throws InvalidArgumentException
538
     */
539 23
    public static function isEmpty($value, $message = '')
540
    {
541 23
        if (!empty($value)) {
542 8
            static::reportInvalidArgument(\sprintf(
543 8
                $message ?: 'Expected an empty value. Got: %s',
544 8
                static::valueToString($value)
545
            ));
546
        }
547 15
    }
548
549
    /**
550
     * @psalm-pure
551
     * @psalm-assert !empty $value
552
     *
553
     * @param mixed  $value
554
     * @param string $message
555
     *
556
     * @throws InvalidArgumentException
557
     */
558 55
    public static function notEmpty($value, $message = '')
559
    {
560 55
        if (empty($value)) {
561 23
            static::reportInvalidArgument(\sprintf(
562 23
                $message ?: 'Expected a non-empty value. Got: %s',
563 23
                static::valueToString($value)
564
            ));
565
        }
566 32
    }
567
568
    /**
569
     * @psalm-pure
570
     * @psalm-assert null $value
571
     *
572
     * @param mixed  $value
573
     * @param string $message
574
     *
575
     * @throws InvalidArgumentException
576
     */
577 11
    public static function null($value, $message = '')
578
    {
579 11
        if (null !== $value) {
580 8
            static::reportInvalidArgument(\sprintf(
581 8
                $message ?: 'Expected null. Got: %s',
582 8
                static::valueToString($value)
583
            ));
584
        }
585 3
    }
586
587
    /**
588
     * @psalm-pure
589
     * @psalm-assert !null $value
590
     *
591
     * @param mixed  $value
592
     * @param string $message
593
     *
594
     * @throws InvalidArgumentException
595
     */
596 11
    public static function notNull($value, $message = '')
597
    {
598 11
        if (null === $value) {
599 3
            static::reportInvalidArgument(
600 3
                $message ?: 'Expected a value other than null.'
601
            );
602
        }
603 8
    }
604
605
    /**
606
     * @psalm-pure
607
     * @psalm-assert true $value
608
     *
609
     * @param mixed  $value
610
     * @param string $message
611
     *
612
     * @throws InvalidArgumentException
613
     */
614 15
    public static function true($value, $message = '')
615
    {
616 15
        if (true !== $value) {
617 11
            static::reportInvalidArgument(\sprintf(
618 11
                $message ?: 'Expected a value to be true. Got: %s',
619 11
                static::valueToString($value)
620
            ));
621
        }
622 4
    }
623
624
    /**
625
     * @psalm-pure
626
     * @psalm-assert false $value
627
     *
628
     * @param mixed  $value
629
     * @param string $message
630
     *
631
     * @throws InvalidArgumentException
632
     */
633 19
    public static function false($value, $message = '')
634
    {
635 19
        if (false !== $value) {
636 15
            static::reportInvalidArgument(\sprintf(
637 15
                $message ?: 'Expected a value to be false. Got: %s',
638 15
                static::valueToString($value)
639
            ));
640
        }
641 4
    }
642
643
    /**
644
     * @psalm-pure
645
     * @psalm-assert !false $value
646
     *
647
     * @param mixed  $value
648
     * @param string $message
649
     *
650
     * @throws InvalidArgumentException
651
     */
652 19
    public static function notFalse($value, $message = '')
653
    {
654 19
        if (false === $value) {
655 4
            static::reportInvalidArgument(
656 4
                $message ?: 'Expected a value other than false.'
657
            );
658
        }
659 15
    }
660
661
    /**
662
     * @param mixed  $value
663
     * @param string $message
664
     *
665
     * @throws InvalidArgumentException
666
     */
667 51 View Code Duplication
    public static function ip($value, $message = '')
668
    {
669 51
        if (false === \filter_var($value, \FILTER_VALIDATE_IP)) {
670 19
            static::reportInvalidArgument(\sprintf(
671 19
                $message ?: 'Expected a value to be an IP. Got: %s',
672 19
                static::valueToString($value)
673
            ));
674
        }
675 32
    }
676
677
    /**
678
     * @param mixed  $value
679
     * @param string $message
680
     *
681
     * @throws InvalidArgumentException
682
     */
683 51 View Code Duplication
    public static function ipv4($value, $message = '')
684
    {
685 51
        if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
686 35
            static::reportInvalidArgument(\sprintf(
687 35
                $message ?: 'Expected a value to be an IPv4. Got: %s',
688 35
                static::valueToString($value)
689
            ));
690
        }
691 16
    }
692
693
    /**
694
     * @param mixed  $value
695
     * @param string $message
696
     *
697
     * @throws InvalidArgumentException
698
     */
699 51 View Code Duplication
    public static function ipv6($value, $message = '')
700
    {
701 51
        if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
702 31
            static::reportInvalidArgument(\sprintf(
703 31
                $message ?: 'Expected a value to be an IPv6. Got: %s',
704 31
                static::valueToString($value)
705
            ));
706
        }
707 20
    }
708
709
    /**
710
     * @psalm-pure
711
     *
712
     * @param mixed  $value
713
     * @param string $message
714
     *
715
     * @throws InvalidArgumentException
716
     */
717 60 View Code Duplication
    public static function url($value, $message = '')
718
    {
719 60
        if (false === \filter_var($value, FILTER_VALIDATE_URL)) {
720 28
            static::reportInvalidArgument(\sprintf(
721 28
                $message ?: 'Expected a value to be a valid URL. Got %s',
722 28
                static::valueToString($value)
723
            ));
724
        }
725 32
    }
726
727
    /**
728
     * @param mixed  $value
729
     * @param string $message
730
     *
731
     * @throws InvalidArgumentException
732
     */
733 20 View Code Duplication
    public static function email($value, $message = '')
734
    {
735 20
        if (false === \filter_var($value, FILTER_VALIDATE_EMAIL)) {
736 12
            static::reportInvalidArgument(\sprintf(
737 12
                $message ?: 'Expected a value to be a valid e-mail address. Got: %s',
738 12
                static::valueToString($value)
739
            ));
740
        }
741 8
    }
742
743
    /**
744
     * Does non strict comparisons on the items, so ['3', 3] will not pass the assertion.
745
     *
746
     * @param array  $values
747
     * @param string $message
748
     *
749
     * @throws InvalidArgumentException
750
     */
751 12
    public static function uniqueValues(array $values, $message = '')
752
    {
753 12
        $allValues = \count($values);
754 12
        $uniqueValues = \count(\array_unique($values));
755
756 12
        if ($allValues !== $uniqueValues) {
757 8
            $difference = $allValues - $uniqueValues;
758
759 8
            static::reportInvalidArgument(\sprintf(
760 8
                $message ?: 'Expected an array of unique values, but %s of them %s duplicated',
761 8
                $difference,
762 8
                (1 === $difference ? 'is' : 'are')
763
            ));
764
        }
765 4
    }
766
767
    /**
768
     * @param mixed  $value
769
     * @param mixed  $expect
770
     * @param string $message
771
     *
772
     * @throws InvalidArgumentException
773
     */
774 33
    public static function eq($value, $expect, $message = '')
775
    {
776 33
        if ($expect != $value) {
777 17
            static::reportInvalidArgument(\sprintf(
778 17
                $message ?: 'Expected a value equal to %2$s. Got: %s',
779 17
                static::valueToString($value),
780 17
                static::valueToString($expect)
781
            ));
782
        }
783 16
    }
784
785
    /**
786
     * @param mixed  $value
787
     * @param mixed  $expect
788
     * @param string $message
789
     *
790
     * @throws InvalidArgumentException
791
     */
792 28
    public static function notEq($value, $expect, $message = '')
793
    {
794 28
        if ($expect == $value) {
795 16
            static::reportInvalidArgument(\sprintf(
796 16
                $message ?: 'Expected a different value than %s.',
797 16
                static::valueToString($expect)
798
            ));
799
        }
800 12
    }
801
802
    /**
803
     * @psalm-pure
804
     *
805
     * @param mixed  $value
806
     * @param mixed  $expect
807
     * @param string $message
808
     *
809
     * @throws InvalidArgumentException
810
     */
811 16
    public static function same($value, $expect, $message = '')
812
    {
813 16
        if ($expect !== $value) {
814 12
            static::reportInvalidArgument(\sprintf(
815 12
                $message ?: 'Expected a value identical to %2$s. Got: %s',
816 12
                static::valueToString($value),
817 12
                static::valueToString($expect)
818
            ));
819
        }
820 4
    }
821
822
    /**
823
     * @psalm-pure
824
     *
825
     * @param mixed  $value
826
     * @param mixed  $expect
827
     * @param string $message
828
     *
829
     * @throws InvalidArgumentException
830
     */
831 16
    public static function notSame($value, $expect, $message = '')
832
    {
833 16
        if ($expect === $value) {
834 4
            static::reportInvalidArgument(\sprintf(
835 4
                $message ?: 'Expected a value not identical to %s.',
836 4
                static::valueToString($expect)
837
            ));
838
        }
839 12
    }
840
841
    /**
842
     * @psalm-pure
843
     *
844
     * @param mixed  $value
845
     * @param mixed  $limit
846
     * @param string $message
847
     *
848
     * @throws InvalidArgumentException
849
     */
850 8
    public static function greaterThan($value, $limit, $message = '')
851
    {
852 8
        if ($value <= $limit) {
853 4
            static::reportInvalidArgument(\sprintf(
854 4
                $message ?: 'Expected a value greater than %2$s. Got: %s',
855 4
                static::valueToString($value),
856 4
                static::valueToString($limit)
857
            ));
858
        }
859 4
    }
860
861
    /**
862
     * @psalm-pure
863
     *
864
     * @param mixed  $value
865
     * @param mixed  $limit
866
     * @param string $message
867
     *
868
     * @throws InvalidArgumentException
869
     */
870 12
    public static function greaterThanEq($value, $limit, $message = '')
871
    {
872 12
        if ($value < $limit) {
873 4
            static::reportInvalidArgument(\sprintf(
874 4
                $message ?: 'Expected a value greater than or equal to %2$s. Got: %s',
875 4
                static::valueToString($value),
876 4
                static::valueToString($limit)
877
            ));
878
        }
879 8
    }
880
881
    /**
882
     * @psalm-pure
883
     *
884
     * @param mixed  $value
885
     * @param mixed  $limit
886
     * @param string $message
887
     *
888
     * @throws InvalidArgumentException
889
     */
890 9
    public static function lessThan($value, $limit, $message = '')
891
    {
892 9
        if ($value >= $limit) {
893 5
            static::reportInvalidArgument(\sprintf(
894 5
                $message ?: 'Expected a value less than %2$s. Got: %s',
895 5
                static::valueToString($value),
896 5
                static::valueToString($limit)
897
            ));
898
        }
899 4
    }
900
901
    /**
902
     * @psalm-pure
903
     *
904
     * @param mixed  $value
905
     * @param mixed  $limit
906
     * @param string $message
907
     *
908
     * @throws InvalidArgumentException
909
     */
910 12
    public static function lessThanEq($value, $limit, $message = '')
911
    {
912 12
        if ($value > $limit) {
913 4
            static::reportInvalidArgument(\sprintf(
914 4
                $message ?: 'Expected a value less than or equal to %2$s. Got: %s',
915 4
                static::valueToString($value),
916 4
                static::valueToString($limit)
917
            ));
918
        }
919 8
    }
920
921
    /**
922
     * Inclusive range, so Assert::(3, 3, 5) passes.
923
     *
924
     * @psalm-pure
925
     *
926
     * @param mixed  $value
927
     * @param mixed  $min
928
     * @param mixed  $max
929
     * @param string $message
930
     *
931
     * @throws InvalidArgumentException
932
     */
933 16 View Code Duplication
    public static function range($value, $min, $max, $message = '')
934
    {
935 16
        if ($value < $min || $value > $max) {
936 8
            static::reportInvalidArgument(\sprintf(
937 8
                $message ?: 'Expected a value between %2$s and %3$s. Got: %s',
938 8
                static::valueToString($value),
939 8
                static::valueToString($min),
940 8
                static::valueToString($max)
941
            ));
942
        }
943 8
    }
944
945
    /**
946
     * A more human-readable alias of Assert::inArray().
947
     *
948
     * @psalm-pure
949
     *
950
     * @param mixed  $value
951
     * @param array  $values
952
     * @param string $message
953
     *
954
     * @throws InvalidArgumentException
955
     */
956 8
    public static function oneOf($value, array $values, $message = '')
957
    {
958 8
        static::inArray($value, $values, $message);
959 4
    }
960
961
    /**
962
     * Does strict comparison, so Assert::inArray(3, ['3']) does not pass the assertion.
963
     *
964
     * @psalm-pure
965
     *
966
     * @param mixed  $value
967
     * @param array  $values
968
     * @param string $message
969
     *
970
     * @throws InvalidArgumentException
971
     */
972 16
    public static function inArray($value, array $values, $message = '')
973
    {
974 16
        if (!\in_array($value, $values, true)) {
975 8
            static::reportInvalidArgument(\sprintf(
976 8
                $message ?: 'Expected one of: %2$s. Got: %s',
977 8
                static::valueToString($value),
978 8
                \implode(', ', \array_map(array('static', 'valueToString'), $values))
979
            ));
980
        }
981 8
    }
982
983
    /**
984
     * @psalm-pure
985
     *
986
     * @param string $value
987
     * @param string $subString
988
     * @param string $message
989
     *
990
     * @throws InvalidArgumentException
991
     */
992 80 View Code Duplication
    public static function contains($value, $subString, $message = '')
993
    {
994 80
        if (false === \strpos($value, $subString)) {
995 32
            static::reportInvalidArgument(\sprintf(
996 32
                $message ?: 'Expected a value to contain %2$s. Got: %s',
997 32
                static::valueToString($value),
998 32
                static::valueToString($subString)
999
            ));
1000
        }
1001 48
    }
1002
1003
    /**
1004
     * @psalm-pure
1005
     *
1006
     * @param string $value
1007
     * @param string $subString
1008
     * @param string $message
1009
     *
1010
     * @throws InvalidArgumentException
1011
     */
1012 80 View Code Duplication
    public static function notContains($value, $subString, $message = '')
1013
    {
1014 80
        if (false !== \strpos($value, $subString)) {
1015 48
            static::reportInvalidArgument(\sprintf(
1016 48
                $message ?: '%2$s was not expected to be contained in a value. Got: %s',
1017 48
                static::valueToString($value),
1018 48
                static::valueToString($subString)
1019
            ));
1020
        }
1021 32
    }
1022
1023
    /**
1024
     * @psalm-pure
1025
     *
1026
     * @param mixed $value
1027
     * @param string $message
1028
     *
1029
     * @throws InvalidArgumentException
1030
     */
1031 40
    public static function notWhitespaceOnly($value, $message = '')
1032
    {
1033 40
        if (\preg_match('/^\s*$/', $value)) {
1034 24
            static::reportInvalidArgument(\sprintf(
1035 24
                $message ?: 'Expected a non-whitespace string. Got: %s',
1036 24
                static::valueToString($value)
1037
            ));
1038
        }
1039 16
    }
1040
1041
    /**
1042
     * @psalm-pure
1043
     *
1044
     * @param string $value
1045
     * @param string $prefix
1046
     * @param string $message
1047
     *
1048
     * @throws InvalidArgumentException
1049
     */
1050 48 View Code Duplication
    public static function startsWith($value, $prefix, $message = '')
1051
    {
1052 48
        if (0 !== \strpos($value, $prefix)) {
1053 32
            static::reportInvalidArgument(\sprintf(
1054 32
                $message ?: 'Expected a value to start with %2$s. Got: %s',
1055 32
                static::valueToString($value),
1056 32
                static::valueToString($prefix)
1057
            ));
1058
        }
1059 16
    }
1060
1061
    /**
1062
     * @psalm-pure
1063
     *
1064
     * @param string $value
1065
     * @param string $prefix
1066
     * @param string $message
1067
     *
1068
     * @throws InvalidArgumentException
1069
     */
1070 48 View Code Duplication
    public static function notStartsWith($value, $prefix, $message = '')
1071
    {
1072 48
        if (0 === \strpos($value, $prefix)) {
1073 16
            static::reportInvalidArgument(\sprintf(
1074 16
                $message ?: 'Expected a value not to start with %2$s. Got: %s',
1075 16
                static::valueToString($value),
1076 16
                static::valueToString($prefix)
1077
            ));
1078
        }
1079 32
    }
1080
1081
    /**
1082
     * @psalm-pure
1083
     *
1084
     * @param mixed  $value
1085
     * @param string $message
1086
     *
1087
     * @throws InvalidArgumentException
1088
     */
1089 35
    public static function startsWithLetter($value, $message = '')
1090
    {
1091 35
        static::string($value);
1092
1093 24
        $valid = isset($value[0]);
1094
1095 24
        if ($valid) {
1096 20
            $locale = \setlocale(LC_CTYPE, 0);
1097 20
            \setlocale(LC_CTYPE, 'C');
1098 20
            $valid = \ctype_alpha($value[0]);
1099 20
            \setlocale(LC_CTYPE, $locale);
1100
        }
1101
1102 24
        if (!$valid) {
1103 12
            static::reportInvalidArgument(\sprintf(
1104 12
                $message ?: 'Expected a value to start with a letter. Got: %s',
1105 12
                static::valueToString($value)
1106
            ));
1107
        }
1108 12
    }
1109
1110
    /**
1111
     * @psalm-pure
1112
     *
1113
     * @param string $value
1114
     * @param string $suffix
1115
     * @param string $message
1116
     *
1117
     * @throws InvalidArgumentException
1118
     */
1119 48 View Code Duplication
    public static function endsWith($value, $suffix, $message = '')
1120
    {
1121 48
        if ($suffix !== \substr($value, -\strlen($suffix))) {
1122 32
            static::reportInvalidArgument(\sprintf(
1123 32
                $message ?: 'Expected a value to end with %2$s. Got: %s',
1124 32
                static::valueToString($value),
1125 32
                static::valueToString($suffix)
1126
            ));
1127
        }
1128 16
    }
1129
1130
    /**
1131
     * @psalm-pure
1132
     *
1133
     * @param string $value
1134
     * @param string $suffix
1135
     * @param string $message
1136
     *
1137
     * @throws InvalidArgumentException
1138
     */
1139 48 View Code Duplication
    public static function notEndsWith($value, $suffix, $message = '')
1140
    {
1141 48
        if ($suffix === \substr($value, -\strlen($suffix))) {
1142 16
            static::reportInvalidArgument(\sprintf(
1143 16
                $message ?: 'Expected a value not to end with %2$s. Got: %s',
1144 16
                static::valueToString($value),
1145 16
                static::valueToString($suffix)
1146
            ));
1147
        }
1148 32
    }
1149
1150
    /**
1151
     * @psalm-pure
1152
     *
1153
     * @param string $value
1154
     * @param string $pattern
1155
     * @param string $message
1156
     *
1157
     * @throws InvalidArgumentException
1158
     */
1159 12
    public static function regex($value, $pattern, $message = '')
1160
    {
1161 12
        if (!\preg_match($pattern, $value)) {
1162 8
            static::reportInvalidArgument(\sprintf(
1163 8
                $message ?: 'The value %s does not match the expected pattern.',
1164 8
                static::valueToString($value)
1165
            ));
1166
        }
1167 4
    }
1168
1169
    /**
1170
     * @psalm-pure
1171
     *
1172
     * @param string $value
1173
     * @param string $pattern
1174
     * @param string $message
1175
     *
1176
     * @throws InvalidArgumentException
1177
     */
1178 12
    public static function notRegex($value, $pattern, $message = '')
1179
    {
1180 12
        if (\preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
1181 4
            static::reportInvalidArgument(\sprintf(
1182 4
                $message ?: 'The value %s matches the pattern %s (at offset %d).',
1183 4
                static::valueToString($value),
1184 4
                static::valueToString($pattern),
1185 4
                $matches[0][1]
1186
            ));
1187
        }
1188 8
    }
1189
1190
    /**
1191
     * @psalm-pure
1192
     *
1193
     * @param mixed  $value
1194
     * @param string $message
1195
     *
1196
     * @throws InvalidArgumentException
1197
     */
1198 28 View Code Duplication
    public static function unicodeLetters($value, $message = '')
1199
    {
1200 28
        static::string($value);
1201
1202 28
        if (!\preg_match('/^\p{L}+$/u', $value)) {
1203 16
            static::reportInvalidArgument(\sprintf(
1204 16
                $message ?: 'Expected a value to contain only Unicode letters. Got: %s',
1205 16
                static::valueToString($value)
1206
            ));
1207
        }
1208 12
    }
1209
1210
    /**
1211
     * @psalm-pure
1212
     *
1213
     * @param mixed  $value
1214
     * @param string $message
1215
     *
1216
     * @throws InvalidArgumentException
1217
     */
1218 20 View Code Duplication
    public static function alpha($value, $message = '')
1219
    {
1220 20
        static::string($value);
1221
1222 12
        $locale = \setlocale(LC_CTYPE, 0);
1223 12
        \setlocale(LC_CTYPE, 'C');
1224 12
        $valid = !\ctype_alpha($value);
1225 12
        \setlocale(LC_CTYPE, $locale);
1226
1227 12
        if ($valid) {
1228 8
            static::reportInvalidArgument(\sprintf(
1229 8
                $message ?: 'Expected a value to contain only letters. Got: %s',
1230 8
                static::valueToString($value)
1231
            ));
1232
        }
1233 4
    }
1234
1235
    /**
1236
     * @psalm-pure
1237
     *
1238
     * @param string $value
1239
     * @param string $message
1240
     *
1241
     * @throws InvalidArgumentException
1242
     */
1243 12 View Code Duplication
    public static function digits($value, $message = '')
1244
    {
1245 12
        $locale = \setlocale(LC_CTYPE, 0);
1246 12
        \setlocale(LC_CTYPE, 'C');
1247 12
        $valid = !\ctype_digit($value);
1248 12
        \setlocale(LC_CTYPE, $locale);
1249
1250 12
        if ($valid) {
1251 8
            static::reportInvalidArgument(\sprintf(
1252 8
                $message ?: 'Expected a value to contain digits only. Got: %s',
1253 8
                static::valueToString($value)
1254
            ));
1255
        }
1256 4
    }
1257
1258
    /**
1259
     * @psalm-pure
1260
     *
1261
     * @param string $value
1262
     * @param string $message
1263
     *
1264
     * @throws InvalidArgumentException
1265
     */
1266 12 View Code Duplication
    public static function alnum($value, $message = '')
1267
    {
1268 12
        $locale = \setlocale(LC_CTYPE, 0);
1269 12
        \setlocale(LC_CTYPE, 'C');
1270 12
        $valid = !\ctype_alnum($value);
1271 12
        \setlocale(LC_CTYPE, $locale);
1272
1273 12
        if ($valid) {
1274 8
            static::reportInvalidArgument(\sprintf(
1275 8
                $message ?: 'Expected a value to contain letters and digits only. Got: %s',
1276 8
                static::valueToString($value)
1277
            ));
1278
        }
1279 4
    }
1280
1281
    /**
1282
     * @psalm-pure
1283
     * @psalm-assert lowercase-string $value
1284
     *
1285
     * @param string $value
1286
     * @param string $message
1287
     *
1288
     * @throws InvalidArgumentException
1289
     */
1290 16 View Code Duplication
    public static function lower($value, $message = '')
1291
    {
1292 16
        $locale = \setlocale(LC_CTYPE, 0);
1293 16
        \setlocale(LC_CTYPE, 'C');
1294 16
        $valid = !\ctype_lower($value);
1295 16
        \setlocale(LC_CTYPE, $locale);
1296
1297 16
        if ($valid) {
1298 12
            static::reportInvalidArgument(\sprintf(
1299 12
                $message ?: 'Expected a value to contain lowercase characters only. Got: %s',
1300 12
                static::valueToString($value)
1301
            ));
1302
        }
1303 4
    }
1304
1305
    /**
1306
     * @psalm-pure
1307
     * @psalm-assert !lowercase-string $value
1308
     *
1309
     * @param string $value
1310
     * @param string $message
1311
     *
1312
     * @throws InvalidArgumentException
1313
     */
1314 16 View Code Duplication
    public static function upper($value, $message = '')
1315
    {
1316 16
        $locale = \setlocale(LC_CTYPE, 0);
1317 16
        \setlocale(LC_CTYPE, 'C');
1318 16
        $valid = !\ctype_upper($value);
1319 16
        \setlocale(LC_CTYPE, $locale);
1320
1321 16
        if ($valid) {
1322 12
            static::reportInvalidArgument(\sprintf(
1323 12
                $message ?: 'Expected a value to contain uppercase characters only. Got: %s',
1324 12
                static::valueToString($value)
1325
            ));
1326
        }
1327 4
    }
1328
1329
    /**
1330
     * @psalm-pure
1331
     *
1332
     * @param string $value
1333
     * @param int    $length
1334
     * @param string $message
1335
     *
1336
     * @throws InvalidArgumentException
1337
     */
1338 36
    public static function length($value, $length, $message = '')
1339
    {
1340 36
        if ($length !== static::strlen($value)) {
1341 24
            static::reportInvalidArgument(\sprintf(
1342 24
                $message ?: 'Expected a value to contain %2$s characters. Got: %s',
1343 24
                static::valueToString($value),
1344 24
                $length
1345
            ));
1346
        }
1347 12
    }
1348
1349
    /**
1350
     * Inclusive min.
1351
     *
1352
     * @psalm-pure
1353
     *
1354
     * @param string    $value
1355
     * @param int|float $min
1356
     * @param string    $message
1357
     *
1358
     * @throws InvalidArgumentException
1359
     */
1360 36
    public static function minLength($value, $min, $message = '')
1361
    {
1362 36
        if (static::strlen($value) < $min) {
1363 12
            static::reportInvalidArgument(\sprintf(
1364 12
                $message ?: 'Expected a value to contain at least %2$s characters. Got: %s',
1365 12
                static::valueToString($value),
1366 12
                $min
1367
            ));
1368
        }
1369 24
    }
1370
1371
    /**
1372
     * Inclusive max.
1373
     *
1374
     * @psalm-pure
1375
     *
1376
     * @param string    $value
1377
     * @param int|float $max
1378
     * @param string    $message
1379
     *
1380
     * @throws InvalidArgumentException
1381
     */
1382 36
    public static function maxLength($value, $max, $message = '')
1383
    {
1384 36
        if (static::strlen($value) > $max) {
1385 12
            static::reportInvalidArgument(\sprintf(
1386 12
                $message ?: 'Expected a value to contain at most %2$s characters. Got: %s',
1387 12
                static::valueToString($value),
1388 12
                $max
1389
            ));
1390
        }
1391 24
    }
1392
1393
    /**
1394
     * Inclusive , so Assert::lengthBetween('asd', 3, 5); passes the assertion.
1395
     *
1396
     * @psalm-pure
1397
     *
1398
     * @param string    $value
1399
     * @param int|float $min
1400
     * @param int|float $max
1401
     * @param string    $message
1402
     *
1403
     * @throws InvalidArgumentException
1404
     */
1405 60 View Code Duplication
    public static function lengthBetween($value, $min, $max, $message = '')
1406
    {
1407 60
        $length = static::strlen($value);
1408
1409 60
        if ($length < $min || $length > $max) {
1410 24
            static::reportInvalidArgument(\sprintf(
1411 24
                $message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s',
1412 24
                static::valueToString($value),
1413 24
                $min,
1414 24
                $max
1415
            ));
1416
        }
1417 36
    }
1418
1419
    /**
1420
     * Will also pass if $value is a directory, use Assert::file() instead if you need to be sure it is a file.
1421
     *
1422
     * @param mixed  $value
1423
     * @param string $message
1424
     *
1425
     * @throws InvalidArgumentException
1426
     */
1427 36 View Code Duplication
    public static function fileExists($value, $message = '')
1428
    {
1429 36
        static::string($value);
1430
1431 36
        if (!\file_exists($value)) {
1432 12
            static::reportInvalidArgument(\sprintf(
1433 12
                $message ?: 'The file %s does not exist.',
1434 12
                static::valueToString($value)
1435
            ));
1436
        }
1437 24
    }
1438
1439
    /**
1440
     * @param mixed  $value
1441
     * @param string $message
1442
     *
1443
     * @throws InvalidArgumentException
1444
     */
1445 12 View Code Duplication
    public static function file($value, $message = '')
1446
    {
1447 12
        static::fileExists($value, $message);
1448
1449 8
        if (!\is_file($value)) {
1450 4
            static::reportInvalidArgument(\sprintf(
1451 4
                $message ?: 'The path %s is not a file.',
1452 4
                static::valueToString($value)
1453
            ));
1454
        }
1455 4
    }
1456
1457
    /**
1458
     * @param mixed  $value
1459
     * @param string $message
1460
     *
1461
     * @throws InvalidArgumentException
1462
     */
1463 12 View Code Duplication
    public static function directory($value, $message = '')
1464
    {
1465 12
        static::fileExists($value, $message);
1466
1467 8
        if (!\is_dir($value)) {
1468 4
            static::reportInvalidArgument(\sprintf(
1469 4
                $message ?: 'The path %s is no directory.',
1470 4
                static::valueToString($value)
1471
            ));
1472
        }
1473 4
    }
1474
1475
    /**
1476
     * @param string $value
1477
     * @param string $message
1478
     *
1479
     * @throws InvalidArgumentException
1480
     */
1481
    public static function readable($value, $message = '')
1482
    {
1483
        if (!\is_readable($value)) {
1484
            static::reportInvalidArgument(\sprintf(
1485
                $message ?: 'The path %s is not readable.',
1486
                static::valueToString($value)
1487
            ));
1488
        }
1489
    }
1490
1491
    /**
1492
     * @param string $value
1493
     * @param string $message
1494
     *
1495
     * @throws InvalidArgumentException
1496
     */
1497
    public static function writable($value, $message = '')
1498
    {
1499
        if (!\is_writable($value)) {
1500
            static::reportInvalidArgument(\sprintf(
1501
                $message ?: 'The path %s is not writable.',
1502
                static::valueToString($value)
1503
            ));
1504
        }
1505
    }
1506
1507
    /**
1508
     * @psalm-assert class-string $value
1509
     *
1510
     * @param mixed  $value
1511
     * @param string $message
1512
     *
1513
     * @throws InvalidArgumentException
1514
     */
1515 8
    public static function classExists($value, $message = '')
1516
    {
1517 8
        if (!\class_exists($value)) {
1518 4
            static::reportInvalidArgument(\sprintf(
1519 4
                $message ?: 'Expected an existing class name. Got: %s',
1520 4
                static::valueToString($value)
1521
            ));
1522
        }
1523 4
    }
1524
1525
    /**
1526
     * @psalm-pure
1527
     * @psalm-template ExpectedType of object
1528
     * @psalm-param class-string<ExpectedType> $class
1529
     * @psalm-assert class-string<ExpectedType>|ExpectedType $value
1530
     *
1531
     * @param mixed         $value
1532
     * @param string|object $class
1533
     * @param string        $message
1534
     *
1535
     * @throws InvalidArgumentException
1536
     */
1537 8
    public static function subclassOf($value, $class, $message = '')
1538
    {
1539 8
        if (!\is_subclass_of($value, $class)) {
1540 4
            static::reportInvalidArgument(\sprintf(
1541 4
                $message ?: 'Expected a sub-class of %2$s. Got: %s',
1542 4
                static::valueToString($value),
1543 4
                static::valueToString($class)
1544
            ));
1545
        }
1546 4
    }
1547
1548
    /**
1549
     * @psalm-assert class-string $value
1550
     *
1551
     * @param mixed  $value
1552
     * @param string $message
1553
     *
1554
     * @throws InvalidArgumentException
1555
     */
1556 8
    public static function interfaceExists($value, $message = '')
1557
    {
1558 8
        if (!\interface_exists($value)) {
1559 4
            static::reportInvalidArgument(\sprintf(
1560 4
                $message ?: 'Expected an existing interface name. got %s',
1561 4
                static::valueToString($value)
1562
            ));
1563
        }
1564 4
    }
1565
1566
    /**
1567
     * @psalm-pure
1568
     * @psalm-template ExpectedType of object
1569
     * @psalm-param class-string<ExpectedType> $interface
1570
     * @psalm-assert class-string<ExpectedType> $value
1571
     *
1572
     * @param mixed  $value
1573
     * @param mixed  $interface
1574
     * @param string $message
1575
     *
1576
     * @throws InvalidArgumentException
1577
     */
1578 8 View Code Duplication
    public static function implementsInterface($value, $interface, $message = '')
1579
    {
1580 8
        if (!\in_array($interface, \class_implements($value))) {
1581 4
            static::reportInvalidArgument(\sprintf(
1582 4
                $message ?: 'Expected an implementation of %2$s. Got: %s',
1583 4
                static::valueToString($value),
1584 4
                static::valueToString($interface)
1585
            ));
1586
        }
1587 4
    }
1588
1589
    /**
1590
     * @psalm-pure
1591
     * @psalm-param class-string|object $classOrObject
1592
     *
1593
     * @param string|object $classOrObject
1594
     * @param mixed         $property
1595
     * @param string        $message
1596
     *
1597
     * @throws InvalidArgumentException
1598
     */
1599 12 View Code Duplication
    public static function propertyExists($classOrObject, $property, $message = '')
1600
    {
1601 12
        if (!\property_exists($classOrObject, $property)) {
1602 4
            static::reportInvalidArgument(\sprintf(
1603 4
                $message ?: 'Expected the property %s to exist.',
1604 4
                static::valueToString($property)
1605
            ));
1606
        }
1607 8
    }
1608
1609
    /**
1610
     * @psalm-pure
1611
     * @psalm-param class-string|object $classOrObject
1612
     *
1613
     * @param string|object $classOrObject
1614
     * @param mixed         $property
1615
     * @param string        $message
1616
     *
1617
     * @throws InvalidArgumentException
1618
     */
1619 12 View Code Duplication
    public static function propertyNotExists($classOrObject, $property, $message = '')
1620
    {
1621 12
        if (\property_exists($classOrObject, $property)) {
1622 8
            static::reportInvalidArgument(\sprintf(
1623 8
                $message ?: 'Expected the property %s to not exist.',
1624 8
                static::valueToString($property)
1625
            ));
1626
        }
1627 4
    }
1628
1629
    /**
1630
     * @psalm-pure
1631
     * @psalm-param class-string|object $classOrObject
1632
     *
1633
     * @param string|object $classOrObject
1634
     * @param mixed         $method
1635
     * @param string        $message
1636
     *
1637
     * @throws InvalidArgumentException
1638
     */
1639 27 View Code Duplication
    public static function methodExists($classOrObject, $method, $message = '')
1640
    {
1641 27
        if (!(\is_string($classOrObject) || \is_object($classOrObject)) || !\method_exists($classOrObject, $method)) {
1642 19
            static::reportInvalidArgument(\sprintf(
1643 19
                $message ?: 'Expected the method %s to exist.',
1644 19
                static::valueToString($method)
1645
            ));
1646
        }
1647 8
    }
1648
1649
    /**
1650
     * @psalm-pure
1651
     * @psalm-param class-string|object $classOrObject
1652
     *
1653
     * @param string|object $classOrObject
1654
     * @param mixed         $method
1655
     * @param string        $message
1656
     *
1657
     * @throws InvalidArgumentException
1658
     */
1659 27 View Code Duplication
    public static function methodNotExists($classOrObject, $method, $message = '')
1660
    {
1661 27
        if ((\is_string($classOrObject) || \is_object($classOrObject)) && \method_exists($classOrObject, $method)) {
1662 8
            static::reportInvalidArgument(\sprintf(
1663 8
                $message ?: 'Expected the method %s to not exist.',
1664 8
                static::valueToString($method)
1665
            ));
1666
        }
1667 19
    }
1668
1669
    /**
1670
     * @psalm-pure
1671
     *
1672
     * @param array      $array
1673
     * @param string|int $key
1674
     * @param string     $message
1675
     *
1676
     * @throws InvalidArgumentException
1677
     */
1678 12 View Code Duplication
    public static function keyExists($array, $key, $message = '')
1679
    {
1680 12
        if (!(isset($array[$key]) || \array_key_exists($key, $array))) {
1681 4
            static::reportInvalidArgument(\sprintf(
1682 4
                $message ?: 'Expected the key %s to exist.',
1683 4
                static::valueToString($key)
1684
            ));
1685
        }
1686 8
    }
1687
1688
    /**
1689
     * @psalm-pure
1690
     *
1691
     * @param array      $array
1692
     * @param string|int $key
1693
     * @param string     $message
1694
     *
1695
     * @throws InvalidArgumentException
1696
     */
1697 12 View Code Duplication
    public static function keyNotExists($array, $key, $message = '')
1698
    {
1699 12
        if (isset($array[$key]) || \array_key_exists($key, $array)) {
1700 8
            static::reportInvalidArgument(\sprintf(
1701 8
                $message ?: 'Expected the key %s to not exist.',
1702 8
                static::valueToString($key)
1703
            ));
1704
        }
1705 4
    }
1706
1707
    /**
1708
     * Checks if a value is a valid array key (int or string).
1709
     *
1710
     * @psalm-pure
1711
     * @psalm-assert array-key $value
1712
     *
1713
     * @param mixed  $value
1714
     * @param string $message
1715
     *
1716
     * @throws InvalidArgumentException
1717
     */
1718 28
    public static function validArrayKey($value, $message = '')
1719
    {
1720 28
        if (!(\is_int($value) || \is_string($value))) {
1721 20
            static::reportInvalidArgument(\sprintf(
1722 20
                $message ?: 'Expected string or integer. Got: %s',
1723 20
                static::typeToString($value)
1724
            ));
1725
        }
1726 8
    }
1727
1728
    /**
1729
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1730
     *
1731
     * @param Countable|array $array
1732
     * @param int             $number
1733
     * @param string          $message
1734
     *
1735
     * @throws InvalidArgumentException
1736
     */
1737 8
    public static function count($array, $number, $message = '')
1738
    {
1739 8
        static::eq(
1740 8
            \count($array),
1741
            $number,
1742 8
            \sprintf(
1743 8
                $message ?: 'Expected an array to contain %d elements. Got: %d.',
1744 8
                $number,
1745 8
                \count($array)
1746
            )
1747
        );
1748 4
    }
1749
1750
    /**
1751
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1752
     *
1753
     * @param Countable|array $array
1754
     * @param int|float       $min
1755
     * @param string          $message
1756
     *
1757
     * @throws InvalidArgumentException
1758
     */
1759 12 View Code Duplication
    public static function minCount($array, $min, $message = '')
1760
    {
1761 12
        if (\count($array) < $min) {
1762 4
            static::reportInvalidArgument(\sprintf(
1763 4
                $message ?: 'Expected an array to contain at least %2$d elements. Got: %d',
1764 4
                \count($array),
1765 4
                $min
1766
            ));
1767
        }
1768 8
    }
1769
1770
    /**
1771
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1772
     *
1773
     * @param Countable|array $array
1774
     * @param int|float       $max
1775
     * @param string          $message
1776
     *
1777
     * @throws InvalidArgumentException
1778
     */
1779 12 View Code Duplication
    public static function maxCount($array, $max, $message = '')
1780
    {
1781 12
        if (\count($array) > $max) {
1782 4
            static::reportInvalidArgument(\sprintf(
1783 4
                $message ?: 'Expected an array to contain at most %2$d elements. Got: %d',
1784 4
                \count($array),
1785 4
                $max
1786
            ));
1787
        }
1788 8
    }
1789
1790
    /**
1791
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1792
     *
1793
     * @param Countable|array $array
1794
     * @param int|float       $min
1795
     * @param int|float       $max
1796
     * @param string          $message
1797
     *
1798
     * @throws InvalidArgumentException
1799
     */
1800 20
    public static function countBetween($array, $min, $max, $message = '')
1801
    {
1802 20
        $count = \count($array);
1803
1804 20
        if ($count < $min || $count > $max) {
1805 8
            static::reportInvalidArgument(\sprintf(
1806 8
                $message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d',
1807 8
                $count,
1808 8
                $min,
1809 8
                $max
1810
            ));
1811
        }
1812 12
    }
1813
1814
    /**
1815
     * @psalm-pure
1816
     * @psalm-assert list $array
1817
     *
1818
     * @param mixed  $array
1819
     * @param string $message
1820
     *
1821
     * @throws InvalidArgumentException
1822
     */
1823 80 View Code Duplication
    public static function isList($array, $message = '')
1824
    {
1825 80
        if (!\is_array($array) || $array !== \array_values($array)) {
1826 32
            static::reportInvalidArgument(
1827 32
                $message ?: 'Expected list - non-associative array.'
1828
            );
1829
        }
1830 48
    }
1831
1832
    /**
1833
     * @psalm-pure
1834
     * @psalm-assert non-empty-list $array
1835
     *
1836
     * @param mixed  $array
1837
     * @param string $message
1838
     *
1839
     * @throws InvalidArgumentException
1840
     */
1841 40
    public static function isNonEmptyList($array, $message = '')
1842
    {
1843 40
        static::isList($array, $message);
1844 24
        static::notEmpty($array, $message);
1845 20
    }
1846
1847
    /**
1848
     * @psalm-pure
1849
     * @psalm-template T
1850
     * @psalm-param mixed|array<T> $array
1851
     * @psalm-assert array<string, T> $array
1852
     *
1853
     * @param mixed  $array
1854
     * @param string $message
1855
     *
1856
     * @throws InvalidArgumentException
1857
     */
1858 32
    public static function isMap($array, $message = '')
1859
    {
1860
        if (
1861 32
            !\is_array($array) ||
1862 32
            \array_keys($array) !== \array_filter(\array_keys($array), '\is_string')
1863
        ) {
1864 16
            static::reportInvalidArgument(
1865 16
                $message ?: 'Expected map - associative array with string keys.'
1866
            );
1867
        }
1868 16
    }
1869
1870
    /**
1871
     * @psalm-pure
1872
     * @psalm-template T
1873
     * @psalm-param mixed|array<T> $array
1874
     * @psalm-assert array<string, T> $array
1875
     * @psalm-assert !empty $array
1876
     *
1877
     * @param mixed  $array
1878
     * @param string $message
1879
     *
1880
     * @throws InvalidArgumentException
1881
     */
1882 16
    public static function isNonEmptyMap($array, $message = '')
1883
    {
1884 16
        static::isMap($array, $message);
1885 8
        static::notEmpty($array, $message);
1886 4
    }
1887
1888
    /**
1889
     * @psalm-pure
1890
     *
1891
     * @param string $value
1892
     * @param string $message
1893
     *
1894
     * @throws InvalidArgumentException
1895
     */
1896 56
    public static function uuid($value, $message = '')
1897
    {
1898 56
        $value = \str_replace(array('urn:', 'uuid:', '{', '}'), '', $value);
1899
1900
        // The nil UUID is special form of UUID that is specified to have all
1901
        // 128 bits set to zero.
1902 56
        if ('00000000-0000-0000-0000-000000000000' === $value) {
1903 4
            return;
1904
        }
1905
1906 52
        if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) {
1907 20
            static::reportInvalidArgument(\sprintf(
1908 20
                $message ?: 'Value %s is not a valid UUID.',
1909 20
                static::valueToString($value)
1910
            ));
1911
        }
1912 32
    }
1913
1914
    /**
1915
     * @psalm-param class-string<Throwable> $class
1916
     *
1917
     * @param Closure $expression
1918
     * @param string  $class
1919
     * @param string  $message
1920
     *
1921
     * @throws InvalidArgumentException
1922
     */
1923 24
    public static function throws(Closure $expression, $class = 'Exception', $message = '')
1924
    {
1925 24
        static::string($class);
1926
1927 24
        $actual = 'none';
1928
1929
        try {
1930 24
            $expression();
1931 24
        } catch (Exception $e) {
1932 20
            $actual = \get_class($e);
1933 20
            if ($e instanceof $class) {
1934 20
                return;
1935
            }
1936 4
        } catch (Throwable $e) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
1937 4
            $actual = \get_class($e);
1938 4
            if ($e instanceof $class) {
1939 4
                return;
1940
            }
1941
        }
1942
1943 8
        static::reportInvalidArgument($message ?: \sprintf(
1944 8
            'Expected to throw "%s", got "%s"',
1945 8
            $class,
1946 8
            $actual
1947
        ));
1948
    }
1949
1950
    /**
1951
     * @throws BadMethodCallException
1952
     */
1953 1688
    public static function __callStatic($name, $arguments)
1954
    {
1955 1688
        if ('nullOr' === \substr($name, 0, 6)) {
1956 623
            if (null !== $arguments[0]) {
1957 516
                $method = \lcfirst(\substr($name, 6));
1958 516
                \call_user_func_array(array('static', $method), $arguments);
1959
            }
1960
1961 363
            return;
1962
        }
1963
1964 1065
        if ('all' === \substr($name, 0, 3)) {
1965 1064
            static::isIterable($arguments[0]);
1966
1967 1064
            $method = \lcfirst(\substr($name, 3));
1968 1064
            $args = $arguments;
1969
1970 1064
            foreach ($arguments[0] as $entry) {
1971 1064
                $args[0] = $entry;
1972
1973 1064
                \call_user_func_array(array('static', $method), $args);
1974
            }
1975
1976 520
            return;
1977
        }
1978
1979 1
        throw new BadMethodCallException('No such method: '.$name);
1980
    }
1981
1982
    /**
1983
     * @param mixed $value
1984
     *
1985
     * @return string
1986
     */
1987 779
    protected static function valueToString($value)
1988
    {
1989 779
        if (null === $value) {
1990 20
            return 'null';
1991
        }
1992
1993 761
        if (true === $value) {
1994 15
            return 'true';
1995
        }
1996
1997 751
        if (false === $value) {
1998 25
            return 'false';
1999
        }
2000
2001 726
        if (\is_array($value)) {
2002 21
            return 'array';
2003
        }
2004
2005 705
        if (\is_object($value)) {
2006 3
            if (\method_exists($value, '__toString')) {
2007 1
                return \get_class($value).': '.self::valueToString($value->__toString());
2008
            }
2009
2010 2
            if ($value instanceof DateTime || $value instanceof DateTimeImmutable) {
2011 1
                return \get_class($value).': '.self::valueToString($value->format('c'));
2012
            }
2013
2014 1
            return \get_class($value);
2015
        }
2016
2017 704
        if (\is_resource($value)) {
2018 1
            return 'resource';
2019
        }
2020
2021 704
        if (\is_string($value)) {
2022 602
            return '"'.$value.'"';
2023
        }
2024
2025 114
        return (string) $value;
2026
    }
2027
2028
    /**
2029
     * @param mixed $value
2030
     *
2031
     * @return string
2032
     */
2033 251
    protected static function typeToString($value)
2034
    {
2035 251
        return \is_object($value) ? \get_class($value) : \gettype($value);
2036
    }
2037
2038 168
    protected static function strlen($value)
2039
    {
2040 168
        if (!\function_exists('mb_detect_encoding')) {
2041
            return \strlen($value);
2042
        }
2043
2044 168
        if (false === $encoding = \mb_detect_encoding($value)) {
2045
            return \strlen($value);
2046
        }
2047
2048 168
        return \mb_strlen($value, $encoding);
2049
    }
2050
2051
    /**
2052
     * @param string $message
2053
     *
2054
     * @throws InvalidArgumentException
2055
     *
2056
     * @psalm-pure this method is not supposed to perform side-effects
2057
     */
2058 1093
    protected static function reportInvalidArgument($message)
2059
    {
2060 1093
        throw new InvalidArgumentException($message);
2061
    }
2062
2063
    private function __construct()
2064
    {
2065
    }
2066
}
2067