Failed Conditions
Pull Request — master (#19)
by Chad
01:45
created

StringsTest.php$1 ➔ provideExplodeData()   A

Complexity

Conditions 1

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 27
cc 1
rs 9.488
1
<?php
2
3
namespace TraderInteractive\Filter;
4
5
use InvalidArgumentException;
6
use PHPUnit\Framework\TestCase;
7
use TraderInteractive\Exceptions\FilterException;
8
9
/**
10
 * @coversDefaultClass \TraderInteractive\Filter\Strings
11
 * @covers ::<private>
12
 */
13
final class StringsTest extends TestCase
14
{
15
    /**
16
     * Verify basic use of filter
17
     *
18
     * @test
19
     * @covers ::filter
20
     * @dataProvider filterData
21
     *
22
     * @param mixed $input    The input.
23
     * @param mixed $expected The expected value(s).
24
     *
25
     * @return void
26
     * @throws FilterException
27
     */
28
    public function filter($input, $expected)
29
    {
30
        $this->assertSame($expected, Strings::filter($input));
31
    }
32
33
    /**
34
     * Data provider for basic filter tests
35
     *
36
     * @return array
37
     */
38
    public function filterData()
39
    {
40
        return [
41
            'string' => ['abc', 'abc'],
42
            'int' => [1, '1'],
43
            'float' => [1.1, '1.1'],
44
            'bool' => [true, '1'],
45
            'object' => [new \SplFileInfo(__FILE__), __FILE__],
46
        ];
47
    }
48
49
    /**
50
     * @test
51
     * @covers ::filter
52
     */
53
    public function filterNullPass()
54
    {
55
        $this->assertNull(Strings::filter(null, true));
56
    }
57
58
    /**
59
     * @test
60
     * @expectedException \TraderInteractive\Exceptions\FilterException
61
     * @expectedExceptionMessage Value failed filtering, $allowNull is set to false
62
     * @covers ::filter
63
     */
64
    public function filterNullFail()
65
    {
66
        Strings::filter(null);
67
    }
68
69
    /**
70
     * @test
71
     * @covers ::filter
72
     */
73
    public function filterMinLengthPass()
74
    {
75
        $this->assertSame('a', Strings::filter('a'));
76
    }
77
78
    /**
79
     * @test
80
     * @expectedException \TraderInteractive\Exceptions\FilterException
81
     * @covers ::filter
82
     */
83
    public function filterMinLengthFail()
84
    {
85
        Strings::filter('');
86
    }
87
88
    /**
89
     * @test
90
     * @covers ::filter
91
     */
92
    public function filterMaxLengthPass()
93
    {
94
        $this->assertSame('a', Strings::filter('a', false, 0, 1));
95
    }
96
97
    /**
98
     * @test
99
     * @expectedException \TraderInteractive\Exceptions\FilterException
100
     * @expectedExceptionMessage Value 'a' with length '1' is less than '0' or greater than '0'
101
     * @covers ::filter
102
     */
103
    public function filterMaxLengthFail()
104
    {
105
        Strings::filter('a', false, 0, 0);
106
    }
107
108
    /**
109
     * @test
110
     * @expectedException InvalidArgumentException
111
     * @expectedExceptionMessage $minLength was not a positive integer value
112
     * @covers ::filter
113
     */
114
    public function filterMinLengthNotInteger()
115
    {
116
        Strings::filter('a', false, -1);
117
    }
118
119
    /**
120
     * @test
121
     * @expectedException InvalidArgumentException
122
     * @expectedExceptionMessage $maxLength was not a positive integer value
123
     * @covers ::filter
124
     */
125
    public function filterMaxLengthNotInteger()
126
    {
127
        Strings::filter('a', false, 1, -1);
128
    }
129
130
    /**
131
     * @test
132
     * @expectedException InvalidArgumentException
133
     * @expectedExceptionMessage $minLength was not a positive integer value
134
     * @covers ::filter
135
     */
136
    public function filterMinLengthNegative()
137
    {
138
        Strings::filter('a', false, -1);
139
    }
140
141
    /**
142
     * @test
143
     * @expectedException InvalidArgumentException
144
     * @expectedExceptionMessage $maxLength was not a positive integer value
145
     * @covers ::filter
146
     */
147
    public function filterMaxLengthNegative()
148
    {
149
        Strings::filter('a', false, 1, -1);
150
    }
151
152
    /**
153
     * @test
154
     * @covers ::filter
155
     */
156
    public function filterWithScalar()
157
    {
158
        $this->assertSame('24141', Strings::filter(24141));
159
    }
160
161
    /**
162
     * @test
163
     * @covers ::filter
164
     */
165
    public function filterWithObject()
166
    {
167
        $testObject = new class() {
168
            private $data;
169
170
            public function __construct()
171
            {
172
                $this->data = [1,2,3,4,5];
173
            }
174
175
            public function __toString()
176
            {
177
                return implode(',', $this->data);
178
            }
179
        };
180
181
        $this->assertSame('1,2,3,4,5', Strings::filter(new $testObject));
182
    }
183
184
    /**
185
     * @test
186
     * @covers ::filter
187
     *
188
     * @expectedException \TraderInteractive\Exceptions\FilterException
189
     * @expectedExceptionMessage Value 'class@anonymous
190
     */
191
    public function filterWithObjectNoToStringMethod()
192
    {
193
        $testObject = new class() {
194
            private $data;
195
196
            public function __construct()
197
            {
198
                $this->data = [1, 2, 3, 4, 5];
199
            }
200
        };
201
202
        Strings::filter(new $testObject);
203
    }
204
205
    /**
206
     * @test
207
     * @covers ::translate
208
     */
209
    public function translateValue()
210
    {
211
        $map = ['foo' => '100', 'bar' => '200'];
212
        $this->assertSame('100', Strings::translate('foo', $map));
213
    }
214
215
    /**
216
     * @test
217
     * @covers ::translate
218
     * @expectedException \TraderInteractive\Exceptions\FilterException
219
     * @expectedExceptionMessage The value 'baz' was not found in the translation map array.
220
     */
221
    public function translateValueNotFoundInMap()
222
    {
223
        $map = ['foo' => '100', 'bar' => '200'];
224
        Strings::translate('baz', $map);
225
    }
226
227
    /**
228
     * @param string   $value          The value to be filtered.
229
     * @param array    $expectedResult The expected filter result.
230
     * @param string   $delimiter      The delimiter to use.
231
     * @param int|null $padLength      The array length of the result.
232
     * @param mixed    $padValue       The value to use when padding.
233
     * @param string   $padType        The direction to pad the resulting array.
234
     *
235
     * @test
236
     * @covers ::explode
237
     * @dataProvider provideExplodeData
238
     */
239
    public function explode(
240
        string $value,
241
        array $expectedResult,
242
        string $delimiter = ',',
243
        int $padLength = null,
244
        $padValue = null,
245
        string $padType = Strings::EXPLODE_PAD_RIGHT
246
    ) {
247
        $actualResult = Strings::explode($value, $delimiter, $padLength, $padValue, $padType);
248
        $this->assertSame($expectedResult, $actualResult);
249
    }
250
251
    /**
252
     * @return array
253
     */
254
    public function provideExplodeData() : array
255
    {
256
        return [
257
            [
258
                'value' => 'a,bcd,e',
259
                'result' => ['a', 'bcd', 'e'],
260
            ],
261
            [
262
                'value' => 'a b c d,e',
263
                'result' => ['a', 'b', 'c', 'd,e'],
264
                'delimiter' => ' ',
265
            ],
266
            [
267
                'value' => 'a-b-c',
268
                'result' => ['a', 'b', 'c', null, null],
269
                'delimiter' => '-',
270
                'padLength' => 5,
271
                'padValue' => null,
272
                'padType' => Strings::EXPLODE_PAD_RIGHT,
273
            ],
274
            [
275
                'value' => 'a-b-c',
276
                'result' => [null, null, 'a', 'b', 'c'],
277
                'delimiter' => '-',
278
                'padLength' => 5,
279
                'padValue' => null,
280
                'padType' => Strings::EXPLODE_PAD_LEFT,
281
            ],
282
        ];
283
    }
284
285
    /**
286
     * @test
287
     * @covers ::explode
288
     */
289
    public function explodeWithInvalidPadType()
290
    {
291
        $this->expectException(InvalidArgumentException::class);
292
        $this->expectExceptionMessage('Invalid $padType value provided');
293
        Strings::explode('a,b,c', ',', 4, null, 'invalid');
294
    }
295
296
    /**
297
     * @test
298
     * @covers ::explode
299
     */
300
    public function explodeNonString()
301
    {
302
        $this->expectException(FilterException::class);
303
        $this->expectExceptionMessage("Value '1234' is not a string");
304
        Strings::explode(1234, '');
305
    }
306
307
    /**
308
     * Verifies explode filter with an empty delimiter.
309
     *
310
     * @test
311
     * @covers ::explode
312
     */
313
    public function explodeEmptyDelimiter()
314
    {
315
        $this->expectException(InvalidArgumentException::class);
316
        $this->expectExceptionMessage("Delimiter '''' is not a non-empty string");
317
        Strings::explode('test', '');
318
    }
319
320
    /**
321
     * @test
322
     * @covers ::stripTags
323
     * @dataProvider provideStripTags
324
     *
325
     * @param string|null $value
326
     * @param string      $replacement
327
     * @param string|null $expected
328
     */
329
    public function stripTags($value, string $replacement, $expected)
330
    {
331
        $actual = Strings::stripTags($value, $replacement);
332
        $this->assertSame($expected, $actual);
333
    }
334
335
    /**
336
     * @return array
337
     */
338
    public function provideStripTags()
339
    {
340
        return [
341
            'null returns null' => [
342
                'value' => null,
343
                'replacement' => '',
344
                'expected' => null,
345
            ],
346
            'remove html from string' => [
347
                'value' => 'A string with <p>paragraph</p> tags',
348
                'replacement' => '',
349
                'expected' => 'A string with paragraph tags',
350
            ],
351
            'remove xml and replace with space' => [
352
                'value' => '<something>inner value</something>',
353
                'replacement' => ' ',
354
                'expected' => ' inner value ',
355
            ],
356
            'remove multiline html from string' => [
357
                'value' => "<p\nclass='something'\nstyle='display:none'></p>",
358
                'replacement' => ' ',
359
                'expected' => '  ',
360
            ],
361
            'remove php tags' => [
362
                'value' => '<?php some php code',
363
                'replacement' => ' ',
364
                'expected' => '',
365
            ],
366
            'remove shorthand php tags' => [
367
                'value' => '<?= some php code ?> something else',
368
                'replacement' => ' ',
369
                'expected' => '  something else',
370
            ],
371
            'do not remove unmatched <' => [
372
                'value' => '1 < 3',
373
                'replacement' => ' ',
374
                'expected' => '1 < 3',
375
            ],
376
            'do not remove unmatched >' => [
377
                'value' => '3 > 1',
378
                'replacement' => ' ',
379
                'expected' => '3 > 1',
380
            ],
381
        ];
382
    }
383
384
    /**
385
     * @test
386
     * @covers ::concat
387
     */
388
    public function concat()
389
    {
390
        $this->assertSame('prefixstringsuffix', Strings::concat('string', 'prefix', 'suffix'));
391
    }
392
393
    /**
394
     * Verify behavior of concat() when $value is not filterable
395
     *
396
     * @test
397
     * @covers ::concat
398
     * @expectedException \TraderInteractive\Exceptions\FilterException
399
     *
400
     * @return void
401
     */
402
    public function concatValueNotFilterable()
403
    {
404
        Strings::concat(new \StdClass(), 'prefix', 'suffix');
405
    }
406
407
    /**
408
     * @test
409
     * @covers ::concat
410
     */
411
    public function concatScalarValue()
412
    {
413
        $this->assertSame('prefix123suffix', Strings::concat(123, 'prefix', 'suffix'));
414
    }
415
416
    /**
417
     * @test
418
     * @covers ::concat
419
     */
420
    public function concatObjectValue()
421
    {
422
        $this->assertSame(
423
            'prefix' . __FILE__ . 'suffix',
424
            Strings::concat(new \SplFileInfo(__FILE__), 'prefix', 'suffix')
425
        );
426
    }
427
428
    /**
429
     * @test
430
     * @covers ::compress
431
     */
432
    public function compressRemovesSuperfluousWhitespace()
433
    {
434
        $this->assertSame('a compressed string', Strings::compress('  a   compressed     string    '));
435
    }
436
437
    /**
438
     * @test
439
     * @covers ::compress
440
     */
441
    public function compressReturnsNullIfValueIsNull()
442
    {
443
        $this->assertNull(Strings::compress(null));
0 ignored issues
show
Bug introduced by
Are you sure the usage of TraderInteractive\Filter\Strings::compress(null) targeting TraderInteractive\Filter\Strings::compress() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
444
    }
445
446
    /**
447
     * @test
448
     * @covers ::compress
449
     */
450
    public function compressRemovesNewLines()
451
    {
452
        $input = " This string\nhas     superfluous   whitespace  and  \nnewlines\n";
453
        $this->assertSame(
454
            'This string has superfluous whitespace and newlines',
455
            Strings::compress($input, true)
456
        );
457
    }
458
459
    /**
460
     * @test
461
     * @covers ::compress
462
     */
463
    public function compressIgnoresNewLinesByDefault()
464
    {
465
        $input = " This string\nhas     superfluous   whitespace  and  \nnewlines\n";
466
        $this->assertSame(
467
            "This string\nhas superfluous whitespace and \nnewlines",
468
            Strings::compress($input)
469
        );
470
    }
471
472
    /**
473
     * @test
474
     * @covers ::redact
475
     * @dataProvider provideRedact
476
     *
477
     * @param string|null    $value       The value to pass to the filter.
478
     * @param array|callable $words       The words to pass to the filter.
479
     * @param string         $replacement The replacement to pass to the filter.
480
     * @param string|null    $expected    The expected result.
481
     */
482
    public function redact($value, $words, string $replacement, $expected)
483
    {
484
        $actual = Strings::redact($value, $words, $replacement);
485
486
        $this->assertSame($expected, $actual);
487
    }
488
489
    /**
490
     * @return array
491
     */
492
    public function provideRedact() : array
493
    {
494
        return [
495
            'null value' => [
496
                'value' => null,
497
                'words' => [],
498
                'replacement' => '',
499
                'expected' => null,
500
            ],
501
            'empty string' => [
502
                'value' => '',
503
                'words' => [],
504
                'replacement' => '',
505
                'expected' => '',
506
            ],
507
            'replace with empty' => [
508
                'value' => 'this message contains something that you want removed',
509
                'words' => ['something that you want removed'],
510
                'replacement' => '',
511
                'expected' => 'this message contains ',
512
            ],
513
            'replace with *' => [
514
                'value' => 'replace certain words that you might want to remove',
515
                'words' => ['might', 'certain'],
516
                'replacement' => '*',
517
                'expected' => 'replace ******* words that you ***** want to remove',
518
            ],
519
            'replace with █' => [
520
                'value' => 'redact specific dates and secret locations',
521
                'words' => ['secret locations', 'specific dates'],
522
                'replacement' => '█',
523
                'expected' => 'redact ██████████████ and ████████████████',
524
            ],
525
            'replace with multi-character string uses first character' => [
526
                'value' => 'replace some particular words',
527
                'words' => ['particular', 'words', 'some'],
528
                'replacement' => ' *** ',
529
                'expected' => 'replace                      ',
530
            ],
531
            'no replacements' => [
532
                'value' => 'some perfectly normal string',
533
                'words' => ['undesired', 'words'],
534
                'replacement' => '*',
535
                'expected' => 'some perfectly normal string',
536
            ],
537
            'closure provides words' => [
538
                'value' => 'doe a deer, a female deer',
539
                'words' => function () {
540
                    return ['doe', 'deer'];
541
                },
542
                'replacement' => '-',
543
                'expected' => '--- a ----, a female ----',
544
            ],
545
        ];
546
    }
547
548
    /**
549
     * @test
550
     * @covers ::redact
551
     * @dataProvider provideRedactFailsOnBadInput
552
     *
553
     * @param mixed  $value       The value to pass to the filter.
554
     * @param mixed  $words       The words to pass to the filter.
555
     * @param string $replacement The replacement to pass to the filter.
556
     * @param string $exception   The exception to expect.
557
     * @param string $message     The exception message to expect.
558
     */
559
    public function redactFailsOnBadInput($value, $words, string $replacement, string $exception, string $message)
560
    {
561
        $this->expectException($exception);
562
        $this->expectExceptionMessage($message);
563
564
        Strings::redact($value, $words, $replacement);
565
    }
566
567
    /**
568
     * @return array
569
     */
570
    public function provideRedactFailsOnBadInput() : array
571
    {
572
        return [
573
            'non-string value' => [
574
                'value' => ['bad', 'input'],
575
                'words' => [],
576
                'replacement' => '',
577
                'exception' => FilterException::class,
578
                'message' => "Value '" . var_export(['bad', 'input'], true) . "' is not a string",
579
            ],
580
            'invalid words argument' => [
581
                'value' => 'some string',
582
                'words' => 'this is not valid',
583
                'replacement' => '',
584
                'exception' => FilterException::class,
585
                'message' => 'Words was not an array or a callable that returns an array',
586
            ],
587
            'invalid return from callable words argument' => [
588
                'value' => 'some string',
589
                'words' => function () {
590
                    return 'this is also not valid';
591
                },
592
                'replacement' => '',
593
                'exception' => FilterException::class,
594
                'message' => 'Words was not an array or a callable that returns an array',
595
            ],
596
        ];
597
    }
598
}
599