Failed Conditions
Pull Request — master (#135)
by Gert de
19:20 queued 18:11
created

Assert   F

Complexity

Total Complexity 289

Size/Duplication

Total Lines 1693
Duplicated Lines 19.55 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 97.14%

Importance

Changes 0
Metric Value
wmc 289
lcom 1
cbo 0
dl 331
loc 1693
ccs 612
cts 630
cp 0.9714
rs 0.8
c 0
b 0
f 0

88 Methods

Rating   Name   Duplication   Size   Complexity  
A resource() 0 17 6
A file() 11 11 3
A isCallable() 0 9 3
A integer() 0 9 3
A integerish() 0 9 4
A string() 0 9 3
A stringNotEmpty() 0 5 1
A float() 0 9 3
A numeric() 0 9 3
A natural() 0 9 4
A boolean() 0 9 3
A scalar() 0 9 3
A object() 0 9 3
A isArray() 0 9 3
A isTraversable() 0 17 4
A isArrayAccessible() 9 9 4
A isCountable() 9 9 4
A isIterable() 9 9 4
A isInstanceOf() 0 10 3
A notInstanceOf() 0 10 3
A isInstanceOfAny() 0 14 4
A isEmpty() 0 9 3
A notEmpty() 0 9 3
A null() 0 9 3
A notNull() 0 8 3
A true() 0 9 3
A false() 0 9 3
A ip() 10 10 3
A ipv4() 10 10 3
A ipv6() 10 10 3
A email() 10 10 3
A uniqueValues() 0 15 4
A eq() 0 10 3
A notEq() 0 9 3
A same() 0 10 3
A notSame() 0 9 3
A greaterThan() 0 10 3
A greaterThanEq() 0 10 3
A lessThan() 0 10 3
A lessThanEq() 0 10 3
A range() 11 11 4
A oneOf() 0 10 3
A contains() 10 10 3
A notContains() 10 10 3
A notWhitespaceOnly() 0 9 3
A startsWith() 10 10 3
A startsWithLetter() 0 18 4
A endsWith() 10 10 3
A regex() 0 9 3
A notRegex() 0 11 3
A unicodeLetters() 11 11 3
A alpha() 16 16 3
A digits() 14 14 3
A alnum() 14 14 3
A lower() 14 14 3
A upper() 14 14 3
A length() 0 10 3
A minLength() 0 10 3
A maxLength() 0 10 3
A lengthBetween() 13 13 4
A fileExists() 11 11 3
A directory() 11 11 3
A readable() 0 9 3
A writable() 0 9 3
A classExists() 0 9 3
A subclassOf() 0 10 3
A interfaceExists() 0 9 3
A implementsInterface() 10 10 3
A propertyExists() 9 9 3
A propertyNotExists() 9 9 3
A methodExists() 9 9 3
A methodNotExists() 9 9 3
A keyExists() 9 9 4
A keyNotExists() 9 9 4
A count() 0 8 2
A minCount() 10 10 3
A maxCount() 10 10 3
A countBetween() 0 13 4
A isList() 0 8 5
A isMap() 0 14 5
A uuid() 0 17 4
B throws() 0 26 6
A __callStatic() 0 28 5
B valueToString() 0 36 9
A typeToString() 0 4 2
A strlen() 0 12 3
A reportInvalidArgument() 0 4 1
A __construct() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Assert often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Assert, and based on these observations, apply Extract Interface, too.

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 Throwable;
21
use Traversable;
22
23
/**
24
 * Efficient assertions to validate the input/output of your methods.
25
 *
26
 * @method static void nullOrString($value, $message = '')
27
 * @method static void nullOrStringNotEmpty($value, $message = '')
28
 * @method static void nullOrInteger($value, $message = '')
29
 * @method static void nullOrIntegerish($value, $message = '')
30
 * @method static void nullOrFloat($value, $message = '')
31
 * @method static void nullOrNumeric($value, $message = '')
32
 * @method static void nullOrNatural($value, $message = '')
33
 * @method static void nullOrBoolean($value, $message = '')
34
 * @method static void nullOrScalar($value, $message = '')
35
 * @method static void nullOrObject($value, $message = '')
36
 * @method static void nullOrResource($value, $type = null, $message = '')
37
 * @method static void nullOrIsCallable($value, $message = '')
38
 * @method static void nullOrIsArray($value, $message = '')
39
 * @method static void nullOrIsTraversable($value, $message = '')
40
 * @method static void nullOrIsArrayAccessible($value, $message = '')
41
 * @method static void nullOrIsCountable($value, $message = '')
42
 * @method static void nullOrIsIterable($value, $message = '')
43
 * @method static void nullOrIsInstanceOf($value, $class, $message = '')
44
 * @method static void nullOrNotInstanceOf($value, $class, $message = '')
45
 * @method static void nullOrIsInstanceOfAny($value, $classes, $message = '')
46
 * @method static void nullOrIsEmpty($value, $message = '')
47
 * @method static void nullOrNotEmpty($value, $message = '')
48
 * @method static void nullOrTrue($value, $message = '')
49
 * @method static void nullOrFalse($value, $message = '')
50
 * @method static void nullOrIp($value, $message = '')
51
 * @method static void nullOrIpv4($value, $message = '')
52
 * @method static void nullOrIpv6($value, $message = '')
53
 * @method static void nullOrEmail($value, $message = '')
54
 * @method static void nullOrUniqueValues($values, $message = '')
55
 * @method static void nullOrEq($value, $expect, $message = '')
56
 * @method static void nullOrNotEq($value, $expect, $message = '')
57
 * @method static void nullOrSame($value, $expect, $message = '')
58
 * @method static void nullOrNotSame($value, $expect, $message = '')
59
 * @method static void nullOrGreaterThan($value, $limit, $message = '')
60
 * @method static void nullOrGreaterThanEq($value, $limit, $message = '')
61
 * @method static void nullOrLessThan($value, $limit, $message = '')
62
 * @method static void nullOrLessThanEq($value, $limit, $message = '')
63
 * @method static void nullOrRange($value, $min, $max, $message = '')
64
 * @method static void nullOrOneOf($value, $values, $message = '')
65
 * @method static void nullOrContains($value, $subString, $message = '')
66
 * @method static void nullOrNotContains($value, $subString, $message = '')
67
 * @method static void nullOrNotWhitespaceOnly($value, $message = '')
68
 * @method static void nullOrStartsWith($value, $prefix, $message = '')
69
 * @method static void nullOrStartsWithLetter($value, $message = '')
70
 * @method static void nullOrEndsWith($value, $suffix, $message = '')
71
 * @method static void nullOrRegex($value, $pattern, $message = '')
72
 * @method static void nullOrNotRegex($value, $pattern, $message = '')
73
 * @method static void nullOrUnicodeLetters($value, $message = '')
74
 * @method static void nullOrAlpha($value, $message = '')
75
 * @method static void nullOrDigits($value, $message = '')
76
 * @method static void nullOrAlnum($value, $message = '')
77
 * @method static void nullOrLower($value, $message = '')
78
 * @method static void nullOrUpper($value, $message = '')
79
 * @method static void nullOrLength($value, $length, $message = '')
80
 * @method static void nullOrMinLength($value, $min, $message = '')
81
 * @method static void nullOrMaxLength($value, $max, $message = '')
82
 * @method static void nullOrLengthBetween($value, $min, $max, $message = '')
83
 * @method static void nullOrFileExists($value, $message = '')
84
 * @method static void nullOrFile($value, $message = '')
85
 * @method static void nullOrDirectory($value, $message = '')
86
 * @method static void nullOrReadable($value, $message = '')
87
 * @method static void nullOrWritable($value, $message = '')
88
 * @method static void nullOrClassExists($value, $message = '')
89
 * @method static void nullOrSubclassOf($value, $class, $message = '')
90
 * @method static void nullOrInterfaceExists($value, $message = '')
91
 * @method static void nullOrImplementsInterface($value, $interface, $message = '')
92
 * @method static void nullOrPropertyExists($value, $property, $message = '')
93
 * @method static void nullOrPropertyNotExists($value, $property, $message = '')
94
 * @method static void nullOrMethodExists($value, $method, $message = '')
95
 * @method static void nullOrMethodNotExists($value, $method, $message = '')
96
 * @method static void nullOrKeyExists($value, $key, $message = '')
97
 * @method static void nullOrKeyNotExists($value, $key, $message = '')
98
 * @method static void nullOrCount($value, $key, $message = '')
99
 * @method static void nullOrMinCount($value, $min, $message = '')
100
 * @method static void nullOrMaxCount($value, $max, $message = '')
101
 * @method static void nullOrIsList($value, $message = '')
102
 * @method static void nullOrIsMap($value, $message = '')
103
 * @method static void nullOrCountBetween($value, $min, $max, $message = '')
104
 * @method static void nullOrUuid($values, $message = '')
105
 * @method static void nullOrThrows($expression, $class = 'Exception', $message = '')
106
 * @method static void allString($values, $message = '')
107
 * @method static void allStringNotEmpty($values, $message = '')
108
 * @method static void allInteger($values, $message = '')
109
 * @method static void allIntegerish($values, $message = '')
110
 * @method static void allFloat($values, $message = '')
111
 * @method static void allNumeric($values, $message = '')
112
 * @method static void allNatural($values, $message = '')
113
 * @method static void allBoolean($values, $message = '')
114
 * @method static void allScalar($values, $message = '')
115
 * @method static void allObject($values, $message = '')
116
 * @method static void allResource($values, $type = null, $message = '')
117
 * @method static void allIsCallable($values, $message = '')
118
 * @method static void allIsArray($values, $message = '')
119
 * @method static void allIsTraversable($values, $message = '')
120
 * @method static void allIsArrayAccessible($values, $message = '')
121
 * @method static void allIsCountable($values, $message = '')
122
 * @method static void allIsIterable($values, $message = '')
123
 * @method static void allIsInstanceOf($values, $class, $message = '')
124
 * @method static void allNotInstanceOf($values, $class, $message = '')
125
 * @method static void allIsInstanceOfAny($values, $classes, $message = '')
126
 * @method static void allNull($values, $message = '')
127
 * @method static void allNotNull($values, $message = '')
128
 * @method static void allIsEmpty($values, $message = '')
129
 * @method static void allNotEmpty($values, $message = '')
130
 * @method static void allTrue($values, $message = '')
131
 * @method static void allFalse($values, $message = '')
132
 * @method static void allIp($values, $message = '')
133
 * @method static void allIpv4($values, $message = '')
134
 * @method static void allIpv6($values, $message = '')
135
 * @method static void allEmail($values, $message = '')
136
 * @method static void allUniqueValues($values, $message = '')
137
 * @method static void allEq($values, $expect, $message = '')
138
 * @method static void allNotEq($values, $expect, $message = '')
139
 * @method static void allSame($values, $expect, $message = '')
140
 * @method static void allNotSame($values, $expect, $message = '')
141
 * @method static void allGreaterThan($values, $limit, $message = '')
142
 * @method static void allGreaterThanEq($values, $limit, $message = '')
143
 * @method static void allLessThan($values, $limit, $message = '')
144
 * @method static void allLessThanEq($values, $limit, $message = '')
145
 * @method static void allRange($values, $min, $max, $message = '')
146
 * @method static void allOneOf($values, $values, $message = '')
147
 * @method static void allContains($values, $subString, $message = '')
148
 * @method static void allNotContains($values, $subString, $message = '')
149
 * @method static void allNotWhitespaceOnly($values, $message = '')
150
 * @method static void allStartsWith($values, $prefix, $message = '')
151
 * @method static void allStartsWithLetter($values, $message = '')
152
 * @method static void allEndsWith($values, $suffix, $message = '')
153
 * @method static void allRegex($values, $pattern, $message = '')
154
 * @method static void allNotRegex($values, $pattern, $message = '')
155
 * @method static void allUnicodeLetters($values, $message = '')
156
 * @method static void allAlpha($values, $message = '')
157
 * @method static void allDigits($values, $message = '')
158
 * @method static void allAlnum($values, $message = '')
159
 * @method static void allLower($values, $message = '')
160
 * @method static void allUpper($values, $message = '')
161
 * @method static void allLength($values, $length, $message = '')
162
 * @method static void allMinLength($values, $min, $message = '')
163
 * @method static void allMaxLength($values, $max, $message = '')
164
 * @method static void allLengthBetween($values, $min, $max, $message = '')
165
 * @method static void allFileExists($values, $message = '')
166
 * @method static void allFile($values, $message = '')
167
 * @method static void allDirectory($values, $message = '')
168
 * @method static void allReadable($values, $message = '')
169
 * @method static void allWritable($values, $message = '')
170
 * @method static void allClassExists($values, $message = '')
171
 * @method static void allSubclassOf($values, $class, $message = '')
172
 * @method static void allInterfaceExists($values, $message = '')
173
 * @method static void allImplementsInterface($values, $interface, $message = '')
174
 * @method static void allPropertyExists($values, $property, $message = '')
175
 * @method static void allPropertyNotExists($values, $property, $message = '')
176
 * @method static void allMethodExists($values, $method, $message = '')
177
 * @method static void allMethodNotExists($values, $method, $message = '')
178
 * @method static void allKeyExists($values, $key, $message = '')
179
 * @method static void allKeyNotExists($values, $key, $message = '')
180
 * @method static void allCount($values, $key, $message = '')
181
 * @method static void allMinCount($values, $min, $message = '')
182
 * @method static void allMaxCount($values, $max, $message = '')
183
 * @method static void allCountBetween($values, $min, $max, $message = '')
184
 * @method static void allIsList($values, $message = '')
185
 * @method static void allIsMap($values, $message = '')
186
 * @method static void allUuid($values, $message = '')
187
 * @method static void allThrows($expressions, $class = 'Exception', $message = '')
188
 *
189
 * @since  1.0
190
 *
191
 * @author Bernhard Schussek <[email protected]>
192
 */
193
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...
194
{
195
    /**
196
     * @psalm-assert string $value
197
     *
198
     * @param mixed  $value
199
     * @param string $message
200
     *
201
     * @throws InvalidArgumentException
202
     */
203 315
    public static function string($value, $message = '')
204
    {
205 315
        if (!\is_string($value)) {
206 87
            static::reportInvalidArgument(\sprintf(
207 87
                $message ?: 'Expected a string. Got: %s',
208 87
                static::typeToString($value)
209
            ));
210
        }
211 228
    }
212
213
    /**
214
     * @psalm-assert string $value
215
     *
216
     * @param mixed  $value
217
     * @param string $message
218
     *
219
     * @throws InvalidArgumentException
220
     */
221 16
    public static function stringNotEmpty($value, $message = '')
222
    {
223 16
        static::string($value, $message);
224 12
        static::notEq($value, '', $message);
225 8
    }
226
227
    /**
228
     * @psalm-assert int $value
229
     *
230
     * @param mixed  $value
231
     * @param string $message
232
     *
233
     * @throws InvalidArgumentException
234
     */
235 17
    public static function integer($value, $message = '')
236
    {
237 17
        if (!\is_int($value)) {
238 13
            static::reportInvalidArgument(\sprintf(
239 13
                $message ?: 'Expected an integer. Got: %s',
240 13
                static::typeToString($value)
241
            ));
242
        }
243 4
    }
244
245
    /**
246
     * @psalm-assert numeric $value
247
     *
248
     * @param mixed  $value
249
     * @param string $message
250
     */
251 16
    public static function integerish($value, $message = '')
252
    {
253 16
        if (!\is_numeric($value) || $value != (int) $value) {
254 4
            static::reportInvalidArgument(\sprintf(
255 4
                $message ?: 'Expected an integerish value. Got: %s',
256 4
                static::typeToString($value)
257
            ));
258
        }
259 12
    }
260
261
    /**
262
     * @psalm-assert float $value
263
     *
264
     * @param mixed  $value
265
     * @param string $message
266
     *
267
     * @throws InvalidArgumentException
268
     */
269 16
    public static function float($value, $message = '')
270
    {
271 16
        if (!\is_float($value)) {
272 8
            static::reportInvalidArgument(\sprintf(
273 8
                $message ?: 'Expected a float. Got: %s',
274 8
                static::typeToString($value)
275
            ));
276
        }
277 8
    }
278
279
    /**
280
     * @psalm-assert numeric $value
281
     *
282
     * @param mixed  $value
283
     * @param string $message
284
     *
285
     * @throws InvalidArgumentException
286
     */
287 20
    public static function numeric($value, $message = '')
288
    {
289 20
        if (!\is_numeric($value)) {
290 4
            static::reportInvalidArgument(\sprintf(
291 4
                $message ?: 'Expected a numeric. Got: %s',
292 4
                static::typeToString($value)
293
            ));
294
        }
295 16
    }
296
297
    /**
298
     * @psalm-assert int $value
299
     *
300
     * @param mixed  $value
301
     * @param string $message
302
     *
303
     * @throws InvalidArgumentException
304
     */
305 24
    public static function natural($value, $message = '')
306
    {
307 24
        if (!\is_int($value) || $value < 0) {
308 16
            static::reportInvalidArgument(\sprintf(
309 16
                $message ?: 'Expected a non-negative integer. Got %s',
310 16
                static::valueToString($value)
311
            ));
312
        }
313 8
    }
314
315
    /**
316
     * @psalm-assert bool $value
317
     *
318
     * @param mixed  $value
319
     * @param string $message
320
     *
321
     * @throws InvalidArgumentException
322
     */
323 16
    public static function boolean($value, $message = '')
324
    {
325 16
        if (!\is_bool($value)) {
326 8
            static::reportInvalidArgument(\sprintf(
327 8
                $message ?: 'Expected a boolean. Got: %s',
328 8
                static::typeToString($value)
329
            ));
330
        }
331 8
    }
332
333
    /**
334
     * @psalm-assert scalar $value
335
     *
336
     * @param mixed  $value
337
     * @param string $message
338
     *
339
     * @throws InvalidArgumentException
340
     */
341 23
    public static function scalar($value, $message = '')
342
    {
343 23
        if (!\is_scalar($value)) {
344 11
            static::reportInvalidArgument(\sprintf(
345 11
                $message ?: 'Expected a scalar. Got: %s',
346 11
                static::typeToString($value)
347
            ));
348
        }
349 12
    }
350
351
    /**
352
     * @psalm-assert object $value
353
     *
354
     * @param mixed  $value
355
     * @param string $message
356
     *
357
     * @throws InvalidArgumentException
358
     */
359 23
    public static function object($value, $message = '')
360
    {
361 23
        if (!\is_object($value)) {
362 15
            static::reportInvalidArgument(\sprintf(
363 15
                $message ?: 'Expected an object. Got: %s',
364 15
                static::typeToString($value)
365
            ));
366
        }
367 8
    }
368
369
    /**
370
     * @psalm-assert resource $value
371
     *
372
     * @param mixed       $value
373
     * @param string|null $type    type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php
374
     * @param string      $message
375
     *
376
     * @throws InvalidArgumentException
377
     */
378 16
    public static function resource($value, $type = null, $message = '')
379
    {
380 16
        if (!\is_resource($value)) {
381 4
            static::reportInvalidArgument(\sprintf(
382 4
                $message ?: 'Expected a resource. Got: %s',
383 4
                static::typeToString($value)
384
            ));
385
        }
386
387 12
        if ($type && $type !== \get_resource_type($value)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $type of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

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

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

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

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
388 4
            static::reportInvalidArgument(\sprintf(
389 4
                $message ?: 'Expected a resource of type %2$s. Got: %s',
390 4
                static::typeToString($value),
391 4
                $type
392
            ));
393
        }
394 8
    }
395
396
    /**
397
     * @psalm-assert callable $value
398
     *
399
     * @param mixed  $value
400
     * @param string $message
401
     *
402
     * @throws InvalidArgumentException
403
     */
404 20
    public static function isCallable($value, $message = '')
405
    {
406 20
        if (!\is_callable($value)) {
407 8
            static::reportInvalidArgument(\sprintf(
408 8
                $message ?: 'Expected a callable. Got: %s',
409 8
                static::typeToString($value)
410
            ));
411
        }
412 12
    }
413
414
    /**
415
     * @psalm-assert array $value
416
     *
417
     * @param mixed  $value
418
     * @param string $message
419
     *
420
     * @throws InvalidArgumentException
421
     */
422 20
    public static function isArray($value, $message = '')
423
    {
424 20
        if (!\is_array($value)) {
425 12
            static::reportInvalidArgument(\sprintf(
426 12
                $message ?: 'Expected an array. Got: %s',
427 12
                static::typeToString($value)
428
            ));
429
        }
430 8
    }
431
432
    /**
433
     * @psalm-assert iterable $value
434
     *
435
     * @deprecated use "isIterable" or "isInstanceOf" instead
436
     *
437
     * @param mixed  $value
438
     * @param string $message
439
     *
440
     * @throws InvalidArgumentException
441
     */
442 20
    public static function isTraversable($value, $message = '')
443
    {
444 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...
445 20
            \sprintf(
446 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.',
447 20
                __METHOD__
448
            ),
449 20
            \E_USER_DEPRECATED
450
        );
451
452 20
        if (!\is_array($value) && !($value instanceof Traversable)) {
453 8
            static::reportInvalidArgument(\sprintf(
454 8
                $message ?: 'Expected a traversable. Got: %s',
455 8
                static::typeToString($value)
456
            ));
457
        }
458 12
    }
459
460
    /**
461
     * @param mixed  $value
462
     * @param string $message
463
     *
464
     * @throws InvalidArgumentException
465
     */
466 20 View Code Duplication
    public static function isArrayAccessible($value, $message = '')
467
    {
468 20
        if (!\is_array($value) && !($value instanceof ArrayAccess)) {
469 8
            static::reportInvalidArgument(\sprintf(
470 8
                $message ?: 'Expected an array accessible. Got: %s',
471 8
                static::typeToString($value)
472
            ));
473
        }
474 12
    }
475
476
    /**
477
     * @psalm-assert countable $value
478
     *
479
     * @param mixed  $value
480
     * @param string $message
481
     *
482
     * @throws InvalidArgumentException
483
     */
484 24 View Code Duplication
    public static function isCountable($value, $message = '')
485
    {
486 24
        if (!\is_array($value) && !($value instanceof Countable)) {
487 12
            static::reportInvalidArgument(\sprintf(
488 12
                $message ?: 'Expected a countable. Got: %s',
489 12
                static::typeToString($value)
490
            ));
491
        }
492 12
    }
493
494
    /**
495
     * @psalm-assert iterable $value
496
     *
497
     * @param mixed  $value
498
     * @param string $message
499
     *
500
     * @throws InvalidArgumentException
501
     */
502 890 View Code Duplication
    public static function isIterable($value, $message = '')
503
    {
504 890
        if (!\is_array($value) && !($value instanceof Traversable)) {
505 8
            static::reportInvalidArgument(\sprintf(
506 8
                $message ?: 'Expected an iterable. Got: %s',
507 8
                static::typeToString($value)
508
            ));
509
        }
510 886
    }
511
512
    /**
513
     * @psalm-template ExpectedType of object
514
     * @psalm-param class-string<ExpectedType> $class
515
     * @psalm-assert ExpectedType $value
516
     *
517
     * @param mixed         $value
518
     * @param string|object $class
519
     * @param string        $message
520
     *
521
     * @throws InvalidArgumentException
522
     */
523 16
    public static function isInstanceOf($value, $class, $message = '')
524
    {
525 16
        if (!($value instanceof $class)) {
526 12
            static::reportInvalidArgument(\sprintf(
527 12
                $message ?: 'Expected an instance of %2$s. Got: %s',
528 12
                static::typeToString($value),
529 12
                $class
530
            ));
531
        }
532 4
    }
533
534
    /**
535
     * @psalm-template ExpectedType of object
536
     * @psalm-param class-string<ExpectedType> $class
537
     * @psalm-assert !ExpectedType $value
538
     *
539
     * @param mixed         $value
540
     * @param string|object $class
541
     * @param string        $message
542
     *
543
     * @throws InvalidArgumentException
544
     */
545 16
    public static function notInstanceOf($value, $class, $message = '')
546
    {
547 16
        if ($value instanceof $class) {
548 4
            static::reportInvalidArgument(\sprintf(
549 4
                $message ?: 'Expected an instance other than %2$s. Got: %s',
550 4
                static::typeToString($value),
551 4
                $class
552
            ));
553
        }
554 12
    }
555
556
    /**
557
     * @param mixed                $value
558
     * @param array<object|string> $classes
559
     * @param string               $message
560
     *
561
     * @throws InvalidArgumentException
562
     */
563 20
    public static function isInstanceOfAny($value, array $classes, $message = '')
564
    {
565 20
        foreach ($classes as $class) {
566 20
            if ($value instanceof $class) {
567 8
                return;
568
            }
569
        }
570
571 12
        static::reportInvalidArgument(\sprintf(
572 12
            $message ?: 'Expected an instance of any of %2$s. Got: %s',
573 12
            static::typeToString($value),
574 12
            \implode(', ', \array_map(array('static', 'valueToString'), $classes))
575
        ));
576
    }
577
578
    /**
579
     * @psalm-assert empty $value
580
     *
581
     * @param mixed  $value
582
     * @param string $message
583
     *
584
     * @throws InvalidArgumentException
585
     */
586 23
    public static function isEmpty($value, $message = '')
587
    {
588 23
        if (!empty($value)) {
589 8
            static::reportInvalidArgument(\sprintf(
590 8
                $message ?: 'Expected an empty value. Got: %s',
591 8
                static::valueToString($value)
592
            ));
593
        }
594 15
    }
595
596
    /**
597
     * @psalm-assert !empty $value
598
     *
599
     * @param mixed  $value
600
     * @param string $message
601
     *
602
     * @throws InvalidArgumentException
603
     */
604 23
    public static function notEmpty($value, $message = '')
605
    {
606 23
        if (empty($value)) {
607 15
            static::reportInvalidArgument(\sprintf(
608 15
                $message ?: 'Expected a non-empty value. Got: %s',
609 15
                static::valueToString($value)
610
            ));
611
        }
612 8
    }
613
614
    /**
615
     * @psalm-assert null $value
616
     *
617
     * @param mixed  $value
618
     * @param string $message
619
     *
620
     * @throws InvalidArgumentException
621
     */
622 11
    public static function null($value, $message = '')
623
    {
624 11
        if (null !== $value) {
625 8
            static::reportInvalidArgument(\sprintf(
626 8
                $message ?: 'Expected null. Got: %s',
627 8
                static::valueToString($value)
628
            ));
629
        }
630 3
    }
631
632
    /**
633
     * @psalm-assert !null $value
634
     *
635
     * @param mixed  $value
636
     * @param string $message
637
     *
638
     * @throws InvalidArgumentException
639
     */
640 11
    public static function notNull($value, $message = '')
641
    {
642 11
        if (null === $value) {
643 3
            static::reportInvalidArgument(
644 3
                $message ?: 'Expected a value other than null.'
645
            );
646
        }
647 8
    }
648
649
    /**
650
     * @psalm-assert true $value
651
     *
652
     * @param mixed  $value
653
     * @param string $message
654
     *
655
     * @throws InvalidArgumentException
656
     */
657 15
    public static function true($value, $message = '')
658
    {
659 15
        if (true !== $value) {
660 11
            static::reportInvalidArgument(\sprintf(
661 11
                $message ?: 'Expected a value to be true. Got: %s',
662 11
                static::valueToString($value)
663
            ));
664
        }
665 4
    }
666
667
    /**
668
     * @psalm-assert false $value
669
     *
670
     * @param mixed  $value
671
     * @param string $message
672
     *
673
     * @throws InvalidArgumentException
674
     */
675 19
    public static function false($value, $message = '')
676
    {
677 19
        if (false !== $value) {
678 15
            static::reportInvalidArgument(\sprintf(
679 15
                $message ?: 'Expected a value to be false. Got: %s',
680 15
                static::valueToString($value)
681
            ));
682
        }
683 4
    }
684
685
    /**
686
     * @psalm-assert string $value
687
     *
688
     * @param mixed  $value
689
     * @param string $message
690
     *
691
     * @throws InvalidArgumentException
692
     */
693 51 View Code Duplication
    public static function ip($value, $message = '')
694
    {
695 51
        static::string($value, $message);
696 32
        if (false === \filter_var($value, \FILTER_VALIDATE_IP)) {
697 4
            static::reportInvalidArgument(\sprintf(
698 4
                $message ?: 'Expected a value to be an IP. Got: %s',
699 4
                static::valueToString($value)
700
            ));
701
        }
702 28
    }
703
704
    /**
705
     * @psalm-assert string $value
706
     *
707
     * @param mixed  $value
708
     * @param string $message
709
     *
710
     * @throws InvalidArgumentException
711
     */
712 51 View Code Duplication
    public static function ipv4($value, $message = '')
713
    {
714 51
        static::string($value, $message);
715 32
        if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) {
716 20
            static::reportInvalidArgument(\sprintf(
717 20
                $message ?: 'Expected a value to be an IPv4. Got: %s',
718 20
                static::valueToString($value)
719
            ));
720
        }
721 12
    }
722
723
    /**
724
     * @psalm-assert string $value
725
     *
726
     * @param mixed  $value
727
     * @param string $message
728
     *
729
     * @throws InvalidArgumentException
730
     */
731 51 View Code Duplication
    public static function ipv6($value, $message = '')
732
    {
733 51
        static::string($value, $message);
734 32
        if (false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) {
735 16
            static::reportInvalidArgument(\sprintf(
736 16
                $message ?: 'Expected a value to be an IPv6. Got %s',
737 16
                static::valueToString($value)
738
            ));
739
        }
740 16
    }
741
742
    /**
743
     * @psalm-assert string $value
744
     *
745
     * @param mixed  $value
746
     * @param string $message
747
     *
748
     * @throws InvalidArgumentException
749
     */
750 20 View Code Duplication
    public static function email($value, $message = '')
751
    {
752 20
        static::string($value, $message);
753 12
        if (false === \filter_var($value, FILTER_VALIDATE_EMAIL)) {
754 8
            static::reportInvalidArgument(\sprintf(
755 8
                $message ?: 'Expected a value to be a valid e-mail address. Got %s',
756 8
                static::valueToString($value)
757
            ));
758
        }
759 4
    }
760
761
    /**
762
     * Does non strict comparisons on the items, so ['3', 3] will not pass the assertion.
763
     *
764
     * @param array  $values
765
     * @param string $message
766
     *
767
     * @throws InvalidArgumentException
768
     */
769 12
    public static function uniqueValues(array $values, $message = '')
770
    {
771 12
        $allValues = \count($values);
772 12
        $uniqueValues = \count(\array_unique($values));
773
774 12
        if ($allValues !== $uniqueValues) {
775 8
            $difference = $allValues - $uniqueValues;
776
777 8
            static::reportInvalidArgument(\sprintf(
778 8
                $message ?: 'Expected an array of unique values, but %s of them %s duplicated',
779 8
                $difference,
780 8
                (1 === $difference ? 'is' : 'are')
781
            ));
782
        }
783 4
    }
784
785
    /**
786
     * @param mixed  $value
787
     * @param mixed  $expect
788
     * @param string $message
789
     *
790
     * @throws InvalidArgumentException
791
     */
792 33
    public static function eq($value, $expect, $message = '')
793
    {
794 33
        if ($expect != $value) {
795 17
            static::reportInvalidArgument(\sprintf(
796 17
                $message ?: 'Expected a value equal to %2$s. Got: %s',
797 17
                static::valueToString($value),
798 17
                static::valueToString($expect)
799
            ));
800
        }
801 16
    }
802
803
    /**
804
     * @param mixed  $value
805
     * @param mixed  $expect
806
     * @param string $message
807
     *
808
     * @throws InvalidArgumentException
809
     */
810 28
    public static function notEq($value, $expect, $message = '')
811
    {
812 28
        if ($expect == $value) {
813 16
            static::reportInvalidArgument(\sprintf(
814 16
                $message ?: 'Expected a different value than %s.',
815 16
                static::valueToString($expect)
816
            ));
817
        }
818 12
    }
819
820
    /**
821
     * @psalm-template ExpectedType
822
     * @psalm-param ExpectedType $expect
823
     * @psalm-assert =ExpectedType $value
824
     *
825
     * @param mixed  $value
826
     * @param mixed  $expect
827
     * @param string $message
828
     *
829
     * @throws InvalidArgumentException
830
     */
831 16
    public static function same($value, $expect, $message = '')
832
    {
833 16
        if ($expect !== $value) {
834 12
            static::reportInvalidArgument(\sprintf(
835 12
                $message ?: 'Expected a value identical to %2$s. Got: %s',
836 12
                static::valueToString($value),
837 12
                static::valueToString($expect)
838
            ));
839
        }
840 4
    }
841
842
    /**
843
     * @param mixed  $value
844
     * @param mixed  $expect
845
     * @param string $message
846
     *
847
     * @throws InvalidArgumentException
848
     */
849 16
    public static function notSame($value, $expect, $message = '')
850
    {
851 16
        if ($expect === $value) {
852 4
            static::reportInvalidArgument(\sprintf(
853 4
                $message ?: 'Expected a value not identical to %s.',
854 4
                static::valueToString($expect)
855
            ));
856
        }
857 12
    }
858
859
    /**
860
     * @param mixed  $value
861
     * @param mixed  $limit
862
     * @param string $message
863
     *
864
     * @throws InvalidArgumentException
865
     */
866 8
    public static function greaterThan($value, $limit, $message = '')
867
    {
868 8
        if ($value <= $limit) {
869 4
            static::reportInvalidArgument(\sprintf(
870 4
                $message ?: 'Expected a value greater than %2$s. Got: %s',
871 4
                static::valueToString($value),
872 4
                static::valueToString($limit)
873
            ));
874
        }
875 4
    }
876
877
    /**
878
     * @param mixed  $value
879
     * @param mixed  $limit
880
     * @param string $message
881
     *
882
     * @throws InvalidArgumentException
883
     */
884 12
    public static function greaterThanEq($value, $limit, $message = '')
885
    {
886 12
        if ($value < $limit) {
887 4
            static::reportInvalidArgument(\sprintf(
888 4
                $message ?: 'Expected a value greater than or equal to %2$s. Got: %s',
889 4
                static::valueToString($value),
890 4
                static::valueToString($limit)
891
            ));
892
        }
893 8
    }
894
895
    /**
896
     * @param mixed  $value
897
     * @param mixed  $limit
898
     * @param string $message
899
     *
900
     * @throws InvalidArgumentException
901
     */
902 8
    public static function lessThan($value, $limit, $message = '')
903
    {
904 8
        if ($value >= $limit) {
905 4
            static::reportInvalidArgument(\sprintf(
906 4
                $message ?: 'Expected a value less than %2$s. Got: %s',
907 4
                static::valueToString($value),
908 4
                static::valueToString($limit)
909
            ));
910
        }
911 4
    }
912
913
    /**
914
     * @param mixed  $value
915
     * @param mixed  $limit
916
     * @param string $message
917
     *
918
     * @throws InvalidArgumentException
919
     */
920 12
    public static function lessThanEq($value, $limit, $message = '')
921
    {
922 12
        if ($value > $limit) {
923 4
            static::reportInvalidArgument(\sprintf(
924 4
                $message ?: 'Expected a value less than or equal to %2$s. Got: %s',
925 4
                static::valueToString($value),
926 4
                static::valueToString($limit)
927
            ));
928
        }
929 8
    }
930
931
    /**
932
     * Inclusive range, so Assert::(3, 3, 5) passes.
933
     *
934
     * @param mixed $value
935
     * @param mixed min
936
     * @param mixed max
937
     * @param string $message
938
     *
939
     * @throws InvalidArgumentException
940
     */
941 16 View Code Duplication
    public static function range($value, $min, $max, $message = '')
942
    {
943 16
        if ($value < $min || $value > $max) {
944 8
            static::reportInvalidArgument(\sprintf(
945 8
                $message ?: 'Expected a value between %2$s and %3$s. Got: %s',
946 8
                static::valueToString($value),
947 8
                static::valueToString($min),
948 8
                static::valueToString($max)
949
            ));
950
        }
951 8
    }
952
953
    /**
954
     * Does strict comparison, so Assert::oneOf(3, ['3']) does not pass the assertion.
955
     *
956
     * @psalm-template ExpectedType
957
     * @psalm-param array<ExpectedType> $values
958
     * @psalm-assert ExpectedType $value
959
     *
960
     * @param mixed  $value
961
     * @param array  $values
962
     * @param string $message
963
     *
964
     * @throws InvalidArgumentException
965
     */
966 8
    public static function oneOf($value, array $values, $message = '')
967
    {
968 8
        if (!\in_array($value, $values, true)) {
969 4
            static::reportInvalidArgument(\sprintf(
970 4
                $message ?: 'Expected one of: %2$s. Got: %s',
971 4
                static::valueToString($value),
972 4
                \implode(', ', \array_map(array('static', 'valueToString'), $values))
973
            ));
974
        }
975 4
    }
976
977
    /**
978
     * @param mixed  $value
979
     * @param string $subString
980
     * @param string $message
981
     *
982
     * @throws InvalidArgumentException
983
     */
984 80 View Code Duplication
    public static function contains($value, $subString, $message = '')
985
    {
986 80
        if (false === \strpos($value, $subString)) {
987 32
            static::reportInvalidArgument(\sprintf(
988 32
                $message ?: 'Expected a value to contain %2$s. Got: %s',
989 32
                static::valueToString($value),
990 32
                static::valueToString($subString)
991
            ));
992
        }
993 48
    }
994
995
    /**
996
     * @param mixed  $value
997
     * @param string $subString
998
     * @param string $message
999
     *
1000
     * @throws InvalidArgumentException
1001
     */
1002 80 View Code Duplication
    public static function notContains($value, $subString, $message = '')
1003
    {
1004 80
        if (false !== \strpos($value, $subString)) {
1005 48
            static::reportInvalidArgument(\sprintf(
1006 48
                $message ?: '%2$s was not expected to be contained in a value. Got: %s',
1007 48
                static::valueToString($value),
1008 48
                static::valueToString($subString)
1009
            ));
1010
        }
1011 32
    }
1012
1013
    /**
1014
     * @param mixed  $value
1015
     * @param string $message
1016
     *
1017
     * @throws InvalidArgumentException
1018
     */
1019 40
    public static function notWhitespaceOnly($value, $message = '')
1020
    {
1021 40
        if (\preg_match('/^\s*$/', $value)) {
1022 24
            static::reportInvalidArgument(\sprintf(
1023 24
                $message ?: 'Expected a non-whitespace string. Got: %s',
1024 24
                static::valueToString($value)
1025
            ));
1026
        }
1027 16
    }
1028
1029
    /**
1030
     * @param mixed  $value
1031
     * @param string $prefix
1032
     * @param string $message
1033
     *
1034
     * @throws InvalidArgumentException
1035
     */
1036 48 View Code Duplication
    public static function startsWith($value, $prefix, $message = '')
1037
    {
1038 48
        if (0 !== \strpos($value, $prefix)) {
1039 32
            static::reportInvalidArgument(\sprintf(
1040 32
                $message ?: 'Expected a value to start with %2$s. Got: %s',
1041 32
                static::valueToString($value),
1042 32
                static::valueToString($prefix)
1043
            ));
1044
        }
1045 16
    }
1046
1047
    /**
1048
     * @param mixed  $value
1049
     * @param string $message
1050
     *
1051
     * @throws InvalidArgumentException
1052
     */
1053 24
    public static function startsWithLetter($value, $message = '')
1054
    {
1055 24
        $valid = isset($value[0]);
1056
1057 24
        if ($valid) {
1058 20
            $locale = \setlocale(LC_CTYPE, 0);
1059 20
            \setlocale(LC_CTYPE, 'C');
1060 20
            $valid = \ctype_alpha($value[0]);
1061 20
            \setlocale(LC_CTYPE, $locale);
1062
        }
1063
1064 24
        if (!$valid) {
1065 12
            static::reportInvalidArgument(\sprintf(
1066 12
                $message ?: 'Expected a value to start with a letter. Got: %s',
1067 12
                static::valueToString($value)
1068
            ));
1069
        }
1070 12
    }
1071
1072
    /**
1073
     * @param mixed  $value
1074
     * @param string $suffix
1075
     * @param string $message
1076
     *
1077
     * @throws InvalidArgumentException
1078
     */
1079 48 View Code Duplication
    public static function endsWith($value, $suffix, $message = '')
1080
    {
1081 48
        if ($suffix !== \substr($value, -\strlen($suffix))) {
1082 32
            static::reportInvalidArgument(\sprintf(
1083 32
                $message ?: 'Expected a value to end with %2$s. Got: %s',
1084 32
                static::valueToString($value),
1085 32
                static::valueToString($suffix)
1086
            ));
1087
        }
1088 16
    }
1089
1090
    /**
1091
     * @param mixed  $value
1092
     * @param mixed  $pattern
1093
     * @param string $message
1094
     *
1095
     * @throws InvalidArgumentException
1096
     */
1097 12
    public static function regex($value, $pattern, $message = '')
1098
    {
1099 12
        if (!\preg_match($pattern, $value)) {
1100 8
            static::reportInvalidArgument(\sprintf(
1101 8
                $message ?: 'The value %s does not match the expected pattern.',
1102 8
                static::valueToString($value)
1103
            ));
1104
        }
1105 4
    }
1106
1107
    /**
1108
     * @param mixed  $value
1109
     * @param mixed  $pattern
1110
     * @param string $message
1111
     *
1112
     * @throws InvalidArgumentException
1113
     */
1114 12
    public static function notRegex($value, $pattern, $message = '')
1115
    {
1116 12
        if (\preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) {
1117 4
            static::reportInvalidArgument(\sprintf(
1118 4
                $message ?: 'The value %s matches the pattern %s (at offset %d).',
1119 4
                static::valueToString($value),
1120 4
                static::valueToString($pattern),
1121 4
                $matches[0][1]
1122
            ));
1123
        }
1124 8
    }
1125
1126
    /**
1127
     * @psalm-assert !numeric $value
1128
     *
1129
     * @param mixed  $value
1130
     * @param string $message
1131
     *
1132
     * @throws InvalidArgumentException
1133
     */
1134 28 View Code Duplication
    public static function unicodeLetters($value, $message = '')
1135
    {
1136 28
        static::string($value);
1137
1138 28
        if (!\preg_match('/^\p{L}+$/u', $value)) {
1139 16
            static::reportInvalidArgument(\sprintf(
1140 16
                $message ?: 'Expected a value to contain only Unicode letters. Got: %s',
1141 16
                static::valueToString($value)
1142
            ));
1143
        }
1144 12
    }
1145
1146
    /**
1147
     * @psalm-assert string $value
1148
     *
1149
     * @param mixed  $value
1150
     * @param string $message
1151
     *
1152
     * @throws InvalidArgumentException
1153
     */
1154 20 View Code Duplication
    public static function alpha($value, $message = '')
1155
    {
1156 20
        static::string($value);
1157
1158 12
        $locale = \setlocale(LC_CTYPE, 0);
1159 12
        \setlocale(LC_CTYPE, 'C');
1160 12
        $valid = !\ctype_alpha($value);
1161 12
        \setlocale(LC_CTYPE, $locale);
1162
1163 12
        if ($valid) {
1164 8
            static::reportInvalidArgument(\sprintf(
1165 8
                $message ?: 'Expected a value to contain only letters. Got: %s',
1166 8
                static::valueToString($value)
1167
            ));
1168
        }
1169 4
    }
1170
1171
    /**
1172
     * @param mixed  $value
1173
     * @param string $message
1174
     *
1175
     * @throws InvalidArgumentException
1176
     */
1177 12 View Code Duplication
    public static function digits($value, $message = '')
1178
    {
1179 12
        $locale = \setlocale(LC_CTYPE, 0);
1180 12
        \setlocale(LC_CTYPE, 'C');
1181 12
        $valid = !\ctype_digit($value);
1182 12
        \setlocale(LC_CTYPE, $locale);
1183
1184 12
        if ($valid) {
1185 8
            static::reportInvalidArgument(\sprintf(
1186 8
                $message ?: 'Expected a value to contain digits only. Got: %s',
1187 8
                static::valueToString($value)
1188
            ));
1189
        }
1190 4
    }
1191
1192
    /**
1193
     * @param mixed  $value
1194
     * @param string $message
1195
     *
1196
     * @throws InvalidArgumentException
1197
     */
1198 12 View Code Duplication
    public static function alnum($value, $message = '')
1199
    {
1200 12
        $locale = \setlocale(LC_CTYPE, 0);
1201 12
        \setlocale(LC_CTYPE, 'C');
1202 12
        $valid = !\ctype_alnum($value);
1203 12
        \setlocale(LC_CTYPE, $locale);
1204
1205 12
        if ($valid) {
1206 8
            static::reportInvalidArgument(\sprintf(
1207 8
                $message ?: 'Expected a value to contain letters and digits only. Got: %s',
1208 8
                static::valueToString($value)
1209
            ));
1210
        }
1211 4
    }
1212
1213
    /**
1214
     * @param mixed  $value
1215
     * @param string $message
1216
     *
1217
     * @throws InvalidArgumentException
1218
     */
1219 16 View Code Duplication
    public static function lower($value, $message = '')
1220
    {
1221 16
        $locale = \setlocale(LC_CTYPE, 0);
1222 16
        \setlocale(LC_CTYPE, 'C');
1223 16
        $valid = !\ctype_lower($value);
1224 16
        \setlocale(LC_CTYPE, $locale);
1225
1226 16
        if ($valid) {
1227 12
            static::reportInvalidArgument(\sprintf(
1228 12
                $message ?: 'Expected a value to contain lowercase characters only. Got: %s',
1229 12
                static::valueToString($value)
1230
            ));
1231
        }
1232 4
    }
1233
1234
    /**
1235
     * @param mixed  $value
1236
     * @param string $message
1237
     *
1238
     * @throws InvalidArgumentException
1239
     */
1240 16 View Code Duplication
    public static function upper($value, $message = '')
1241
    {
1242 16
        $locale = \setlocale(LC_CTYPE, 0);
1243 16
        \setlocale(LC_CTYPE, 'C');
1244 16
        $valid = !\ctype_upper($value);
1245 16
        \setlocale(LC_CTYPE, $locale);
1246
1247 16
        if ($valid) {
1248 12
            static::reportInvalidArgument(\sprintf(
1249 12
                $message ?: 'Expected a value to contain uppercase characters only. Got: %s',
1250 12
                static::valueToString($value)
1251
            ));
1252
        }
1253 4
    }
1254
1255
    /**
1256
     * @param mixed  $value
1257
     * @param mixed  $length
1258
     * @param string $message
1259
     *
1260
     * @throws InvalidArgumentException
1261
     */
1262 36
    public static function length($value, $length, $message = '')
1263
    {
1264 36
        if ($length !== static::strlen($value)) {
1265 24
            static::reportInvalidArgument(\sprintf(
1266 24
                $message ?: 'Expected a value to contain %2$s characters. Got: %s',
1267 24
                static::valueToString($value),
1268 24
                $length
1269
            ));
1270
        }
1271 12
    }
1272
1273
    /**
1274
     * Inclusive min.
1275
     *
1276
     * @param mixed  $value
1277
     * @param mixed  $min
1278
     * @param string $message
1279
     *
1280
     * @throws InvalidArgumentException
1281
     */
1282 36
    public static function minLength($value, $min, $message = '')
1283
    {
1284 36
        if (static::strlen($value) < $min) {
1285 12
            static::reportInvalidArgument(\sprintf(
1286 12
                $message ?: 'Expected a value to contain at least %2$s characters. Got: %s',
1287 12
                static::valueToString($value),
1288 12
                $min
1289
            ));
1290
        }
1291 24
    }
1292
1293
    /**
1294
     * Inclusive max.
1295
     *
1296
     * @param mixed  $value
1297
     * @param mixed  $max
1298
     * @param string $message
1299
     *
1300
     * @throws InvalidArgumentException
1301
     */
1302 36
    public static function maxLength($value, $max, $message = '')
1303
    {
1304 36
        if (static::strlen($value) > $max) {
1305 12
            static::reportInvalidArgument(\sprintf(
1306 12
                $message ?: 'Expected a value to contain at most %2$s characters. Got: %s',
1307 12
                static::valueToString($value),
1308 12
                $max
1309
            ));
1310
        }
1311 24
    }
1312
1313
    /**
1314
     * Inclusive , so Assert::lengthBetween('asd', 3, 5); passes the assertion.
1315
     *
1316
     * @param mixed  $value
1317
     * @param mixed  $min
1318
     * @param mixed  $max
1319
     * @param string $message
1320
     *
1321
     * @throws InvalidArgumentException
1322
     */
1323 60 View Code Duplication
    public static function lengthBetween($value, $min, $max, $message = '')
1324
    {
1325 60
        $length = static::strlen($value);
1326
1327 60
        if ($length < $min || $length > $max) {
1328 24
            static::reportInvalidArgument(\sprintf(
1329 24
                $message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s',
1330 24
                static::valueToString($value),
1331 24
                $min,
1332 24
                $max
1333
            ));
1334
        }
1335 36
    }
1336
1337
    /**
1338
     * Will also pass if $value is a directory, use Assert::file() instead if you need to be sure it is a file.
1339
     *
1340
     * @param mixed  $value
1341
     * @param string $message
1342
     *
1343
     * @throws InvalidArgumentException
1344
     */
1345 36 View Code Duplication
    public static function fileExists($value, $message = '')
1346
    {
1347 36
        static::string($value);
1348
1349 36
        if (!\file_exists($value)) {
1350 12
            static::reportInvalidArgument(\sprintf(
1351 12
                $message ?: 'The file %s does not exist.',
1352 12
                static::valueToString($value)
1353
            ));
1354
        }
1355 24
    }
1356
1357
    /**
1358
     * @param mixed  $value
1359
     * @param string $message
1360
     *
1361
     * @throws InvalidArgumentException
1362
     */
1363 12 View Code Duplication
    public static function file($value, $message = '')
1364
    {
1365 12
        static::fileExists($value, $message);
1366
1367 8
        if (!\is_file($value)) {
1368 4
            static::reportInvalidArgument(\sprintf(
1369 4
                $message ?: 'The path %s is not a file.',
1370 4
                static::valueToString($value)
1371
            ));
1372
        }
1373 4
    }
1374
1375
    /**
1376
     * @param mixed  $value
1377
     * @param string $message
1378
     *
1379
     * @throws InvalidArgumentException
1380
     */
1381 12 View Code Duplication
    public static function directory($value, $message = '')
1382
    {
1383 12
        static::fileExists($value, $message);
1384
1385 8
        if (!\is_dir($value)) {
1386 4
            static::reportInvalidArgument(\sprintf(
1387 4
                $message ?: 'The path %s is no directory.',
1388 4
                static::valueToString($value)
1389
            ));
1390
        }
1391 4
    }
1392
1393
    /**
1394
     * @param mixed  $value
1395
     * @param string $message
1396
     *
1397
     * @throws InvalidArgumentException
1398
     */
1399
    public static function readable($value, $message = '')
1400
    {
1401
        if (!\is_readable($value)) {
1402
            static::reportInvalidArgument(\sprintf(
1403
                $message ?: 'The path %s is not readable.',
1404
                static::valueToString($value)
1405
            ));
1406
        }
1407
    }
1408
1409
    /**
1410
     * @param mixed  $value
1411
     * @param string $message
1412
     *
1413
     * @throws InvalidArgumentException
1414
     */
1415
    public static function writable($value, $message = '')
1416
    {
1417
        if (!\is_writable($value)) {
1418
            static::reportInvalidArgument(\sprintf(
1419
                $message ?: 'The path %s is not writable.',
1420
                static::valueToString($value)
1421
            ));
1422
        }
1423
    }
1424
1425
    /**
1426
     * @psalm-assert class-string $value
1427
     *
1428
     * @param mixed  $value
1429
     * @param string $message
1430
     *
1431
     * @throws InvalidArgumentException
1432
     */
1433 8
    public static function classExists($value, $message = '')
1434
    {
1435 8
        if (!\class_exists($value)) {
1436 4
            static::reportInvalidArgument(\sprintf(
1437 4
                $message ?: 'Expected an existing class name. Got: %s',
1438 4
                static::valueToString($value)
1439
            ));
1440
        }
1441 4
    }
1442
1443
    /**
1444
     * @param mixed         $value
1445
     * @param string|object $class
1446
     * @param string        $message
1447
     *
1448
     * @throws InvalidArgumentException
1449
     */
1450 8
    public static function subclassOf($value, $class, $message = '')
1451
    {
1452 8
        if (!\is_subclass_of($value, $class)) {
1453 4
            static::reportInvalidArgument(\sprintf(
1454 4
                $message ?: 'Expected a sub-class of %2$s. Got: %s',
1455 4
                static::valueToString($value),
1456 4
                static::valueToString($class)
1457
            ));
1458
        }
1459 4
    }
1460
1461
    /**
1462
     * @psalm-assert class-string $value
1463
     *
1464
     * @param mixed  $value
1465
     * @param string $message
1466
     *
1467
     * @throws InvalidArgumentException
1468
     */
1469 8
    public static function interfaceExists($value, $message = '')
1470
    {
1471 8
        if (!\interface_exists($value)) {
1472 4
            static::reportInvalidArgument(\sprintf(
1473 4
                $message ?: 'Expected an existing interface name. got %s',
1474 4
                static::valueToString($value)
1475
            ));
1476
        }
1477 4
    }
1478
1479
    /**
1480
     * @param mixed  $value
1481
     * @param mixed  $interface
1482
     * @param string $message
1483
     *
1484
     * @throws InvalidArgumentException
1485
     */
1486 8 View Code Duplication
    public static function implementsInterface($value, $interface, $message = '')
1487
    {
1488 8
        if (!\in_array($interface, \class_implements($value))) {
1489 4
            static::reportInvalidArgument(\sprintf(
1490 4
                $message ?: 'Expected an implementation of %2$s. Got: %s',
1491 4
                static::valueToString($value),
1492 4
                static::valueToString($interface)
1493
            ));
1494
        }
1495 4
    }
1496
1497
    /**
1498
     * @param string|object $classOrObject
1499
     * @param mixed         $property
1500
     * @param string        $message
1501
     *
1502
     * @throws InvalidArgumentException
1503
     */
1504 12 View Code Duplication
    public static function propertyExists($classOrObject, $property, $message = '')
1505
    {
1506 12
        if (!\property_exists($classOrObject, $property)) {
1507 4
            static::reportInvalidArgument(\sprintf(
1508 4
                $message ?: 'Expected the property %s to exist.',
1509 4
                static::valueToString($property)
1510
            ));
1511
        }
1512 8
    }
1513
1514
    /**
1515
     * @param string|object $classOrObject
1516
     * @param mixed         $property
1517
     * @param string        $message
1518
     *
1519
     * @throws InvalidArgumentException
1520
     */
1521 12 View Code Duplication
    public static function propertyNotExists($classOrObject, $property, $message = '')
1522
    {
1523 12
        if (\property_exists($classOrObject, $property)) {
1524 8
            static::reportInvalidArgument(\sprintf(
1525 8
                $message ?: 'Expected the property %s to not exist.',
1526 8
                static::valueToString($property)
1527
            ));
1528
        }
1529 4
    }
1530
1531
    /**
1532
     * @param string|object $classOrObject
1533
     * @param mixed         $method
1534
     * @param string        $message
1535
     *
1536
     * @throws InvalidArgumentException
1537
     */
1538 27 View Code Duplication
    public static function methodExists($classOrObject, $method, $message = '')
1539
    {
1540 27
        if (!\method_exists($classOrObject, $method)) {
1541 19
            static::reportInvalidArgument(\sprintf(
1542 19
                $message ?: 'Expected the method %s to exist.',
1543 19
                static::valueToString($method)
1544
            ));
1545
        }
1546 8
    }
1547
1548
    /**
1549
     * @param string|object $classOrObject
1550
     * @param mixed         $method
1551
     * @param string        $message
1552
     *
1553
     * @throws InvalidArgumentException
1554
     */
1555 27 View Code Duplication
    public static function methodNotExists($classOrObject, $method, $message = '')
1556
    {
1557 27
        if (\method_exists($classOrObject, $method)) {
1558 8
            static::reportInvalidArgument(\sprintf(
1559 8
                $message ?: 'Expected the method %s to not exist.',
1560 8
                static::valueToString($method)
1561
            ));
1562
        }
1563 19
    }
1564
1565
    /**
1566
     * @param array      $array
1567
     * @param string|int $key
1568
     * @param string     $message
1569
     *
1570
     * @throws InvalidArgumentException
1571
     */
1572 12 View Code Duplication
    public static function keyExists($array, $key, $message = '')
1573
    {
1574 12
        if (!(isset($array[$key]) || \array_key_exists($key, $array))) {
1575 4
            static::reportInvalidArgument(\sprintf(
1576 4
                $message ?: 'Expected the key %s to exist.',
1577 4
                static::valueToString($key)
1578
            ));
1579
        }
1580 8
    }
1581
1582
    /**
1583
     * @param array      $array
1584
     * @param string|int $key
1585
     * @param string     $message
1586
     *
1587
     * @throws InvalidArgumentException
1588
     */
1589 12 View Code Duplication
    public static function keyNotExists($array, $key, $message = '')
1590
    {
1591 12
        if (isset($array[$key]) || \array_key_exists($key, $array)) {
1592 8
            static::reportInvalidArgument(\sprintf(
1593 8
                $message ?: 'Expected the key %s to not exist.',
1594 8
                static::valueToString($key)
1595
            ));
1596
        }
1597 4
    }
1598
1599
    /**
1600
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1601
     *
1602
     * @param mixed  $array
1603
     * @param mixed  $number
1604
     * @param string $message
1605
     *
1606
     * @throws InvalidArgumentException
1607
     */
1608 8
    public static function count($array, $number, $message = '')
1609
    {
1610 8
        static::eq(
1611 8
            \count($array),
1612
            $number,
1613 8
            $message ?: \sprintf('Expected an array to contain %d elements. Got: %d.', $number, \count($array))
1614
        );
1615 4
    }
1616
1617
    /**
1618
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1619
     *
1620
     * @param mixed  $array
1621
     * @param mixed  $min
1622
     * @param string $message
1623
     *
1624
     * @throws InvalidArgumentException
1625
     */
1626 12 View Code Duplication
    public static function minCount($array, $min, $message = '')
1627
    {
1628 12
        if (\count($array) < $min) {
1629 4
            static::reportInvalidArgument(\sprintf(
1630 4
                $message ?: 'Expected an array to contain at least %2$d elements. Got: %d',
1631 4
                \count($array),
1632 4
                $min
1633
            ));
1634
        }
1635 8
    }
1636
1637
    /**
1638
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1639
     *
1640
     * @param mixed  $array
1641
     * @param mixed  $max
1642
     * @param string $message
1643
     *
1644
     * @throws InvalidArgumentException
1645
     */
1646 12 View Code Duplication
    public static function maxCount($array, $max, $message = '')
1647
    {
1648 12
        if (\count($array) > $max) {
1649 4
            static::reportInvalidArgument(\sprintf(
1650 4
                $message ?: 'Expected an array to contain at most %2$d elements. Got: %d',
1651 4
                \count($array),
1652 4
                $max
1653
            ));
1654
        }
1655 8
    }
1656
1657
    /**
1658
     * Does not check if $array is countable, this can generate a warning on php versions after 7.2.
1659
     *
1660
     * @param mixed  $array
1661
     * @param mixed  $min
1662
     * @param mixed  $max
1663
     * @param string $message
1664
     *
1665
     * @throws InvalidArgumentException
1666
     */
1667 20
    public static function countBetween($array, $min, $max, $message = '')
1668
    {
1669 20
        $count = \count($array);
1670
1671 20
        if ($count < $min || $count > $max) {
1672 8
            static::reportInvalidArgument(\sprintf(
1673 8
                $message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d',
1674 8
                $count,
1675 8
                $min,
1676 8
                $max
1677
            ));
1678
        }
1679 12
    }
1680
1681
    /**
1682
     * @param mixed  $array
1683
     * @param string $message
1684
     *
1685
     * @throws InvalidArgumentException
1686
     */
1687 24
    public static function isList($array, $message = '')
1688
    {
1689 24
        if (!\is_array($array) || !$array || \array_keys($array) !== \range(0, \count($array) - 1)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $array of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1690 20
            static::reportInvalidArgument(
1691 20
                $message ?: 'Expected list - non-associative array.'
1692
            );
1693
        }
1694 4
    }
1695
1696
    /**
1697
     * @param mixed  $array
1698
     * @param string $message
1699
     *
1700
     * @throws InvalidArgumentException
1701
     */
1702 16
    public static function isMap($array, $message = '')
1703
    {
1704
        if (
1705 16
            !\is_array($array) ||
1706 16
            !$array ||
0 ignored issues
show
Bug Best Practice introduced by
The expression $array of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1707
            \array_keys($array) !== \array_filter(\array_keys($array), function ($key) {
1708 12
                return \is_string($key);
1709 16
            })
1710
        ) {
1711 12
            static::reportInvalidArgument(
1712 12
                $message ?: 'Expected map - associative array with string keys.'
1713
            );
1714
        }
1715 4
    }
1716
1717
    /**
1718
     * @param mixed  $value
1719
     * @param string $message
1720
     *
1721
     * @throws InvalidArgumentException
1722
     */
1723 56
    public static function uuid($value, $message = '')
1724
    {
1725 56
        $value = \str_replace(array('urn:', 'uuid:', '{', '}'), '', $value);
1726
1727
        // The nil UUID is special form of UUID that is specified to have all
1728
        // 128 bits set to zero.
1729 56
        if ('00000000-0000-0000-0000-000000000000' === $value) {
1730 4
            return;
1731
        }
1732
1733 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)) {
1734 20
            static::reportInvalidArgument(\sprintf(
1735 20
                $message ?: 'Value %s is not a valid UUID.',
1736 20
                static::valueToString($value)
1737
            ));
1738
        }
1739 32
    }
1740
1741
    /**
1742
     * @param Closure       $expression
1743
     * @param string|object $class
1744
     * @param string        $message
1745
     *
1746
     * @throws InvalidArgumentException
1747
     */
1748 24
    public static function throws(Closure $expression, $class = 'Exception', $message = '')
1749
    {
1750 24
        static::string($class);
1751
1752 24
        $actual = 'none';
1753
1754
        try {
1755 24
            $expression();
1756 24
        } catch (Exception $e) {
1757 20
            $actual = \get_class($e);
1758 20
            if ($e instanceof $class) {
1759 20
                return;
1760
            }
1761 4
        } catch (Throwable $e) {
0 ignored issues
show
Bug introduced by
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
1762 4
            $actual = \get_class($e);
1763 4
            if ($e instanceof $class) {
1764 4
                return;
1765
            }
1766
        }
1767
1768 8
        static::reportInvalidArgument($message ?: \sprintf(
1769 8
            'Expected to throw "%s", got "%s"',
1770 8
            $class,
1771 8
            $actual
1772
        ));
1773
    }
1774
1775
    /**
1776
     * @throws BadMethodCallException
1777
     */
1778 1401
    public static function __callStatic($name, $arguments)
1779
    {
1780 1401
        if ('nullOr' === \substr($name, 0, 6)) {
1781 520
            if (null !== $arguments[0]) {
1782 427
                $method = \lcfirst(\substr($name, 6));
1783 427
                \call_user_func_array(array('static', $method), $arguments);
1784
            }
1785
1786 296
            return;
1787
        }
1788
1789 881
        if ('all' === \substr($name, 0, 3)) {
1790 880
            static::isIterable($arguments[0]);
1791
1792 880
            $method = \lcfirst(\substr($name, 3));
1793 880
            $args = $arguments;
1794
1795 880
            foreach ($arguments[0] as $entry) {
1796 880
                $args[0] = $entry;
1797
1798 880
                \call_user_func_array(array('static', $method), $args);
1799
            }
1800
1801 412
            return;
1802
        }
1803
1804 1
        throw new BadMethodCallException('No such method: '.$name);
1805
    }
1806
1807
    /**
1808
     * @param mixed $value
1809
     *
1810
     * @return string
1811
     */
1812 645
    protected static function valueToString($value)
1813
    {
1814 645
        if (null === $value) {
1815 11
            return 'null';
1816
        }
1817
1818 636
        if (true === $value) {
1819 15
            return 'true';
1820
        }
1821
1822 626
        if (false === $value) {
1823 13
            return 'false';
1824
        }
1825
1826 613
        if (\is_array($value)) {
1827 1
            return 'array';
1828
        }
1829
1830 612
        if (\is_object($value)) {
1831 2
            if (\method_exists($value, '__toString')) {
1832 1
                return \get_class($value).': '.self::valueToString($value->__toString());
1833
            }
1834
1835 1
            return \get_class($value);
1836
        }
1837
1838 611
        if (\is_resource($value)) {
1839 1
            return 'resource';
1840
        }
1841
1842 611
        if (\is_string($value)) {
1843 525
            return '"'.$value.'"';
1844
        }
1845
1846 94
        return (string) $value;
1847
    }
1848
1849
    /**
1850
     * @param mixed $value
1851
     *
1852
     * @return string
1853
     */
1854 242
    protected static function typeToString($value)
1855
    {
1856 242
        return \is_object($value) ? \get_class($value) : \gettype($value);
1857
    }
1858
1859 168
    protected static function strlen($value)
1860
    {
1861 168
        if (!\function_exists('mb_detect_encoding')) {
1862
            return \strlen($value);
1863
        }
1864
1865 168
        if (false === $encoding = \mb_detect_encoding($value)) {
1866
            return \strlen($value);
1867
        }
1868
1869 168
        return \mb_strlen($value, $encoding);
1870
    }
1871
1872
    /**
1873
     * @param string $message
1874
     *
1875
     * @throws InvalidArgumentException
1876
     */
1877 942
    protected static function reportInvalidArgument($message)
1878
    {
1879 942
        throw new InvalidArgumentException($message);
1880
    }
1881
1882
    private function __construct()
1883
    {
1884
    }
1885
}
1886