Failed Conditions
Pull Request — master (#75)
by
unknown
01:48
created

FiltererTest   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 436
Duplicated Lines 11.24 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 37
lcom 1
cbo 2
dl 49
loc 436
rs 8.6
c 1
b 0
f 0

37 Methods

Rating   Name   Duplication   Size   Complexity  
A requiredPass() 0 5 1
A requiredFail() 0 5 1
A requiredWithADefaultWithoutInput() 0 5 1
A requiredWithANullDefaultWithoutInput() 0 5 1
A requiredWithADefaultWithInput() 8 8 1
A notRequiredWithADefaultWithoutInput() 0 5 1
A notRequiredWithADefaultWithInput() 0 5 1
A requiredDefaultPass() 0 5 1
A requiredDefaultFail() 0 5 1
A filterPass() 0 5 1
A filterDefaultShortNamePass() 0 5 1
A filterCustomShortNamePass() 0 6 1
A filterGetSetKnownFilters() 0 6 1
A filterFail() 0 11 1
A chainPass() 0 5 1
A chainFail() 11 11 1
A multiInputPass() 0 8 1
A multiInputFail() 0 13 1
A emptyFilter() 0 5 1
A unknownsAllowed() 0 5 1
A unknownsNotAllowed() 0 5 1
A objectFilter() 0 5 1
A notCallable() 0 4 1
A allowUnknownsNotBool() 0 4 1
A defaultRequiredNotBool() 0 4 1
A filtersNotArrayInLeftOverSpec() 0 4 1
A filtersNotArrayWithInput() 0 4 1
A filterNotArray() 0 4 1
A requiredNotBool() 0 4 1
A registerAliasAliasNotString() 0 4 1
A registerExistingAliasOverwriteFalse() 0 6 1
A registerExistingAliasOverwriteTrue() 0 6 1
A failingFilter() 0 4 1
A passingFilter() 0 4 1
A filterWithCustomError() 16 16 1
A filterWithNonStringError() 7 7 1
A filterWithEmptyStringError() 7 7 1

How to fix   Duplicated Code   

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:

1
<?php
2
3
namespace TraderInteractive;
4
5
use Exception;
6
use InvalidArgumentException;
7
use PHPUnit\Framework\TestCase;
8
use StdClass;
9
10
/**
11
 * @coversDefaultClass \TraderInteractive\Filterer
12
 */
13
final class FiltererTest extends TestCase
14
{
15
    /**
16
     * @test
17
     * @covers ::filter
18
     */
19
    public function requiredPass()
20
    {
21
        $result = Filterer::filter(['fieldOne' => ['required' => false]], []);
22
        $this->assertSame([true, [], null, []], $result);
23
    }
24
25
    /**
26
     * @test
27
     * @covers ::filter
28
     */
29
    public function requiredFail()
30
    {
31
        $result = Filterer::filter(['fieldOne' => ['required' => true]], []);
32
        $this->assertSame([false, null, "Field 'fieldOne' was required and not present", []], $result);
33
    }
34
35
    /**
36
     * @test
37
     * @covers ::filter
38
     */
39
    public function requiredWithADefaultWithoutInput()
40
    {
41
        $result = Filterer::filter(['fieldOne' => ['required' => true, 'default' => 'theDefault']], []);
42
        $this->assertSame([true, ['fieldOne' => 'theDefault'], null, []], $result);
43
    }
44
45
    /**
46
     * @test
47
     * @covers ::filter
48
     */
49
    public function requiredWithANullDefaultWithoutInput()
50
    {
51
        $result = Filterer::filter(['fieldOne' => ['required' => true, 'default' => null]], []);
52
        $this->assertSame([true, ['fieldOne' => null], null, []], $result);
53
    }
54
55
    /**
56
     * @test
57
     * @covers ::filter
58
     */
59 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...
60
    {
61
        $result = Filterer::filter(
62
            ['fieldOne' => ['required' => true, 'default' => 'theDefault']],
63
            ['fieldOne' => 'notTheDefault']
64
        );
65
        $this->assertSame([true, ['fieldOne' => 'notTheDefault'], null, []], $result);
66
    }
67
68
    /**
69
     * @test
70
     * @covers ::filter
71
     */
72
    public function notRequiredWithADefaultWithoutInput()
73
    {
74
        $result = Filterer::filter(['fieldOne' => ['default' => 'theDefault']], []);
75
        $this->assertSame([true, ['fieldOne' => 'theDefault'], null, []], $result);
76
    }
77
78
    /**
79
     * @test
80
     * @covers ::filter
81
     */
82
    public function notRequiredWithADefaultWithInput()
83
    {
84
        $result = Filterer::filter(['fieldOne' => ['default' => 'theDefault']], ['fieldOne' => 'notTheDefault']);
85
        $this->assertSame([true, ['fieldOne' => 'notTheDefault'], null, []], $result);
86
    }
87
88
    /**
89
     * @test
90
     * @covers ::filter
91
     */
92
    public function requiredDefaultPass()
93
    {
94
        $result = Filterer::filter(['fieldOne' => []], []);
95
        $this->assertSame([true, [], null, []], $result);
96
    }
97
98
    /**
99
     * @test
100
     * @covers ::filter
101
     */
102
    public function requiredDefaultFail()
103
    {
104
        $result = Filterer::filter(['fieldOne' => []], [], ['defaultRequired' => true]);
105
        $this->assertSame([false, null, "Field 'fieldOne' was required and not present", []], $result);
106
    }
107
108
    /**
109
     * @test
110
     * @covers ::filter
111
     */
112
    public function filterPass()
113
    {
114
        $result = Filterer::filter(['fieldOne' => [['floatval']]], ['fieldOne' => '3.14']);
115
        $this->assertSame([true, ['fieldOne' => 3.14], null, []], $result);
116
    }
117
118
    /**
119
     * @test
120
     * @covers ::filter
121
     */
122
    public function filterDefaultShortNamePass()
123
    {
124
        $result = Filterer::filter(['fieldOne' => [['float']]], ['fieldOne' => '3.14']);
125
        $this->assertSame([true, ['fieldOne' => 3.14], null, []], $result);
126
    }
127
128
    /**
129
     * @test
130
     * @covers ::filter
131
     * @covers ::setFilterAliases
132
     */
133
    public function filterCustomShortNamePass()
134
    {
135
        Filterer::setFilterAliases(['fval' => 'floatval']);
136
        $result = Filterer::filter(['fieldOne' => [['fval']]], ['fieldOne' => '3.14']);
137
        $this->assertSame([true, ['fieldOne' => 3.14], null, []], $result);
138
    }
139
140
    /**
141
     * @test
142
     * @covers ::filter
143
     * @covers ::setFilterAliases
144
     * @covers ::getFilterAliases
145
     */
146
    public function filterGetSetKnownFilters()
147
    {
148
        $knownFilters = ['lower' => 'strtolower', 'upper' => 'strtoupper'];
149
        Filterer::setFilterAliases($knownFilters);
150
        $this->assertSame($knownFilters, Filterer::getFilterAliases());
151
    }
152
153
    /**
154
     * @test
155
     * @covers ::filter
156
     */
157
    public function filterFail()
158
    {
159
        $result = Filterer::filter(
160
            ['fieldOne' => [['\TraderInteractive\FiltererTest::failingFilter']]],
161
            ['fieldOne' => 'valueOne']
162
        );
163
        $this->assertSame(
164
            [false, null, "Field 'fieldOne' with value 'valueOne' failed filtering, message 'i failed'", []],
165
            $result
166
        );
167
    }
168
169
    /**
170
     * @test
171
     * @covers ::filter
172
     */
173
    public function chainPass()
174
    {
175
        $result = Filterer::filter(['fieldOne' => [['trim', 'a'], ['floatval']]], ['fieldOne' => 'a3.14']);
176
        $this->assertSame([true, ['fieldOne' => 3.14], null, []], $result);
177
    }
178
179
    /**
180
     * @test
181
     * @covers ::filter
182
     */
183 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...
184
    {
185
        $result = Filterer::filter(
186
            ['fieldOne' => [['trim'], ['\TraderInteractive\FiltererTest::failingFilter']]],
187
            ['fieldOne' => 'the value']
188
        );
189
        $this->assertSame(
190
            [false, null, "Field 'fieldOne' with value 'the value' failed filtering, message 'i failed'", []],
191
            $result
192
        );
193
    }
194
195
    /**
196
     * @test
197
     * @covers ::filter
198
     */
199
    public function multiInputPass()
200
    {
201
        $result = Filterer::filter(
202
            ['fieldOne' => [['trim']], 'fieldTwo' => [['strtoupper']]],
203
            ['fieldOne' => ' value', 'fieldTwo' => 'bob']
204
        );
205
        $this->assertSame([true, ['fieldOne' => 'value', 'fieldTwo' => 'BOB'], null, []], $result);
206
    }
207
208
    /**
209
     * @test
210
     * @covers ::filter
211
     */
212
    public function multiInputFail()
213
    {
214
        $result = Filterer::filter(
215
            [
216
                'fieldOne' => [['\TraderInteractive\FiltererTest::failingFilter']],
217
                'fieldTwo' => [['\TraderInteractive\FiltererTest::failingFilter']],
218
            ],
219
            ['fieldOne' => 'value one', 'fieldTwo' => 'value two']
220
        );
221
        $expectedMessage = "Field 'fieldOne' with value 'value one' failed filtering, message 'i failed'\n";
222
        $expectedMessage .= "Field 'fieldTwo' with value 'value two' failed filtering, message 'i failed'";
223
        $this->assertSame([false, null, $expectedMessage, []], $result);
224
    }
225
226
    /**
227
     * @test
228
     * @covers ::filter
229
     */
230
    public function emptyFilter()
231
    {
232
        $result = Filterer::filter(['fieldOne' => [[]]], ['fieldOne' => 0]);
233
        $this->assertSame([true, ['fieldOne' => 0], null, []], $result);
234
    }
235
236
    /**
237
     * @test
238
     * @covers ::filter
239
     */
240
    public function unknownsAllowed()
241
    {
242
        $result = Filterer::filter([], ['fieldTwo' => 0], ['allowUnknowns' => true]);
243
        $this->assertSame([true, [], null, ['fieldTwo' => 0]], $result);
244
    }
245
246
    /**
247
     * @test
248
     * @covers ::filter
249
     */
250
    public function unknownsNotAllowed()
251
    {
252
        $result = Filterer::filter([], ['fieldTwo' => 0]);
253
        $this->assertSame([false, null, "Field 'fieldTwo' with value '0' is unknown", ['fieldTwo' => 0]], $result);
254
    }
255
256
    /**
257
     * @test
258
     * @covers ::filter
259
     */
260
    public function objectFilter()
261
    {
262
        $result = Filterer::filter(['fieldOne' => [[[$this, 'passingFilter']]]], ['fieldOne' => 'foo']);
263
        $this->assertSame([true, ['fieldOne' => 'fooboo'], null, []], $result);
264
    }
265
266
    /**
267
     * @test
268
     * @covers ::filter
269
     * @expectedException Exception
270
     * @expectedExceptionMessage Function 'boo' for field 'foo' is not callable
271
     */
272
    public function notCallable()
273
    {
274
        Filterer::filter(['foo' => [['boo']]], ['foo' => 0]);
275
    }
276
277
    /**
278
     * @test
279
     * @covers ::filter
280
     * @expectedException InvalidArgumentException
281
     * @expectedExceptionMessage 'allowUnknowns' option was not a bool
282
     */
283
    public function allowUnknownsNotBool()
284
    {
285
        Filterer::filter([], [], ['allowUnknowns' => 1]);
286
    }
287
288
    /**
289
     * @test
290
     * @covers ::filter
291
     * @expectedException InvalidArgumentException
292
     * @expectedExceptionMessage 'defaultRequired' option was not a bool
293
     */
294
    public function defaultRequiredNotBool()
295
    {
296
        Filterer::filter([], [], ['defaultRequired' => 1]);
297
    }
298
299
    /**
300
     * @test
301
     * @covers ::filter
302
     * @expectedException InvalidArgumentException
303
     * @expectedExceptionMessage filters for field 'boo' was not a array
304
     */
305
    public function filtersNotArrayInLeftOverSpec()
306
    {
307
        Filterer::filter(['boo' => 1], []);
308
    }
309
310
    /**
311
     * @test
312
     * @covers ::filter
313
     * @expectedException InvalidArgumentException
314
     * @expectedExceptionMessage filters for field 'boo' was not a array
315
     */
316
    public function filtersNotArrayWithInput()
317
    {
318
        Filterer::filter(['boo' => 1], ['boo' => 'notUnderTest']);
319
    }
320
321
    /**
322
     * @test
323
     * @covers ::filter
324
     * @expectedException InvalidArgumentException
325
     * @expectedExceptionMessage filter for field 'boo' was not a array
326
     */
327
    public function filterNotArray()
328
    {
329
        Filterer::filter(['boo' => [1]], ['boo' => 'notUnderTest']);
330
    }
331
332
    /**
333
     * @test
334
     * @covers ::filter
335
     * @expectedException InvalidArgumentException
336
     * @expectedExceptionMessage 'required' for field 'boo' was not a bool
337
     */
338
    public function requiredNotBool()
339
    {
340
        Filterer::filter(['boo' => ['required' => 1]], []);
341
    }
342
343
    /**
344
     * @test
345
     * @covers ::registerAlias
346
     * @expectedException InvalidArgumentException
347
     * @expectedExceptionMessage $alias was not a string or int
348
     */
349
    public function registerAliasAliasNotString()
350
    {
351
        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...
352
    }
353
354
    /**
355
     * @test
356
     * @covers ::registerAlias
357
     * @expectedException Exception
358
     * @expectedExceptionMessage Alias 'upper' exists
359
     */
360
    public function registerExistingAliasOverwriteFalse()
361
    {
362
        Filterer::setFilterAliases([]);
363
        Filterer::registerAlias('upper', 'strtoupper');
364
        Filterer::registerAlias('upper', 'strtoupper', false);
365
    }
366
367
    /**
368
     * @test
369
     * @covers ::registerAlias
370
     */
371
    public function registerExistingAliasOverwriteTrue()
372
    {
373
        Filterer::setFilterAliases(['upper' => 'strtoupper', 'lower' => 'strtolower']);
374
        Filterer::registerAlias('upper', 'ucfirst', true);
375
        $this->assertSame(['upper' => 'ucfirst', 'lower' => 'strtolower'], Filterer::getFilterAliases());
376
    }
377
378
    public static function failingFilter()
379
    {
380
        throw new Exception('i failed');
381
    }
382
383
    public static function passingFilter($value)
384
    {
385
        return $value . 'boo';
386
    }
387
388
    /**
389
     * Verify custom errors can be added to filter spec.
390
     *
391
     * @test
392
     * @covers ::filter
393
     *
394
     * @return void
395
     */
396 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...
397
    {
398
        $result = Filterer::filter(
399
            [
400
                'fieldOne' => [
401
                    ['\TraderInteractive\FiltererTest::failingFilter'],
402
                    'error' => 'My custom error message'
403
                ],
404
            ],
405
            ['fieldOne' => 'valueOne']
406
        );
407
        $this->assertSame(
408
            [false, null, 'My custom error message', []],
409
            $result
410
        );
411
    }
412
413
    /**
414
     * Verify behavior of filter() when 'error' is not a string value.
415
     *
416
     * @test
417
     * @covers ::filter
418
     * @expectedException InvalidArgumentException
419
     * @expectedExceptionMessage error for field 'fieldOne' was not a non-empty string
420
     *
421
     * @return void
422
     */
423 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...
424
    {
425
        Filterer::filter(
426
            ['fieldOne' => [['strtoupper'], 'error' => new StdClass()]],
427
            ['fieldOne' => 'valueOne']
428
        );
429
    }
430
431
    /**
432
     * Verify behavior of filter() when 'error' is an empty string.
433
     *
434
     * @test
435
     * @covers ::filter
436
     * @expectedException InvalidArgumentException
437
     * @expectedExceptionMessage error for field 'fieldOne' was not a non-empty string
438
     *
439
     * @return void
440
     */
441 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...
442
    {
443
        Filterer::filter(
444
            ['fieldOne' => [['strtoupper'], 'error' => "\n   \t"]],
445
            ['fieldOne' => 'valueOne']
446
        );
447
    }
448
}
449