Completed
Pull Request — master (#26)
by Stepan
05:53
created

InstallerTest::testHasCommandProviderCapability()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
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\RootAliasPackage;
12
use Composer\Package\RootPackage;
13
use Composer\Package\RootPackageInterface;
14
use Composer\Repository\InstalledRepositoryInterface;
15
use Composer\Repository\RepositoryManager;
16
use Composer\Script\Event;
17
use PackageVersions\CommandProvider;
18
use PackageVersions\Installer;
19
use PHPUnit_Framework_TestCase;
20
21
/**
22
 * @covers \PackageVersions\Installer
23
 */
24
final class InstallerTest extends PHPUnit_Framework_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->getMock(IOInterface::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::getMock() has been deprecated with message: Method deprecated since Release 5.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
57
        $this->composer        = $this->getMock(Composer::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::getMock() has been deprecated with message: Method deprecated since Release 5.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
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 testActivate()
64
    {
65
        $this->eventDispatcher->expects(self::once())->method('addSubscriber')->with($this->installer);
66
67
        $this->installer->activate($this->composer, $this->io);
68
    }
69
70
    public function testGetSubscribedEvents()
71
    {
72
        $events = Installer::getSubscribedEvents();
73
74
        self::assertSame(
75
            [
76
                'post-install-cmd' => 'dumpVersionsClass',
77
                'post-update-cmd'  => 'dumpVersionsClass',
78
            ],
79
            $events
80
        );
81
82
        foreach ($events as $callback) {
83
            self::assertInternalType('callable', [$this->installer, $callback]);
84
        }
85
    }
86
87
    public function testDumpVersionsClass()
88
    {
89
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
90
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
91
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
92
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
93
        $repository        = $this->getMock(InstalledRepositoryInterface::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::getMock() has been deprecated with message: Method deprecated since Release 5.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
94
        $package           = $this->getMock(RootPackageInterface::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::getMock() has been deprecated with message: Method deprecated since Release 5.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
95
96
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
97
98
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
99
100
        mkdir($expectedPath, 0777, true);
101
102
        $locker
103
            ->expects(self::any())
104
            ->method('getLockData')
105
            ->willReturn([
106
                'packages' => [
107
                    [
108
                        'name'    => 'foo/bar',
109
                        'version' => '1.2.3',
110
                        'source'  => [
111
                            'reference' => 'abc123',
112
                        ],
113
                    ],
114
                    [
115
                        'name'    => 'baz/tab',
116
                        'version' => '4.5.6',
117
                        'source'  => [
118
                            'reference' => 'def456',
119
                        ],
120
                    ],
121
                ],
122
                'packages-dev' => [
123
                    [
124
                        'name'    => 'tar/taz',
125
                        'version' => '7.8.9',
126
                        'source'  => [
127
                            'reference' => 'ghi789',
128
                        ],
129
                    ]
130
                ],
131
            ]);
132
133
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
134
135
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
136
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
137
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
138
        $this->composer->expects(self::any())->method('getPackage')->willReturn($package);
139
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
140
141
        $package->expects(self::any())->method('getName')->willReturn('root/package');
142
        $package->expects(self::any())->method('getVersion')->willReturn('1.3.5');
143
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
144
145
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
146
147
        Installer::dumpVersionsClass(new Event(
148
            'post-install-cmd',
149
            $this->composer,
150
            $this->io
151
        ));
152
153
        $expectedSource = <<<'PHP'
154
<?php
155
156
namespace PackageVersions;
157
158
/**
159
 * This class is generated by ocramius/package-versions, specifically by
160
 * @see \PackageVersions\Installer
161
 *
162
 * This file is overwritten at every run of `composer install` or `composer update`.
163
 */
164
final class Versions
165
{
166
    const VERSIONS = array (
167
  'foo/bar' => '1.2.3@abc123',
168
  'baz/tab' => '4.5.6@def456',
169
  'tar/taz' => '7.8.9@ghi789',
170
  'root/package' => '1.3.5@aaabbbcccddd',
171
);
172
173
    private function __construct()
174
    {
175
    }
176
177
    /**
178
     * @throws \OutOfBoundsException if a version cannot be located
179
     */
180
    public static function getVersion(string $packageName) : string
181
    {
182
        if (! isset(self::VERSIONS[$packageName])) {
183
            throw new \OutOfBoundsException(
184
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
185
            );
186
        }
187
188
        return self::VERSIONS[$packageName];
189
    }
190
}
191
192
PHP;
193
194
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
195
196
        $this->rmDir($vendorDir);
197
    }
198
199
    public function testDumpVersionsClassNoDev()
200
    {
201
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
202
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
203
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
204
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
205
        $repository        = $this->getMock(InstalledRepositoryInterface::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::getMock() has been deprecated with message: Method deprecated since Release 5.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
206
        $package           = $this->getMock(RootPackageInterface::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::getMock() has been deprecated with message: Method deprecated since Release 5.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
207
208
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
209
210
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
211
212
        mkdir($expectedPath, 0777, true);
213
214
        $locker
215
            ->expects(self::any())
216
            ->method('getLockData')
217
            ->willReturn([
218
                'packages' => [
219
                    [
220
                        'name'    => 'foo/bar',
221
                        'version' => '1.2.3',
222
                        'source'  => [
223
                            'reference' => 'abc123',
224
                        ],
225
                    ],
226
                    [
227
                        'name'    => 'baz/tab',
228
                        'version' => '4.5.6',
229
                        'source'  => [
230
                            'reference' => 'def456',
231
                        ],
232
                    ],
233
                ],
234
            ]);
235
236
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
237
238
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
239
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
240
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
241
        $this->composer->expects(self::any())->method('getPackage')->willReturn($package);
242
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
243
244
        $package->expects(self::any())->method('getName')->willReturn('root/package');
245
        $package->expects(self::any())->method('getVersion')->willReturn('1.3.5');
246
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
247
248
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
249
250
        Installer::dumpVersionsClass(new Event(
251
            'post-install-cmd',
252
            $this->composer,
253
            $this->io
254
        ));
255
256
        $expectedSource = <<<'PHP'
257
<?php
258
259
namespace PackageVersions;
260
261
/**
262
 * This class is generated by ocramius/package-versions, specifically by
263
 * @see \PackageVersions\Installer
264
 *
265
 * This file is overwritten at every run of `composer install` or `composer update`.
266
 */
267
final class Versions
268
{
269
    const VERSIONS = array (
270
  'foo/bar' => '1.2.3@abc123',
271
  'baz/tab' => '4.5.6@def456',
272
  'root/package' => '1.3.5@aaabbbcccddd',
273
);
274
275
    private function __construct()
276
    {
277
    }
278
279
    /**
280
     * @throws \OutOfBoundsException if a version cannot be located
281
     */
282
    public static function getVersion(string $packageName) : string
283
    {
284
        if (! isset(self::VERSIONS[$packageName])) {
285
            throw new \OutOfBoundsException(
286
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
287
            );
288
        }
289
290
        return self::VERSIONS[$packageName];
291
    }
292
}
293
294
PHP;
295
296
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
297
298
        $this->rmDir($vendorDir);
299
    }
300
301
    /**
302
     * @group #12
303
     * 
304
     * @throws \RuntimeException
305
     */
306
    public function testDumpVersionsWithoutPackageSourceDetails()
307
    {
308
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
309
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
310
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
311
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
312
        $repository        = $this->getMock(InstalledRepositoryInterface::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::getMock() has been deprecated with message: Method deprecated since Release 5.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
313
        $package           = $this->getMock(RootPackageInterface::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::getMock() has been deprecated with message: Method deprecated since Release 5.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
314
315
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
316
317
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
318
319
        mkdir($expectedPath, 0777, true);
320
321
        $locker
322
            ->expects(self::any())
323
            ->method('getLockData')
324
            ->willReturn([
325
                'packages' => [
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($package);
346
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
347
348
        $package->expects(self::any())->method('getName')->willReturn('root/package');
349
        $package->expects(self::any())->method('getVersion')->willReturn('1.3.5');
350
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
351
352
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
353
354
        Installer::dumpVersionsClass(new Event(
355
            'post-install-cmd',
356
            $this->composer,
357
            $this->io
358
        ));
359
360
        $expectedSource = <<<'PHP'
361
<?php
362
363
namespace PackageVersions;
364
365
/**
366
 * This class is generated by ocramius/package-versions, specifically by
367
 * @see \PackageVersions\Installer
368
 *
369
 * This file is overwritten at every run of `composer install` or `composer update`.
370
 */
371
final class Versions
372
{
373
    const VERSIONS = array (
374
  'foo/bar' => '1.2.3@abc123',
375
  'baz/tab' => '4.5.6@',
376
  'root/package' => '1.3.5@aaabbbcccddd',
377
);
378
379
    private function __construct()
380
    {
381
    }
382
383
    /**
384
     * @throws \OutOfBoundsException if a version cannot be located
385
     */
386
    public static function getVersion(string $packageName) : string
387
    {
388
        if (! isset(self::VERSIONS[$packageName])) {
389
            throw new \OutOfBoundsException(
390
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
391
            );
392
        }
393
394
        return self::VERSIONS[$packageName];
395
    }
396
}
397
398
PHP;
399
400
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
401
402
        $this->rmDir($vendorDir);
403
    }
404
405
    /**
406
     * @dataProvider rootPackageProvider
407
     *
408
     * @param RootPackageInterface $rootPackage
409
     * @param bool                 $inVendor
410
     *
411
     * @throws \RuntimeException
412
     */
413
    public function testDumpsVersionsClassToSpecificLocation(RootPackageInterface $rootPackage, bool $inVendor)
414
    {
415
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
416
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
417
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
418
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
419
        $repository        = $this->getMock(InstalledRepositoryInterface::class);
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::getMock() has been deprecated with message: Method deprecated since Release 5.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
420
421
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/vendor';
422
423
        mkdir($vendorDir, 0777, true);
424
425
        $expectedPath = $inVendor
426
            ? $vendorDir . '/ocramius/package-versions/src/PackageVersions'
427
            : realpath($vendorDir . '/..') . '/src/PackageVersions';
428
429
        mkdir($expectedPath, 0777, true);
430
431
        $locker
432
            ->expects(self::any())
433
            ->method('getLockData')
434
            ->willReturn([
435
                'packages' => [],
436
                'packages-dev' => [],
437
            ]);
438
439
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
440
441
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
442
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
443
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
444
        $this->composer->expects(self::any())->method('getPackage')->willReturn($rootPackage);
445
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
446
447
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
448
449
        Installer::dumpVersionsClass(new Event(
450
            'post-install-cmd',
451
            $this->composer,
452
            $this->io
453
        ));
454
455
        self::assertStringMatchesFormat(
456
            '%Aclass Versions%A1.2.3@%A',
457
            file_get_contents($expectedPath . '/Versions.php')
458
        );
459
460
        $this->rmDir($vendorDir);
461
    }
462
463
    /**
464
     * @return bool[][]|RootPackageInterface[][] the root package and whether the versions class is to be generated in
465
     *                                           the vendor dir or not
466
     */
467
    public function rootPackageProvider() : array
468
    {
469
        $baseRootPackage                         = new RootPackage('root/package', '1.2.3', '1.2.3');
470
        $aliasRootPackage                        = new RootAliasPackage($baseRootPackage, '1.2.3', '1.2.3');
471
        $indirectAliasRootPackage                = new RootAliasPackage($aliasRootPackage, '1.2.3', '1.2.3');
472
        $packageVersionsRootPackage              = new RootPackage('ocramius/package-versions', '1.2.3', '1.2.3');
473
        $aliasPackageVersionsRootPackage         = new RootAliasPackage($packageVersionsRootPackage, '1.2.3', '1.2.3');
474
        $indirectAliasPackageVersionsRootPackage = new RootAliasPackage(
475
            $aliasPackageVersionsRootPackage,
476
            '1.2.3',
477
            '1.2.3'
478
        );
479
480
        return [
481
            'root package is not ocramius/package-versions' => [
482
                $baseRootPackage,
483
                true
484
            ],
485
            'alias root package is not ocramius/package-versions' => [
486
                $aliasRootPackage,
487
                true
488
            ],
489
            'indirect alias root package is not ocramius/package-versions' => [
490
                $indirectAliasRootPackage,
491
                true
492
            ],
493
            'root package is ocramius/package-versions' => [
494
                $packageVersionsRootPackage,
495
                false
496
            ],
497
            'alias root package is ocramius/package-versions' => [
498
                $aliasPackageVersionsRootPackage,
499
                false
500
            ],
501
            'indirect alias root package is ocramius/package-versions' => [
502
                $indirectAliasPackageVersionsRootPackage,
503
                false
504
            ],
505
        ];
506
    }
507
508
    /**
509
     * @param string $directory
510
     *
511
     * @return void
512
     */
513
    private function rmDir(string $directory)
514
    {
515
        if (! is_dir($directory)) {
516
            unlink($directory);
517
518
            return;
519
        }
520
521
        array_map(
522
            function ($item) use ($directory) {
523
                $this->rmDir($directory . '/' . $item);
524
            },
525
            array_filter(
526
                scandir($directory),
527
                function (string $dirItem) {
528
                    return ! in_array($dirItem, ['.', '..'], true);
529
                }
530
            )
531
        );
532
    }
533
534
    /**
535
     * @group composer/composer#5237
536
     */
537
    public function testWillEscapeRegexParsingOfClassDefinitions()
538
    {
539
        self::assertSame(
540
            1,
541
            preg_match_all(
542
                '{^((?:final\s+)?(?:\s*))class\s+(\S+)}mi',
543
                file_get_contents((new \ReflectionClass(Installer::class))->getFileName())
544
            )
545
        );
546
    }
547
548
    public function testHasCommandProviderCapability()
549
    {
550
        $installer = new Installer();
551
552
        static::assertContains(CommandProvider::class, $installer->getCapabilities());
553
    }
554
}
555