Passed
Push — master ( 5b74be...84d61d )
by Eric
18:51 queued 06:03
created

FilesystemTest::testLineCounter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 28
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 1
eloc 20
nc 1
nop 0
dl 0
loc 28
rs 9.6
c 5
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\Filesystem;
37
use PHPUnit\Framework\TestCase;
38
use PHPUnit\Framework\Attributes\CoversClass;
39
40
use InvalidArgumentException;
41
use RuntimeException;
42
43
use function array_diff;
44
use function array_sum;
45
use function chmod;
46
use function count;
47
use function dirname;
48
use function file_exists;
49
use function implode;
50
use function is_dir;
51
use function mkdir;
52
use function natsort;
53
use function range;
54
use function rmdir;
55
use function str_replace;
56
use function touch;
57
use function trim;
58
use function unlink;
59
use function usleep;
60
61
use const DIRECTORY_SEPARATOR;
62
63
/**
64
 * File system utility tests.
65
 */
66
#[CoversClass(Filesystem::class)]
67
class FilesystemTest extends TestCase
68
{
69
    protected static string $testDir;
70
71
    /**
72
     * @var array<string>
73
     */
74
    protected static array $testFiles;
75
76
    #[\Override]
77
    public static function setUpBeforeClass(): void
78
    {
79
        self::$testDir   = __DIR__ . DIRECTORY_SEPARATOR . 'dir1';
80
        self::$testFiles = [
81
            'file1' => self::$testDir . DIRECTORY_SEPARATOR . 'file1',
82
            'file2' => self::$testDir . DIRECTORY_SEPARATOR . 'file2',
83
            'file3' => self::$testDir . DIRECTORY_SEPARATOR . 'file3.txt',
84
        ];
85
86
        if (!is_dir(self::$testDir)) {
87
            mkdir(self::$testDir);
88
        }
89
90
        if (!file_exists(self::$testFiles['file1'])) {
91
            touch(self::$testFiles['file1']);
92
        }
93
94
        if (!file_exists(self::$testFiles['file2'])) {
95
            touch(self::$testFiles['file2']);
96
        }
97
98
        if (!file_exists(self::$testFiles['file3'])) {
99
            touch(self::$testFiles['file3']);
100
        }
101
    }
102
103
    #[\Override]
104
    public static function tearDownAfterClass(): void
105
    {
106
        unlink(self::$testFiles['file1']);
107
        unlink(self::$testFiles['file2']);
108
        unlink(self::$testFiles['file3']);
109
        usleep(90_000);
1 ignored issue
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_STRING, expecting ',' or ')' on line 109 at column 17
Loading history...
110
        rmdir(self::$testDir);
111
112
        self::$testDir   = '';
113
        self::$testFiles = [];
114
    }
115
116
    /**
117
     * Test Filesystem::lineCounter().
118
     */
119
    public function testLineCounter(): void
120
    {
121
        Filesystem::fileWrite(self::$testFiles['file1'], "This\nis\na\nnew\nline.\n");
122
        self::assertSame(5, array_sum(Filesystem::lineCounter(directory: self::$testDir, onlyLineCount: true)));
123
        self::assertSame(0, array_sum(Filesystem::lineCounter(directory: self::$testDir, ignore: ['dir1'], onlyLineCount: true)));
124
        self::assertSame(0, array_sum(Filesystem::lineCounter(self::$testDir, extensions: ['.txt'], onlyLineCount: true)));
125
126
        $result = Filesystem::lineCounter(directory: self::$testDir);
127
128
        self::assertArrayHasKey(self::$testDir, $result);
129
        self::assertArrayHasKey('file1', $result[self::$testDir]); // @phpstan-ignore-line
130
        self::assertArrayHasKey('file2', $result[self::$testDir]);
131
        self::assertArrayHasKey('file3.txt', $result[self::$testDir]);
132
        self::assertSame(5, $result[self::$testDir]['file1']);
133
        self::assertSame(0, $result[self::$testDir]['file2']);
134
        self::assertSame(0, $result[self::$testDir]['file3.txt']);
135
136
        self::assertSame([], Filesystem::lineCounter(directory: self::$testDir, ignore: ['dir1']));
137
        self::assertSame([], Filesystem::lineCounter(self::$testDir, extensions: ['.txt']));
138
139
        Filesystem::fileWrite(self::$testFiles['file1']);
140
141
        self::expectException(InvalidArgumentException::class);
142
        array_sum(Filesystem::lineCounter('/this/should/not/exist', onlyLineCount: true));
143
144
        self::expectException(InvalidArgumentException::class);
145
        count(Filesystem::lineCounter('/this/should/not/exist'));
146
147
        self::expectException(InvalidArgumentException::class);
148
        array_sum(Filesystem::lineCounter('/this/should/not/exist', ignore: ['dir1'], onlyLineCount: true));
149
150
        self::expectException(InvalidArgumentException::class);
151
        count(Filesystem::lineCounter('/this/should/not/exist', ignore: ['dir1']));
152
    }
153
154
    /**
155
     * Test Filesystem::directorySize().
156
     */
157
    public function testDirectorySize(): void
158
    {
159
        Filesystem::fileWrite(self::$testFiles['file1'], '1234567890');
160
        Filesystem::fileWrite(self::$testFiles['file2'], implode('', range('a', 'z')));
161
162
        self::assertSame(10 + 26, Filesystem::directorySize(self::$testDir));
163
        self::assertSame(0, Filesystem::directorySize(self::$testDir, ['dir1']));
164
165
        Filesystem::fileWrite(self::$testFiles['file1']);
166
        Filesystem::fileWrite(self::$testFiles['file2']);
167
168
        self::expectException(InvalidArgumentException::class);
169
        Filesystem::directorySize('/this/should/not/exist');
170
    }
171
172
    /**
173
     * Test Filesystem::directoryList().
174
     */
175
    public function testDirectoryList(): void
176
    {
177
        Filesystem::fileWrite(self::$testFiles['file1'], '1234567890');
178
        Filesystem::fileWrite(self::$testFiles['file2'], implode('', range('a', 'z')));
179
180
        $expected = [
181
            0 => self::$testFiles['file1'],
182
            1 => self::$testFiles['file2'],
183
        ];
184
        natsort($expected);
185
186
        $actual = Filesystem::directoryList(self::$testDir);
187
        natsort($actual);
188
189
        self::assertSame([], array_diff($expected, $actual));
190
        self::assertSame([], Filesystem::directoryList(self::$testDir, ['dir1']));
191
192
        Filesystem::fileWrite(self::$testFiles['file1']);
193
        Filesystem::fileWrite(self::$testFiles['file2']);
194
195
        self::expectException(InvalidArgumentException::class);
196
        Filesystem::directoryList('/this/should/not/exist');
197
    }
198
199
    /**
200
     * Test Filesystem::normalizeFilePath().
201
     */
202
    public function testNormalizeFilePath(): void
203
    {
204
        $separator = DIRECTORY_SEPARATOR;
205
206
        $path1 = __DIR__ . $separator . 'dir1' . $separator . 'file1';
207
        self::assertSame($path1, Filesystem::normalizeFilePath($path1));
208
209
        $path2 = $path1 . $separator;
210
        self::assertSame($path1, Filesystem::normalizeFilePath($path2));
211
212
        $path3 = str_replace($separator, '\\//', $path2);
213
        self::assertSame($path1, Filesystem::normalizeFilePath($path3));
214
215
        $path4 = $path2 . '..' . $separator;
216
        self::assertSame(str_replace($separator . 'file1', '', $path1), Filesystem::normalizeFilePath($path4));
217
218
        $path5 = $path4 . '..';
219
        self::assertSame(str_replace($separator . 'dir1' . $separator . 'file1', '', $path1), Filesystem::normalizeFilePath($path5));
220
    }
221
222
    /**
223
     * Test Filesystem::fileRead().
224
     */
225
    public function testFileRead(): void
226
    {
227
        Filesystem::fileWrite(self::$testFiles['file1'], "This is a test.");
228
229
        /** @var string $data */
230
        $data = Filesystem::fileRead(self::$testFiles['file1']);
231
        $data = trim($data);
232
233
        self::assertSame('This is a test.', $data);
234
235
        Filesystem::fileWrite(self::$testFiles['file1']);
236
237
        self::expectException(InvalidArgumentException::class);
238
        Filesystem::fileRead(self::$testFiles['file1'] . '.php');
239
    }
240
241
    /**
242
     * Test Filesystem::fileWrite().
243
     */
244
    public function testFileWrite(): void
245
    {
246
        self::assertSame(15, Filesystem::fileWrite(self::$testFiles['file1'], "This is a test."));
247
248
        Filesystem::fileWrite(self::$testFiles['file1']);
249
250
        self::assertSame(15, Filesystem::fileWrite(self::$testFiles['file1'], "This is a test.", -1));
251
252
        self::expectException(InvalidArgumentException::class);
253
        Filesystem::fileWrite(self::$testFiles['file1'] . '.php');
254
255
        chmod(self::$testFiles['file1'], 0o644);
256
        Filesystem::fileWrite(self::$testFiles['file1']);
257
    }
258
259
    /**
260
     * Test Filesystem::isReallyWritable().
261
     */
262
    public function testIsReallyWritable(): void
263
    {
264
        self::assertTrue(Filesystem::isReallyWritable(self::$testDir));
265
        self::assertTrue(Filesystem::isReallyWritable(self::$testFiles['file1']));
266
        self::assertTrue(Filesystem::isReallyWritable(self::$testFiles['file2']));
267
268
        self::expectException(RuntimeException::class);
269
        self::assertFalse(Filesystem::isReallyWritable('/this/should/not/exist'));
270
        self::assertFalse(Filesystem::isReallyWritable('/this/should/not/exist/file'));
271
    }
272
}
273