Failed Conditions
Pull Request — master (#199)
by Tomasz
16:07
created

Assert::notNull()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

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