Failed Conditions
Pull Request — master (#225)
by Roel van
24:22 queued 04:22
created

Assert::implies()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 3

Importance

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