Passed
Push — master ( eb151a...2c3ea5 )
by Eric
02:25
created

StringsTest::testRandomBytes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Utility - Collection of various PHP utility functions.
7
 *
8
 * @author    Eric Sizemore <[email protected]>
9
 * @version   2.0.0
10
 * @copyright (C) 2017 - 2024 Eric Sizemore
11
 * @license   The MIT License (MIT)
12
 *
13
 * Copyright (C) 2017 - 2024 Eric Sizemore <https://www.secondversion.com>.
14
 *
15
 * Permission is hereby granted, free of charge, to any person obtaining a copy
16
 * of this software and associated documentation files (the "Software"), to
17
 * deal in the Software without restriction, including without limitation the
18
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
19
 * sell copies of the Software, and to permit persons to whom the Software is
20
 * furnished to do so, subject to the following conditions:
21
 *
22
 * The above copyright notice and this permission notice shall be included in
23
 * all copies or substantial portions of the Software.
24
 *
25
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
30
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
 * THE SOFTWARE.
32
 */
33
34
namespace Esi\Utility\Tests;
35
36
use Esi\Utility\Strings;
37
use Esi\Utility\Environment;
38
use PHPUnit\Framework\TestCase;
39
use PHPUnit\Framework\Attributes\CoversClass;
40
use PHPUnit\Framework\Attributes\DataProvider;
41
use Random\RandomException;
1 ignored issue
show
Bug introduced by
The type Random\RandomException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
42
use InvalidArgumentException;
43
44
/**
45
 * String utility tests.
46
 */
47
#[CoversClass(Strings::class)]
48
class StringsTest extends TestCase
49
{
50
    /**
51
     * Test Strings::getEncoding().
52
     */
53
    public function testGetEncoding(): void
54
    {
55
        self::assertSame('UTF-8', Strings::getEncoding());
56
    }
57
58
    /**
59
     * Test Strings::setEncoding().
60
     */
61
    public function testSetEncoding(): void
62
    {
63
        // With no ini update.
64
        Strings::setEncoding('UCS-2');
65
66
        self::assertSame('UCS-2', Strings::getEncoding());
67
68
        Strings::setEncoding('UTF-8');
69
70
        // With ini update.
71
        Strings::setEncoding('UCS-2', true);
72
73
        self::assertSame('UCS-2', Strings::getEncoding());
74
        self::assertSame('UCS-2', Environment::iniGet('default_charset'));
75
        self::assertSame('UCS-2', Environment::iniGet('internal_encoding'));
76
77
        Strings::setEncoding('UTF-8', true);
78
    }
79
80
    /**
81
 * Test Strings::title().
82
 */
83
    public function testTitle(): void
84
    {
85
        $title = Strings::title('Mary had A little lamb and She Loved it so');
86
        self::assertSame('Mary Had A Little Lamb And She Loved It So', $title);
87
    }
88
89
    /**
90
     * Test Strings::lower().
91
     */
92
    public function testLower(): void
93
    {
94
        self::assertSame('test', Strings::lower('tESt'));
95
        self::assertSame('test', Strings::lower('TEST'));
96
    }
97
98
    /**
99
     * Test Strings::upper().
100
     */
101
    public function testUpper(): void
102
    {
103
        self::assertSame('TEST', Strings::upper('teSt'));
104
    }
105
106
    /**
107
     * Test Strings::substr().
108
     */
109
    public function testSubstr(): void
110
    {
111
        self::assertSame('f', Strings::substr('abcdef', -1));
112
    }
113
114
    /**
115
     * Test Strings::lcfirst().
116
     */
117
    public function testLcfirst(): void
118
    {
119
        self::assertSame('test', Strings::lcfirst('Test'));
120
        self::assertSame('tEST', Strings::lcfirst('TEST'));
121
    }
122
123
    /**
124
     * Test Strings::ucfirst().
125
     */
126
    public function testUcfirst(): void
127
    {
128
        self::assertSame('Test', Strings::ucfirst('test'));
129
        self::assertSame('TEsT', Strings::ucfirst('tEsT'));
130
    }
131
132
    /**
133
     * Test Strings::strcasecmp().
134
     */
135
    public function testStrcasecmp(): void
136
    {
137
        // Returns -1 if string1 is less than string2; 1 if string1 is greater than string2, and 0 if they are equal.
138
        $str1 = 'test';
139
        $str2 = 'Test';
140
141
        self::assertSame(0, Strings::strcasecmp($str1, $str2));
142
143
        $str1 = 'tes';
144
145
        self::assertSame(-1, Strings::strcasecmp($str1, $str2));
146
147
        $str1 = 'testing';
148
149
        self::assertSame(1, Strings::strcasecmp($str1, $str2));
150
    }
151
152
    /**
153
     * Test Strings::beginsWith().
154
     */
155
    public function testBeginsWith(): void
156
    {
157
        self::assertTrue(Strings::beginsWith('this is a test', 'this'));
158
        self::assertFalse(Strings::beginsWith('this is a test', 'test'));
159
160
        self::assertTrue(Strings::beginsWith('THIS IS A TEST', 'this', true));
161
        self::assertFalse(Strings::beginsWith('THIS IS A TEST', 'test', true));
162
163
        self::assertTrue(Strings::beginsWith('THIS IS A TEST', 'this', true, true));
164
        self::assertFalse(Strings::beginsWith('THIS IS A TEST', 'test', true, true));
165
    }
166
167
    /**
168
     * Test Strings::endsWith().
169
     */
170
    public function testEndsWith(): void
171
    {
172
        self::assertTrue(Strings::endsWith('this is a test', 'test'));
173
        self::assertFalse(Strings::endsWith('this is a test', 'this'));
174
175
        self::assertTrue(Strings::endsWith('THIS IS A TEST', 'test', true));
176
        self::assertFalse(Strings::endsWith('THIS IS A TEST', 'this', true));
177
178
        self::assertTrue(Strings::endsWith('THIS IS A TEST', 'test', true, true));
179
        self::assertFalse(Strings::endsWith('THIS IS A TEST', 'this', true, true));
180
    }
181
182
    /**
183
     * Test Strings::doesContain().
184
     */
185
    public function testDoesContain(): void
186
    {
187
        self::assertTrue(Strings::doesContain('start a string', 'a string'));
188
        self::assertFalse(Strings::doesContain('start a string', 'starting'));
189
190
        self::assertTrue(Strings::doesContain('START A STRING', 'a string', true));
191
        self::assertFalse(Strings::doesContain('START A STRING', 'starting', true));
192
193
        self::assertTrue(Strings::doesContain('START A STRING', 'a string', true, true));
194
        self::assertFalse(Strings::doesContain('START A STRING', 'starting', true, true));
195
    }
196
197
    /**
198
     * Test Strings::doesNotContain().
199
     */
200
    public function testDoesNotContain(): void
201
    {
202
        self::assertTrue(Strings::doesNotContain('start a string', 'stringly'));
203
        self::assertFalse(Strings::doesNotContain('start a string', 'string'));
204
205
        self::assertTrue(Strings::doesNotContain('START A STRING', 'stringly', true));
206
        self::assertFalse(Strings::doesNotContain('START A STRING', 'string', true));
207
208
        self::assertTrue(Strings::doesNotContain('START A STRING', 'stringly', true, true));
209
        self::assertFalse(Strings::doesNotContain('START A STRING', 'string', true, true));
210
    }
211
212
    /**
213
     * Provides data for testCamelCase().
214
     *
215
     * Shoutout to Daniel St. Jules (https://github.com/danielstjules/Stringy/) for
216
     * inspiration for this function. This function is based on Stringy/Test/camelizeProvider().
217
     *
218
     * @return array<int, array<int, string>>
219
     */
220
    public static function camelCaseProvider(): array
221
    {
222
        return [
223
            ['camelCase', 'CamelCase'],
224
            ['camelCase', 'Camel-Case'],
225
            ['camelCase', 'camel case'],
226
            ['camelCase', 'camel -case'],
227
            ['camelCase', 'camel - case'],
228
            ['camelCase', 'camel_case'],
229
            ['camelCTest', 'camel c test'],
230
            ['stringWith1Number', 'string_with1number'],
231
            ['stringWith22Numbers', 'string-with-2-2 numbers'],
232
            ['dataRate', 'data_rate'],
233
            ['backgroundColor', 'background-color'],
234
            ['yesWeCan', 'yes_we_can'],
235
            ['mozSomething', '-moz-something'],
236
            ['carSpeed', '_car_speed_'],
237
            ['serveHTTP', 'ServeHTTP'],
238
            ['1Camel2Case', '1camel2case'],
239
            ['camelΣase', 'camel σase', 'UTF-8'],
240
            ['στανιλCase', 'Στανιλ case', 'UTF-8'],
241
            ['σamelCase', 'σamel  Case', 'UTF-8'],
242
        ];
243
    }
244
245
    /**
246
     * Test Strings::camelCase().
247
     */
248
    #[DataProvider('camelCaseProvider')]
249
    public function testCamelCase(string $expected, string $string, ?string $encoding = null): void
250
    {
251
        if ($encoding !== null) {
252
            Strings::setEncoding($encoding);
253
        }
254
255
        $result = Strings::camelCase($string);
256
257
        self::assertSame($expected, $result);
258
    }
259
260
    /**
261
     * Test Strings::ascii().
262
     */
263
    public function testAscii(): void
264
    {
265
        self::assertSame('AA ', Strings::ascii("ǍǺ\xE2\x80\x87"));
266
    }
267
268
    /**
269
     * Test Strings::ascii().
270
     */
271
    public function testAsciiWithLanguage(): void
272
    {
273
        self::assertSame('aaistAAIST', Strings::ascii('ăâîșțĂÂÎȘȚ', 'ro'));
274
    }
275
276
    /**
277
     * Test Strings::slugify().
278
     */
279
    public function testSlugify(): void
280
    {
281
        self::assertSame('a-simple-title', Strings::slugify('A simple title'));
282
        self::assertSame('this-post-it-has-a-dash', Strings::slugify('This post -- it has a dash'));
283
        self::assertSame('123-1251251', Strings::slugify('123----1251251'));
284
285
        self::assertSame('a_simple_title', Strings::slugify('A simple title', '_'));
286
        self::assertSame('this_post_it_has_a_dash', Strings::slugify('This post -- it has a dash', '_'));
287
        self::assertSame('123_1251251', Strings::slugify('123----1251251', '_'));
288
289
        self::assertSame('a-simple-title', Strings::slugify('a-simple-title'));
290
        self::assertSame('', Strings::slugify(' '));
291
292
        self::assertSame('this-is-a-simple-title', Strings::slugify('Țhîș îș ă șîmple țîțle', '-', 'ro'));
293
    }
294
295
    /**
296
     * Test Strings::randomBytes().
297
     */
298
    public function testRandomBytes(): void
299
    {
300
        $bytes = Strings::randomBytes(8);
301
        self::assertNotEmpty($bytes);
302
303
        self::expectException(RandomException::class);
1 ignored issue
show
Bug Best Practice introduced by
The method PHPUnit\Framework\TestCase::expectException() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

303
        self::/** @scrutinizer ignore-call */ 
304
              expectException(RandomException::class);
Loading history...
304
        $str = Strings::randomBytes(-10); // @phpstan-ignore-line
0 ignored issues
show
Unused Code introduced by
The assignment to $str is dead and can be removed.
Loading history...
305
    }
306
307
    /**
308
     * Test Strings::randomString().
309
     */
310
    public function testRandomString(): void
311
    {
312
        $str = Strings::randomString(16);
313
        self::assertTrue(Strings::length($str) === 16);
314
315
        self::expectException(RandomException::class);
1 ignored issue
show
Bug Best Practice introduced by
The method PHPUnit\Framework\TestCase::expectException() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

315
        self::/** @scrutinizer ignore-call */ 
316
              expectException(RandomException::class);
Loading history...
316
        $str = Strings::randomString(-10);
0 ignored issues
show
Unused Code introduced by
The assignment to $str is dead and can be removed.
Loading history...
317
    }
318
319
    /**
320
     * Test Strings::validEmail().
321
     */
322
    public function testValidEmail(): void
323
    {
324
        self::assertTrue(Strings::validEmail('[email protected]'));
325
        self::assertTrue(Strings::validEmail('[email protected]'));
326
        self::assertTrue(Strings::validEmail('[email protected]'));
327
        self::assertFalse(Strings::validEmail('j@'));
328
    }
329
330
    /**
331
     * Test Strings::validJson().
332
     */
333
    public function testValidJson(): void
334
    {
335
        self::assertTrue(Strings::validJson('{ "test": { "foo": "bar" } }'));
1 ignored issue
show
Deprecated Code introduced by
The function Esi\Utility\Strings::validJson() has been deprecated: as of 2.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

335
        self::assertTrue(/** @scrutinizer ignore-deprecated */ Strings::validJson('{ "test": { "foo": "bar" } }'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
336
        self::assertFalse(Strings::validJson('{ "": "": "" } }'));
1 ignored issue
show
Deprecated Code introduced by
The function Esi\Utility\Strings::validJson() has been deprecated: as of 2.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

336
        self::assertFalse(/** @scrutinizer ignore-deprecated */ Strings::validJson('{ "": "": "" } }'));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
337
    }
338
339
    /**
340
     * Test Strings::obscureEmail().
341
     */
342
    public function testObscureEmail(): void
343
    {
344
        self::assertSame(
345
            '&#97;&#100;&#109;&#105;&#110;&#64;&#115;&#101;&#99;&#111;&#110;&#100;&#118;&#101;&#114;&#115;&#105;&#111;&#110;&#46;&#99;&#111;&#109;',
346
            Strings::obscureEmail('[email protected]')
347
        );
348
349
        self::expectException(InvalidArgumentException::class);
1 ignored issue
show
Bug Best Practice introduced by
The method PHPUnit\Framework\TestCase::expectException() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

349
        self::/** @scrutinizer ignore-call */ 
350
              expectException(InvalidArgumentException::class);
Loading history...
350
        $email = Strings::obscureEmail('thisisnotvalid&!--');
0 ignored issues
show
Unused Code introduced by
The assignment to $email is dead and can be removed.
Loading history...
351
    }
352
353
    /**
354
     * Test Strings::guid().
355
     */
356
    public function testGuid(): void
357
    {
358
        $guid = Strings::guid();
359
        self::assertMatchesRegularExpression('/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $guid);
360
    }
361
}
362