Completed
Push — master ( 09303e...b0f758 )
by
unknown
10s queued 10s
created

FiltererTest::getAliases()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
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 Throwable;
10
use TraderInteractive\Exceptions\FilterException;
11
use TypeError;
12
13
/**
14
 * @coversDefaultClass \TraderInteractive\Filterer
15
 * @covers ::__construct
16
 * @covers ::<private>
17
 */
18
final class FiltererTest extends TestCase
19
{
20
    public function setUp()
21
    {
22
        Filterer::setFilterAliases(Filterer::DEFAULT_FILTER_ALIASES);
23
    }
24
25
    /**
26
     * @test
27
     * @covers ::filter
28
     * @covers ::execute
29
     * @dataProvider provideValidFilterData
30
     *
31
     * @param array $spec  The filter specification to be use.
32
     * @param array $input The input to be filtered.
33
     * @param array $options The filterer options
34
     * @param array $expectedResult The expected filterer result.
35
     */
36
    public function filter(array $spec, array $input, array $options, array $expectedResult)
37
    {
38
        $this->assertSame($expectedResult, Filterer::filter($spec, $input, $options));
39
    }
40
41
    public function provideValidFilterData() : array
42
    {
43
        return [
44
            'not required field not present' => [
45
                'spec' => ['fieldOne' => ['required' => false]],
46
                'input' => [],
47
                'options' => [],
48
                'result' => [true, [], null, []],
49
            ],
50
            'Required With A Default Without Input' => [
51
                'spec' => ['fieldOne' => ['required' => true, 'default' => 'theDefault']],
52
                'input' => [],
53
                'options' => [],
54
                'result' => [true, ['fieldOne' => 'theDefault'], null, []],
55
            ],
56
            'Required With A Null Default Without Input' => [
57
                'spec' => ['fieldOne' => ['required' => true, 'default' => null]],
58
                'input' => [],
59
                'options' => [],
60
                'result' => [true, ['fieldOne' => null], null, []],
61
            ],
62
            'Required With A Default With Input' => [
63
                'spec' => ['fieldOne' => ['required' => true, 'default' => 'theDefault']],
64
                'input' => ['fieldOne' => 'notTheDefault'],
65
                'options' => [],
66
                'result' => [true, ['fieldOne' => 'notTheDefault'], null, []],
67
            ],
68
            'Not Required With A Default Without Input' => [
69
                'spec' => ['fieldOne' => ['default' => 'theDefault']],
70
                'input' => [],
71
                'options' => [],
72
                'result' => [true, ['fieldOne' => 'theDefault'], null, []],
73
            ],
74
            'Not Required With A Default With Input' => [
75
                'spec' => ['fieldOne' => ['default' => 'theDefault']],
76
                'input' => ['fieldOne' => 'notTheDefault'],
77
                'options' => [],
78
                'result' => [true, ['fieldOne' => 'notTheDefault'], null, []],
79
            ],
80
            'Required Fail' => [
81
                'spec' => ['fieldOne' => ['required' => true]],
82
                'input' => [],
83
                'options' => [],
84
                'result' => [false, null, "Field 'fieldOne' was required and not present", []],
85
            ],
86
            'Required Default Pass' => [
87
                'spec' => ['fieldOne' => []],
88
                'input' => [],
89
                'options' => [],
90
                'result' => [true, [], null, []],
91
            ],
92
            'requiredDefaultFail' => [
93
                'spec' => ['fieldOne' => []],
94
                'input' => [],
95
                'options' => ['defaultRequired' => true],
96
                'result' => [false, null, "Field 'fieldOne' was required and not present", []],
97
            ],
98
            'filterPass' => [
99
                'spec' => ['fieldOne' => [['floatval']]],
100
                'input' => ['fieldOne' => '3.14'],
101
                'options' => [],
102
                'result' => [true, ['fieldOne' => 3.14], null, []],
103
            ],
104
            'filterDefaultShortNamePass' => [
105
                'spec' => ['fieldOne' => [['float']]],
106
                'input' => ['fieldOne' => '3.14'],
107
                'options' => [],
108
                'result' => [true, ['fieldOne' => 3.14], null, []],
109
            ],
110
            'filterFail' => [
111
                'spec' => ['fieldOne' => [['\TraderInteractive\FiltererTest::failingFilter']]],
112
                'input' => ['fieldOne' => 'valueOne'],
113
                'options' => [],
114
                'result' => [
115
                    false,
116
                    null,
117
                    "Field 'fieldOne' with value 'valueOne' failed filtering, message 'i failed'",
118
                    [],
119
                ],
120
            ],
121
            'chainPass' => [
122
                'spec' => ['fieldOne' => [['trim', 'a'], ['floatval']]],
123
                'input' => ['fieldOne' => 'a3.14'],
124
                'options' => [],
125
                'result' => [true, ['fieldOne' => 3.14], null, []],
126
            ],
127
            'chainFail' => [
128
                'spec' => ['fieldOne' => [['trim'], ['\TraderInteractive\FiltererTest::failingFilter']]],
129
                'input' => ['fieldOne' => 'the value'],
130
                'options' => [],
131
                'result' => [
132
                    false,
133
                    null,
134
                    "Field 'fieldOne' with value 'the value' failed filtering, message 'i failed'",
135
                    [],
136
                ],
137
            ],
138
            'multiInputPass' => [
139
                'spec' => ['fieldOne' => [['trim']], 'fieldTwo' => [['strtoupper']]],
140
                'input' => ['fieldOne' => ' value', 'fieldTwo' => 'bob'],
141
                'options' => [],
142
                'result' => [true, ['fieldOne' => 'value', 'fieldTwo' => 'BOB'], null, []],
143
            ],
144
            'multiInputFail' => [
145
                'spec' => [
146
                    'fieldOne' => [['\TraderInteractive\FiltererTest::failingFilter']],
147
                    'fieldTwo' => [['\TraderInteractive\FiltererTest::failingFilter']],
148
                ],
149
                'input' => ['fieldOne' => 'value one', 'fieldTwo' => 'value two'],
150
                'options' => [],
151
                'result' => [
152
                    false,
153
                    null,
154
                    "Field 'fieldOne' with value 'value one' failed filtering, message 'i failed'\n"
155
                    . "Field 'fieldTwo' with value 'value two' failed filtering, message 'i failed'",
156
                    [],
157
                ],
158
            ],
159
            'emptyFilter' => [
160
                'spec' => ['fieldOne' => [[]]],
161
                'input' => ['fieldOne' => 0],
162
                'options' => [],
163
                'result' => [true, ['fieldOne' => 0], null, []],
164
            ],
165
            'unknownsAllowed' => [
166
                'spec' => [],
167
                'input'=> ['fieldTwo' => 0],
168
                'options' => ['allowUnknowns' => true],
169
                'result' => [true, [], null, ['fieldTwo' => 0]],
170
            ],
171
            'unknownsNotAllowed' => [
172
                'spec' => [],
173
                'input' => ['fieldTwo' => 0],
174
                'options' => [],
175
                'result' => [false, null, "Field 'fieldTwo' with value '0' is unknown", ['fieldTwo' => 0]],
176
            ],
177
            'objectFilter' => [
178
                'spec' => ['fieldOne' => [[[$this, 'passingFilter']]]],
179
                'input' => ['fieldOne' => 'foo'],
180
                'options' => [],
181
                'result' => [true, ['fieldOne' => 'fooboo'], null, []],
182
            ],
183
            'filterWithCustomError' => [
184
                'spec' => [
185
                    'fieldOne' => [
186
                        'error' => 'My custom error message',
187
                        ['\TraderInteractive\FiltererTest::failingFilter'],
188
                    ],
189
                ],
190
                'input' => ['fieldOne' => 'valueOne'],
191
                'options' => [],
192
                'result' => [false, null, 'My custom error message', []],
193
            ],
194
            'filterWithCustomErrorContainingValuePlaceholder' => [
195
                'spec' => [
196
                    'fieldOne' => [
197
                        'error' => "The value '{value}' is invalid.",
198
                        ['uint'],
199
                    ],
200
                ],
201
                'input' => ['fieldOne' => 'abc'],
202
                'options' => [],
203
                'result' => [false, null, "The value 'abc' is invalid.", []],
204
            ],
205
            'arrayizeAliasIsCalledProperly' => [
206
                'spec' => ['field' => [['arrayize']]],
207
                'input' => ['field' => 'a string value'],
208
                'options' => [],
209
                'result' => [true, ['field' => ['a string value']], null, []],
210
            ],
211
            'concatAliasIsCalledProperly' => [
212
                'spec' => ['field' => [['concat', '%', '%']]],
213
                'input' => ['field' => 'value'],
214
                'options' => [],
215
                'result' => [true, ['field' => '%value%'], null, []],
216
            ],
217
            'translate alias' => [
218
                'spec' => ['field' => [['translate', ['active' => 'A', 'inactive' => 'I']]]],
219
                'input' => ['field' => 'inactive'],
220
                'options' => [],
221
                'result' => [true, ['field' => 'I'], null, []],
222
            ],
223
            'redact alias' => [
224
                'spec' => ['field' => [['redact', ['other'], '*']]],
225
                'input' => ['field' => 'one or other'],
226
                'options' => [],
227
                'result' => [true, ['field' => 'one or *****'], null, []],
228
            ],
229
        ];
230
    }
231
232
    /**
233
     * @test
234
     * @covers ::filter
235
     * @covers ::execute
236
     */
237
    public function filterReturnsResponseType()
238
    {
239
        $specification = ['id' => [['uint']]];
240
        $input = ['id' => 1];
241
        $options = ['responseType' => Filterer::RESPONSE_TYPE_FILTER];
242
243
        $result = Filterer::filter($specification, $input, $options);
244
245
        $this->assertInstanceOf(FilterResponse::class, $result);
246
        $this->assertSame(true, $result->success);
247
        $this->assertSame($input, $result->filteredValue);
248
        $this->assertSame([], $result->errors);
249
        $this->assertSame(null, $result->errorMessage);
250
        $this->assertSame([], $result->unknowns);
251
    }
252
253
    /**
254
     * @test
255
     * @covers ::filter
256
     * @covers ::execute
257
     */
258
    public function filterReturnsResponseTypeWithErrors()
259
    {
260
        $specification = ['name' => [['string']]];
261
        $input = ['name' => 'foo', 'id' => 1];
262
        $options = ['responseType' => Filterer::RESPONSE_TYPE_FILTER];
263
264
        $result = Filterer::filter($specification, $input, $options);
265
266
        $this->assertInstanceOf(FilterResponse::class, $result);
267
        $this->assertSame(false, $result->success);
268
        $this->assertSame(['name' => 'foo'], $result->filteredValue);
269
        $this->assertSame(['id' => "Field 'id' with value '1' is unknown"], $result->errors);
270
        $this->assertSame("Field 'id' with value '1' is unknown", $result->errorMessage);
271
        $this->assertSame(['id' => 1], $result->unknowns);
272
    }
273
274
    /**
275
     * @test
276
     * @covers ::filter
277
     * @covers ::execute
278
     * @covers ::setFilterAliases
279
     */
280
    public function filterCustomShortNamePass()
281
    {
282
        Filterer::setFilterAliases(['fval' => 'floatval']);
283
        $result = Filterer::filter(['fieldOne' => [['fval']]], ['fieldOne' => '3.14']);
284
        $this->assertSame([true, ['fieldOne' => 3.14], null, []], $result);
285
    }
286
287
    /**
288
     * @test
289
     * @covers ::filter
290
     * @covers ::execute
291
     * @covers ::setFilterAliases
292
     * @covers ::getFilterAliases
293
     */
294
    public function filterGetSetKnownFilters()
295
    {
296
        $knownFilters = ['lower' => 'strtolower', 'upper' => 'strtoupper'];
297
        Filterer::setFilterAliases($knownFilters);
298
        $this->assertSame($knownFilters, Filterer::getFilterAliases());
299
    }
300
301
    /**
302
     * @test
303
     * @covers ::setFilterAliases
304
     */
305
    public function setBadFilterAliases()
306
    {
307
        $originalAliases = Filterer::getFilterAliases();
308
309
        $actualThrowable = null;
310
        try {
311
            Filterer::setFilterAliases(['foo' => 'not callable']);
312
        } catch (Throwable $throwable) {
313
            $actualThrowable = $throwable;
314
        }
315
316
        $this->assertSame($originalAliases, Filterer::getFilterAliases());
317
        $this->assertInstanceOf(TypeError::class, $actualThrowable);
318
    }
319
320
    /**
321
     * @test
322
     * @covers ::filter
323
     * @covers ::execute
324
     * @expectedException Exception
325
     * @expectedExceptionMessage Function 'boo' for field 'foo' is not callable
326
     */
327
    public function notCallable()
328
    {
329
        Filterer::filter(['foo' => [['boo']]], ['foo' => 0]);
330
    }
331
332
    /**
333
     * @test
334
     * @covers ::filter
335
     * @covers ::execute
336
     * @expectedException InvalidArgumentException
337
     * @expectedExceptionMessage 'allowUnknowns' option was not a bool
338
     */
339
    public function allowUnknownsNotBool()
340
    {
341
        Filterer::filter([], [], ['allowUnknowns' => 1]);
342
    }
343
344
    /**
345
     * @test
346
     * @covers ::filter
347
     * @covers ::execute
348
     * @expectedException InvalidArgumentException
349
     * @expectedExceptionMessage 'defaultRequired' option was not a bool
350
     */
351
    public function defaultRequiredNotBool()
352
    {
353
        Filterer::filter([], [], ['defaultRequired' => 1]);
354
    }
355
356
    /**
357
     * @test
358
     * @covers ::filter
359
     * @covers ::execute
360
     */
361
    public function filterThrowsExceptionOnInvalidResponseType()
362
    {
363
        $this->expectException(InvalidArgumentException::class);
364
        $this->expectExceptionMessage("'responseType' was not a recognized value");
365
366
        Filterer::filter([], [], ['responseType' => 'invalid']);
367
    }
368
369
    /**
370
     * @test
371
     * @covers ::filter
372
     * @covers ::execute
373
     * @expectedException InvalidArgumentException
374
     * @expectedExceptionMessage filters for field 'boo' was not a array
375
     */
376
    public function filtersNotArrayInLeftOverSpec()
377
    {
378
        Filterer::filter(['boo' => 1], []);
379
    }
380
381
    /**
382
     * @test
383
     * @covers ::filter
384
     * @covers ::execute
385
     * @expectedException InvalidArgumentException
386
     * @expectedExceptionMessage filters for field 'boo' was not a array
387
     */
388
    public function filtersNotArrayWithInput()
389
    {
390
        Filterer::filter(['boo' => 1], ['boo' => 'notUnderTest']);
391
    }
392
393
    /**
394
     * @test
395
     * @covers ::filter
396
     * @covers ::execute
397
     * @expectedException InvalidArgumentException
398
     * @expectedExceptionMessage filter for field 'boo' was not a array
399
     */
400
    public function filterNotArray()
401
    {
402
        Filterer::filter(['boo' => [1]], ['boo' => 'notUnderTest']);
403
    }
404
405
    /**
406
     * @test
407
     * @covers ::filter
408
     * @covers ::execute
409
     * @expectedException InvalidArgumentException
410
     * @expectedExceptionMessage 'required' for field 'boo' was not a bool
411
     */
412
    public function requiredNotBool()
413
    {
414
        Filterer::filter(['boo' => ['required' => 1]], []);
415
    }
416
417
    /**
418
     * @test
419
     * @covers ::registerAlias
420
     * @expectedException InvalidArgumentException
421
     * @expectedExceptionMessage $alias was not a string or int
422
     */
423
    public function registerAliasAliasNotString()
424
    {
425
        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...
426
    }
427
428
    /**
429
     * @test
430
     * @covers ::registerAlias
431
     * @expectedException Exception
432
     * @expectedExceptionMessage Alias 'upper' exists
433
     */
434
    public function registerExistingAliasOverwriteFalse()
435
    {
436
        Filterer::setFilterAliases([]);
437
        Filterer::registerAlias('upper', 'strtoupper');
438
        Filterer::registerAlias('upper', 'strtoupper', false);
439
    }
440
441
    /**
442
     * @test
443
     * @covers ::registerAlias
444
     */
445
    public function registerExistingAliasOverwriteTrue()
446
    {
447
        Filterer::setFilterAliases(['upper' => 'strtoupper', 'lower' => 'strtolower']);
448
        Filterer::registerAlias('upper', 'ucfirst', true);
449
        $this->assertSame(['upper' => 'ucfirst', 'lower' => 'strtolower'], Filterer::getFilterAliases());
450
    }
451
452
    public static function failingFilter()
453
    {
454
        throw new Exception('i failed');
455
    }
456
457
    public static function passingFilter($value)
458
    {
459
        return $value . 'boo';
460
    }
461
462
    /**
463
     * Verify behavior of filter() when 'error' is not a string value.
464
     *
465
     * @test
466
     * @covers ::filter
467
     * @covers ::execute
468
     * @expectedException InvalidArgumentException
469
     * @expectedExceptionMessage error for field 'fieldOne' was not a non-empty string
470
     *
471
     * @return void
472
     */
473 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...
474
    {
475
        Filterer::filter(
476
            ['fieldOne' => [['strtoupper'], 'error' => new stdClass()]],
477
            ['fieldOne' => 'valueOne']
478
        );
479
    }
480
481
    /**
482
     * Verify behavior of filter() when 'error' is an empty string.
483
     *
484
     * @test
485
     * @covers ::filter
486
     * @covers ::execute
487
     * @expectedException InvalidArgumentException
488
     * @expectedExceptionMessage error for field 'fieldOne' was not a non-empty string
489
     *
490
     * @return void
491
     */
492 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...
493
    {
494
        Filterer::filter(
495
            ['fieldOne' => [['strtoupper'], 'error' => "\n   \t"]],
496
            ['fieldOne' => 'valueOne']
497
        );
498
    }
499
500
    /**
501
     * @test
502
     * @covers ::ofScalars
503
     */
504
    public function ofScalars()
505
    {
506
        $this->assertSame([1, 2], Filterer::ofScalars(['1', '2'], [['uint']]));
507
    }
508
509
    /**
510
     * @test
511
     * @covers ::ofScalars
512
     */
513
    public function ofScalarsChained()
514
    {
515
        $this->assertSame([3.3, 5.5], Filterer::ofScalars(['a3.3', 'a5.5'], [['trim', 'a'], ['floatval']]));
516
    }
517
518
    /**
519
     * @test
520
     * @covers ::ofScalars
521
     */
522
    public function ofScalarsWithMeaninglessKeys()
523
    {
524
        $this->assertSame(['key1' => 1, 'key2' => 2], Filterer::ofScalars(['key1' => '1', 'key2' => '2'], [['uint']]));
525
    }
526
527
    /**
528
     * @test
529
     * @covers ::ofScalars
530
     */
531 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...
532
    {
533
        try {
534
            Filterer::ofScalars(['1', [], new stdClass], [['string']]);
535
            $this->fail();
536
        } catch (FilterException $e) {
537
            $expected = <<<TXT
538
Field '1' with value 'array (
539
)' failed filtering, message 'Value 'array (
540
)' is not a string'
541
Field '2' with value 'stdClass::__set_state(array(
542
))' failed filtering, message 'Value 'stdClass::__set_state(array(
543
))' is not a string'
544
TXT;
545
            $this->assertSame($expected, $e->getMessage());
546
        }
547
    }
548
549
    /**
550
     * @test
551
     * @covers ::ofArrays
552
     */
553
    public function ofArrays()
554
    {
555
        $expected = [['key' => 1], ['key' => 2]];
556
        $this->assertSame($expected, Filterer::ofArrays([['key' => '1'], ['key' => '2']], ['key' => [['uint']]]));
557
    }
558
559
    /**
560
     * @test
561
     * @covers ::ofArrays
562
     */
563
    public function ofArraysChained()
564
    {
565
        $expected = [['key' => 3.3], ['key' => 5.5]];
566
        $spec = ['key' => [['trim', 'a'], ['floatval']]];
567
        $this->assertSame($expected, Filterer::ofArrays([['key' => 'a3.3'], ['key' => 'a5.5']], $spec));
568
    }
569
570
    /**
571
     * @test
572
     * @covers ::ofArrays
573
     */
574 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...
575
    {
576
        try {
577
            Filterer::ofArrays([['key' => '1'], ['key2' => '2']], ['key' => ['required' => true, ['uint']]]);
578
            $this->fail();
579
        } catch (Exception $e) {
580
            $expected = "Field 'key' was required and not present\nField 'key2' with value '2' is unknown";
581
            $this->assertSame($expected, $e->getMessage());
582
        }
583
    }
584
585
    /**
586
     * @test
587
     * @covers ::ofArrays
588
     */
589
    public function ofArraysFail()
590
    {
591
        try {
592
            Filterer::ofArrays(
593
                [['key' => new stdClass], ['key' => []], ['key' => null], 'key'],
594
                ['key' => [['string']]]
595
            );
596
            $this->fail();
597
        } catch (FilterException $e) {
598
            $expected = <<<TXT
599
Field 'key' with value 'stdClass::__set_state(array(
600
))' failed filtering, message 'Value 'stdClass::__set_state(array(
601
))' is not a string'
602
Field 'key' with value 'array (
603
)' failed filtering, message 'Value 'array (
604
)' is not a string'
605
Field 'key' with value 'NULL' failed filtering, message 'Value failed filtering, \$allowNull is set to false'
606
Value at position '3' was not an array
607
TXT;
608
            $this->assertSame($expected, $e->getMessage());
609
        }
610
    }
611
612
    /**
613
     * @test
614
     * @covers ::ofArray
615
     */
616
    public function ofArray()
617
    {
618
        $expected = ['key1' => 1, 'key2' => 2];
619
        $spec = ['key1' => [['uint']], 'key2' => [['uint']]];
620
        $this->assertSame($expected, Filterer::ofArray(['key1' => '1', 'key2' => '2'], $spec));
621
    }
622
623
    /**
624
     * @test
625
     * @covers ::ofArray
626
     */
627
    public function ofArrayChained()
628
    {
629
        $expected = ['key' => 3.3];
630
        $spec = ['key' => [['trim', 'a'], ['floatval']]];
631
        $this->assertSame($expected, Filterer::ofArray(['key' => 'a3.3'], $spec));
632
    }
633
634
    /**
635
     * @test
636
     * @covers ::ofArray
637
     */
638
    public function ofArrayRequiredSuccess()
639
    {
640
        $expected = ['key2' => 2];
641
        $spec = ['key1' => [['uint']], 'key2' => ['required' => true, ['uint']]];
642
        $this->assertSame($expected, Filterer::ofArray(['key2' => '2'], $spec));
643
    }
644
645
    /**
646
     * @test
647
     * @covers ::ofArray
648
     */
649 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...
650
    {
651
        try {
652
            Filterer::ofArray(['key1' => '1'], ['key1' => [['uint']], 'key2' => ['required' => true, ['uint']]]);
653
            $this->fail();
654
        } catch (FilterException $e) {
655
            $expected = "Field 'key2' was required and not present";
656
            $this->assertSame($expected, $e->getMessage());
657
        }
658
    }
659
660
    /**
661
     * @test
662
     * @covers ::ofArray
663
     */
664 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...
665
    {
666
        try {
667
            Filterer::ofArray(['key' => '1'], ['key2' => [['uint']]]);
668
            $this->fail();
669
        } catch (FilterException $e) {
670
            $expected = "Field 'key' with value '1' is unknown";
671
            $this->assertSame($expected, $e->getMessage());
672
        }
673
    }
674
675
    /**
676
     * @test
677
     * @covers ::getAliases
678
     */
679
    public function getAliases()
680
    {
681
        $expected = ['some' => 'alias'];
682
683
        $filterer = new Filterer([], [], $expected);
684
        $actual = $filterer->getAliases();
685
686
        $this->assertSame($expected, $actual);
687
    }
688
689
    /**
690
     * @test
691
     * @covers ::getAliases
692
     */
693
    public function getAliasesReturnsStaticValueIfNull()
694
    {
695
        $filterer = new Filterer([]);
696
        $actual = $filterer->getAliases();
697
698
        $this->assertSame(Filterer::getFilterAliases(), $actual);
699
    }
700
701
    /**
702
     * @test
703
     * @covers ::getSpecification
704
     */
705
    public function getSpecification()
706
    {
707
        $expected = ['some' => 'specification'];
708
709
        $filterer = new Filterer($expected);
710
        $actual = $filterer->getSpecification();
711
712
        $this->assertSame($expected, $actual);
713
    }
714
715
    /**
716
     * @test
717
     * @covers ::withAliases
718
     */
719 View Code Duplication
    public function withAliases()
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...
720
    {
721
        $expected = ['foo' => 'bar'];
722
723
        $filterer = new Filterer([]);
724
        $filtererCopy = $filterer->withAliases($expected);
725
726
        $this->assertNotSame($filterer, $filtererCopy);
727
        $this->assertSame($expected, $filtererCopy->getAliases());
728
    }
729
730
    /**
731
     * @test
732
     * @covers ::withSpecification
733
     */
734 View Code Duplication
    public function withSpecification()
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...
735
    {
736
        $expected = ['foo' => 'bar'];
737
738
        $filterer = new Filterer([]);
739
        $filtererCopy = $filterer->withSpecification($expected);
740
741
        $this->assertNotSame($filterer, $filtererCopy);
742
        $this->assertSame($expected, $filtererCopy->getSpecification());
743
    }
744
}
745