Completed
Pull Request — master (#143)
by Marco
20:29
created

InstallerTest::rmDir()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 11
c 2
b 0
f 0
nc 2
nop 1
dl 0
loc 21
rs 9.9
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PackageVersionsTest;
6
7
use Composer\Composer;
8
use Composer\Config;
9
use Composer\EventDispatcher\EventDispatcher;
10
use Composer\Installer\InstallationManager;
11
use Composer\IO\IOInterface;
12
use Composer\Package\Link;
13
use Composer\Package\Locker;
14
use Composer\Package\RootAliasPackage;
15
use Composer\Package\RootPackage;
16
use Composer\Package\RootPackageInterface;
17
use Composer\Repository\InstalledRepositoryInterface;
18
use Composer\Repository\RepositoryManager;
19
use Composer\Script\Event;
20
use PackageVersions\Installer;
21
use PHPUnit\Framework\Exception;
22
use PHPUnit\Framework\MockObject\MockObject;
23
use PHPUnit\Framework\TestCase;
24
use ReflectionClass;
25
use RuntimeException;
26
use function array_filter;
27
use function array_map;
28
use function chmod;
29
use function file_get_contents;
30
use function file_put_contents;
31
use function fileperms;
32
use function in_array;
33
use function is_dir;
34
use function mkdir;
35
use function preg_match_all;
36
use function realpath;
37
use function rmdir;
38
use function scandir;
39
use function sprintf;
40
use function strpos;
41
use function substr;
42
use function sys_get_temp_dir;
43
use function uniqid;
44
use function unlink;
45
use const PHP_OS;
46
47
/**
48
 * @covers \PackageVersions\Installer
49
 */
50
final class InstallerTest extends TestCase
51
{
52
    /** @var Composer&MockObject */
53
    private $composer;
54
55
    /** @var EventDispatcher&MockObject */
56
    private $eventDispatcher;
57
58
    /** @var IOInterface&MockObject */
59
    private $io;
60
61
    private Installer $installer;
62
63
    /**
64
     * {@inheritDoc}
65
     *
66
     * @throws Exception
67
     */
68
    protected function setUp() : void
69
    {
70
        parent::setUp();
71
72
        $this->installer       = new Installer();
73
        $this->io              = $this->createMock(IOInterface::class);
74
        $this->composer        = $this->createMock(Composer::class);
75
        $this->eventDispatcher = $this->createMock(EventDispatcher::class);
76
77
        $this->composer->expects(self::any())->method('getEventDispatcher')->willReturn($this->eventDispatcher);
78
    }
79
80
    public function testGetSubscribedEvents() : void
81
    {
82
        $events = Installer::getSubscribedEvents();
83
84
        self::assertSame(
85
            ['post-autoload-dump' => 'dumpVersionsClass'],
86
            $events
87
        );
88
89
        foreach ($events as $callback) {
90
            self::assertIsCallable([$this->installer, $callback]);
91
        }
92
    }
93
94
    public function testDumpVersionsClassIfExistingFileIsNotWritable() : void
95
    {
96
        $config            = $this->createMock(Config::class);
97
        $locker            = $this->createMock(Locker::class);
98
        $repositoryManager = $this->createMock(RepositoryManager::class);
99
        $installManager    = $this->createMock(InstallationManager::class);
100
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
101
102
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
103
104
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
105
106
        /** @noinspection MkdirRaceConditionInspection */
107
        mkdir($expectedPath, 0777, true);
108
109
        $expectedFileName = $expectedPath . '/Versions.php';
110
        file_put_contents($expectedFileName, 'NOT PHP!');
111
        chmod($expectedFileName, 0444);
112
113
        $locker
114
            ->method('getLockData')
115
            ->willReturn([
116
                'packages' => [
117
                    [
118
                        'name'    => 'ocramius/package-versions',
119
                        'version' => '1.0.0',
120
                    ],
121
                ],
122
            ]);
123
124
        $repositoryManager->method('getLocalRepository')->willReturn($repository);
125
126
        $this->composer->method('getConfig')->willReturn($config);
0 ignored issues
show
Bug introduced by
The method method() does not exist on Composer\Composer. ( Ignorable by Annotation )

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

126
        $this->composer->/** @scrutinizer ignore-call */ 
127
                         method('getConfig')->willReturn($config);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
127
        $this->composer->method('getLocker')->willReturn($locker);
128
        $this->composer->method('getRepositoryManager')->willReturn($repositoryManager);
129
        $this->composer->method('getPackage')->willReturn($this->getRootPackageMock());
130
        $this->composer->method('getInstallationManager')->willReturn($installManager);
131
132
        $config->method('get')->with('vendor-dir')->willReturn($vendorDir);
133
134
        Installer::dumpVersionsClass(new Event(
135
            'post-install-cmd',
136
            $this->composer,
137
            $this->io
138
        ));
139
140
        self::assertStringStartsWith('<?php', file_get_contents($expectedFileName));
141
142
        $this->rmDir($vendorDir);
143
    }
144
145
    public function testDumpVersionsClass() : void
146
    {
147
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
148
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
149
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
150
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
151
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
152
153
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
154
155
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
156
157
        /** @noinspection MkdirRaceConditionInspection */
158
        mkdir($expectedPath, 0777, true);
159
160
        $locker
161
            ->expects(self::any())
162
            ->method('getLockData')
163
            ->willReturn([
164
                'packages' => [
165
                    [
166
                        'name'    => 'ocramius/package-versions',
167
                        'version' => '1.0.0',
168
                    ],
169
                    [
170
                        'name'    => 'foo/bar',
171
                        'version' => '1.2.3',
172
                        'source'  => ['reference' => 'abc123'],
173
                    ],
174
                    [
175
                        'name'    => 'baz/tab',
176
                        'version' => '4.5.6',
177
                        'source'  => ['reference' => 'def456'],
178
                    ],
179
                ],
180
                'packages-dev' => [
181
                    [
182
                        'name'    => 'tar/taz',
183
                        'version' => '7.8.9',
184
                        'source'  => ['reference' => 'ghi789'],
185
                    ],
186
                ],
187
            ]);
188
189
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
190
191
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
192
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
193
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
194
        $this->composer->expects(self::any())->method('getPackage')->willReturn($this->getRootPackageMock());
195
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
196
197
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
198
199
        Installer::dumpVersionsClass(new Event(
200
            'post-install-cmd',
201
            $this->composer,
202
            $this->io
203
        ));
204
205
        $expectedSource = <<<'PHP'
206
<?php
207
208
declare(strict_types=1);
209
210
namespace PackageVersions;
211
212
use Composer\InstalledVersions;
213
use OutOfBoundsException;
214
215
/**
216
 * This class is generated by ocramius/package-versions, specifically by
217
 * @see \PackageVersions\Installer
218
 *
219
 * This file is overwritten at every run of `composer install` or `composer update`.
220
 */
221
final class Versions
222
{
223
    public const ROOT_PACKAGE_NAME = 'root/package';
224
225
    private function __construct()
226
    {
227
    }
228
229
    /**
230
     * @throws OutOfBoundsException If a version cannot be located.
231
     *
232
     * @psalm-pure
233
     */
234
    public static function getVersion(string $packageName) : string
235
    {
236
        return InstalledVersions::getPrettyVersion($packageName)
237
            . '@' . InstalledVersions::getReference($packageName);
238
    }
239
}
240
241
PHP;
242
243
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
244
245
        $this->rmDir($vendorDir);
246
    }
247
248
    public function testDumpVersionsClassNoDev() : void
249
    {
250
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
251
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
252
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
253
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
254
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
255
256
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
257
258
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
259
260
        /** @noinspection MkdirRaceConditionInspection */
261
        mkdir($expectedPath, 0777, true);
262
263
        $locker
264
            ->expects(self::any())
265
            ->method('getLockData')
266
            ->willReturn([
267
                'packages' => [
268
                    [
269
                        'name'    => 'ocramius/package-versions',
270
                        'version' => '1.0.0',
271
                    ],
272
                    [
273
                        'name'    => 'foo/bar',
274
                        'version' => '1.2.3',
275
                        'source'  => ['reference' => 'abc123'],
276
                    ],
277
                    [
278
                        'name'    => 'baz/tab',
279
                        'version' => '4.5.6',
280
                        'source'  => ['reference' => 'def456'],
281
                    ],
282
                ],
283
            ]);
284
285
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
286
287
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
288
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
289
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
290
        $this->composer->expects(self::any())->method('getPackage')->willReturn($this->getRootPackageMock());
291
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
292
293
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
294
295
        Installer::dumpVersionsClass(new Event(
296
            'post-install-cmd',
297
            $this->composer,
298
            $this->io
299
        ));
300
301
        $expectedSource = <<<'PHP'
302
<?php
303
304
declare(strict_types=1);
305
306
namespace PackageVersions;
307
308
use Composer\InstalledVersions;
309
use OutOfBoundsException;
310
311
/**
312
 * This class is generated by ocramius/package-versions, specifically by
313
 * @see \PackageVersions\Installer
314
 *
315
 * This file is overwritten at every run of `composer install` or `composer update`.
316
 */
317
final class Versions
318
{
319
    public const ROOT_PACKAGE_NAME = 'root/package';
320
321
    private function __construct()
322
    {
323
    }
324
325
    /**
326
     * @throws OutOfBoundsException If a version cannot be located.
327
     *
328
     * @psalm-pure
329
     */
330
    public static function getVersion(string $packageName) : string
331
    {
332
        return InstalledVersions::getPrettyVersion($packageName)
333
            . '@' . InstalledVersions::getReference($packageName);
334
    }
335
}
336
337
PHP;
338
339
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
340
341
        $this->rmDir($vendorDir);
342
    }
343
344
    /**
345
     * @throws RuntimeException
346
     *
347
     * @group #12
348
     */
349
    public function testDumpVersionsWithoutPackageSourceDetails() : void
350
    {
351
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
352
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
353
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
354
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
355
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
356
357
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
358
359
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
360
361
        /** @noinspection MkdirRaceConditionInspection */
362
        mkdir($expectedPath, 0777, true);
363
364
        $locker
365
            ->expects(self::any())
366
            ->method('getLockData')
367
            ->willReturn([
368
                'packages' => [
369
                    [
370
                        'name'    => 'ocramius/package-versions',
371
                        'version' => '1.0.0',
372
                    ],
373
                    [
374
                        'name'    => 'foo/bar',
375
                        'version' => '1.2.3',
376
                        'dist'  => ['reference' => 'abc123'], // version defined in the dist, this time
377
                    ],
378
                    [
379
                        'name'    => 'baz/tab',
380
                        'version' => '4.5.6', // source missing
381
                    ],
382
                ],
383
            ]);
384
385
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
386
387
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
388
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
389
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
390
        $this->composer->expects(self::any())->method('getPackage')->willReturn($this->getRootPackageMock());
391
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
392
393
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
394
395
        Installer::dumpVersionsClass(new Event(
396
            'post-install-cmd',
397
            $this->composer,
398
            $this->io
399
        ));
400
401
        $expectedSource = <<<'PHP'
402
<?php
403
404
declare(strict_types=1);
405
406
namespace PackageVersions;
407
408
use Composer\InstalledVersions;
409
use OutOfBoundsException;
410
411
/**
412
 * This class is generated by ocramius/package-versions, specifically by
413
 * @see \PackageVersions\Installer
414
 *
415
 * This file is overwritten at every run of `composer install` or `composer update`.
416
 */
417
final class Versions
418
{
419
    public const ROOT_PACKAGE_NAME = 'root/package';
420
421
    private function __construct()
422
    {
423
    }
424
425
    /**
426
     * @throws OutOfBoundsException If a version cannot be located.
427
     *
428
     * @psalm-pure
429
     */
430
    public static function getVersion(string $packageName) : string
431
    {
432
        return InstalledVersions::getPrettyVersion($packageName)
433
            . '@' . InstalledVersions::getReference($packageName);
434
    }
435
}
436
437
PHP;
438
439
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
440
441
        $this->rmDir($vendorDir);
442
    }
443
444
    /**
445
     * @throws RuntimeException
446
     *
447
     * @dataProvider rootPackageProvider
448
     */
449
    public function testDumpsVersionsClassToSpecificLocation(RootPackageInterface $rootPackage, bool $inVendor) : void
450
    {
451
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
452
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
453
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
454
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
455
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
456
457
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/vendor';
458
459
        /** @noinspection MkdirRaceConditionInspection */
460
        mkdir($vendorDir, 0777, true);
461
462
        /** @noinspection RealpathInSteamContextInspection */
463
        $expectedPath = $inVendor
464
            ? $vendorDir . '/ocramius/package-versions/src/PackageVersions'
465
            : realpath($vendorDir . '/..') . '/src/PackageVersions';
466
467
        /** @noinspection MkdirRaceConditionInspection */
468
        mkdir($expectedPath, 0777, true);
469
470
        $locker
471
            ->expects(self::any())
472
            ->method('getLockData')
473
            ->willReturn([
474
                'packages' => [
475
                    [
476
                        'name'    => 'ocramius/package-versions',
477
                        'version' => '1.0.0',
478
                    ],
479
                ],
480
                'packages-dev' => [],
481
            ]);
482
483
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
484
485
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
486
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
487
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
488
        $this->composer->expects(self::any())->method('getPackage')->willReturn($rootPackage);
489
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
490
491
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
492
493
        Installer::dumpVersionsClass(new Event(
494
            'post-install-cmd',
495
            $this->composer,
496
            $this->io
497
        ));
498
499
        $generatedSource = file_get_contents($expectedPath . '/Versions.php');
500
501
        self::assertStringNotContainsString(
502
            'unknown/root-package@UNKNOWN',
503
            $generatedSource
504
        );
505
506
        self::assertStringMatchesFormat(
507
            '%Aclass Versions%AROOT_PACKAGE_NAME%A',
508
            $generatedSource
509
        );
510
511
        $this->rmDir($vendorDir);
512
    }
513
514
    /**
515
     * @return bool[][]|RootPackageInterface[][] the root package and whether the versions class is to be generated in
516
     *                                           the vendor dir or not
517
     */
518
    public function rootPackageProvider() : array
519
    {
520
        $baseRootPackage                         = new RootPackage('root/package', '1.2.3', '1.2.3');
521
        $aliasRootPackage                        = new RootAliasPackage($baseRootPackage, '1.2.3', '1.2.3');
522
        $indirectAliasRootPackage                = new RootAliasPackage($aliasRootPackage, '1.2.3', '1.2.3');
523
        $packageVersionsRootPackage              = new RootPackage('ocramius/package-versions', '1.2.3', '1.2.3');
524
        $aliasPackageVersionsRootPackage         = new RootAliasPackage($packageVersionsRootPackage, '1.2.3', '1.2.3');
525
        $indirectAliasPackageVersionsRootPackage = new RootAliasPackage(
526
            $aliasPackageVersionsRootPackage,
527
            '1.2.3',
528
            '1.2.3'
529
        );
530
531
        return [
532
            'root package is not ocramius/package-versions' => [
533
                $baseRootPackage,
534
                true,
535
            ],
536
            'alias root package is not ocramius/package-versions' => [
537
                $aliasRootPackage,
538
                true,
539
            ],
540
            'indirect alias root package is not ocramius/package-versions' => [
541
                $indirectAliasRootPackage,
542
                true,
543
            ],
544
            'root package is ocramius/package-versions' => [
545
                $packageVersionsRootPackage,
546
                false,
547
            ],
548
            'alias root package is ocramius/package-versions' => [
549
                $aliasPackageVersionsRootPackage,
550
                false,
551
            ],
552
            'indirect alias root package is ocramius/package-versions' => [
553
                $indirectAliasPackageVersionsRootPackage,
554
                false,
555
            ],
556
        ];
557
    }
558
559
    public function testVersionsAreNotDumpedIfPackageVersionsNotExplicitlyRequired() : void
560
    {
561
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
562
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
563
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
564
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
565
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
566
        $package           = $this->createMock(RootPackageInterface::class);
567
568
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
569
570
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
571
572
        /** @noinspection MkdirRaceConditionInspection */
573
        mkdir($expectedPath, 0777, true);
574
575
        $locker
576
            ->expects(self::any())
577
            ->method('getLockData')
578
            ->willReturn([
579
                'packages' => [
580
                    [
581
                        'name'    => 'foo/bar',
582
                        'version' => '1.2.3',
583
                        'dist'  => ['reference' => 'abc123'], // version defined in the dist, this time
584
                    ],
585
                    [
586
                        'name'    => 'baz/tab',
587
                        'version' => '4.5.6', // source missing
588
                    ],
589
                ],
590
            ]);
591
592
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
593
594
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
595
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
596
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
597
        $this->composer->expects(self::any())->method('getPackage')->willReturn($package);
598
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
599
600
        $package->expects(self::any())->method('getName')->willReturn('root/package');
601
        $package->expects(self::any())->method('getVersion')->willReturn('1.3.5');
602
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
603
        $package->expects(self::any())->method('getReplaces')->willReturn([]);
604
605
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
606
607
        Installer::dumpVersionsClass(new Event(
608
            'post-install-cmd',
609
            $this->composer,
610
            $this->io
611
        ));
612
613
        self::assertFileDoesNotExist($expectedPath . '/Versions.php');
614
615
        $this->rmDir($vendorDir);
616
    }
617
618
    /**
619
     * @group #41
620
     * @group #46
621
     */
622
    public function testVersionsAreNotDumpedIfPackageIsScheduledForRemoval() : void
623
    {
624
        $config  = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
625
        $locker  = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
626
        $package = $this->createMock(RootPackageInterface::class);
627
        $package->expects(self::any())->method('getReplaces')->willReturn([]);
628
        $vendorDir    = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
629
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
630
631
        $locker
632
            ->expects(self::any())
633
            ->method('getLockData')
634
            ->willReturn([
635
                'packages' => [
636
                    [
637
                        'name'    => 'ocramius/package-versions',
638
                        'version' => '1.0.0',
639
                    ],
640
                ],
641
            ]);
642
643
        $package->expects(self::any())->method('getName')->willReturn('root/package');
644
645
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
646
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
647
        $this->composer->expects(self::any())->method('getPackage')->willReturn($package);
648
649
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
650
651
        Installer::dumpVersionsClass(new Event(
652
            'post-install-cmd',
653
            $this->composer,
654
            $this->io
655
        ));
656
657
        self::assertFileDoesNotExist($expectedPath . '/Versions.php');
658
        self::assertFileDoesNotExist($expectedPath . '/Versions.php');
659
    }
660
661
    public function testGeneratedVersionFileAccessRights() : void
662
    {
663
        if (strpos(PHP_OS, 'WIN') === 0) {
664
            $this->markTestSkipped('Windows is kinda "meh" at file access levels');
665
        }
666
667
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
668
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
669
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
670
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
671
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
672
        $package           = $this->createMock(RootPackageInterface::class);
673
        $package->expects(self::any())->method('getReplaces')->willReturn([]);
674
675
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
676
677
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
678
679
        /** @noinspection MkdirRaceConditionInspection */
680
        mkdir($expectedPath, 0777, true);
681
682
        $locker
683
            ->expects(self::any())
684
            ->method('getLockData')
685
            ->willReturn([
686
                'packages' => [
687
                    [
688
                        'name'    => 'ocramius/package-versions',
689
                        'version' => '1.0.0',
690
                    ],
691
                ],
692
            ]);
693
694
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
695
696
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
697
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
698
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
699
        $this->composer->expects(self::any())->method('getPackage')->willReturn($package);
700
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
701
702
        $package->expects(self::any())->method('getName')->willReturn('root/package');
703
        $package->expects(self::any())->method('getVersion')->willReturn('1.3.5');
704
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
705
706
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
707
708
        Installer::dumpVersionsClass(new Event(
709
            'post-install-cmd',
710
            $this->composer,
711
            $this->io
712
        ));
713
714
        $filePath = $expectedPath . '/Versions.php';
715
716
        self::assertFileExists($filePath);
717
        self::assertSame('0664', substr(sprintf('%o', fileperms($filePath)), -4));
718
719
        $this->rmDir($vendorDir);
720
    }
721
722
    private function rmDir(string $directory) : void
723
    {
724
        if (! is_dir($directory)) {
725
            unlink($directory);
726
727
            return;
728
        }
729
730
        array_map(
731
            function ($item) use ($directory) : void {
732
                $this->rmDir($directory . '/' . $item);
733
            },
734
            array_filter(
735
                scandir($directory),
0 ignored issues
show
Bug introduced by
It seems like scandir($directory) can also be of type false; however, parameter $input of array_filter() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

735
                /** @scrutinizer ignore-type */ scandir($directory),
Loading history...
736
                static function (string $dirItem) {
737
                    return ! in_array($dirItem, ['.', '..'], true);
738
                }
739
            )
740
        );
741
742
        rmdir($directory);
743
    }
744
745
    /**
746
     * @group composer/composer#5237
747
     */
748
    public function testWillEscapeRegexParsingOfClassDefinitions() : void
749
    {
750
        self::assertSame(
751
            1,
752
            preg_match_all(
753
                '{^((?:final\s+)?(?:\s*))class\s+(\S+)}mi',
754
                file_get_contents((new ReflectionClass(Installer::class))->getFileName())
755
            )
756
        );
757
    }
758
759
    public function testGetVersionsIsNotNormalizedForRootPackage() : void
760
    {
761
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
762
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
763
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
764
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
765
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
766
767
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
768
769
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
770
771
        /** @noinspection MkdirRaceConditionInspection */
772
        mkdir($expectedPath, 0777, true);
773
774
        $locker
775
            ->expects(self::any())
776
            ->method('getLockData')
777
            ->willReturn([
778
                'packages' => [
779
                    [
780
                        'name'    => 'ocramius/package-versions',
781
                        'version' => '1.0.0',
782
                    ],
783
                ],
784
            ]);
785
786
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
787
788
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
789
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
790
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
791
        $this->composer->expects(self::any())->method('getPackage')->willReturn($this->getRootPackageMock());
792
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
793
794
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
795
796
        Installer::dumpVersionsClass(new Event(
797
            'post-install-cmd',
798
            $this->composer,
799
            $this->io
800
        ));
801
802
        $expectedSource = <<<'PHP'
803
<?php
804
805
declare(strict_types=1);
806
807
namespace PackageVersions;
808
809
use Composer\InstalledVersions;
810
use OutOfBoundsException;
811
812
/**
813
 * This class is generated by ocramius/package-versions, specifically by
814
 * @see \PackageVersions\Installer
815
 *
816
 * This file is overwritten at every run of `composer install` or `composer update`.
817
 */
818
final class Versions
819
{
820
    public const ROOT_PACKAGE_NAME = 'root/package';
821
822
    private function __construct()
823
    {
824
    }
825
826
    /**
827
     * @throws OutOfBoundsException If a version cannot be located.
828
     *
829
     * @psalm-pure
830
     */
831
    public static function getVersion(string $packageName) : string
832
    {
833
        return InstalledVersions::getPrettyVersion($packageName)
834
            . '@' . InstalledVersions::getReference($packageName);
835
    }
836
}
837
838
PHP;
839
840
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
841
842
        $this->rmDir($vendorDir);
843
    }
844
845
    private function getRootPackageMock() : RootPackageInterface
846
    {
847
        $package = $this->createMock(RootPackageInterface::class);
848
        $package->expects(self::any())->method('getName')->willReturn('root/package');
849
        $package->expects(self::any())->method('getPrettyVersion')->willReturn('1.3.5');
850
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
851
852
        $link = $this->createMock(Link::class);
853
        $link->expects(self::any())->method('getTarget')->willReturn('some-replaced/package');
854
        $link->expects(self::any())->method('getPrettyConstraint')->willReturn('self.version');
855
856
        $package->expects(self::any())->method('getReplaces')->willReturn([$link]);
857
858
        return $package;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $package returns the type PHPUnit\Framework\MockObject\MockObject which is incompatible with the type-hinted return Composer\Package\RootPackageInterface.
Loading history...
859
    }
860
}
861