Failed Conditions
Pull Request — master (#141)
by Gert de
17:12 queued 16:13
created

src/Assert.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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