testFileExistsUsesTheFirstCheckedFilesystem()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 14
nc 1
nop 0
dl 0
loc 24
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Framework\Assets\CacheManager;
6
7
use League\Flysystem\DirectoryListing;
8
use League\Flysystem\Filesystem;
9
use League\Flysystem\FilesystemOperator;
10
use League\Flysystem\UnableToReadFile;
11
use League\Flysystem\UnableToWriteFile;
12
use PHPUnit\Framework\MockObject\MockObject;
13
use PHPUnit\Framework\TestCase;
14
15
class FlysystemTest extends TestCase
16
{
17
    /** @var Flysystem - System Under Test */
18
    protected Flysystem $sut;
19
20
    public function setUp(): void
21
    {
22
        $this->sut = new Flysystem();
23
24
        parent::setUp();
25
    }
26
27
    /**
28
     * @return FilesystemOperator|MockObject
29
     */
30
    protected function createFilesystemMock()
31
    {
32
        return $this->createMock(Filesystem::class);
33
    }
34
35
    public function testHasThrowsExceptionWhenThereAreNoFilesystemsRegistered(): void
36
    {
37
        $this->expectException(\InvalidArgumentException::class);
38
39
        $path = 'foo.ext';
40
41
        $this->sut->fileExists($path);
42
    }
43
44
    public function testHasThrowsExceptionWhenNoMatchingFilesystemIsFound(): void
45
    {
46
        $this->expectException(\InvalidArgumentException::class);
47
48
        $fs = $this->createFilesystemMock();
49
50
        $this->sut->registerFilesystem(
51
            $fs,
52
            fn () => false
53
        );
54
55
        $path = 'foo.ext';
56
57
        $this->sut->fileExists($path);
58
    }
59
60
    public function testFileExistsUsesTheFirstCheckedFilesystem(): void
61
    {
62
        $expectedResult = true;
63
64
        $fs1 = $this->createFilesystemMock();
65
        $fs2 = $this->createFilesystemMock();
66
67
        $this->sut->registerFilesystem(
68
            $fs1,
69
            fn () => false
70
        );
71
        $this->sut->registerFilesystem(
72
            $fs2,
73
            fn () => true
74
        );
75
76
        $path = 'foo.ext';
77
78
        $fs1->expects($this->never())->method('read')->willThrowException(new UnableToReadFile($path));
79
        $fs2->expects($this->once())->method('fileExists')->willReturn($expectedResult);
80
81
        $actualResult = $this->sut->fileExists($path);
82
83
        $this->assertEquals($expectedResult, $actualResult);
84
    }
85
86
    public function testReadThrowsExceptionWhenThereAreNoFilesystemsRegistered(): void
87
    {
88
        $this->expectException(\InvalidArgumentException::class);
89
90
        $path = 'foo.ext';
91
92
        $this->sut->read($path);
93
    }
94
95
    public function testReadThrowsExceptionWhenNoMatchingFilesystemIsFound(): void
96
    {
97
        $this->expectException(\InvalidArgumentException::class);
98
99
        $fs = $this->createFilesystemMock();
100
101
        $this->sut->registerFilesystem(
102
            $fs,
103
            fn () => false
104
        );
105
106
        $path = 'foo.ext';
107
108
        $this->sut->read($path);
109
    }
110
111
    public function testReadReturnsNullIfPathDoesNotExist(): void
112
    {
113
        $fs = $this->createFilesystemMock();
114
        $fs->expects($this->once())->method('fileExists')->willReturn(false);
115
        $this->sut->registerFilesystem($fs);
116
117
        $path = 'foo.ext';
118
119
        $actualResult = $this->sut->read($path);
120
121
        $this->assertNull($actualResult);
122
    }
123
124
    public function testReadReturnsNullIfFileCanNotBeRead(): void
125
    {
126
        $path = 'foo.ext';
127
128
        $fs = $this->createFilesystemMock();
129
        $fs->expects($this->any())->method('fileExists')->willReturn(true);
130
        $fs->expects($this->once())->method('read')->willThrowException(new UnableToReadFile($path));
131
        $this->sut->registerFilesystem($fs);
132
133
        $actualResult = $this->sut->read($path);
134
135
        $this->assertNull($actualResult);
136
    }
137
138
    public function testReadReturnsContentIfFileIsReadable(): void
139
    {
140
        $expectedResult = 'bar';
141
142
        $fs = $this->createFilesystemMock();
143
        $fs->expects($this->any())->method('fileExists')->willReturn(true);
144
        $fs->expects($this->once())->method('read')->willReturn($expectedResult);
145
        $this->sut->registerFilesystem($fs);
146
147
        $path = 'foo.ext';
148
149
        $actualResult = $this->sut->read($path);
150
151
        $this->assertEquals($expectedResult, $actualResult);
152
    }
153
154
    public function testReadUsesTheFirstCheckedFilesystem(): void
155
    {
156
        $expectedResult = 'bar';
157
158
        $fs1 = $this->createFilesystemMock();
159
        $fs2 = $this->createFilesystemMock();
160
161
        $this->sut->registerFilesystem(
162
            $fs1,
163
            fn () => false
164
        );
165
        $this->sut->registerFilesystem(
166
            $fs2,
167
            fn () => true
168
        );
169
170
        $path = 'foo.ext';
171
172
        $fs1->expects($this->never())->method('read')->willThrowException(new UnableToReadFile($path));
173
        $fs2->expects($this->once())->method('fileExists')->willReturn(true);
174
        $fs2->expects($this->once())->method('read')->willReturn($expectedResult);
175
176
        $actualResult = $this->sut->read($path);
177
178
        $this->assertEquals($expectedResult, $actualResult);
179
    }
180
181
    public function testWriteThrowsExceptionWhenThereAreNoFilesystemsRegistered(): void
182
    {
183
        $this->expectException(\InvalidArgumentException::class);
184
185
        $path    = 'foo.ext';
186
        $content = 'bar';
187
188
        $this->sut->write($path, $content);
189
    }
190
191
    public function testWriteThrowsExceptionWhenNoMatchingFilesystemIsFound(): void
192
    {
193
        $this->expectException(\InvalidArgumentException::class);
194
195
        $fs = $this->createFilesystemMock();
196
197
        $this->sut->registerFilesystem(
198
            $fs,
199
            fn () => false
200
        );
201
202
        $path    = 'foo.ext';
203
        $content = 'bar';
204
205
        $this->sut->write($path, $content);
206
    }
207
208
    public function testWriteReturnsFalseIfWritingFails(): void
209
    {
210
        $fs = $this->createFilesystemMock();
211
212
        $path    = 'foo.ext';
213
        $content = 'bar';
214
215
        $this->sut->registerFilesystem($fs);
216
217
        $fs->expects($this->once())->method('write')->willThrowException(new UnableToWriteFile($path));
218
219
        $this->sut->write($path, $content);
220
    }
221
222
    public function testWriteReturnsTrueOnSuccess(): void
223
    {
224
        $fs = $this->createFilesystemMock();
225
226
        $path    = 'foo.ext';
227
        $content = 'bar';
228
229
        $this->sut->registerFilesystem($fs);
230
231
        $fs->expects($this->once())->method('write');
232
233
        $actualResult = $this->sut->write($path, $content);
234
235
        $this->assertTrue($actualResult);
236
    }
237
238
    public function testWriteUsesTheFirstCheckedFilesystem(): void
239
    {
240
        $fs1 = $this->createFilesystemMock();
241
        $fs2 = $this->createFilesystemMock();
242
243
        $this->sut->registerFilesystem(
244
            $fs1,
245
            fn () => false
246
        );
247
        $this->sut->registerFilesystem(
248
            $fs2,
249
            fn () => true
250
        );
251
252
        $path    = 'foo.ext';
253
        $content = 'bar';
254
255
        $fs1->expects($this->never())->method('write')->willThrowException(new UnableToWriteFile($path));
256
        $fs2->expects($this->once())->method('write');
257
258
        $actualResult = $this->sut->write($path, $content);
259
260
        $this->assertTrue($actualResult);
261
    }
262
263
    public function testWriteReturnsFalseOnFileExistExceptionIfWritingIsNotForced(): void
264
    {
265
        $fs = $this->createFilesystemMock();
266
267
        $this->sut->registerFilesystem($fs);
268
269
        $path    = 'foo.ext';
270
        $content = 'bar';
271
272
        $fs->expects($this->once())->method('write')->willThrowException(new UnableToWriteFile($path));
273
274
        $actualResult = $this->sut->write($path, $content, false);
275
276
        $this->assertFalse($actualResult);
277
    }
278
279
    public function testWriteTriesToDeleteExistingFileIfWritingIsForcedAndFileExists(): void
280
    {
281
        $expectedResult = true;
282
283
        $fs = $this->createFilesystemMock();
284
285
        $this->sut->registerFilesystem($fs);
286
287
        $path    = 'foo.ext';
288
        $content = 'bar';
289
290
        $fs->expects($this->once())->method('fileExists')->with($path)->willReturn(true);
291
        $fs->expects($this->once())->method('delete');
292
        $fs->expects($this->once())->method('write')->with($path, $content);
293
294
        $actualResult = $this->sut->write($path, $content);
295
296
        $this->assertSame($expectedResult, $actualResult);
297
    }
298
299
    public function testGetWebPath(): void
300
    {
301
        $path      = 'foo.ext';
302
        $timestamp = time();
303
304
        $fs = $this->createFilesystemMock();
305
306
        $this->sut->registerFilesystem($fs);
307
308
        $fs->expects($this->once())->method('lastModified')->with($path)->willReturn($timestamp);
309
310
        $actualResult = $this->sut->getWebPath($path);
311
312
        $this->assertStringContainsString($path, $actualResult);
313
        $this->assertNotSame($path, $actualResult);
314
    }
315
316
    public function testFlushDeletesAllFlushableFilesInAllRegisteredFilesystems(): void
317
    {
318
        $fs1 = $this->createFilesystemMock();
319
        $fs2 = $this->createFilesystemMock();
320
321
        $this->sut->registerFilesystem($fs1);
322
        $this->sut->registerFilesystem($fs2);
323
324
        $obj1 = ['path' => 'foo', 'basename' => ''];
325
        $obj2 = ['path' => 'bar', 'basename' => ''];
326
        $obj3 = ['path' => 'baz', 'basename' => ''];
327
        $obj4 = ['path' => 'quix', 'basename' => ''];
328
329
        $fs1->expects($this->once())->method('listContents')->willReturn(new DirectoryListing([$obj1, $obj2]));
330
        $fs2->expects($this->once())->method('listContents')->willReturn(new DirectoryListing([$obj3, $obj4]));
331
332
        $fs1->expects($this->exactly(2))->method('delete');
333
        $fs2->expects($this->exactly(2))->method('delete');
334
335
        $this->sut->flush();
336
    }
337
338
    public function testFlushIgnoresDotGitignoreFiles(): void
339
    {
340
        $fs = $this->createFilesystemMock();
341
342
        $this->sut->registerFilesystem($fs);
343
344
        $obj1 = ['path' => 'foo', 'basename' => '.gitignore'];
345
346
        $fs->expects($this->once())->method('listContents')->willReturn(new DirectoryListing([$obj1]));
347
348
        $fs->expects($this->never())->method('delete');
349
350
        $this->sut->flush();
351
    }
352
353
    public function testFlushIgnoresPhpFiles(): void
354
    {
355
        $fs = $this->createFilesystemMock();
356
357
        $this->sut->registerFilesystem($fs);
358
359
        $obj1 = ['path' => 'foo', 'basename' => 'index', 'extension' => 'php'];
360
361
        $fs->expects($this->once())->method('listContents')->willReturn(new DirectoryListing([$obj1]));
362
363
        $fs->expects($this->never())->method('delete');
364
365
        $this->sut->flush();
366
    }
367
368
    public function testFlushUsesSetIsFlushableCallback(): void
369
    {
370
        $this->sut->setIsFlushable(
371
            function ($obj) {
372
                if ($obj['path'] === 'protected') {
373
                    return false;
374
                }
375
376
                return true;
377
            }
378
        );
379
380
        $fs1 = $this->createFilesystemMock();
381
        $fs2 = $this->createFilesystemMock();
382
383
        $this->sut->registerFilesystem($fs1);
384
        $this->sut->registerFilesystem($fs2);
385
386
        $obj1 = ['path' => 'foo', 'basename' => 'index', 'extension' => 'php'];
387
        $obj2 = ['path' => 'foo', 'basename' => '.gitignore'];
388
        $obj3 = ['path' => 'protected', 'basename' => 'abc'];
389
        $obj4 = ['path' => 'protected', 'basename' => 'cba'];
390
391
        $fs1->expects($this->once())->method('listContents')->willReturn(new DirectoryListing([$obj1, $obj2]));
392
        $fs2->expects($this->once())->method('listContents')->willReturn(new DirectoryListing([$obj3, $obj4]));
393
394
        $fs1->expects($this->exactly(2))->method('delete');
395
        $fs2->expects($this->never())->method('delete');
396
397
        $this->sut->flush();
398
    }
399
}
400