Passed
Pull Request — master (#117)
by Pavel
01:41
created

testInstallingPluginWithNoScriptsOverridesOriginalRequirements()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 52
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 30
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 52
rs 9.44

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace PackageVersionsTest;
6
7
use PHPUnit\Framework\TestCase;
8
use RecursiveCallbackFilterIterator;
9
use RecursiveDirectoryIterator;
10
use RecursiveIteratorIterator;
11
use SplFileInfo;
12
use ZipArchive;
13
use function array_filter;
14
use function array_map;
15
use function array_walk;
16
use function chdir;
17
use function escapeshellarg;
18
use function exec;
19
use function file_get_contents;
20
use function file_put_contents;
21
use function getcwd;
22
use function in_array;
23
use function is_dir;
24
use function iterator_to_array;
25
use function json_decode;
26
use function json_encode;
27
use function mkdir;
28
use function putenv;
29
use function realpath;
30
use function rmdir;
31
use function scandir;
32
use function strlen;
33
use function substr;
34
use function sys_get_temp_dir;
35
use function uniqid;
36
use function unlink;
37
use const JSON_PRETTY_PRINT;
38
use const JSON_UNESCAPED_SLASHES;
39
use const PHP_BINARY;
40
41
/**
42
 * @coversNothing
43
 */
44
class E2EInstallerTest extends TestCase
45
{
46
    private string $tempGlobalComposerHome;
47
48
    private string $tempLocalComposerHome;
49
50
    private string $tempArtifact;
51
52
    public function setUp() : void
53
    {
54
        $this->tempGlobalComposerHome = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/global';
55
        $this->tempLocalComposerHome  = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/local';
56
        $this->tempArtifact           = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/artifacts';
57
        mkdir($this->tempGlobalComposerHome, 0700, true);
58
        mkdir($this->tempLocalComposerHome, 0700, true);
59
        mkdir($this->tempArtifact, 0700, true);
60
61
        putenv('COMPOSER_HOME=' . $this->tempGlobalComposerHome);
62
    }
63
64
    public function tearDown() : void
65
    {
66
        $this->rmDir($this->tempGlobalComposerHome);
67
        $this->rmDir($this->tempLocalComposerHome);
68
        $this->rmDir($this->tempArtifact);
69
70
        putenv('COMPOSER_HOME');
71
    }
72
73
    public function testGloballyInstalledPluginDoesNotGenerateVersionsForLocalProject() : void
74
    {
75
        $this->createPackageVersionsArtifact();
76
77
        $this->writeComposerJsonFile(
78
            [
79
                'name'         => 'package-versions/e2e-global',
80
                'require'      => ['ocramius/package-versions' => '1.0.0'],
81
                'repositories' => [
82
                    ['packagist' => false],
83
                    [
84
                        'type' => 'artifact',
85
                        'url' => $this->tempArtifact,
86
                    ],
87
                ],
88
            ],
89
            $this->tempGlobalComposerHome
90
        );
91
92
        $this->execComposerInDir('global update', $this->tempGlobalComposerHome);
93
94
        $this->createArtifact();
95
        $this->writeComposerJsonFile(
96
            [
97
                'name'         => 'package-versions/e2e-local',
98
                'require'      => ['test/package' => '2.0.0'],
99
                'repositories' => [
100
                    ['packagist' => false],
101
                    [
102
                        'type' => 'artifact',
103
                        'url' => $this->tempArtifact,
104
                    ],
105
                ],
106
            ],
107
            $this->tempLocalComposerHome
108
        );
109
110
        $this->execComposerInDir('update', $this->tempLocalComposerHome);
111
        $this->assertFileNotExists(
112
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
113
        );
114
    }
115
116
    public function testRemovingPluginDoesNotAttemptToGenerateVersions() : void
117
    {
118
        $this->createPackageVersionsArtifact();
119
        $this->createArtifact();
120
121
        $this->writeComposerJsonFile(
122
            [
123
                'name'         => 'package-versions/e2e-local',
124
                'require'      => [
125
                    'test/package' => '2.0.0',
126
                    'ocramius/package-versions' => '1.0.0',
127
                ],
128
                'repositories' => [
129
                    ['packagist' => false],
130
                    [
131
                        'type' => 'artifact',
132
                        'url' => $this->tempArtifact,
133
                    ],
134
                ],
135
            ],
136
            $this->tempLocalComposerHome
137
        );
138
139
        $this->execComposerInDir('update', $this->tempLocalComposerHome);
140
        $this->assertFileExists(
141
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
142
        );
143
144
        $this->execComposerInDir('remove ocramius/package-versions', $this->tempLocalComposerHome);
145
146
        $this->assertFileNotExists(
147
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
148
        );
149
    }
150
151
    /**
152
     * @group #41
153
     * @group #46
154
     */
155
    public function testRemovingPluginWithNoDevDoesNotAttemptToGenerateVersions() : void
156
    {
157
        $this->createPackageVersionsArtifact();
158
        $this->createArtifact();
159
160
        $this->writeComposerJsonFile(
161
            [
162
                'name'         => 'package-versions/e2e-local',
163
                'require-dev'      => ['ocramius/package-versions' => '1.0.0'],
164
                'repositories' => [
165
                    ['packagist' => false],
166
                    [
167
                        'type' => 'artifact',
168
                        'url' => $this->tempArtifact,
169
                    ],
170
                ],
171
            ],
172
            $this->tempLocalComposerHome
173
        );
174
175
        $this->execComposerInDir('update', $this->tempLocalComposerHome);
176
        $this->assertFileExists(
177
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
178
        );
179
180
        $this->execComposerInDir('install --no-dev', $this->tempLocalComposerHome);
181
182
        $this->assertFileNotExists(
183
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
184
        );
185
    }
186
187
    public function testInstallingPluginWithNoScriptsOverridesOriginalRequirements() : void
188
    {
189
        $this->createPackageVersionsArtifact();
190
        $this->createGenericArtifact(
191
            'infection-infection',
192
            '0.15.0',
193
            [
194
                'name' => 'infection/infection',
195
                'require' => [
196
                    'symfony/process' => '^5.0',
197
                ],
198
            ]
199
        );
200
        $this->createGenericArtifact(
201
            'symfony-process',
202
            '4.0.0',
203
            [
204
                'name' => 'symfony/process',
205
            ]
206
        );
207
        $this->createGenericArtifact(
208
            'symfony-process',
209
            '5.0.0',
210
            [
211
                'name' => 'symfony/process',
212
            ]
213
        );
214
        $this->writeComposerJsonFile(
215
            [
216
                'name'         => 'package-versions/e2e-transitive',
217
                'require'      => [
218
                    'ocramius/package-versions' => '1.0.0',
219
                    'infection/infection' => '^0.15.0',
220
                ],
221
                'repositories' => [
222
                    ['packagist' => false],
223
                    [
224
                        'type' => 'artifact',
225
                        'url' => $this->tempArtifact,
226
                    ],
227
                ],
228
            ],
229
            $this->tempLocalComposerHome
230
        );
231
232
        $this->execComposerInDir('install --no-scripts', $this->tempLocalComposerHome);
233
        $this->assertFileExists(
234
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
235
        );
236
237
        $this->writeSymfonyPackageVersionUsingFile($this->tempLocalComposerHome);
238
        $this->assertSymfonyPackageVersionsIsUsable($this->tempLocalComposerHome);
239
    }
240
241
    /**
242
     * @group 101
243
     */
244
    public function testInstallingPluginWithNoScriptsLeadsToUsableVersionsClass() : void
245
    {
246
        $this->createPackageVersionsArtifact();
247
        $this->createArtifact();
248
249
        $this->writeComposerJsonFile(
250
            [
251
                'name'         => 'package-versions/e2e-local',
252
                'require'      => ['ocramius/package-versions' => '1.0.0'],
253
                'repositories' => [
254
                    ['packagist' => false],
255
                    [
256
                        'type' => 'artifact',
257
                        'url' => $this->tempArtifact,
258
                    ],
259
                ],
260
            ],
261
            $this->tempLocalComposerHome
262
        );
263
264
        $this->execComposerInDir('install --no-scripts', $this->tempLocalComposerHome);
265
        $this->assertFileExists(
266
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
267
        );
268
269
        $this->writePackageVersionUsingFile($this->tempLocalComposerHome);
270
        $this->assertPackageVersionsIsUsable($this->tempLocalComposerHome);
271
    }
272
273
    private function createPackageVersionsArtifact() : void
274
    {
275
        $zip = new ZipArchive();
276
277
        $zip->open($this->tempArtifact . '/ocramius-package-versions-1.0.0.zip', ZipArchive::CREATE);
278
279
        $files = array_filter(
280
            iterator_to_array(new RecursiveIteratorIterator(
281
                new RecursiveCallbackFilterIterator(
282
                    new RecursiveDirectoryIterator(realpath(__DIR__ . '/../../'), RecursiveDirectoryIterator::SKIP_DOTS),
283
                    static function (SplFileInfo $file, string $key, RecursiveDirectoryIterator $iterator) {
0 ignored issues
show
Bug introduced by
function(...) { /* ... */ } of type callable is incompatible with the type string expected by parameter $callback of RecursiveCallbackFilterIterator::__construct(). ( Ignorable by Annotation )

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

283
                    /** @scrutinizer ignore-type */ static function (SplFileInfo $file, string $key, RecursiveDirectoryIterator $iterator) {
Loading history...
284
                        return $iterator->getSubPathname()[0]  !== '.' && $iterator->getSubPathname() !== 'vendor';
285
                    }
286
                ),
287
                RecursiveIteratorIterator::LEAVES_ONLY
288
            )),
289
            static function (SplFileInfo $file) {
290
                return ! $file->isDir();
291
            }
292
        );
293
294
        array_walk(
295
            $files,
296
            static function (SplFileInfo $file) use ($zip) {
297
                if ($file->getFilename() === 'composer.json') {
298
                    $contents            = json_decode(file_get_contents($file->getRealPath()), true);
299
                    $contents['version'] = '1.0.0';
300
301
                    return $zip->addFromString('composer.json', json_encode($contents));
302
                }
303
304
                $zip->addFile(
305
                    $file->getRealPath(),
306
                    substr($file->getRealPath(), strlen(realpath(__DIR__ . '/../../')) + 1)
307
                );
308
            }
309
        );
310
311
        $zip->close();
312
    }
313
314
    private function createArtifact() : void
315
    {
316
        $this->createGenericArtifact(
317
            'test-package',
318
            '2.0.0',
319
            [
320
                'name' => 'test/package',
321
            ]
322
        );
323
    }
324
325
    /**
326
     * @param mixed[] $composerJsonContent
327
     */
328
    private function createGenericArtifact(string $name, string $version, array $composerJsonContent): void
329
    {
330
        $composerJsonContent['version'] = $version;
331
        $zip = new ZipArchive();
332
333
        $zip->open(sprintf('%s/%s-%s.zip', $this->tempArtifact , $name, $version), ZipArchive::CREATE);
334
        $zip->addFromString('composer.json', json_encode($composerJsonContent, JSON_PRETTY_PRINT));
335
        $zip->close();
336
    }
337
338
    /**
339
     * @param mixed[] $config
340
     */
341
    private function writeComposerJsonFile(array $config, string $directory) : void
342
    {
343
        file_put_contents(
344
            $directory . '/composer.json',
345
            json_encode($config, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)
346
        );
347
    }
348
349
    private function writeSymfonyPackageVersionUsingFile(string $directory) : void
350
    {
351
        file_put_contents(
352
            $directory . '/use-package-versions.php',
353
            <<<'PHP'
354
<?php
355
356
require_once __DIR__ . '/vendor/autoload.php';
357
358
echo \PackageVersions\Versions::getVersion('symfony/process');
359
PHP
360
        );
361
    }
362
363
    private function assertSymfonyPackageVersionsIsUsable(string $directory) : void
364
    {
365
        exec(PHP_BINARY . ' ' . escapeshellarg($directory . '/use-package-versions.php'), $output, $exitCode);
366
367
        self::assertSame(0, $exitCode);
368
        self::assertCount(1, $output);
369
        self::assertRegExp('/^v?5\\..*\\@[a-f0-9]*$/', $output[0]);
370
    }
371
372
    private function writePackageVersionUsingFile(string $directory) : void
373
    {
374
        file_put_contents(
375
            $directory . '/use-package-versions.php',
376
            <<<'PHP'
377
<?php
378
379
require_once __DIR__ . '/vendor/autoload.php';
380
381
echo \PackageVersions\Versions::getVersion('ocramius/package-versions');
382
PHP
383
        );
384
    }
385
386
    private function assertPackageVersionsIsUsable(string $directory) : void
387
    {
388
        exec(PHP_BINARY . ' ' . escapeshellarg($directory . '/use-package-versions.php'), $output, $exitCode);
389
390
        self::assertSame(0, $exitCode);
391
        self::assertCount(1, $output);
392
        self::assertRegExp('/^1\\..*\\@[a-f0-9]*$/', $output[0]);
393
    }
394
395
    /**
396
     * @return mixed[]
397
     */
398
    private function execComposerInDir(string $command, string $dir) : array
399
    {
400
        $currentDir = getcwd();
401
        chdir($dir);
402
        exec(__DIR__ . '/../../vendor/bin/composer ' . $command . ' 2>&1', $output, $exitCode);
403
        $this->assertEquals(0, $exitCode, implode(PHP_EOL, $output));
404
        chdir($currentDir);
405
406
        return $output;
407
    }
408
409
    private function rmDir(string $directory) : void
410
    {
411
        if (! is_dir($directory)) {
412
            unlink($directory);
413
414
            return;
415
        }
416
417
        array_map(
418
            function ($item) use ($directory) : void {
419
                $this->rmDir($directory . '/' . $item);
420
            },
421
            array_filter(
422
                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

422
                /** @scrutinizer ignore-type */ scandir($directory),
Loading history...
423
                static function (string $dirItem) {
424
                    return ! in_array($dirItem, ['.', '..'], true);
425
                }
426
            )
427
        );
428
429
        rmdir($directory);
430
    }
431
}
432