Passed
Push — master ( e6d102...7dc300 )
by Eric
12:39
created

StringsTest::testSetEncoding()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 8
nc 1
nop 0
dl 0
loc 17
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::slugify().
270
     */
271
    public function testSlugify(): void
272
    {
273
        self::assertSame('a-simple-title', Strings::slugify('A simple title'));
274
        self::assertSame('this-post-it-has-a-dash', Strings::slugify('This post -- it has a dash'));
275
        self::assertSame('123-1251251', Strings::slugify('123----1251251'));
276
277
        self::assertSame('a_simple_title', Strings::slugify('A simple title', '_'));
278
        self::assertSame('this_post_it_has_a_dash', Strings::slugify('This post -- it has a dash', '_'));
279
        self::assertSame('123_1251251', Strings::slugify('123----1251251', '_'));
280
281
        self::assertSame('a-simple-title', Strings::slugify('a-simple-title'));
282
        self::assertSame('', Strings::slugify(' '));
283
    }
284
285
    /**
286
     * Test Strings::randomBytes().
287
     */
288
    public function testRandomBytes(): void
289
    {
290
        $bytes = Strings::randomBytes(8);
291
        self::assertNotEmpty($bytes);
292
293
        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

293
        self::/** @scrutinizer ignore-call */ 
294
              expectException(RandomException::class);
Loading history...
294
        $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...
295
    }
296
297
    /**
298
     * Test Strings::randomString().
299
     */
300
    public function testRandomString(): void
301
    {
302
        $str = Strings::randomString(16);
303
        self::assertTrue(Strings::length($str) === 16);
304
305
        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

305
        self::/** @scrutinizer ignore-call */ 
306
              expectException(RandomException::class);
Loading history...
306
        $str = Strings::randomString(-10);
0 ignored issues
show
Unused Code introduced by
The assignment to $str is dead and can be removed.
Loading history...
307
    }
308
309
    /**
310
     * Test Strings::validEmail().
311
     */
312
    public function testValidEmail(): void
313
    {
314
        self::assertTrue(Strings::validEmail('[email protected]'));
315
        self::assertTrue(Strings::validEmail('[email protected]'));
316
        self::assertTrue(Strings::validEmail('[email protected]'));
317
        self::assertFalse(Strings::validEmail('j@'));
318
    }
319
320
    /**
321
     * Test Strings::validJson().
322
     */
323
    public function testValidJson(): void
324
    {
325
        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

325
        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...
326
        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

326
        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...
327
    }
328
329
    /**
330
     * Test Strings::obscureEmail().
331
     */
332
    public function testObscureEmail(): void
333
    {
334
        self::assertSame(
335
            '&#97;&#100;&#109;&#105;&#110;&#64;&#115;&#101;&#99;&#111;&#110;&#100;&#118;&#101;&#114;&#115;&#105;&#111;&#110;&#46;&#99;&#111;&#109;',
336
            Strings::obscureEmail('[email protected]')
337
        );
338
339
        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

339
        self::/** @scrutinizer ignore-call */ 
340
              expectException(InvalidArgumentException::class);
Loading history...
340
        $email = Strings::obscureEmail('thisisnotvalid&!--');
0 ignored issues
show
Unused Code introduced by
The assignment to $email is dead and can be removed.
Loading history...
341
    }
342
343
    /**
344
     * Test Strings::guid().
345
     */
346
    public function testGuid(): void
347
    {
348
        $guid = Strings::guid();
349
        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);
350
    }
351
}
352