1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace TraderInteractive; |
4
|
|
|
|
5
|
|
|
use Exception; |
6
|
|
|
use InvalidArgumentException; |
7
|
|
|
use PHPUnit\Framework\TestCase; |
8
|
|
|
use StdClass; |
9
|
|
|
use TraderInteractive\Exceptions\FilterException; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* @coversDefaultClass \TraderInteractive\Filterer |
13
|
|
|
* @covers ::<private> |
14
|
|
|
*/ |
15
|
|
|
final class FiltererTest extends TestCase |
16
|
|
|
{ |
17
|
|
|
public function setUp() |
18
|
|
|
{ |
19
|
|
|
Filterer::setFilterAliases(Filterer::DEFAULT_FILTER_ALIASES); |
20
|
|
|
} |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @test |
24
|
|
|
* @covers ::filter |
25
|
|
|
*/ |
26
|
|
|
public function requiredPass() |
27
|
|
|
{ |
28
|
|
|
$result = Filterer::filter(['fieldOne' => ['required' => false]], []); |
29
|
|
|
$this->assertSame([true, [], null, []], $result); |
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @test |
34
|
|
|
* @covers ::filter |
35
|
|
|
*/ |
36
|
|
|
public function requiredFail() |
37
|
|
|
{ |
38
|
|
|
$result = Filterer::filter(['fieldOne' => ['required' => true]], []); |
39
|
|
|
$this->assertSame([false, null, "Field 'fieldOne' was required and not present", []], $result); |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @test |
44
|
|
|
* @covers ::filter |
45
|
|
|
*/ |
46
|
|
|
public function requiredWithADefaultWithoutInput() |
47
|
|
|
{ |
48
|
|
|
$result = Filterer::filter(['fieldOne' => ['required' => true, 'default' => 'theDefault']], []); |
49
|
|
|
$this->assertSame([true, ['fieldOne' => 'theDefault'], null, []], $result); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @test |
54
|
|
|
* @covers ::filter |
55
|
|
|
*/ |
56
|
|
|
public function requiredWithANullDefaultWithoutInput() |
57
|
|
|
{ |
58
|
|
|
$result = Filterer::filter(['fieldOne' => ['required' => true, 'default' => null]], []); |
59
|
|
|
$this->assertSame([true, ['fieldOne' => null], null, []], $result); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @test |
64
|
|
|
* @covers ::filter |
65
|
|
|
*/ |
66
|
|
View Code Duplication |
public function requiredWithADefaultWithInput() |
|
|
|
|
67
|
|
|
{ |
68
|
|
|
$result = Filterer::filter( |
69
|
|
|
['fieldOne' => ['required' => true, 'default' => 'theDefault']], |
70
|
|
|
['fieldOne' => 'notTheDefault'] |
71
|
|
|
); |
72
|
|
|
$this->assertSame([true, ['fieldOne' => 'notTheDefault'], null, []], $result); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @test |
77
|
|
|
* @covers ::filter |
78
|
|
|
*/ |
79
|
|
|
public function notRequiredWithADefaultWithoutInput() |
80
|
|
|
{ |
81
|
|
|
$result = Filterer::filter(['fieldOne' => ['default' => 'theDefault']], []); |
82
|
|
|
$this->assertSame([true, ['fieldOne' => 'theDefault'], null, []], $result); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* @test |
87
|
|
|
* @covers ::filter |
88
|
|
|
*/ |
89
|
|
|
public function notRequiredWithADefaultWithInput() |
90
|
|
|
{ |
91
|
|
|
$result = Filterer::filter(['fieldOne' => ['default' => 'theDefault']], ['fieldOne' => 'notTheDefault']); |
92
|
|
|
$this->assertSame([true, ['fieldOne' => 'notTheDefault'], null, []], $result); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @test |
97
|
|
|
* @covers ::filter |
98
|
|
|
*/ |
99
|
|
|
public function requiredDefaultPass() |
100
|
|
|
{ |
101
|
|
|
$result = Filterer::filter(['fieldOne' => []], []); |
102
|
|
|
$this->assertSame([true, [], null, []], $result); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* @test |
107
|
|
|
* @covers ::filter |
108
|
|
|
*/ |
109
|
|
|
public function requiredDefaultFail() |
110
|
|
|
{ |
111
|
|
|
$result = Filterer::filter(['fieldOne' => []], [], ['defaultRequired' => true]); |
112
|
|
|
$this->assertSame([false, null, "Field 'fieldOne' was required and not present", []], $result); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* @test |
117
|
|
|
* @covers ::filter |
118
|
|
|
*/ |
119
|
|
|
public function filterPass() |
120
|
|
|
{ |
121
|
|
|
$result = Filterer::filter(['fieldOne' => [['floatval']]], ['fieldOne' => '3.14']); |
122
|
|
|
$this->assertSame([true, ['fieldOne' => 3.14], null, []], $result); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* @test |
127
|
|
|
* @covers ::filter |
128
|
|
|
*/ |
129
|
|
|
public function filterDefaultShortNamePass() |
130
|
|
|
{ |
131
|
|
|
$result = Filterer::filter(['fieldOne' => [['float']]], ['fieldOne' => '3.14']); |
132
|
|
|
$this->assertSame([true, ['fieldOne' => 3.14], null, []], $result); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
/** |
136
|
|
|
* @test |
137
|
|
|
* @covers ::filter |
138
|
|
|
* @covers ::setFilterAliases |
139
|
|
|
*/ |
140
|
|
|
public function filterCustomShortNamePass() |
141
|
|
|
{ |
142
|
|
|
Filterer::setFilterAliases(['fval' => 'floatval']); |
143
|
|
|
$result = Filterer::filter(['fieldOne' => [['fval']]], ['fieldOne' => '3.14']); |
144
|
|
|
$this->assertSame([true, ['fieldOne' => 3.14], null, []], $result); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* @test |
149
|
|
|
* @covers ::filter |
150
|
|
|
* @covers ::setFilterAliases |
151
|
|
|
* @covers ::getFilterAliases |
152
|
|
|
*/ |
153
|
|
|
public function filterGetSetKnownFilters() |
154
|
|
|
{ |
155
|
|
|
$knownFilters = ['lower' => 'strtolower', 'upper' => 'strtoupper']; |
156
|
|
|
Filterer::setFilterAliases($knownFilters); |
157
|
|
|
$this->assertSame($knownFilters, Filterer::getFilterAliases()); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* @test |
162
|
|
|
* @covers ::filter |
163
|
|
|
*/ |
164
|
|
|
public function filterFail() |
165
|
|
|
{ |
166
|
|
|
$result = Filterer::filter( |
167
|
|
|
['fieldOne' => [['\TraderInteractive\FiltererTest::failingFilter']]], |
168
|
|
|
['fieldOne' => 'valueOne'] |
169
|
|
|
); |
170
|
|
|
$this->assertSame( |
171
|
|
|
[false, null, "Field 'fieldOne' with value 'valueOne' failed filtering, message 'i failed'", []], |
172
|
|
|
$result |
173
|
|
|
); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* @test |
178
|
|
|
* @covers ::filter |
179
|
|
|
*/ |
180
|
|
|
public function chainPass() |
181
|
|
|
{ |
182
|
|
|
$result = Filterer::filter(['fieldOne' => [['trim', 'a'], ['floatval']]], ['fieldOne' => 'a3.14']); |
183
|
|
|
$this->assertSame([true, ['fieldOne' => 3.14], null, []], $result); |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** |
187
|
|
|
* @test |
188
|
|
|
* @covers ::filter |
189
|
|
|
*/ |
190
|
|
View Code Duplication |
public function chainFail() |
|
|
|
|
191
|
|
|
{ |
192
|
|
|
$result = Filterer::filter( |
193
|
|
|
['fieldOne' => [['trim'], ['\TraderInteractive\FiltererTest::failingFilter']]], |
194
|
|
|
['fieldOne' => 'the value'] |
195
|
|
|
); |
196
|
|
|
$this->assertSame( |
197
|
|
|
[false, null, "Field 'fieldOne' with value 'the value' failed filtering, message 'i failed'", []], |
198
|
|
|
$result |
199
|
|
|
); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* @test |
204
|
|
|
* @covers ::filter |
205
|
|
|
*/ |
206
|
|
|
public function multiInputPass() |
207
|
|
|
{ |
208
|
|
|
$result = Filterer::filter( |
209
|
|
|
['fieldOne' => [['trim']], 'fieldTwo' => [['strtoupper']]], |
210
|
|
|
['fieldOne' => ' value', 'fieldTwo' => 'bob'] |
211
|
|
|
); |
212
|
|
|
$this->assertSame([true, ['fieldOne' => 'value', 'fieldTwo' => 'BOB'], null, []], $result); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* @test |
217
|
|
|
* @covers ::filter |
218
|
|
|
*/ |
219
|
|
|
public function multiInputFail() |
220
|
|
|
{ |
221
|
|
|
$result = Filterer::filter( |
222
|
|
|
[ |
223
|
|
|
'fieldOne' => [['\TraderInteractive\FiltererTest::failingFilter']], |
224
|
|
|
'fieldTwo' => [['\TraderInteractive\FiltererTest::failingFilter']], |
225
|
|
|
], |
226
|
|
|
['fieldOne' => 'value one', 'fieldTwo' => 'value two'] |
227
|
|
|
); |
228
|
|
|
$expectedMessage = "Field 'fieldOne' with value 'value one' failed filtering, message 'i failed'\n"; |
229
|
|
|
$expectedMessage .= "Field 'fieldTwo' with value 'value two' failed filtering, message 'i failed'"; |
230
|
|
|
$this->assertSame([false, null, $expectedMessage, []], $result); |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
/** |
234
|
|
|
* @test |
235
|
|
|
* @covers ::filter |
236
|
|
|
*/ |
237
|
|
|
public function emptyFilter() |
238
|
|
|
{ |
239
|
|
|
$result = Filterer::filter(['fieldOne' => [[]]], ['fieldOne' => 0]); |
240
|
|
|
$this->assertSame([true, ['fieldOne' => 0], null, []], $result); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* @test |
245
|
|
|
* @covers ::filter |
246
|
|
|
*/ |
247
|
|
|
public function unknownsAllowed() |
248
|
|
|
{ |
249
|
|
|
$result = Filterer::filter([], ['fieldTwo' => 0], ['allowUnknowns' => true]); |
250
|
|
|
$this->assertSame([true, [], null, ['fieldTwo' => 0]], $result); |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* @test |
255
|
|
|
* @covers ::filter |
256
|
|
|
*/ |
257
|
|
|
public function unknownsNotAllowed() |
258
|
|
|
{ |
259
|
|
|
$result = Filterer::filter([], ['fieldTwo' => 0]); |
260
|
|
|
$this->assertSame([false, null, "Field 'fieldTwo' with value '0' is unknown", ['fieldTwo' => 0]], $result); |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* @test |
265
|
|
|
* @covers ::filter |
266
|
|
|
*/ |
267
|
|
|
public function objectFilter() |
268
|
|
|
{ |
269
|
|
|
$result = Filterer::filter(['fieldOne' => [[[$this, 'passingFilter']]]], ['fieldOne' => 'foo']); |
270
|
|
|
$this->assertSame([true, ['fieldOne' => 'fooboo'], null, []], $result); |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* @test |
275
|
|
|
* @covers ::filter |
276
|
|
|
* @expectedException Exception |
277
|
|
|
* @expectedExceptionMessage Function 'boo' for field 'foo' is not callable |
278
|
|
|
*/ |
279
|
|
|
public function notCallable() |
280
|
|
|
{ |
281
|
|
|
Filterer::filter(['foo' => [['boo']]], ['foo' => 0]); |
282
|
|
|
} |
283
|
|
|
|
284
|
|
|
/** |
285
|
|
|
* @test |
286
|
|
|
* @covers ::filter |
287
|
|
|
* @expectedException InvalidArgumentException |
288
|
|
|
* @expectedExceptionMessage 'allowUnknowns' option was not a bool |
289
|
|
|
*/ |
290
|
|
|
public function allowUnknownsNotBool() |
291
|
|
|
{ |
292
|
|
|
Filterer::filter([], [], ['allowUnknowns' => 1]); |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
/** |
296
|
|
|
* @test |
297
|
|
|
* @covers ::filter |
298
|
|
|
* @expectedException InvalidArgumentException |
299
|
|
|
* @expectedExceptionMessage 'defaultRequired' option was not a bool |
300
|
|
|
*/ |
301
|
|
|
public function defaultRequiredNotBool() |
302
|
|
|
{ |
303
|
|
|
Filterer::filter([], [], ['defaultRequired' => 1]); |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* @test |
308
|
|
|
* @covers ::filter |
309
|
|
|
* @expectedException InvalidArgumentException |
310
|
|
|
* @expectedExceptionMessage filters for field 'boo' was not a array |
311
|
|
|
*/ |
312
|
|
|
public function filtersNotArrayInLeftOverSpec() |
313
|
|
|
{ |
314
|
|
|
Filterer::filter(['boo' => 1], []); |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
/** |
318
|
|
|
* @test |
319
|
|
|
* @covers ::filter |
320
|
|
|
* @expectedException InvalidArgumentException |
321
|
|
|
* @expectedExceptionMessage filters for field 'boo' was not a array |
322
|
|
|
*/ |
323
|
|
|
public function filtersNotArrayWithInput() |
324
|
|
|
{ |
325
|
|
|
Filterer::filter(['boo' => 1], ['boo' => 'notUnderTest']); |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
/** |
329
|
|
|
* @test |
330
|
|
|
* @covers ::filter |
331
|
|
|
* @expectedException InvalidArgumentException |
332
|
|
|
* @expectedExceptionMessage filter for field 'boo' was not a array |
333
|
|
|
*/ |
334
|
|
|
public function filterNotArray() |
335
|
|
|
{ |
336
|
|
|
Filterer::filter(['boo' => [1]], ['boo' => 'notUnderTest']); |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
/** |
340
|
|
|
* @test |
341
|
|
|
* @covers ::filter |
342
|
|
|
* @expectedException InvalidArgumentException |
343
|
|
|
* @expectedExceptionMessage 'required' for field 'boo' was not a bool |
344
|
|
|
*/ |
345
|
|
|
public function requiredNotBool() |
346
|
|
|
{ |
347
|
|
|
Filterer::filter(['boo' => ['required' => 1]], []); |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
/** |
351
|
|
|
* @test |
352
|
|
|
* @covers ::registerAlias |
353
|
|
|
* @expectedException InvalidArgumentException |
354
|
|
|
* @expectedExceptionMessage $alias was not a string or int |
355
|
|
|
*/ |
356
|
|
|
public function registerAliasAliasNotString() |
357
|
|
|
{ |
358
|
|
|
Filterer::registerAlias(true, 'strtolower'); |
|
|
|
|
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
/** |
362
|
|
|
* @test |
363
|
|
|
* @covers ::registerAlias |
364
|
|
|
* @expectedException Exception |
365
|
|
|
* @expectedExceptionMessage Alias 'upper' exists |
366
|
|
|
*/ |
367
|
|
|
public function registerExistingAliasOverwriteFalse() |
368
|
|
|
{ |
369
|
|
|
Filterer::setFilterAliases([]); |
370
|
|
|
Filterer::registerAlias('upper', 'strtoupper'); |
371
|
|
|
Filterer::registerAlias('upper', 'strtoupper', false); |
372
|
|
|
} |
373
|
|
|
|
374
|
|
|
/** |
375
|
|
|
* @test |
376
|
|
|
* @covers ::registerAlias |
377
|
|
|
*/ |
378
|
|
|
public function registerExistingAliasOverwriteTrue() |
379
|
|
|
{ |
380
|
|
|
Filterer::setFilterAliases(['upper' => 'strtoupper', 'lower' => 'strtolower']); |
381
|
|
|
Filterer::registerAlias('upper', 'ucfirst', true); |
382
|
|
|
$this->assertSame(['upper' => 'ucfirst', 'lower' => 'strtolower'], Filterer::getFilterAliases()); |
383
|
|
|
} |
384
|
|
|
|
385
|
|
|
public static function failingFilter() |
386
|
|
|
{ |
387
|
|
|
throw new Exception('i failed'); |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
public static function passingFilter($value) |
391
|
|
|
{ |
392
|
|
|
return $value . 'boo'; |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
/** |
396
|
|
|
* Verify custom errors can be added to filter spec. |
397
|
|
|
* |
398
|
|
|
* @test |
399
|
|
|
* @covers ::filter |
400
|
|
|
* |
401
|
|
|
* @return void |
402
|
|
|
*/ |
403
|
|
View Code Duplication |
public function filterWithCustomError() |
|
|
|
|
404
|
|
|
{ |
405
|
|
|
$result = Filterer::filter( |
406
|
|
|
[ |
407
|
|
|
'fieldOne' => [ |
408
|
|
|
'error' => 'My custom error message', |
409
|
|
|
['\TraderInteractive\FiltererTest::failingFilter'], |
410
|
|
|
], |
411
|
|
|
], |
412
|
|
|
['fieldOne' => 'valueOne'] |
413
|
|
|
); |
414
|
|
|
$this->assertSame( |
415
|
|
|
[false, null, 'My custom error message', []], |
416
|
|
|
$result |
417
|
|
|
); |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
/** |
421
|
|
|
* @test |
422
|
|
|
* @covers ::filter |
423
|
|
|
*/ |
424
|
|
View Code Duplication |
public function filterWithCustomErrorContainingValuePlaceholder() |
|
|
|
|
425
|
|
|
{ |
426
|
|
|
$result = Filterer::filter( |
427
|
|
|
[ |
428
|
|
|
'fieldOne' => [ |
429
|
|
|
'error' => "The value '{value}' is invalid.", |
430
|
|
|
['uint'], |
431
|
|
|
], |
432
|
|
|
], |
433
|
|
|
['fieldOne' => 'abc'] |
434
|
|
|
); |
435
|
|
|
$this->assertSame( |
436
|
|
|
[false, null, "The value 'abc' is invalid.", []], |
437
|
|
|
$result |
438
|
|
|
); |
439
|
|
|
} |
440
|
|
|
/** |
441
|
|
|
* Verify behavior of filter() when 'error' is not a string value. |
442
|
|
|
* |
443
|
|
|
* @test |
444
|
|
|
* @covers ::filter |
445
|
|
|
* @expectedException InvalidArgumentException |
446
|
|
|
* @expectedExceptionMessage error for field 'fieldOne' was not a non-empty string |
447
|
|
|
* |
448
|
|
|
* @return void |
449
|
|
|
*/ |
450
|
|
View Code Duplication |
public function filterWithNonStringError() |
|
|
|
|
451
|
|
|
{ |
452
|
|
|
Filterer::filter( |
453
|
|
|
['fieldOne' => [['strtoupper'], 'error' => new StdClass()]], |
454
|
|
|
['fieldOne' => 'valueOne'] |
455
|
|
|
); |
456
|
|
|
} |
457
|
|
|
|
458
|
|
|
/** |
459
|
|
|
* Verify behavior of filter() when 'error' is an empty string. |
460
|
|
|
* |
461
|
|
|
* @test |
462
|
|
|
* @covers ::filter |
463
|
|
|
* @expectedException InvalidArgumentException |
464
|
|
|
* @expectedExceptionMessage error for field 'fieldOne' was not a non-empty string |
465
|
|
|
* |
466
|
|
|
* @return void |
467
|
|
|
*/ |
468
|
|
View Code Duplication |
public function filterWithEmptyStringError() |
|
|
|
|
469
|
|
|
{ |
470
|
|
|
Filterer::filter( |
471
|
|
|
['fieldOne' => [['strtoupper'], 'error' => "\n \t"]], |
472
|
|
|
['fieldOne' => 'valueOne'] |
473
|
|
|
); |
474
|
|
|
} |
475
|
|
|
|
476
|
|
|
/** |
477
|
|
|
* @test |
478
|
|
|
* @covers ::ofScalars |
479
|
|
|
*/ |
480
|
|
|
public function ofScalars() |
481
|
|
|
{ |
482
|
|
|
$this->assertSame([1, 2], Filterer::ofScalars(['1', '2'], [['uint']])); |
483
|
|
|
} |
484
|
|
|
|
485
|
|
|
/** |
486
|
|
|
* @test |
487
|
|
|
* @covers ::ofScalars |
488
|
|
|
*/ |
489
|
|
|
public function ofScalarsChained() |
490
|
|
|
{ |
491
|
|
|
$this->assertSame([3.3, 5.5], Filterer::ofScalars(['a3.3', 'a5.5'], [['trim', 'a'], ['floatval']])); |
492
|
|
|
} |
493
|
|
|
|
494
|
|
|
/** |
495
|
|
|
* @test |
496
|
|
|
* @covers ::ofScalars |
497
|
|
|
*/ |
498
|
|
|
public function ofScalarsWithMeaninglessKeys() |
499
|
|
|
{ |
500
|
|
|
$this->assertSame(['key1' => 1, 'key2' => 2], Filterer::ofScalars(['key1' => '1', 'key2' => '2'], [['uint']])); |
501
|
|
|
} |
502
|
|
|
|
503
|
|
|
/** |
504
|
|
|
* @test |
505
|
|
|
* @covers ::ofScalars |
506
|
|
|
*/ |
507
|
|
View Code Duplication |
public function ofScalarsFail() |
|
|
|
|
508
|
|
|
{ |
509
|
|
|
try { |
510
|
|
|
Filterer::ofScalars(['1', [], new \StdClass], [['string']]); |
511
|
|
|
$this->fail(); |
512
|
|
|
} catch (FilterException $e) { |
513
|
|
|
$expected = <<<TXT |
514
|
|
|
Field '1' with value 'array ( |
515
|
|
|
)' failed filtering, message 'Value 'array ( |
516
|
|
|
)' is not a string' |
517
|
|
|
Field '2' with value 'stdClass::__set_state(array( |
518
|
|
|
))' failed filtering, message 'Value 'stdClass::__set_state(array( |
519
|
|
|
))' is not a string' |
520
|
|
|
TXT; |
521
|
|
|
$this->assertSame($expected, $e->getMessage()); |
522
|
|
|
} |
523
|
|
|
} |
524
|
|
|
|
525
|
|
|
/** |
526
|
|
|
* @test |
527
|
|
|
* @covers ::ofArrays |
528
|
|
|
*/ |
529
|
|
|
public function ofArrays() |
530
|
|
|
{ |
531
|
|
|
$expected = [['key' => 1], ['key' => 2]]; |
532
|
|
|
$this->assertSame($expected, Filterer::ofArrays([['key' => '1'], ['key' => '2']], ['key' => [['uint']]])); |
533
|
|
|
} |
534
|
|
|
|
535
|
|
|
/** |
536
|
|
|
* @test |
537
|
|
|
* @covers ::ofArrays |
538
|
|
|
*/ |
539
|
|
|
public function ofArraysChained() |
540
|
|
|
{ |
541
|
|
|
$expected = [['key' => 3.3], ['key' => 5.5]]; |
542
|
|
|
$spec = ['key' => [['trim', 'a'], ['floatval']]]; |
543
|
|
|
$this->assertSame($expected, Filterer::ofArrays([['key' => 'a3.3'], ['key' => 'a5.5']], $spec)); |
544
|
|
|
} |
545
|
|
|
|
546
|
|
|
/** |
547
|
|
|
* @test |
548
|
|
|
* @covers ::ofArrays |
549
|
|
|
*/ |
550
|
|
View Code Duplication |
public function ofArraysRequiredAndUnknown() |
|
|
|
|
551
|
|
|
{ |
552
|
|
|
try { |
553
|
|
|
Filterer::ofArrays([['key' => '1'], ['key2' => '2']], ['key' => ['required' => true, ['uint']]]); |
554
|
|
|
$this->fail(); |
555
|
|
|
} catch (Exception $e) { |
556
|
|
|
$expected = "Field 'key' was required and not present\nField 'key2' with value '2' is unknown"; |
557
|
|
|
$this->assertSame($expected, $e->getMessage()); |
558
|
|
|
} |
559
|
|
|
} |
560
|
|
|
|
561
|
|
|
/** |
562
|
|
|
* @test |
563
|
|
|
* @covers ::ofArrays |
564
|
|
|
*/ |
565
|
|
|
public function ofArraysFail() |
566
|
|
|
{ |
567
|
|
|
try { |
568
|
|
|
Filterer::ofArrays( |
569
|
|
|
[['key' => new \StdClass], ['key' => []], ['key' => null], 'key'], |
570
|
|
|
['key' => [['string']]] |
571
|
|
|
); |
572
|
|
|
$this->fail(); |
573
|
|
|
} catch (FilterException $e) { |
574
|
|
|
$expected = <<<TXT |
575
|
|
|
Field 'key' with value 'stdClass::__set_state(array( |
576
|
|
|
))' failed filtering, message 'Value 'stdClass::__set_state(array( |
577
|
|
|
))' is not a string' |
578
|
|
|
Field 'key' with value 'array ( |
579
|
|
|
)' failed filtering, message 'Value 'array ( |
580
|
|
|
)' is not a string' |
581
|
|
|
Field 'key' with value 'NULL' failed filtering, message 'Value failed filtering, \$allowNull is set to false' |
582
|
|
|
Value at position '3' was not an array |
583
|
|
|
TXT; |
584
|
|
|
$this->assertSame($expected, $e->getMessage()); |
585
|
|
|
} |
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
/** |
589
|
|
|
* @test |
590
|
|
|
* @covers ::ofArray |
591
|
|
|
*/ |
592
|
|
|
public function ofArray() |
593
|
|
|
{ |
594
|
|
|
$expected = ['key1' => 1, 'key2' => 2]; |
595
|
|
|
$spec = ['key1' => [['uint']], 'key2' => [['uint']]]; |
596
|
|
|
$this->assertSame($expected, Filterer::ofArray(['key1' => '1', 'key2' => '2'], $spec)); |
597
|
|
|
} |
598
|
|
|
|
599
|
|
|
/** |
600
|
|
|
* @test |
601
|
|
|
* @covers ::ofArray |
602
|
|
|
*/ |
603
|
|
|
public function ofArrayChained() |
604
|
|
|
{ |
605
|
|
|
$expected = ['key' => 3.3]; |
606
|
|
|
$spec = ['key' => [['trim', 'a'], ['floatval']]]; |
607
|
|
|
$this->assertSame($expected, Filterer::ofArray(['key' => 'a3.3'], $spec)); |
608
|
|
|
} |
609
|
|
|
|
610
|
|
|
/** |
611
|
|
|
* @test |
612
|
|
|
* @covers ::ofArray |
613
|
|
|
*/ |
614
|
|
|
public function ofArrayRequiredSuccess() |
615
|
|
|
{ |
616
|
|
|
$expected = ['key2' => 2]; |
617
|
|
|
$spec = ['key1' => [['uint']], 'key2' => ['required' => true, ['uint']]]; |
618
|
|
|
$this->assertSame($expected, Filterer::ofArray(['key2' => '2'], $spec)); |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
/** |
622
|
|
|
* @test |
623
|
|
|
* @covers ::ofArray |
624
|
|
|
*/ |
625
|
|
View Code Duplication |
public function ofArrayRequiredFail() |
|
|
|
|
626
|
|
|
{ |
627
|
|
|
try { |
628
|
|
|
Filterer::ofArray(['key1' => '1'], ['key1' => [['uint']], 'key2' => ['required' => true, ['uint']]]); |
629
|
|
|
$this->fail(); |
630
|
|
|
} catch (FilterException $e) { |
631
|
|
|
$expected = "Field 'key2' was required and not present"; |
632
|
|
|
$this->assertSame($expected, $e->getMessage()); |
633
|
|
|
} |
634
|
|
|
} |
635
|
|
|
|
636
|
|
|
/** |
637
|
|
|
* @test |
638
|
|
|
* @covers ::ofArray |
639
|
|
|
*/ |
640
|
|
View Code Duplication |
public function ofArrayUnknown() |
|
|
|
|
641
|
|
|
{ |
642
|
|
|
try { |
643
|
|
|
Filterer::ofArray(['key' => '1'], ['key2' => [['uint']]]); |
644
|
|
|
$this->fail(); |
645
|
|
|
} catch (FilterException $e) { |
646
|
|
|
$expected = "Field 'key' with value '1' is unknown"; |
647
|
|
|
$this->assertSame($expected, $e->getMessage()); |
648
|
|
|
} |
649
|
|
|
} |
650
|
|
|
} |
651
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.