comparison core/lib/Drupal/Component/Assertion/Inspector.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
1 <?php
2
3 namespace Drupal\Component\Assertion;
4
5 use Traversable;
6
7 /**
8 * Generic inspections for the assert() statement.
9 *
10 * This is a static function collection for inspecting variable contents. All
11 * functions in this collection check a variable against an assertion about its
12 * structure.
13 *
14 * Example call:
15 * @code
16 * assert('Drupal\\Component\\Assertion\\Inspector::assertAllStrings($array)');
17 * @endcode
18 *
19 * @ingroup php_assert
20 */
21 class Inspector {
22
23 /**
24 * Asserts argument can be traversed with foreach.
25 *
26 * @param mixed $traversable
27 * Variable to be examined.
28 *
29 * @return bool
30 * TRUE if $traversable can be traversed with foreach.
31 */
32 public static function assertTraversable($traversable) {
33 return is_array($traversable) || $traversable instanceof Traversable;
34 }
35
36 /**
37 * Asserts callback returns TRUE for each member of a traversable.
38 *
39 * This is less memory intensive than using array_filter() to build a second
40 * array and then comparing the arrays. Many of the other functions in this
41 * collection alias this function passing a specific callback to make the
42 * code more readable.
43 *
44 * @param callable $callable
45 * Callback function.
46 * @param mixed $traversable
47 * Variable to be examined.
48 *
49 * @return bool
50 * TRUE if $traversable can be traversed and $callable returns TRUE on
51 * all members.
52 *
53 * @see http://php.net/manual/language.types.callable.php
54 */
55 public static function assertAll(callable $callable, $traversable) {
56 if (static::assertTraversable($traversable)) {
57 foreach ($traversable as $member) {
58 if (!$callable($member)) {
59 return FALSE;
60 }
61 }
62 return TRUE;
63 }
64 return FALSE;
65 }
66
67 /**
68 * Asserts that all members are strings.
69 *
70 * Use this only if it is vital that the members not be objects, otherwise
71 * test with ::assertAllStringable().
72 *
73 * @param mixed $traversable
74 * Variable to be examined.
75 *
76 * @return bool
77 * TRUE if $traversable can be traversed and all members are strings.
78 */
79 public static function assertAllStrings($traversable) {
80 return static::assertAll('is_string', $traversable);
81 }
82
83 /**
84 * Asserts all members are strings or objects with magic __toString() method.
85 *
86 * @param mixed $traversable
87 * Variable to be examined.
88 *
89 * @return bool
90 * TRUE if $traversable can be traversed and all members are strings or
91 * objects with __toString().
92 */
93 public static function assertAllStringable($traversable) {
94 if (static::assertTraversable($traversable)) {
95 foreach ($traversable as $member) {
96 if (!static::assertStringable($member)) {
97 return FALSE;
98 }
99 }
100 return TRUE;
101 }
102 return FALSE;
103 }
104
105 /**
106 * Asserts argument is a string or an object castable to a string.
107 *
108 * Use this instead of is_string() alone unless the argument being an object
109 * in any way will cause a problem.
110 *
111 * @param mixed $string
112 * Variable to be examined
113 *
114 * @return bool
115 * TRUE if $string is a string or an object castable to a string.
116 */
117 public static function assertStringable($string) {
118 return is_string($string) || (is_object($string) && method_exists($string, '__toString'));
119 }
120
121 /**
122 * Asserts that all members are arrays.
123 *
124 * @param mixed $traversable
125 * Variable to be examined.
126 *
127 * @return bool
128 * TRUE if $traversable can be traversed and all members are arrays.
129 */
130 public static function assertAllArrays($traversable) {
131 return static::assertAll('is_array', $traversable);
132 }
133
134 /**
135 * Asserts that the array is strict.
136 *
137 * What PHP calls arrays are more formally called maps in most other
138 * programming languages. A map is a datatype that associates values to keys.
139 * The term 'strict array' here refers to a 0-indexed array in the classic
140 * sense found in programming languages other than PHP.
141 *
142 * @param mixed $array
143 * Variable to be examined.
144 *
145 * @return bool
146 * TRUE if $traversable is a 0-indexed array.
147 *
148 * @see http://php.net/manual/language.types.array.php
149 */
150 public static function assertStrictArray($array) {
151 if (!is_array($array)) {
152 return FALSE;
153 }
154 $i = 0;
155
156 foreach (array_keys($array) as $key) {
157 if ($i !== $key) {
158 return FALSE;
159 }
160 $i++;
161 }
162 return TRUE;
163 }
164
165 /**
166 * Asserts all members are strict arrays.
167 *
168 * @param mixed $traversable
169 * Variable to be examined.
170 *
171 * @return bool
172 * TRUE if $traversable can be traversed and all members are strict arrays.
173 *
174 * @see ::assertStrictArray
175 */
176 public static function assertAllStrictArrays($traversable) {
177 return static::assertAll([__CLASS__, 'assertStrictArray'], $traversable);
178 }
179
180 /**
181 * Asserts all given keys exist in every member array.
182 *
183 * Drupal has several data structure arrays that require certain keys be set.
184 * You can overload this function to specify a list of required keys. All
185 * of the keys must be set for this method to return TRUE.
186 *
187 * As an example, this assertion tests for the keys of a theme registry.
188 *
189 * @code
190 * assert('Drupal\\Component\\Assertion\\Inspector::assertAllHaveKey(
191 * $arrayToTest, "type", "theme path", "function", "template", "variables", "render element", "preprocess functions")');
192 * @endcode
193 *
194 * Note: If a method requires certain keys to be present it will usually be
195 * specific about the data types for the values of those keys. Therefore it
196 * will be best to write a specific test for it. Such tests are either bound
197 * to the object that uses them, or are collected into one assertion set for
198 * the package.
199 *
200 * @param mixed $traversable
201 * Variable to be examined.
202 * @param string ...
203 * Keys to be searched for.
204 *
205 * @return bool
206 * TRUE if $traversable can be traversed and all members have all keys.
207 */
208 public static function assertAllHaveKey($traversable) {
209 $args = func_get_args();
210 unset($args[0]);
211
212 if (static::assertTraversable($traversable)) {
213 foreach ($traversable as $member) {
214 foreach ($args as $key) {
215 if (!array_key_exists($key, $member)) {
216 return FALSE;
217 }
218 }
219 }
220 return TRUE;
221 }
222 return FALSE;
223 }
224
225 /**
226 * Asserts that all members are integer values.
227 *
228 * @param mixed $traversable
229 * Variable to be examined.
230 *
231 * @return bool
232 * TRUE if $traversable can be traversed and all members are integers.
233 */
234 public static function assertAllIntegers($traversable) {
235 return static::assertAll('is_int', $traversable);
236 }
237
238 /**
239 * Asserts that all members are float values.
240 *
241 * @param mixed $traversable
242 * Variable to be examined.
243 *
244 * @return bool
245 * TRUE if $traversable can be traversed and all members are floating point
246 * numbers.
247 */
248 public static function assertAllFloat($traversable) {
249 return static::assertAll('is_float', $traversable);
250 }
251
252 /**
253 * Asserts that all members are callable.
254 *
255 * @param mixed $traversable
256 * Variable to be examined.
257 *
258 * @return bool
259 * TRUE if $traversable can be traversed and all members are callable.
260 */
261 public static function assertAllCallable($traversable) {
262 return static::assertAll('is_callable', $traversable);
263 }
264
265 /**
266 * Asserts that all members are not empty.
267 *
268 * @param mixed $traversable
269 * Variable to be examined.
270 *
271 * @return bool
272 * TRUE if $traversable can be traversed and all members not empty.
273 */
274 public static function assertAllNotEmpty($traversable) {
275 if (static::assertTraversable($traversable)) {
276 foreach ($traversable as $member) {
277 if (empty($member)) {
278 return FALSE;
279 }
280 }
281 return TRUE;
282 }
283 return FALSE;
284 }
285
286 /**
287 * Asserts all members are numeric data types or strings castable to such.
288 *
289 * @param mixed $traversable
290 * Variable to be examined.
291 *
292 * @return bool
293 * TRUE if $traversable can be traversed and all members are numeric.
294 */
295 public static function assertAllNumeric($traversable) {
296 return static::assertAll('is_numeric', $traversable);
297 }
298
299 /**
300 * Asserts that all members are strings that contain the specified string.
301 *
302 * This runs faster than the regular expression equivalent.
303 *
304 * @param string $pattern
305 * The needle to find.
306 * @param mixed $traversable
307 * Variable to examine.
308 * @param bool $case_sensitive
309 * TRUE to use strstr(), FALSE to use stristr() which is case insensitive.
310 *
311 * @return bool
312 * TRUE if $traversable can be traversed and all members are strings
313 * containing $pattern.
314 */
315 public static function assertAllMatch($pattern, $traversable, $case_sensitive = FALSE) {
316 if (static::assertTraversable($traversable)) {
317 if ($case_sensitive) {
318 foreach ($traversable as $member) {
319 if (!(is_string($member) && strstr($member, $pattern))) {
320 return FALSE;
321 }
322 }
323 }
324 else {
325 foreach ($traversable as $member) {
326 if (!(is_string($member) && stristr($member, $pattern))) {
327 return FALSE;
328 }
329 }
330 }
331 return TRUE;
332 }
333 return FALSE;
334 }
335
336
337 /**
338 * Asserts that all members are strings matching a regular expression.
339 *
340 * @param string $pattern
341 * Regular expression string to find.
342 * @param mixed $traversable
343 * Variable to be examined.
344 *
345 * @return bool
346 * TRUE if $traversable can be traversed and all members are strings
347 * matching $pattern.
348 */
349 public static function assertAllRegularExpressionMatch($pattern, $traversable) {
350 if (static::assertTraversable($traversable)) {
351 foreach ($traversable as $member) {
352 if (!is_string($member)) {
353 return FALSE;
354 }
355
356 if (!preg_match($pattern, $member)) {
357 return FALSE;
358 }
359 }
360 return TRUE;
361 }
362 return FALSE;
363 }
364
365 /**
366 * Asserts that all members are objects.
367 *
368 * When testing if a collection is composed of objects those objects should
369 * be given a common interface to implement and the test should be written to
370 * search for just that interface. While this method will allow tests for
371 * just object status or for multiple classes and interfaces this was done to
372 * allow tests to be written for existing code without altering it. Only use
373 * this method in that manner when testing code from third party vendors.
374 *
375 * Here are some examples:
376 * @code
377 * // Just test all are objects, like a cache.
378 * assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects(
379 * $collection');
380 *
381 * // Test if traversable objects (arrays won't pass this)
382 * assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects(
383 * $collection', \'\\Traversable\');
384 *
385 * // Test for the Foo class or Bar\None interface
386 * assert('Drupal\\Component\\Assertion\\Inspector::assertAllObjects(
387 * $collection', \'\\Foo\', \'\\Bar\\None\'');
388 * @endcode
389 *
390 * @param mixed $traversable
391 * Variable to be examined.
392 * @param string ...
393 * Classes and interfaces to test objects against.
394 *
395 * @return bool
396 * TRUE if $traversable can be traversed and all members are objects with
397 * at least one of the listed classes or interfaces.
398 */
399 public static function assertAllObjects($traversable) {
400 $args = func_get_args();
401 unset($args[0]);
402
403 if (static::assertTraversable($traversable)) {
404 foreach ($traversable as $member) {
405 if (count($args) > 0) {
406 foreach ($args as $instance) {
407 if ($member instanceof $instance) {
408 // We're continuing to the next member on the outer loop.
409 // @see http://php.net/continue
410 continue 2;
411 }
412 }
413 return FALSE;
414 }
415 elseif (!is_object($member)) {
416 return FALSE;
417 }
418 }
419 return TRUE;
420 }
421 return FALSE;
422 }
423
424 }