Completed
Pull Request — master (#16)
by Marco
02:18
created

testWillEscapeRegexParsingOfClassDefinitions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 10
rs 9.4285
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\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\Installer;
18
use PHPUnit_Framework_TestCase;
19
20
/**
21
 * @covers \PackageVersions\Installer
22
 */
23
final class InstallerTest extends PHPUnit_Framework_TestCase
24
{
25
    /**
26
     * @var Composer|\PHPUnit_Framework_MockObject_MockObject
27
     */
28
    private $composer;
29
30
    /**
31
     * @var EventDispatcher|\PHPUnit_Framework_MockObject_MockObject
32
     */
33
    private $eventDispatcher;
34
35
    /**
36
     * @var IOInterface|\PHPUnit_Framework_MockObject_MockObject
37
     */
38
    private $io;
39
40
    /**
41
     * @var Installer
42
     */
43
    private $installer;
44
45
    /**
46
     * {@inheritDoc}
47
     * 
48
     * @throws \PHPUnit_Framework_Exception
49
     */
50
    protected function setUp()
51
    {
52
        parent::setUp();
53
54
        $this->installer       = new Installer();
55
        $this->io              = $this->getMock(IOInterface::class);
56
        $this->composer        = $this->getMock(Composer::class);
57
        $this->eventDispatcher = $this->getMockBuilder(EventDispatcher::class)->disableOriginalConstructor()->getMock();
58
59
        $this->composer->expects(self::any())->method('getEventDispatcher')->willReturn($this->eventDispatcher);
60
    }
61
62
    public function testActivate()
63
    {
64
        $this->eventDispatcher->expects(self::once())->method('addSubscriber')->with($this->installer);
65
66
        $this->installer->activate($this->composer, $this->io);
67
    }
68
69
    public function testGetSubscribedEvents()
70
    {
71
        $events = Installer::getSubscribedEvents();
72
73
        self::assertSame(
74
            [
75
                'post-install-cmd' => 'dumpVersionsClass',
76
                'post-update-cmd'  => 'dumpVersionsClass',
77
            ],
78
            $events
79
        );
80
81
        foreach ($events as $callback) {
82
            self::assertInternalType('callable', [$this->installer, $callback]);
83
        }
84
    }
85
86
    public function testDumpVersionsClass()
87
    {
88
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
89
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
90
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
91
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
92
        $repository        = $this->getMock(InstalledRepositoryInterface::class);
93
        $package           = $this->getMock(RootPackageInterface::class);
94
95
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
96
97
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
98
99
        mkdir($expectedPath, 0777, true);
100
101
        $locker
102
            ->expects(self::any())
103
            ->method('getLockData')
104
            ->willReturn([
105
                'packages' => [
106
                    [
107
                        'name'    => 'foo/bar',
108
                        'version' => '1.2.3',
109
                        'source'  => [
110
                            'reference' => 'abc123',
111
                        ],
112
                    ],
113
                    [
114
                        'name'    => 'baz/tab',
115
                        'version' => '4.5.6',
116
                        'source'  => [
117
                            'reference' => 'def456',
118
                        ],
119
                    ],
120
                ],
121
                'packages-dev' => [
122
                    [
123
                        'name'    => 'tar/taz',
124
                        'version' => '7.8.9',
125
                        'source'  => [
126
                            'reference' => 'ghi789',
127
                        ],
128
                    ]
129
                ],
130
            ]);
131
132
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
133
134
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
135
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
136
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
137
        $this->composer->expects(self::any())->method('getPackage')->willReturn($package);
138
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
139
140
        $package->expects(self::any())->method('getName')->willReturn('root/package');
141
        $package->expects(self::any())->method('getVersion')->willReturn('1.3.5');
142
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
143
144
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
145
146
        Installer::dumpVersionsClass(new Event(
147
            'post-install-cmd',
148
            $this->composer,
149
            $this->io
150
        ));
151
152
        $expectedSource = <<<'PHP'
153
<?php
154
155
namespace PackageVersions;
156
157
/**
158
 * This class is generated by ocramius/package-versions, specifically by
159
 * @see \PackageVersions\Installer
160
 *
161
 * This file is overwritten at every run of `composer install` or `composer update`.
162
 */
163
final class Versions
164
{
165
    const VERSIONS = array (
166
  'foo/bar' => '1.2.3@abc123',
167
  'baz/tab' => '4.5.6@def456',
168
  'tar/taz' => '7.8.9@ghi789',
169
  'root/package' => '1.3.5@aaabbbcccddd',
170
);
171
172
    private function __construct()
173
    {
174
    }
175
176
    /**
177
     * @throws \OutOfBoundsException if a version cannot be located
178
     */
179
    public static function getVersion(string $packageName) : string
180
    {
181
        if (! isset(self::VERSIONS[$packageName])) {
182
            throw new \OutOfBoundsException(
183
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
184
            );
185
        }
186
187
        return self::VERSIONS[$packageName];
188
    }
189
}
190
191
PHP;
192
193
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
194
195
        $this->rmDir($vendorDir);
196
    }
197
198
    public function testDumpVersionsClassNoDev()
199
    {
200
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
201
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
202
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
203
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
204
        $repository        = $this->getMock(InstalledRepositoryInterface::class);
205
        $package           = $this->getMock(RootPackageInterface::class);
206
207
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
208
209
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
210
211
        mkdir($expectedPath, 0777, true);
212
213
        $locker
214
            ->expects(self::any())
215
            ->method('getLockData')
216
            ->willReturn([
217
                'packages' => [
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($package);
241
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
242
243
        $package->expects(self::any())->method('getName')->willReturn('root/package');
244
        $package->expects(self::any())->method('getVersion')->willReturn('1.3.5');
245
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
246
247
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
248
249
        Installer::dumpVersionsClass(new Event(
250
            'post-install-cmd',
251
            $this->composer,
252
            $this->io
253
        ));
254
255
        $expectedSource = <<<'PHP'
256
<?php
257
258
namespace PackageVersions;
259
260
/**
261
 * This class is generated by ocramius/package-versions, specifically by
262
 * @see \PackageVersions\Installer
263
 *
264
 * This file is overwritten at every run of `composer install` or `composer update`.
265
 */
266
final class Versions
267
{
268
    const VERSIONS = array (
269
  'foo/bar' => '1.2.3@abc123',
270
  'baz/tab' => '4.5.6@def456',
271
  'root/package' => '1.3.5@aaabbbcccddd',
272
);
273
274
    private function __construct()
275
    {
276
    }
277
278
    /**
279
     * @throws \OutOfBoundsException if a version cannot be located
280
     */
281
    public static function getVersion(string $packageName) : string
282
    {
283
        if (! isset(self::VERSIONS[$packageName])) {
284
            throw new \OutOfBoundsException(
285
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
286
            );
287
        }
288
289
        return self::VERSIONS[$packageName];
290
    }
291
}
292
293
PHP;
294
295
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
296
297
        $this->rmDir($vendorDir);
298
    }
299
300
    /**
301
     * @group #12
302
     * 
303
     * @throws \RuntimeException
304
     */
305
    public function testDumpVersionsWithoutPackageSourceDetails()
306
    {
307
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
308
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
309
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
310
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
311
        $repository        = $this->getMock(InstalledRepositoryInterface::class);
312
        $package           = $this->getMock(RootPackageInterface::class);
313
314
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true);
315
316
        $expectedPath = $vendorDir . '/ocramius/package-versions/src/PackageVersions';
317
318
        mkdir($expectedPath, 0777, true);
319
320
        $locker
321
            ->expects(self::any())
322
            ->method('getLockData')
323
            ->willReturn([
324
                'packages' => [
325
                    [
326
                        'name'    => 'foo/bar',
327
                        'version' => '1.2.3',
328
                        'dist'  => [
329
                            'reference' => 'abc123', // version defined in the dist, this time
330
                        ],
331
                    ],
332
                    [
333
                        'name'    => 'baz/tab',
334
                        'version' => '4.5.6', // source missing
335
                    ],
336
                ],
337
            ]);
338
339
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
340
341
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
342
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
343
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
344
        $this->composer->expects(self::any())->method('getPackage')->willReturn($package);
345
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
346
347
        $package->expects(self::any())->method('getName')->willReturn('root/package');
348
        $package->expects(self::any())->method('getVersion')->willReturn('1.3.5');
349
        $package->expects(self::any())->method('getSourceReference')->willReturn('aaabbbcccddd');
350
351
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
352
353
        Installer::dumpVersionsClass(new Event(
354
            'post-install-cmd',
355
            $this->composer,
356
            $this->io
357
        ));
358
359
        $expectedSource = <<<'PHP'
360
<?php
361
362
namespace PackageVersions;
363
364
/**
365
 * This class is generated by ocramius/package-versions, specifically by
366
 * @see \PackageVersions\Installer
367
 *
368
 * This file is overwritten at every run of `composer install` or `composer update`.
369
 */
370
final class Versions
371
{
372
    const VERSIONS = array (
373
  'foo/bar' => '1.2.3@abc123',
374
  'baz/tab' => '4.5.6@',
375
  'root/package' => '1.3.5@aaabbbcccddd',
376
);
377
378
    private function __construct()
379
    {
380
    }
381
382
    /**
383
     * @throws \OutOfBoundsException if a version cannot be located
384
     */
385
    public static function getVersion(string $packageName) : string
386
    {
387
        if (! isset(self::VERSIONS[$packageName])) {
388
            throw new \OutOfBoundsException(
389
                'Required package "' . $packageName . '" is not installed: cannot detect its version'
390
            );
391
        }
392
393
        return self::VERSIONS[$packageName];
394
    }
395
}
396
397
PHP;
398
399
        self::assertSame($expectedSource, file_get_contents($expectedPath . '/Versions.php'));
400
401
        $this->rmDir($vendorDir);
402
    }
403
404
    /**
405
     * @dataProvider rootPackageProvider
406
     *
407
     * @param RootPackageInterface $rootPackage
408
     * @param bool                 $inVendor
409
     *
410
     * @throws \RuntimeException
411
     */
412
    public function testDumpsVersionsClassToSpecificLocation(RootPackageInterface $rootPackage, bool $inVendor)
413
    {
414
        $config            = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock();
415
        $locker            = $this->getMockBuilder(Locker::class)->disableOriginalConstructor()->getMock();
416
        $repositoryManager = $this->getMockBuilder(RepositoryManager::class)->disableOriginalConstructor()->getMock();
417
        $installManager    = $this->getMockBuilder(InstallationManager::class)->disableOriginalConstructor()->getMock();
418
        $repository        = $this->getMock(InstalledRepositoryInterface::class);
419
420
        $vendorDir = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/vendor';
421
422
        mkdir($vendorDir, 0777, true);
423
424
        $expectedPath = $inVendor
425
            ? $vendorDir . '/ocramius/package-versions/src/PackageVersions'
426
            : realpath($vendorDir . '/..') . '/src/PackageVersions';
427
428
        mkdir($expectedPath, 0777, true);
429
430
        $locker
431
            ->expects(self::any())
432
            ->method('getLockData')
433
            ->willReturn([
434
                'packages' => [],
435
                'packages-dev' => [],
436
            ]);
437
438
        $repositoryManager->expects(self::any())->method('getLocalRepository')->willReturn($repository);
439
440
        $this->composer->expects(self::any())->method('getConfig')->willReturn($config);
441
        $this->composer->expects(self::any())->method('getLocker')->willReturn($locker);
442
        $this->composer->expects(self::any())->method('getRepositoryManager')->willReturn($repositoryManager);
443
        $this->composer->expects(self::any())->method('getPackage')->willReturn($rootPackage);
444
        $this->composer->expects(self::any())->method('getInstallationManager')->willReturn($installManager);
445
446
        $config->expects(self::any())->method('get')->with('vendor-dir')->willReturn($vendorDir);
447
448
        Installer::dumpVersionsClass(new Event(
449
            'post-install-cmd',
450
            $this->composer,
451
            $this->io
452
        ));
453
454
        self::assertStringMatchesFormat(
455
            '%Aclass Versions%A1.2.3@%A',
456
            file_get_contents($expectedPath . '/Versions.php')
457
        );
458
459
        $this->rmDir($vendorDir);
460
    }
461
462
    /**
463
     * @return bool[][]|RootPackageInterface[][] the root package and whether the versions class is to be generated in
464
     *                                           the vendor dir or not
465
     */
466
    public function rootPackageProvider() : array
467
    {
468
        $baseRootPackage                         = new RootPackage('root/package', '1.2.3', '1.2.3');
469
        $aliasRootPackage                        = new RootAliasPackage($baseRootPackage, '1.2.3', '1.2.3');
470
        $indirectAliasRootPackage                = new RootAliasPackage($aliasRootPackage, '1.2.3', '1.2.3');
471
        $packageVersionsRootPackage              = new RootPackage('ocramius/package-versions', '1.2.3', '1.2.3');
472
        $aliasPackageVersionsRootPackage         = new RootAliasPackage($packageVersionsRootPackage, '1.2.3', '1.2.3');
473
        $indirectAliasPackageVersionsRootPackage = new RootAliasPackage(
474
            $aliasPackageVersionsRootPackage,
475
            '1.2.3',
476
            '1.2.3'
477
        );
478
479
        return [
480
            'root package is not ocramius/package-versions' => [
481
                $baseRootPackage,
482
                true
483
            ],
484
            'alias root package is not ocramius/package-versions' => [
485
                $aliasRootPackage,
486
                true
487
            ],
488
            'indirect alias root package is not ocramius/package-versions' => [
489
                $indirectAliasRootPackage,
490
                true
491
            ],
492
            'root package is ocramius/package-versions' => [
493
                $packageVersionsRootPackage,
494
                false
495
            ],
496
            'alias root package is ocramius/package-versions' => [
497
                $aliasPackageVersionsRootPackage,
498
                false
499
            ],
500
            'indirect alias root package is ocramius/package-versions' => [
501
                $indirectAliasPackageVersionsRootPackage,
502
                false
503
            ],
504
        ];
505
    }
506
507
    /**
508
     * @param string $directory
509
     *
510
     * @return void
511
     */
512
    private function rmDir(string $directory)
513
    {
514
        if (! is_dir($directory)) {
515
            unlink($directory);
516
517
            return;
518
        }
519
520
        array_map(
521
            function ($item) use ($directory) {
522
                $this->rmDir($directory . '/' . $item);
523
            },
524
            array_filter(
525
                scandir($directory),
526
                function (string $dirItem) {
527
                    return ! in_array($dirItem, ['.', '..'], true);
528
                }
529
            )
530
        );
531
    }
532
533
    /**
534
     * @group composer/composer#5237
535
     */
536
    public function testWillEscapeRegexParsingOfClassDefinitions()
537
    {
538
        self::assertSame(
539
            1,
540
            preg_match_all(
541
                '{^((?:final\s+)?(?:\s*))class\s+(\S+)}mi',
542
                file_get_contents((new \ReflectionClass(Installer::class))->getFileName())
543
            )
544
        );
545
    }
546
}
547