Passed
Pull Request — master (#5)
by Wilmer
01:14
created

FileHelperTest::tearDown()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 2
b 0
f 1
1
<?php
2
declare(strict_types = 1);
3
4
namespace Yiisoft\Files\Tests;
5
6
use PHPUnit\Framework\TestCase;
7
use Yiisoft\Files\FileHelper;
8
9
/**
10
 * File helper tests class.
11
 */
12
final class FileHelperTest extends TestCase
13
{
14
    /**
15
     * @var string test files path.
16
     */
17
    private $testFilePath = '';
18
19
    /**
20
     * Setup.
21
     *
22
     * @return void
23
     */
24
    public function setUp(): void
25
    {
26
        $this->testFilePath = FileHelper::normalizePath(sys_get_temp_dir() . '/' . get_class($this));
27
        
28
        FileHelper::createDirectory($this->testFilePath, 0777);
29
30
        if (!file_exists($this->testFilePath)) {
31
            $this->markTestIncomplete('Unit tests runtime directory should have writable permissions!');
32
        }
33
    }
34
35
    /**
36
     * Check if chmod works as expected.
37
     *
38
     * On remote file systems and vagrant mounts chmod returns true but file permissions are not set properly.
39
     */
40
    private function isChmodReliable(): bool
41
    {
42
        $directory = $this->testFilePath . '/test_chmod';
43
        mkdir($directory);
44
        chmod($directory, 0700);
45
        $mode = $this->getMode($directory);
46
        rmdir($directory);
47
48
        return $mode === '0700';
49
    }
50
51
    /**
52
     * TearDown.
53
     *
54
     * @return void
55
     */
56
    public function tearDown(): void
57
    {
58
        FileHelper::removeDirectory($this->testFilePath);
59
    }
60
61
    /**
62
     * Get file permission mode.
63
     *
64
     * @param string $file file name.
65
     *
66
     * @return string permission mode.
67
     */
68
    private function getMode(string $file): string
69
    {
70
        return substr(sprintf('%04o', fileperms($file)), -4);
71
    }
72
73
    /**
74
     * Asserts that file has specific permission mode.
75
     *
76
     * @param int $expectedMode expected file permission mode.
77
     * @param string $fileName file name.
78
     * @param string $message error message
79
     *
80
     * @return void
81
     */
82
    private function assertFileMode(int $expectedMode, string $fileName, string $message = ''): void
83
    {
84
        $expectedMode = sprintf('%04o', $expectedMode);
85
        $this->assertEquals($expectedMode, $this->getMode($fileName), $message);
86
    }
87
88
    /**
89
     * Create directory.
90
     *
91
     * @return void
92
     */
93
    public function testCreateDirectory(): void
94
    {
95
        $basePath = $this->testFilePath;
96
        $directory = $basePath . '/test_dir_level_1/test_dir_level_2';
97
        $this->assertTrue(FileHelper::createDirectory($directory), 'FileHelper::createDirectory should return true if directory was created!');
98
        $this->assertFileExists($directory, 'Unable to create directory recursively!');
99
        $this->assertTrue(FileHelper::createDirectory($directory), 'FileHelper::createDirectory should return true for already existing directories!');
100
    }
101
102
    /**
103
     * Create directory permissions.
104
     *
105
     * @return void
106
     */
107
    public function testCreateDirectoryPermissions(): void
108
    {
109
        if (!$this->isChmodReliable()) {
110
            $this->markTestSkipped('Skipping test since chmod is not reliable in this environment.');
111
        }
112
113
        $basePath = $this->testFilePath;
114
        $dirName = $basePath . '/test_dir_perms';
115
116
        $this->assertTrue(FileHelper::createDirectory($dirName, 0700));
117
        $this->assertFileMode(0700, $dirName);
118
    }
119
120
    /**
121
     * Remove directory.
122
     *
123
     * @return void
124
     */
125
    public function testRemoveDirectory(): void
126
    {
127
        $dirName = 'test_dir_for_remove';
128
129
        $this->createFileStructure([
130
            $dirName => [
131
                'file1.txt' => 'file 1 content',
132
                'file2.txt' => 'file 2 content',
133
                'test_sub_dir' => [
134
                    'sub_dir_file_1.txt' => 'sub dir file 1 content',
135
                    'sub_dir_file_2.txt' => 'sub dir file 2 content',
136
                ],
137
            ],
138
        ]);
139
140
        $basePath = $this->testFilePath;
141
        $dirName = $basePath . '/' . $dirName;
142
143
        FileHelper::removeDirectory($dirName);
144
145
        $this->assertFileNotExists($dirName, 'Unable to remove directory!');
146
147
        // should be silent about non-existing directories
148
        FileHelper::removeDirectory($basePath . '/nonExisting');
149
    }
150
151
    /**
152
     * Remove directory symlinks1.
153
     *
154
     * @return void
155
     */
156
    public function testRemoveDirectorySymlinks1(): void
157
    {
158
        $dirName = 'remove-directory-symlinks-1';
159
160
        $this->createFileStructure([
161
            $dirName => [
162
                'file' => 'Symlinked file.',
163
                'directory' => [
164
                    'standard-file-1' => 'Standard file 1.',
165
                ],
166
                'symlinks' => [
167
                    'standard-file-2' => 'Standard file 2.',
168
                    'symlinked-file' => ['symlink', '../file'],
169
                    'symlinked-directory' => ['symlink', '../directory'],
170
                ],
171
            ],
172
        ]);
173
174
        $basePath = $this->testFilePath . '/' . $dirName . '/';
175
176
        $this->assertFileExists($basePath . 'file');
177
        $this->assertDirectoryExists($basePath . 'directory');
178
        $this->assertFileExists($basePath . 'directory/standard-file-1');
179
        $this->assertDirectoryExists($basePath . 'symlinks');
180
        $this->assertFileExists($basePath . 'symlinks/standard-file-2');
181
        $this->assertFileExists($basePath . 'symlinks/symlinked-file');
182
        $this->assertDirectoryExists($basePath . 'symlinks/symlinked-directory');
183
        $this->assertFileExists($basePath . 'symlinks/symlinked-directory/standard-file-1');
184
185
        FileHelper::removeDirectory($basePath . 'symlinks');
186
187
        $this->assertFileExists($basePath . 'file');
188
        $this->assertDirectoryExists($basePath . 'directory');
189
        $this->assertFileExists($basePath . 'directory/standard-file-1'); // symlinked directory still have it's file
190
        $this->assertDirectoryNotExists($basePath . 'symlinks');
191
        $this->assertFileNotExists($basePath . 'symlinks/standard-file-2');
192
        $this->assertFileNotExists($basePath . 'symlinks/symlinked-file');
193
        $this->assertDirectoryNotExists($basePath . 'symlinks/symlinked-directory');
194
        $this->assertFileNotExists($basePath . 'symlinks/symlinked-directory/standard-file-1');
195
    }
196
197
    /**
198
     * Remove directory symlinks2.
199
     *
200
     * @return void
201
     */
202
    public function testRemoveDirectorySymlinks2(): void
203
    {
204
        $dirName = 'remove-directory-symlinks-2';
205
206
        $this->createFileStructure([
207
            $dirName => [
208
                'file' => 'Symlinked file.',
209
                'directory' => [
210
                    'standard-file-1' => 'Standard file 1.',
211
                ],
212
                'symlinks' => [
213
                    'standard-file-2' => 'Standard file 2.',
214
                    'symlinked-file' => ['symlink', '../file'],
215
                    'symlinked-directory' => ['symlink', '../directory'],
216
                ],
217
            ],
218
        ]);
219
220
        $basePath = $this->testFilePath . '/' . $dirName . '/';
221
222
        $this->assertFileExists($basePath . 'file');
223
        $this->assertDirectoryExists($basePath . 'directory');
224
        $this->assertFileExists($basePath . 'directory/standard-file-1');
225
        $this->assertDirectoryExists($basePath . 'symlinks');
226
        $this->assertFileExists($basePath . 'symlinks/standard-file-2');
227
        $this->assertFileExists($basePath . 'symlinks/symlinked-file');
228
        $this->assertDirectoryExists($basePath . 'symlinks/symlinked-directory');
229
        $this->assertFileExists($basePath . 'symlinks/symlinked-directory/standard-file-1');
230
231
        FileHelper::removeDirectory($basePath . 'symlinks', ['traverseSymlinks' => true]);
232
233
        $this->assertFileExists($basePath . 'file');
234
        $this->assertDirectoryExists($basePath . 'directory');
235
        $this->assertFileNotExists($basePath . 'directory/standard-file-1'); // symlinked directory doesn't have it's file now
236
        $this->assertDirectoryNotExists($basePath . 'symlinks');
237
        $this->assertFileNotExists($basePath . 'symlinks/standard-file-2');
238
        $this->assertFileNotExists($basePath . 'symlinks/symlinked-file');
239
        $this->assertDirectoryNotExists($basePath . 'symlinks/symlinked-directory');
240
        $this->assertFileNotExists($basePath . 'symlinks/symlinked-directory/standard-file-1');
241
    }
242
243
    /**
244
     * Normalize path.
245
     *
246
     * @return void
247
     */
248
    public function testNormalizePath(): void
249
    {
250
        $this->assertEquals('/a/b', FileHelper::normalizePath('//a\\b/'));
251
        $this->assertEquals('/b/c', FileHelper::normalizePath('/a/../b/c'));
252
        $this->assertEquals('/c', FileHelper::normalizePath('/a\\b/../..///c'));
253
        $this->assertEquals('/c', FileHelper::normalizePath('/a/.\\b//../../c'));
254
        $this->assertEquals('c', FileHelper::normalizePath('/a/.\\b/../..//../c'));
255
        $this->assertEquals('../c', FileHelper::normalizePath('//a/.\\b//..//..//../../c'));
256
257
        // relative paths
258
        $this->assertEquals('.', FileHelper::normalizePath('.'));
259
        $this->assertEquals('.', FileHelper::normalizePath('./'));
260
        $this->assertEquals('a', FileHelper::normalizePath('.\\a'));
261
        $this->assertEquals('a/b', FileHelper::normalizePath('./a\\b'));
262
        $this->assertEquals('.', FileHelper::normalizePath('./a\\../'));
263
        $this->assertEquals('../../a', FileHelper::normalizePath('../..\\a'));
264
        $this->assertEquals('../../a', FileHelper::normalizePath('../..\\a/../a'));
265
        $this->assertEquals('../../b', FileHelper::normalizePath('../..\\a/../b'));
266
        $this->assertEquals('../a', FileHelper::normalizePath('./..\\a'));
267
        $this->assertEquals('../a', FileHelper::normalizePath('././..\\a'));
268
        $this->assertEquals('../a', FileHelper::normalizePath('./..\\a/../a'));
269
        $this->assertEquals('../b', FileHelper::normalizePath('./..\\a/../b'));
270
271
        // Windows file system may have paths for network shares that start with two backslashes. These two backslashes
272
        // should not be touched.
273
        // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
274
        // https://github.com/yiisoft/yii2/issues/13034
275
        $this->assertEquals('\\\\server/share/path/file', FileHelper::normalizePath('\\\\server\share\path\file'));
276
    }
277
278
    /**
279
     * Copy directory.
280
     *
281
     * @depends testCreateDirectory
282
     *
283
     * @return void
284
     */
285
    public function testCopyDirectory(): void
286
    {
287
        $source = 'test_src_dir';
288
        $files = [
289
            'file1.txt' => 'file 1 content',
290
            'file2.txt' => 'file 2 content',
291
        ];
292
293
        $this->createFileStructure([
294
            $source => $files,
295
        ]);
296
297
        $basePath = $this->testFilePath;
298
        $source = $basePath . '/' . $source;
299
        $destination = $basePath . '/test_dst_dir';
300
301
        FileHelper::copyDirectory($source, $destination);
302
303
        $this->assertFileExists($destination, 'Destination directory does not exist!');
304
305
        foreach ($files as $name => $content) {
306
            $fileName = $destination . '/' . $name;
307
            $this->assertFileExists($fileName);
308
            $this->assertStringEqualsFile($fileName, $content, 'Incorrect file content!');
309
        }
310
    }
311
312
    /**
313
     * Copy directory recursive.
314
     *
315
     * @return void
316
     */
317
    public function testCopyDirectoryRecursive(): void
318
    {
319
        $source = 'test_src_dir_rec';
320
        $structure = [
321
            'directory1' => [
322
                'file1.txt' => 'file 1 content',
323
                'file2.txt' => 'file 2 content',
324
            ],
325
            'directory2' => [
326
                'file3.txt' => 'file 3 content',
327
                'file4.txt' => 'file 4 content',
328
            ],
329
            'file5.txt' => 'file 5 content',
330
        ];
331
332
        $this->createFileStructure([
333
            $source => $structure,
334
        ]);
335
336
        $basePath = $this->testFilePath;
337
        $source = $basePath . '/' . $source;
338
        $destination = $basePath . '/test_dst_dir';
339
340
        FileHelper::copyDirectory($source, $destination);
341
342
        $this->assertFileExists($destination, 'Destination directory does not exist!');
343
344
        $checker = function ($structure, $dstDirName) use (&$checker) {
345
            foreach ($structure as $name => $content) {
346
                if (is_array($content)) {
347
                    $checker($content, $dstDirName . '/' . $name);
348
                } else {
349
                    $fileName = $dstDirName . '/' . $name;
350
                    $this->assertFileExists($fileName);
351
                    $this->assertStringEqualsFile($fileName, $content, 'Incorrect file content!');
352
                }
353
            }
354
        };
355
        $checker($structure, $destination);
356
    }
357
358
    /**
359
     * Copy directory not recursive.
360
     *
361
     * @return void
362
     */
363
    public function testCopyDirectoryNotRecursive(): void
364
    {
365
        $source = 'test_src_dir_not_rec';
366
        $structure = [
367
            'directory1' => [
368
                'file1.txt' => 'file 1 content',
369
                'file2.txt' => 'file 2 content',
370
            ],
371
            'directory2' => [
372
                'file3.txt' => 'file 3 content',
373
                'file4.txt' => 'file 4 content',
374
            ],
375
            'file5.txt' => 'file 5 content',
376
        ];
377
378
        $this->createFileStructure([
379
            $source => $structure,
380
        ]);
381
382
        $basePath = $this->testFilePath;
383
        $source = $basePath . '/' . $source;
384
        $destination = $basePath . '/' . 'test_dst_dir';
385
386
        FileHelper::copyDirectory($source, $destination, ['recursive' => false]);
387
388
        $this->assertFileExists($destination, 'Destination directory does not exist!');
389
390
        foreach ($structure as $name => $content) {
391
            $fileName = $destination . '/' . $name;
392
            if (is_array($content)) {
393
                $this->assertFileNotExists($fileName);
394
            } else {
395
                $this->assertFileExists($fileName);
396
                $this->assertStringEqualsFile($fileName, $content, 'Incorrect file content!');
397
            }
398
        }
399
    }
400
401
    /**
402
     * Copy directory permissions.
403
     *
404
     * @depends testCopyDirectory
405
     *
406
     * @return void
407
     */
408
    public function testCopyDirectoryPermissions(): void
409
    {
410
        if (!$this->isChmodReliable()) {
411
            $this->markTestSkipped('Skipping test since chmod is not reliable in this environment.');
412
        }
413
414
        $isWindows = DIRECTORY_SEPARATOR === '\\';
415
416
        if ($isWindows) {
417
            $this->markTestSkipped('Skipping tests on Windows because fileperms() always return 0777.');
418
        }
419
420
        $source = 'test_src_dir';
421
        $subDirectory = 'test_sub_dir';
422
        $fileName = 'test_file.txt';
423
424
        $this->createFileStructure([
425
            $source => [
426
                $subDirectory => [],
427
                $fileName => 'test file content',
428
            ],
429
        ]);
430
431
        $basePath = $this->testFilePath;
432
        $source = $basePath . '/' . $source;
433
        $destination = $basePath . '/test_dst_dir';
434
        $directoryMode = 0755;
435
        $fileMode = 0755;
436
        $options = [
437
            'dirMode' => $directoryMode,
438
            'fileMode' => $fileMode,
439
        ];
440
441
        FileHelper::copyDirectory($source, $destination, $options);
442
443
        $this->assertFileMode($directoryMode, $destination, 'Destination directory has wrong mode!');
444
        $this->assertFileMode($directoryMode, $destination . '/' . $subDirectory, 'Copied sub directory has wrong mode!');
445
        $this->assertFileMode($fileMode, $destination . '/' . $fileName, 'Copied file has wrong mode!');
446
    }
447
448
    /**
449
     * Copy directory to it self.
450
     *
451
     * @see https://github.com/yiisoft/yii2/issues/10710
452
     *
453
     * @return void
454
     */
455
    public function testCopyDirectoryToItself(): void
456
    {
457
        $directoryName = 'test_dir';
458
459
        $this->createFileStructure([
460
            $directoryName => [],
461
        ]);
462
        $this->expectException(\InvalidArgumentException::class);
463
464
        $directoryName = $this->testFilePath . '/test_dir';
465
466
        FileHelper::copyDirectory($directoryName, $directoryName);
467
    }
468
469
    /**
470
     * Copy directory to sudirectory of it self.
471
     *
472
     * @see https://github.com/yiisoft/yii2/issues/10710
473
     *
474
     * @return void
475
     */
476
    public function testCopyDirToSubdirOfItself(): void
477
    {
478
        $this->createFileStructure([
479
            'data' => [],
480
            'backup' => ['data' => []],
481
        ]);
482
        $this->expectException(\InvalidArgumentException::class);
483
484
        FileHelper::copyDirectory(
485
            $this->testFilePath . '/backup',
486
            $this->testFilePath . '/backup/data'
487
        );
488
    }
489
490
    /**
491
     * Copy directory to another with same name.
492
     *
493
     * @see https://github.com/yiisoft/yii2/issues/10710
494
     *
495
     * @return void
496
     */
497
    public function testCopyDirToAnotherWithSameName(): void
498
    {
499
        $this->createFileStructure([
500
            'data' => [],
501
            'backup' => ['data' => []],
502
        ]);
503
504
        FileHelper::copyDirectory(
505
            $this->testFilePath . '/data',
506
            $this->testFilePath . '/backup/data'
507
        );
508
509
        $this->assertFileExists($this->testFilePath . '/backup/data');
510
    }
511
512
    /**
513
     * Copy directory with same name.
514
     *
515
     * @see https://github.com/yiisoft/yii2/issues/10710
516
     *
517
     * @return void
518
     */
519
    public function testCopyDirWithSameName(): void
520
    {
521
        $this->createFileStructure([
522
            'data' => [],
523
            'data-backup' => [],
524
        ]);
525
526
        FileHelper::copyDirectory(
527
            $this->testFilePath . '/data',
528
            $this->testFilePath . '/data-backup'
529
        );
530
531
        $this->assertTrue(true, 'no error');
532
    }
533
534
    public function testsCopyDirectoryFilterPath()
535
    {
536
        $source = 'boostrap4';
537
538
        $structure = [
539
            'css' => [
540
                'bootstrap.css'           => 'file 1 content',
541
                'bootstrap.css.map'       => 'file 2 content',
542
                'bootstrap.min.css'       => 'file 3 content',
543
                'bootstrap.min.css.map'   => 'file 4 content'
544
            ],
545
            'js' => [
546
                'bootstrap.js'            => 'file 5 content',
547
                'bootstrap.bundle.js'     => 'file 6 content',
548
                'bootstrap.bundle.js.map' => 'file 7 content',
549
                'bootstrap.min.js'        => 'file 8 content'
550
            ]
551
        ];
552
553
        $this->createFileStructure([
554
            $source => $structure,
555
        ]);
556
557
        $basePath = $this->testFilePath;
558
        $source = $basePath . '/' . $source;
559
        $destination = $basePath . '/assets';
560
561
        // without filter options return all directory.
562
        $options = [];
563
564
        FileHelper::copyDirectory($source, $destination, $options);
565
566
        $this->assertFileExists($destination, 'Destination directory does not exist!');
567
568
        $checker = function ($structure, $dstDirName) use (&$checker) {
569
            foreach ($structure as $name => $content) {
570
                if (is_array($content)) {
571
                    $checker($content, $dstDirName . '/' . $name);
572
                } else {
573
                    $fileName = $dstDirName . '/' . $name;
574
                    $this->assertFileExists($fileName);
575
                    $this->assertStringEqualsFile($fileName, $content, 'Incorrect file content!');
576
                }
577
            }
578
        };
579
580
        $checker($structure, $destination);
581
    }
582
583
    public function testsCopyDirectoryFilterPathOnly()
584
    {
585
        $source = 'boostrap4';
586
587
        $structure = [
588
            'css' => [
589
                'bootstrap.css'           => 'file 1 content',
590
                'bootstrap.css.map'       => 'file 2 content',
591
                'bootstrap.min.css'       => 'file 3 content',
592
                'bootstrap.min.css.map'   => 'file 4 content'
593
            ],
594
            'js' => [
595
                'bootstrap.js'            => 'file 5 content',
596
                'bootstrap.bundle.js'     => 'file 6 content',
597
                'bootstrap.bundle.js.map' => 'file 7 content',
598
                'bootstrap.min.js'        => 'file 8 content'
599
            ]
600
        ];
601
602
        $exist = [
0 ignored issues
show
Unused Code introduced by
The assignment to $exist is dead and can be removed.
Loading history...
603
            'css' => [
604
                'bootstrap.css'           => 'file 1 content',
605
                'bootstrap.min.css'       => 'file 3 content',
606
            ]
607
        ];
608
609
        $noexist = [
0 ignored issues
show
Unused Code introduced by
The assignment to $noexist is dead and can be removed.
Loading history...
610
            'css' => [
611
                'bootstrap.css.map'       => 'file 2 content',
612
                'bootstrap.min.css.map'   => 'file 4 content'
613
            ],
614
            'js' => [
615
                'bootstrap.js'            => 'file 5 content',
616
                'bootstrap.bundle.js'     => 'file 6 content',
617
                'bootstrap.bundle.js.map' => 'file 7 content',
618
                'bootstrap.min.js'        => 'file 8 content'
619
            ]
620
        ];
621
622
        $this->createFileStructure([
623
            $source => $structure,
624
        ]);
625
626
        $basePath = $this->testFilePath;
627
        $source = $basePath . '/' . $source;
628
        $destination = $basePath . '/assets';
629
630
        // without filter options return all directory.
631
        $options = [
632
            // options default false AssetManager
633
            'copyEmptyDirectories' => false,
634
            'only' => [
635
                'css/*.css',
636
            ]
637
        ];
638
639
        FileHelper::copyDirectory($source, $destination, $options);
640
641
        $this->assertFileExists($destination, 'Destination directory does not exist!');
642
643
        $exist = function ($exist, $dstDirName) use (&$checker) {
644
            foreach ($exist as $name => $content) {
645
                if (is_array($content)) {
646
                    $checker($content, $dstDirName . '/' . $name);
647
                } else {
648
                    $fileName = $dstDirName . '/' . $name;
649
                    $this->assertFileExists($fileName);
650
                    $this->assertStringEqualsFile($fileName, $content, 'Incorrect file content!');
651
                }
652
            }
653
        };
654
        $exist($exist, $destination);
655
656
        $noexist = function ($noexist, $dstDirName) use (&$checker) {
657
            foreach ($noexist as $name => $content) {
658
                if (is_array($content)) {
659
                    $checker($content, $dstDirName . '/' . $name);
660
                } else {
661
                    $fileName = $dstDirName . '/' . $name;
662
                    $this->assertFileNotExists($fileName);
663
                    $this->assertStringEqualsFile($fileName, $content, 'Incorrect file content!');
664
                }
665
            }
666
        };
667
        $noexist($noexist, $destination);
668
    }
669
670
    public function testsCopyDirectoryFilterPathExcept()
671
    {
672
        $source = 'boostrap4';
673
674
        $structure = [
675
            'css' => [
676
                'bootstrap.css'           => 'file 1 content',
677
                'bootstrap.css.map'       => 'file 2 content',
678
                'bootstrap.min.css'       => 'file 3 content',
679
                'bootstrap.min.css.map'   => 'file 4 content'
680
            ],
681
            'js' => [
682
                'bootstrap.js'            => 'file 5 content',
683
                'bootstrap.bundle.js'     => 'file 6 content',
684
                'bootstrap.bundle.js.map' => 'file 7 content',
685
                'bootstrap.min.js'        => 'file 8 content'
686
            ]
687
        ];
688
689
        $exist = [
0 ignored issues
show
Unused Code introduced by
The assignment to $exist is dead and can be removed.
Loading history...
690
            'css' => [
691
                'bootstrap.css'           => 'file 1 content',
692
            ]
693
        ];
694
695
        $noexist = [
0 ignored issues
show
Unused Code introduced by
The assignment to $noexist is dead and can be removed.
Loading history...
696
            'css' => [
697
                'bootstrap.css.map'       => 'file 2 content',
698
                'bootstrap.min.css'       => 'file 3 content',
699
                'bootstrap.min.css.map'   => 'file 4 content'
700
            ],
701
            'js' => [
702
                'bootstrap.js'            => 'file 5 content',
703
                'bootstrap.bundle.js'     => 'file 6 content',
704
                'bootstrap.bundle.js.map' => 'file 7 content',
705
                'bootstrap.min.js'        => 'file 8 content'
706
            ]
707
        ];
708
709
        $this->createFileStructure([
710
            $source => $structure,
711
        ]);
712
713
        $basePath = $this->testFilePath;
714
        $source = $basePath . '/' . $source;
715
        $destination = $basePath . '/assets';
716
717
        // without filter options return all directory.
718
        $options = [
719
            // options default false AssetManager
720
            'copyEmptyDirectories' => false,
721
            'only' => [
722
                'css/*.css',
723
            ],
724
            'except' => [
725
                'css/bootstrap.min.css'
726
            ]
727
        ];
728
729
        FileHelper::copyDirectory($source, $destination, $options);
730
731
        $this->assertFileExists($destination, 'Destination directory does not exist!');
732
733
        $exist = function ($exist, $dstDirName) use (&$checker) {
734
            foreach ($exist as $name => $content) {
735
                if (is_array($content)) {
736
                    $checker($content, $dstDirName . '/' . $name);
737
                } else {
738
                    $fileName = $dstDirName . '/' . $name;
739
                    $this->assertFileExists($fileName);
740
                    $this->assertStringEqualsFile($fileName, $content, 'Incorrect file content!');
741
                }
742
            }
743
        };
744
        $exist($exist, $destination);
745
746
        $noexist = function ($noexist, $dstDirName) use (&$checker) {
747
            foreach ($noexist as $name => $content) {
748
                if (is_array($content)) {
749
                    $checker($content, $dstDirName . '/' . $name);
750
                } else {
751
                    $fileName = $dstDirName . '/' . $name;
752
                    $this->assertFileNotExists($fileName);
753
                    $this->assertStringEqualsFile($fileName, $content, 'Incorrect file content!');
754
                }
755
            }
756
        };
757
        $noexist($noexist, $destination);
758
    }
759
760
    /**
761
     * Creates test files structure.
762
     *
763
     * @param array $items file system objects to be created in format: objectName => objectContent
764
     *                         Arrays specifies directories, other values - files.
765
     * @param string $basePath structure base file path.
766
     *
767
     * @return void
768
     */
769
    private function createFileStructure(array $items, ?string $basePath = null): void
770
    {
771
        $basePath = $basePath ?? $this->testFilePath;
772
773
        if (empty($basePath)) {
774
            $basePath = $this->testFilePath;
775
        }
776
        foreach ($items as $name => $content) {
777
            $itemName = $basePath . DIRECTORY_SEPARATOR . $name;
778
            if (is_array($content)) {
779
                if (isset($content[0], $content[1]) && $content[0] === 'symlink') {
780
                    symlink($basePath . '/' . $content[1], $itemName);
781
                } else {
782
                    mkdir($itemName, 0777, true);
783
                    $this->createFileStructure($content, $itemName);
784
                }
785
            } else {
786
                file_put_contents($itemName, $content);
787
            }
788
        }
789
    }
790
}
791