Completed
Push — master ( 7a6826...fad882 )
by Chad
14s
created

filterWithCustomErrorContainingValuePlaceholder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16

Duplication

Lines 16
Ratio 100 %

Importance

Changes 0
Metric Value
dl 16
loc 16
rs 9.7333
c 0
b 0
f 0
cc 1
nc 1
nop 0
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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');
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string|integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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