Failed Conditions
Pull Request — master (#214)
by Marco
23:24 queued 03:30
created

Assert::positiveInteger()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Code Coverage

Tests 6
CRAP Score 4

Importance

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