Failed Conditions
Pull Request — master (#75)
by
unknown
03:37
created

FiltererTest   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 447
Duplicated Lines 10.96 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 38
lcom 1
cbo 2
dl 49
loc 447
rs 8.3999
c 1
b 0
f 0

38 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 registerAliasOverwriteNotBool() 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 PHPUnit\Framework\TestCase;
6
7
/**
8
 * @coversDefaultClass \TraderInteractive\Filterer
9
 */
10
final class FiltererTest extends TestCase
11
{
12
    /**
13
     * @test
14
     * @covers ::filter
15
     */
16
    public function requiredPass()
17
    {
18
        $result = Filterer::filter(['fieldOne' => ['required' => false]], []);
19
        $this->assertSame([true, [], null, []], $result);
20
    }
21
22
    /**
23
     * @test
24
     * @covers ::filter
25
     */
26
    public function requiredFail()
27
    {
28
        $result = Filterer::filter(['fieldOne' => ['required' => true]], []);
29
        $this->assertSame([false, null, "Field 'fieldOne' was required and not present", []], $result);
30
    }
31
32
    /**
33
     * @test
34
     * @covers ::filter
35
     */
36
    public function requiredWithADefaultWithoutInput()
37
    {
38
        $result = Filterer::filter(['fieldOne' => ['required' => true, 'default' => 'theDefault']], []);
39
        $this->assertSame([true, ['fieldOne' => 'theDefault'], null, []], $result);
40
    }
41
42
    /**
43
     * @test
44
     * @covers ::filter
45
     */
46
    public function requiredWithANullDefaultWithoutInput()
47
    {
48
        $result = Filterer::filter(['fieldOne' => ['required' => true, 'default' => null]], []);
49
        $this->assertSame([true, ['fieldOne' => null], null, []], $result);
50
    }
51
52
    /**
53
     * @test
54
     * @covers ::filter
55
     */
56 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...
57
    {
58
        $result = Filterer::filter(
59
            ['fieldOne' => ['required' => true, 'default' => 'theDefault']],
60
            ['fieldOne' => 'notTheDefault']
61
        );
62
        $this->assertSame([true, ['fieldOne' => 'notTheDefault'], null, []], $result);
63
    }
64
65
    /**
66
     * @test
67
     * @covers ::filter
68
     */
69
    public function notRequiredWithADefaultWithoutInput()
70
    {
71
        $result = Filterer::filter(['fieldOne' => ['default' => 'theDefault']], []);
72
        $this->assertSame([true, ['fieldOne' => 'theDefault'], null, []], $result);
73
    }
74
75
    /**
76
     * @test
77
     * @covers ::filter
78
     */
79
    public function notRequiredWithADefaultWithInput()
80
    {
81
        $result = Filterer::filter(['fieldOne' => ['default' => 'theDefault']], ['fieldOne' => 'notTheDefault']);
82
        $this->assertSame([true, ['fieldOne' => 'notTheDefault'], null, []], $result);
83
    }
84
85
    /**
86
     * @test
87
     * @covers ::filter
88
     */
89
    public function requiredDefaultPass()
90
    {
91
        $result = Filterer::filter(['fieldOne' => []], []);
92
        $this->assertSame([true, [], null, []], $result);
93
    }
94
95
    /**
96
     * @test
97
     * @covers ::filter
98
     */
99
    public function requiredDefaultFail()
100
    {
101
        $result = Filterer::filter(['fieldOne' => []], [], ['defaultRequired' => true]);
102
        $this->assertSame([false, null, "Field 'fieldOne' was required and not present", []], $result);
103
    }
104
105
    /**
106
     * @test
107
     * @covers ::filter
108
     */
109
    public function filterPass()
110
    {
111
        $result = Filterer::filter(['fieldOne' => [['floatval']]], ['fieldOne' => '3.14']);
112
        $this->assertSame([true, ['fieldOne' => 3.14], null, []], $result);
113
    }
114
115
    /**
116
     * @test
117
     * @covers ::filter
118
     */
119
    public function filterDefaultShortNamePass()
120
    {
121
        $result = Filterer::filter(['fieldOne' => [['float']]], ['fieldOne' => '3.14']);
122
        $this->assertSame([true, ['fieldOne' => 3.14], null, []], $result);
123
    }
124
125
    /**
126
     * @test
127
     * @covers ::filter
128
     * @covers ::setFilterAliases
129
     */
130
    public function filterCustomShortNamePass()
131
    {
132
        Filterer::setFilterAliases(['fval' => 'floatval']);
133
        $result = Filterer::filter(['fieldOne' => [['fval']]], ['fieldOne' => '3.14']);
134
        $this->assertSame([true, ['fieldOne' => 3.14], null, []], $result);
135
    }
136
137
    /**
138
     * @test
139
     * @covers ::filter
140
     * @covers ::setFilterAliases
141
     * @covers ::getFilterAliases
142
     */
143
    public function filterGetSetKnownFilters()
144
    {
145
        $knownFilters = ['lower' => 'strtolower', 'upper' => 'strtoupper'];
146
        Filterer::setFilterAliases($knownFilters);
147
        $this->assertSame($knownFilters, Filterer::getFilterAliases());
148
    }
149
150
    /**
151
     * @test
152
     * @covers \TraderInteractive\Filterer::filter
153
     */
154
    public function filterFail()
155
    {
156
        $result = Filterer::filter(
157
            ['fieldOne' => [['\TraderInteractive\FiltererTest::failingFilter']]],
158
            ['fieldOne' => 'valueOne']
159
        );
160
        $this->assertSame(
161
            [false, null, "Field 'fieldOne' with value 'valueOne' failed filtering, message 'i failed'", []],
162
            $result
163
        );
164
    }
165
166
    /**
167
     * @test
168
     * @covers ::filter
169
     */
170
    public function chainPass()
171
    {
172
        $result = Filterer::filter(['fieldOne' => [['trim', 'a'], ['floatval']]], ['fieldOne' => 'a3.14']);
173
        $this->assertSame([true, ['fieldOne' => 3.14], null, []], $result);
174
    }
175
176
    /**
177
     * @test
178
     * @covers ::filter
179
     */
180 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...
181
    {
182
        $result = Filterer::filter(
183
            ['fieldOne' => [['trim'], ['\TraderInteractive\FiltererTest::failingFilter']]],
184
            ['fieldOne' => 'the value']
185
        );
186
        $this->assertSame(
187
            [false, null, "Field 'fieldOne' with value 'the value' failed filtering, message 'i failed'", []],
188
            $result
189
        );
190
    }
191
192
    /**
193
     * @test
194
     * @covers ::filter
195
     */
196
    public function multiInputPass()
197
    {
198
        $result = Filterer::filter(
199
            ['fieldOne' => [['trim']], 'fieldTwo' => [['strtoupper']]],
200
            ['fieldOne' => ' value', 'fieldTwo' => 'bob']
201
        );
202
        $this->assertSame([true, ['fieldOne' => 'value', 'fieldTwo' => 'BOB'], null, []], $result);
203
    }
204
205
    /**
206
     * @test
207
     * @covers ::filter
208
     */
209
    public function multiInputFail()
210
    {
211
        $result = Filterer::filter(
212
            [
213
                'fieldOne' => [['\TraderInteractive\FiltererTest::failingFilter']],
214
                'fieldTwo' => [['\TraderInteractive\FiltererTest::failingFilter']],
215
            ],
216
            ['fieldOne' => 'value one', 'fieldTwo' => 'value two']
217
        );
218
        $expectedMessage = "Field 'fieldOne' with value 'value one' failed filtering, message 'i failed'\n";
219
        $expectedMessage .= "Field 'fieldTwo' with value 'value two' failed filtering, message 'i failed'";
220
        $this->assertSame([false, null, $expectedMessage, []], $result);
221
    }
222
223
    /**
224
     * @test
225
     * @covers ::filter
226
     */
227
    public function emptyFilter()
228
    {
229
        $result = Filterer::filter(['fieldOne' => [[]]], ['fieldOne' => 0]);
230
        $this->assertSame([true, ['fieldOne' => 0], null, []], $result);
231
    }
232
233
    /**
234
     * @test
235
     * @covers ::filter
236
     */
237
    public function unknownsAllowed()
238
    {
239
        $result = Filterer::filter([], ['fieldTwo' => 0], ['allowUnknowns' => true]);
240
        $this->assertSame([true, [], null, ['fieldTwo' => 0]], $result);
241
    }
242
243
    /**
244
     * @test
245
     * @covers ::filter
246
     */
247
    public function unknownsNotAllowed()
248
    {
249
        $result = Filterer::filter([], ['fieldTwo' => 0]);
250
        $this->assertSame([false, null, "Field 'fieldTwo' with value '0' is unknown", ['fieldTwo' => 0]], $result);
251
    }
252
253
    /**
254
     * @test
255
     * @covers ::filter
256
     */
257
    public function objectFilter()
258
    {
259
        $result = Filterer::filter(['fieldOne' => [[[$this, 'passingFilter']]]], ['fieldOne' => 'foo']);
260
        $this->assertSame([true, ['fieldOne' => 'fooboo'], null, []], $result);
261
    }
262
263
    /**
264
     * @test
265
     * @covers ::filter
266
     * @expectedException Exception
267
     * @expectedExceptionMessage Function 'boo' for field 'foo' is not callable
268
     */
269
    public function notCallable()
270
    {
271
        Filterer::filter(['foo' => [['boo']]], ['foo' => 0]);
272
    }
273
274
    /**
275
     * @test
276
     * @covers ::filter
277
     * @expectedException InvalidArgumentException
278
     * @expectedExceptionMessage 'allowUnknowns' option was not a bool
279
     */
280
    public function allowUnknownsNotBool()
281
    {
282
        Filterer::filter([], [], ['allowUnknowns' => 1]);
283
    }
284
285
    /**
286
     * @test
287
     * @covers ::filter
288
     * @expectedException InvalidArgumentException
289
     * @expectedExceptionMessage 'defaultRequired' option was not a bool
290
     */
291
    public function defaultRequiredNotBool()
292
    {
293
        Filterer::filter([], [], ['defaultRequired' => 1]);
294
    }
295
296
    /**
297
     * @test
298
     * @covers ::filter
299
     * @expectedException InvalidArgumentException
300
     * @expectedExceptionMessage filters for field 'boo' was not a array
301
     */
302
    public function filtersNotArrayInLeftOverSpec()
303
    {
304
        Filterer::filter(['boo' => 1], []);
305
    }
306
307
    /**
308
     * @test
309
     * @covers ::filter
310
     * @expectedException InvalidArgumentException
311
     * @expectedExceptionMessage filters for field 'boo' was not a array
312
     */
313
    public function filtersNotArrayWithInput()
314
    {
315
        Filterer::filter(['boo' => 1], ['boo' => 'notUnderTest']);
316
    }
317
318
    /**
319
     * @test
320
     * @covers ::filter
321
     * @expectedException InvalidArgumentException
322
     * @expectedExceptionMessage filter for field 'boo' was not a array
323
     */
324
    public function filterNotArray()
325
    {
326
        Filterer::filter(['boo' => [1]], ['boo' => 'notUnderTest']);
327
    }
328
329
    /**
330
     * @test
331
     * @covers ::filter
332
     * @expectedException InvalidArgumentException
333
     * @expectedExceptionMessage 'required' for field 'boo' was not a bool
334
     */
335
    public function requiredNotBool()
336
    {
337
        Filterer::filter(['boo' => ['required' => 1]], []);
338
    }
339
340
    /**
341
     * @test
342
     * @covers ::registerAlias
343
     * @expectedException \InvalidArgumentException
344
     * @expectedExceptionMessage $alias was not a string or int
345
     */
346
    public function registerAliasAliasNotString()
347
    {
348
        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...
349
    }
350
351
    /**
352
     * @test
353
     * @covers ::registerAlias
354
     * @expectedException \InvalidArgumentException
355
     * @expectedExceptionMessage $overwrite was not a bool
356
     */
357
    public function registerAliasOverwriteNotBool()
358
    {
359
        Filterer::registerAlias('lower', 'strtolower', 'foo');
0 ignored issues
show
Documentation introduced by
'foo' is of type string, but the function expects a boolean.

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...
360
    }
361
362
    /**
363
     * @test
364
     * @covers ::registerAlias
365
     * @expectedException \Exception
366
     * @expectedExceptionMessage Alias 'upper' exists
367
     */
368
    public function registerExistingAliasOverwriteFalse()
369
    {
370
        Filterer::setFilterAliases([]);
371
        Filterer::registerAlias('upper', 'strtoupper');
372
        Filterer::registerAlias('upper', 'strtoupper', false);
373
    }
374
375
    /**
376
     * @test
377
     * @covers ::registerAlias
378
     */
379
    public function registerExistingAliasOverwriteTrue()
380
    {
381
        Filterer::setFilterAliases(['upper' => 'strtoupper', 'lower' => 'strtolower']);
382
        Filterer::registerAlias('upper', 'ucfirst', true);
383
        $this->assertSame(['upper' => 'ucfirst', 'lower' => 'strtolower'], Filterer::getFilterAliases());
384
    }
385
386
    public static function failingFilter($val)
0 ignored issues
show
Unused Code introduced by
The parameter $val is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
387
    {
388
        throw new \Exception('i failed');
389
    }
390
391
    public static function passingFilter($value)
392
    {
393
        return $value . 'boo';
394
    }
395
396
    /**
397
     * Verify custom errors can be added to filter spec.
398
     *
399
     * @test
400
     * @covers ::filter
401
     *
402
     * @return void
403
     */
404 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...
405
    {
406
        $result = Filterer::filter(
407
            [
408
                'fieldOne' => [
409
                    ['\TraderInteractive\FiltererTest::failingFilter'],
410
                    'error' => 'My custom error message'
411
                ],
412
            ],
413
            ['fieldOne' => 'valueOne']
414
        );
415
        $this->assertSame(
416
            [false, null, 'My custom error message', []],
417
            $result
418
        );
419
    }
420
421
    /**
422
     * Verify behavior of filter() when 'error' is not a string value.
423
     *
424
     * @test
425
     * @covers ::filter
426
     * @expectedException \InvalidArgumentException
427
     * @expectedExceptionMessage error for field 'fieldOne' was not a non-empty string
428
     *
429
     * @return void
430
     */
431 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...
432
    {
433
        Filterer::filter(
434
            ['fieldOne' => [['strtoupper'], 'error' => new \StdClass()]],
435
            ['fieldOne' => 'valueOne']
436
        );
437
    }
438
439
    /**
440
     * Verify behavior of filter() when 'error' is an empty string.
441
     *
442
     * @test
443
     * @covers ::filter
444
     * @expectedException \InvalidArgumentException
445
     * @expectedExceptionMessage error for field 'fieldOne' was not a non-empty string
446
     *
447
     * @return void
448
     */
449 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...
450
    {
451
        Filterer::filter(
452
            ['fieldOne' => [['strtoupper'], 'error' => "\n   \t"]],
453
            ['fieldOne' => 'valueOne']
454
        );
455
    }
456
}
457