Completed
Pull Request — master (#118)
by Marco
01:39
created

E2EInstallerTest::testGloballyInstalledPluginDoesNotGenerateVersionsForLocalProject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 42
rs 9.248
c 0
b 0
f 0
cc 1
nc 1
nop 0
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;
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_STRING, expecting T_FUNCTION or T_CONST
Loading history...
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
    /**
188
     * @group 101
189
     */
190
    public function testInstallingPluginWithNoScriptsLeadsToUsableVersionsClass() : void
191
    {
192
        $this->createPackageVersionsArtifact();
193
        $this->createArtifact();
194
195
        $this->writeComposerJsonFile(
196
            [
197
                'name'         => 'package-versions/e2e-local',
198
                'require'      => ['ocramius/package-versions' => '1.0.0'],
199
                'repositories' => [
200
                    ['packagist' => false],
201
                    [
202
                        'type' => 'artifact',
203
                        'url' => $this->tempArtifact,
204
                    ],
205
                ],
206
            ],
207
            $this->tempLocalComposerHome
208
        );
209
210
        $this->execComposerInDir('install --no-scripts', $this->tempLocalComposerHome);
211
        $this->assertFileExists(
212
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
213
        );
214
215
        $this->writePackageVersionUsingFile($this->tempLocalComposerHome);
216
        $this->assertPackageVersionsIsUsable($this->tempLocalComposerHome);
217
    }
218
219
    private function createPackageVersionsArtifact() : void
220
    {
221
        $zip = new ZipArchive();
222
223
        $zip->open($this->tempArtifact . '/ocramius-package-versions-1.0.0.zip', ZipArchive::CREATE);
224
225
        $files = array_filter(
226
            iterator_to_array(new RecursiveIteratorIterator(
227
                new RecursiveCallbackFilterIterator(
228
                    new RecursiveDirectoryIterator(realpath(__DIR__ . '/../../'), RecursiveDirectoryIterator::SKIP_DOTS),
229
                    static function (SplFileInfo $file, string $key, RecursiveDirectoryIterator $iterator) {
230
                        return $iterator->getSubPathname()[0]  !== '.' && $iterator->getSubPathname() !== 'vendor';
231
                    }
232
                ),
233
                RecursiveIteratorIterator::LEAVES_ONLY
234
            )),
235
            static function (SplFileInfo $file) {
236
                return ! $file->isDir();
237
            }
238
        );
239
240
        array_walk(
241
            $files,
242
            static function (SplFileInfo $file) use ($zip) {
243
                if ($file->getFilename() === 'composer.json') {
244
                    $contents            = json_decode(file_get_contents($file->getRealPath()), true);
245
                    $contents['version'] = '1.0.0';
246
247
                    return $zip->addFromString('composer.json', json_encode($contents));
248
                }
249
250
                $zip->addFile(
251
                    $file->getRealPath(),
252
                    substr($file->getRealPath(), strlen(realpath(__DIR__ . '/../../')) + 1)
253
                );
254
            }
255
        );
256
257
        $zip->close();
258
    }
259
260
    private function createArtifact() : void
261
    {
262
        $zip = new ZipArchive();
263
264
        $zip->open($this->tempArtifact . '/test-package-2.0.0.zip', ZipArchive::CREATE);
265
        $zip->addFromString(
266
            'composer.json',
267
            json_encode(
268
                [
269
                    'name'    => 'test/package',
270
                    'version' => '2.0.0',
271
                ],
272
                JSON_PRETTY_PRINT
273
            )
274
        );
275
        $zip->close();
276
    }
277
278
    /**
279
     * @param mixed[] $config
280
     */
281
    private function writeComposerJsonFile(array $config, string $directory) : void
282
    {
283
        file_put_contents(
284
            $directory . '/composer.json',
285
            json_encode($config, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)
286
        );
287
    }
288
289
    private function writePackageVersionUsingFile(string $directory) : void
290
    {
291
        file_put_contents(
292
            $directory . '/use-package-versions.php',
293
            <<<'PHP'
294
<?php
295
296
require_once __DIR__ . '/vendor/autoload.php';
297
298
echo \PackageVersions\Versions::getVersion('ocramius/package-versions');
299
PHP
300
        );
301
    }
302
303
    private function assertPackageVersionsIsUsable(string $directory) : void
304
    {
305
        exec(PHP_BINARY . ' ' . escapeshellarg($directory . '/use-package-versions.php'), $output, $exitCode);
306
307
        self::assertSame(0, $exitCode);
308
        self::assertCount(1, $output);
309
        self::assertRegExp('/^1\\..*\\@[a-f0-9]*$/', $output[0]);
310
    }
311
312
    /**
313
     * @return mixed[]
314
     */
315
    private function execComposerInDir(string $command, string $dir) : array
316
    {
317
        $currentDir = getcwd();
318
        chdir($dir);
319
        exec(__DIR__ . '/../../vendor/bin/composer ' . $command . ' 2> /dev/null', $output, $exitCode);
320
        $this->assertEquals(0, $exitCode);
321
        chdir($currentDir);
322
323
        return $output;
324
    }
325
326
    private function rmDir(string $directory) : void
327
    {
328
        if (! is_dir($directory)) {
329
            unlink($directory);
330
331
            return;
332
        }
333
334
        array_map(
335
            function ($item) use ($directory) : void {
336
                $this->rmDir($directory . '/' . $item);
337
            },
338
            array_filter(
339
                scandir($directory),
340
                static function (string $dirItem) {
341
                    return ! in_array($dirItem, ['.', '..'], true);
342
                }
343
            )
344
        );
345
346
        rmdir($directory);
347
    }
348
}
349