Completed
Push — master ( 611925...ad8a24 )
by Marco
14s
created

InstallerTest::getRootPackageMock()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 1
eloc 6
nc 1
nop 0
1
<?php
2
3
namespace PackageVersionsTest;
4
5
use Composer\Composer;
6
use Composer\Config;
7
use Composer\EventDispatcher\EventDispatcher;
8
use Composer\Installer\InstallationManager;
9
use Composer\IO\IOInterface;
10
use Composer\Package\Locker;
11
use Composer\Package\Package;
12
use Composer\Package\RootAliasPackage;
13
use Composer\Package\RootPackage;
14
use Composer\Package\RootPackageInterface;
15
use Composer\Repository\InstalledRepositoryInterface;
16
use Composer\Repository\RepositoryManager;
17
use Composer\Script\Event;
18
use PackageVersions\Installer;
19
use PHPUnit\Framework\TestCase;
20
21
/**
22
 * @covers \PackageVersions\Installer
23
 */
24
final class InstallerTest extends TestCase
25
{
26
    /**
27
     * @var Composer|\PHPUnit_Framework_MockObject_MockObject
28
     */
29
    private $composer;
30
31
    /**
32
     * @var EventDispatcher|\PHPUnit_Framework_MockObject_MockObject
33
     */
34
    private $eventDispatcher;
35
36
    /**
37
     * @var IOInterface|\PHPUnit_Framework_MockObject_MockObject
38
     */
39
    private $io;
40
41
    /**
42
     * @var Installer
43
     */
44
    private $installer;
45
46
    /**
47
     * {@inheritDoc}
48
     *
49
     * @throws \PHPUnit\Framework\Exception
50
     */
51
    protected function setUp()
52
    {
53
        parent::setUp();
54
55
        $this->installer       = new Installer();
56
        $this->io              = $this->createMock(IOInterface::class);
57
        $this->composer        = $this->createMock(Composer::class);
58
        $this->eventDispatcher = $this->getMockBuilder(EventDispatcher::class)->disableOriginalConstructor()->getMock();
59
60
        $this->composer->expects(self::any())->method('getEventDispatcher')->willReturn($this->eventDispatcher);
61
    }
62
63
    public function testGetSubscribedEvents()
64
    {
65
        $events = Installer::getSubscribedEvents();
66
67
        self::assertSame(
68
            [
69
                'post-install-cmd' => 'dumpVersionsClass',
70
                'post-update-cmd'  => 'dumpVersionsClass',
71
            ],
72
            $events
73
        );
74
75
        foreach ($events as $callback) {
76
            self::assertInternalType('callable', [$this->installer, $callback]);
77
        }
78
    }
79
80
    public function testDumpVersionsClass()
81
    {
82
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
83
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
84
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
85
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
86
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
87
88
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
89
90
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
91
92
        /** @noinspection MkdirRaceConditionInspection */
93
        mkdir($expectedPath, 0777, true);
94
95
        $locker
96
            ->expects(self::any())
97
            ->method('getLockData')
98
            ->willReturn([
99
                'packages' => [
100
                    [
101
                        'name'    => 'ocramius/package-versions',
102
                        'version' => '1.0.0',
103
                    ],
104
                    [
105
                        'name'    => 'foo/bar',
106
                        'version' => '1.2.3',
107
                        'source'  => [
108
                            'reference' => 'abc123',
109
                        ],
110
                    ],
111
                    [
112
                        'name'    => 'baz/tab',
113
                        'version' => '4.5.6',
114
                        'source'  => [
115
                            'reference' => 'def456',
116
                        ],
117
                    ],
118
                ],
119
                'packages-dev' => [
120
                    [
121
                        'name'    => 'tar/taz',
122
                        'version' => '7.8.9',
123
                        'source'  => [
124
                            'reference' => 'ghi789',
125
                        ],
126
                    ]
127
                ],
128
            ]);
129
130
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
131
132
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
133
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
134
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
135
        $this->composer->expects(self::any())->method('getPackage')->willReturn($this->getRootPackageMock());
136
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
137
138
139
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
140
141
        Installer::dumpVersionsClass(new Event(
142
            'post-install-cmd',
143
            $this->composer,
144
            $this->io
145
        ));
146
147
        $expectedSource = <<<'PHP'
148
<?php
149
150
namespace PackageVersions;
151
152
/**
153
 * This class is generated by ocramius/package-versions, specifically by
154
 * @see \PackageVersions\Installer
155
 *
156
 * This file is overwritten at every run of `composer install` or `composer update`.
157
 */
158
final class Versions
159
{
160
    const VERSIONS = array (
161
  'ocramius/package-versions' => '1.0.0@',
162
  'foo/bar' => '1.2.3@abc123',
163
  'baz/tab' => '4.5.6@def456',
164
  'tar/taz' => '7.8.9@ghi789',
165
  'root/package' => '1.3.5@aaabbbcccddd',
166
);
167
168
    private function __construct()
169
    {
170
    }
171
172
    /**
173
     * @throws \OutOfBoundsException if a version cannot be located
174
     */
175
    public static function getVersion(string $packageName) : string
176
    {
177
        if (! isset(self::VERSIONS[$packageName])) {
178
            throw new \OutOfBoundsException(
179
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
180
            );
181
        }
182
183
        return self::VERSIONS[$packageName];
184
    }
185
}
186
187
PHP;
188
189
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
190
191
        $this->rmDir($vendorDir);
192
    }
193
194
    public function testDumpVersionsClassNoDev()
195
    {
196
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
197
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
198
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
199
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
200
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
201
202
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
203
204
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
205
206
        /** @noinspection MkdirRaceConditionInspection */
207
        mkdir($expectedPath, 0777, true);
208
209
        $locker
210
            ->expects(self::any())
211
            ->method('getLockData')
212
            ->willReturn([
213
                'packages' => [
214
                    [
215
                        'name'    => 'ocramius/package-versions',
216
                        'version' => '1.0.0',
217
                    ],
218
                    [
219
                        'name'    => 'foo/bar',
220
                        'version' => '1.2.3',
221
                        'source'  => [
222
                            'reference' => 'abc123',
223
                        ],
224
                    ],
225
                    [
226
                        'name'    => 'baz/tab',
227
                        'version' => '4.5.6',
228
                        'source'  => [
229
                            'reference' => 'def456',
230
                        ],
231
                    ],
232
                ],
233
            ]);
234
235
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
236
237
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
238
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
239
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
240
        $this->composer->expects(self::any())->method('getPackage')->willReturn($this->getRootPackageMock());
241
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
242
243
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
244
245
        Installer::dumpVersionsClass(new Event(
246
            'post-install-cmd',
247
            $this->composer,
248
            $this->io
249
        ));
250
251
        $expectedSource = <<<'PHP'
252
<?php
253
254
namespace PackageVersions;
255
256
/**
257
 * This class is generated by ocramius/package-versions, specifically by
258
 * @see \PackageVersions\Installer
259
 *
260
 * This file is overwritten at every run of `composer install` or `composer update`.
261
 */
262
final class Versions
263
{
264
    const VERSIONS = array (
265
  'ocramius/package-versions' => '1.0.0@',
266
  'foo/bar' => '1.2.3@abc123',
267
  'baz/tab' => '4.5.6@def456',
268
  'root/package' => '1.3.5@aaabbbcccddd',
269
);
270
271
    private function __construct()
272
    {
273
    }
274
275
    /**
276
     * @throws \OutOfBoundsException if a version cannot be located
277
     */
278
    public static function getVersion(string $packageName) : string
279
    {
280
        if (! isset(self::VERSIONS[$packageName])) {
281
            throw new \OutOfBoundsException(
282
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
283
            );
284
        }
285
286
        return self::VERSIONS[$packageName];
287
    }
288
}
289
290
PHP;
291
292
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
293
294
        $this->rmDir($vendorDir);
295
    }
296
297
    /**
298
     * @group #12
299
     *
300
     * @throws \RuntimeException
301
     */
302
    public function testDumpVersionsWithoutPackageSourceDetails()
303
    {
304
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
305
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
306
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
307
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
308
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
309
310
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
311
312
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
313
314
        /** @noinspection MkdirRaceConditionInspection */
315
        mkdir($expectedPath, 0777, true);
316
317
        $locker
318
            ->expects(self::any())
319
            ->method('getLockData')
320
            ->willReturn([
321
                'packages' => [
322
                    [
323
                        'name'    => 'ocramius/package-versions',
324
                        'version' => '1.0.0',
325
                    ],
326
                    [
327
                        'name'    => 'foo/bar',
328
                        'version' => '1.2.3',
329
                        'dist'  => [
330
                            'reference' => 'abc123', // version defined in the dist, this time
331
                        ],
332
                    ],
333
                    [
334
                        'name'    => 'baz/tab',
335
                        'version' => '4.5.6', // source missing
336
                    ],
337
                ],
338
            ]);
339
340
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
341
342
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
343
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
344
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
345
        $this->composer->expects(self::any())->method('getPackage')->willReturn($this->getRootPackageMock());
346
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
347
348
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
349
350
        Installer::dumpVersionsClass(new Event(
351
            'post-install-cmd',
352
            $this->composer,
353
            $this->io
354
        ));
355
356
        $expectedSource = <<<'PHP'
357
<?php
358
359
namespace PackageVersions;
360
361
/**
362
 * This class is generated by ocramius/package-versions, specifically by
363
 * @see \PackageVersions\Installer
364
 *
365
 * This file is overwritten at every run of `composer install` or `composer update`.
366
 */
367
final class Versions
368
{
369
    const VERSIONS = array (
370
  'ocramius/package-versions' => '1.0.0@',
371
  'foo/bar' => '1.2.3@abc123',
372
  'baz/tab' => '4.5.6@',
373
  'root/package' => '1.3.5@aaabbbcccddd',
374
);
375
376
    private function __construct()
377
    {
378
    }
379
380
    /**
381
     * @throws \OutOfBoundsException if a version cannot be located
382
     */
383
    public static function getVersion(string $packageName) : string
384
    {
385
        if (! isset(self::VERSIONS[$packageName])) {
386
            throw new \OutOfBoundsException(
387
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
388
            );
389
        }
390
391
        return self::VERSIONS[$packageName];
392
    }
393
}
394
395
PHP;
396
397
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
398
399
        $this->rmDir($vendorDir);
400
    }
401
402
    /**
403
     * @dataProvider rootPackageProvider
404
     *
405
     * @param RootPackageInterface $rootPackage
406
     * @param bool                 $inVendor
407
     *
408
     * @throws \RuntimeException
409
     */
410
    public function testDumpsVersionsClassToSpecificLocation(RootPackageInterface $rootPackage, bool $inVendor)
411
    {
412
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
413
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
414
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
415
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
416
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
417
418
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/vendor';
419
420
        /** @noinspection MkdirRaceConditionInspection */
421
        mkdir($vendorDir, 0777, true);
422
423
        /** @noinspection RealpathInSteamContextInspection */
424
        $expectedPath      = $inVendor
425
            ? $vendorDir . '/ocramius/package-versions/src/PackageVersions'
426
            : realpath($vendorDir . '/..') . '/src/PackageVersions';
427
428
        /** @noinspection MkdirRaceConditionInspection */
429
        mkdir($expectedPath, 0777, true);
430
431
        $locker
432
            ->expects(self::any())
433
            ->method('getLockData')
434
            ->willReturn([
435
                'packages' => [
436
                    [
437
                        'name'    => 'ocramius/package-versions',
438
                        'version' => '1.0.0',
439
                    ]
440
                ],
441
                'packages-dev' => [],
442
            ]);
443
444
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
445
446
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
447
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
448
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
449
        $this->composer->expects(self::any())->method('getPackage')->willReturn($rootPackage);
450
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
451
452
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
453
454
        Installer::dumpVersionsClass(new Event(
455
            'post-install-cmd',
456
            $this->composer,
457
            $this->io
458
        ));
459
460
        self::assertStringMatchesFormat(
461
            '%Aclass Versions%A1.2.3@%A',
462
            file_get_contents($expectedPath . '/Versions.php')
463
        );
464
465
        $this->rmDir($vendorDir);
466
    }
467
468
    /**
469
     * @return bool[][]|RootPackageInterface[][] the root package and whether the versions class is to be generated in
470
     *                                           the vendor dir or not
471
     */
472
    public function rootPackageProvider() : array
473
    {
474
        $baseRootPackage                         = new RootPackage('root/package', '1.2.3', '1.2.3');
475
        $aliasRootPackage                        = new RootAliasPackage($baseRootPackage, '1.2.3', '1.2.3');
476
        $indirectAliasRootPackage                = new RootAliasPackage($aliasRootPackage, '1.2.3', '1.2.3');
477
        $packageVersionsRootPackage              = new RootPackage('ocramius/package-versions', '1.2.3', '1.2.3');
478
        $aliasPackageVersionsRootPackage         = new RootAliasPackage($packageVersionsRootPackage, '1.2.3', '1.2.3');
479
        $indirectAliasPackageVersionsRootPackage = new RootAliasPackage(
480
            $aliasPackageVersionsRootPackage,
481
            '1.2.3',
482
            '1.2.3'
483
        );
484
485
        return [
486
            'root package is not ocramius/package-versions' => [
487
                $baseRootPackage,
488
                true
489
            ],
490
            'alias root package is not ocramius/package-versions' => [
491
                $aliasRootPackage,
492
                true
493
            ],
494
            'indirect alias root package is not ocramius/package-versions' => [
495
                $indirectAliasRootPackage,
496
                true
497
            ],
498
            'root package is ocramius/package-versions' => [
499
                $packageVersionsRootPackage,
500
                false
501
            ],
502
            'alias root package is ocramius/package-versions' => [
503
                $aliasPackageVersionsRootPackage,
504
                false
505
            ],
506
            'indirect alias root package is ocramius/package-versions' => [
507
                $indirectAliasPackageVersionsRootPackage,
508
                false
509
            ],
510
        ];
511
    }
512
513
    public function testVersionsAreNotDumpedIfPackageVersionsNotExplicitlyRequired()
514
    {
515
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
516
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
517
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
518
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
519
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
520
        $package           = $this->createMock(RootPackageInterface::class);
521
522
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
523
524
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
525
526
        /** @noinspection MkdirRaceConditionInspection */
527
        mkdir($expectedPath, 0777, true);
528
529
        $locker
530
            ->expects(self::any())
531
            ->method('getLockData')
532
            ->willReturn([
533
                 'packages' => [
534
                     [
535
                         'name'    => 'foo/bar',
536
                         'version' => '1.2.3',
537
                         'dist'  => [
538
                             'reference' => 'abc123', // version defined in the dist, this time
539
                         ],
540
                     ],
541
                     [
542
                         'name'    => 'baz/tab',
543
                         'version' => '4.5.6', // source missing
544
                     ],
545
                 ],
546
             ]);
547
548
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
549
550
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
551
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
552
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
553
        $this->composer->expects(self::any())->method('getPackage')->willReturn($package);
554
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
555
556
        $package->expects(self::any())->method('getName')->willReturn('root/package');
557
        $package->expects(self::any())->method('getVersion')->willReturn('1.3.5');
558
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
559
560
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
561
562
        Installer::dumpVersionsClass(new Event(
563
            'post-install-cmd',
564
            $this->composer,
565
            $this->io
566
        ));
567
568
        self::assertFileNotExists($expectedPath . '/Versions.php');
569
570
        $this->rmDir($vendorDir);
571
    }
572
573
    /**
574
     * @group #41
575
     * @group #46
576
     */
577
    public function testVersionsAreNotDumpedIfPackageIsScheduledForRemoval()
578
    {
579
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
580
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
581
        $package           = $this->createMock(RootPackageInterface::class);
582
        $vendorDir         = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
583
        $expectedPath      = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
584
585
        $locker
586
            ->expects(self::any())
587
            ->method('getLockData')
588
            ->willReturn([
589
                 'packages' => [
590
                     [
591
                         'name'    => 'ocramius/package-versions',
592
                         'version' => '1.0.0',
593
                     ]
594
                 ],
595
             ]);
596
597
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
598
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
599
        $this->composer->expects(self::any())->method('getPackage')->willReturn($package);
600
601
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
602
603
        Installer::dumpVersionsClass(new Event(
604
            'post-install-cmd',
605
            $this->composer,
606
            $this->io
607
        ));
608
609
        self::assertFileNotExists($expectedPath . '/Versions.php');
610
        self::assertFileNotExists($expectedPath . '/Versions.php');
611
    }
612
613
    public function testGeneratedVersionFileAccessRights()
614
    {
615
        if (0 === strpos(\PHP_OS, 'WIN')) {
616
            $this->markTestSkipped('Windows is kinda "meh" at file access levels');
617
        }
618
619
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
620
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
621
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
622
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
623
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
624
        $package           = $this->createMock(RootPackageInterface::class);
625
626
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
627
628
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
629
630
        /** @noinspection MkdirRaceConditionInspection */
631
        mkdir($expectedPath, 0777, true);
632
633
        $locker
634
            ->expects(self::any())
635
            ->method('getLockData')
636
            ->willReturn([
637
                'packages' => [
638
                    [
639
                        'name'    => 'ocramius/package-versions',
640
                        'version' => '1.0.0',
641
                    ],
642
                ],
643
            ]);
644
645
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
646
647
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
648
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
649
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
650
        $this->composer->expects(self::any())->method('getPackage')->willReturn($package);
651
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
652
653
        $package->expects(self::any())->method('getName')->willReturn('root/package');
654
        $package->expects(self::any())->method('getVersion')->willReturn('1.3.5');
655
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
656
657
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
658
659
        Installer::dumpVersionsClass(new Event(
660
            'post-install-cmd',
661
            $this->composer,
662
            $this->io
663
        ));
664
665
        $filePath = $expectedPath . '/Versions.php';
666
667
        self::assertFileExists($filePath);
668
        self::assertSame('0664', substr(sprintf('%o', fileperms($filePath)), -4));
669
670
        $this->rmDir($vendorDir);
671
    }
672
673
    /**
674
     * @param string $directory
675
     *
676
     * @return void
677
     */
678
    private function rmDir(string $directory)
679
    {
680
        if (! is_dir($directory)) {
681
            unlink($directory);
682
683
            return;
684
        }
685
686
        array_map(
687
            function ($item) use ($directory) {
688
                $this->rmDir($directory . '/' . $item);
689
            },
690
            array_filter(
691
                scandir($directory),
692
                function (string $dirItem) {
693
                    return ! in_array($dirItem, ['.', '..'], true);
694
                }
695
            )
696
        );
697
698
        rmdir($directory);
699
    }
700
701
    /**
702
     * @group composer/composer#5237
703
     */
704
    public function testWillEscapeRegexParsingOfClassDefinitions()
705
    {
706
        self::assertSame(
707
            1,
708
            preg_match_all(
709
                '{^((?:final\s+)?(?:\s*))class\s+(\S+)}mi',
710
                file_get_contents((new \ReflectionClass(Installer::class))->getFileName())
711
            )
712
        );
713
    }
714
715
    public function testGetVersionsIsNotNormalizedForRootPackage()
716
    {
717
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
718
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
719
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
720
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
721
        $repository        = $this->createMock(InstalledRepositoryInterface::class);
722
723
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
724
725
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
726
727
        /** @noinspection MkdirRaceConditionInspection */
728
        mkdir($expectedPath, 0777, true);
729
730
        $locker
731
            ->expects(self::any())
732
            ->method('getLockData')
733
            ->willReturn([
734
                'packages' => [
735
                    [
736
                        'name'    => 'ocramius/package-versions',
737
                        'version' => '1.0.0',
738
                    ],
739
                ],
740
            ]);
741
742
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
743
744
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
745
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
746
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
747
        $this->composer->expects(self::any())->method('getPackage')->willReturn($this->getRootPackageMock());
748
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
749
750
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
751
752
        Installer::dumpVersionsClass(new Event(
753
            'post-install-cmd',
754
            $this->composer,
755
            $this->io
756
        ));
757
758
        $expectedSource = <<<'PHP'
759
<?php
760
761
namespace PackageVersions;
762
763
/**
764
 * This class is generated by ocramius/package-versions, specifically by
765
 * @see \PackageVersions\Installer
766
 *
767
 * This file is overwritten at every run of `composer install` or `composer update`.
768
 */
769
final class Versions
770
{
771
    const VERSIONS = array (
772
  'ocramius/package-versions' => '1.0.0@',
773
  'root/package' => '1.3.5@aaabbbcccddd',
774
);
775
776
    private function __construct()
777
    {
778
    }
779
780
    /**
781
     * @throws \OutOfBoundsException if a version cannot be located
782
     */
783
    public static function getVersion(string $packageName) : string
784
    {
785
        if (! isset(self::VERSIONS[$packageName])) {
786
            throw new \OutOfBoundsException(
787
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
788
            );
789
        }
790
791
        return self::VERSIONS[$packageName];
792
    }
793
}
794
795
PHP;
796
797
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
798
799
        $this->rmDir($vendorDir);
800
    }
801
802
    private function getRootPackageMock(): RootPackageInterface
803
    {
804
        $package = $this->createMock(RootPackageInterface::class);
805
        $package->expects(self::any())->method('getName')->willReturn('root/package');
806
        $package->expects(self::any())->method('getPrettyVersion')->willReturn('1.3.5');
807
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
808
809
        return $package;
810
    }
811
}
812