Completed
Push — master ( da0d9d...1d3234 )
by Marco
61:43 queued 37:01
created

E2EInstallerTest::writePackageVersionUsingFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 1
nc 1
nop 1
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 const JSON_PRETTY_PRINT;
14
use const JSON_UNESCAPED_SLASHES;
15
use const PHP_BINARY;
16
use function array_filter;
17
use function array_map;
18
use function array_walk;
19
use function chdir;
20
use function escapeshellarg;
21
use function exec;
22
use function file_get_contents;
23
use function file_put_contents;
24
use function getcwd;
25
use function in_array;
26
use function is_dir;
27
use function iterator_to_array;
28
use function json_decode;
29
use function json_encode;
30
use function mkdir;
31
use function putenv;
32
use function realpath;
33
use function rmdir;
34
use function scandir;
35
use function strlen;
36
use function substr;
37
use function sys_get_temp_dir;
38
use function uniqid;
39
use function unlink;
40
41
/**
42
 * @coversNothing
43
 */
44
class E2EInstallerTest extends TestCase
45
{
46
    /** @var string */
47
    private $tempGlobalComposerHome;
48
49
    /** @var string */
50
    private $tempLocalComposerHome;
51
52
    /** @var string */
53
    private $tempArtifact;
54
55
    public function setUp() : void
56
    {
57
        $this->tempGlobalComposerHome = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/global';
58
        $this->tempLocalComposerHome  = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/local';
59
        $this->tempArtifact           = sys_get_temp_dir() . '/' . uniqid('InstallerTest', true) . '/artifacts';
60
        mkdir($this->tempGlobalComposerHome, 0700, true);
61
        mkdir($this->tempLocalComposerHome, 0700, true);
62
        mkdir($this->tempArtifact, 0700, true);
63
64
        putenv('COMPOSER_HOME=' . $this->tempGlobalComposerHome);
65
    }
66
67
    public function tearDown() : void
68
    {
69
        $this->rmDir($this->tempGlobalComposerHome);
70
        $this->rmDir($this->tempLocalComposerHome);
71
        $this->rmDir($this->tempArtifact);
72
73
        putenv('COMPOSER_HOME');
74
    }
75
76
    public function testGloballyInstalledPluginDoesNotGenerateVersionsForLocalProject() : void
77
    {
78
        $this->createPackageVersionsArtifact();
79
80
        $this->writeComposerJsonFile(
81
            [
82
                'name'         => 'package-versions/e2e-global',
83
                'require'      => ['ocramius/package-versions' => '1.0.0'],
84
                'repositories' => [
85
                    ['packagist' => false],
86
                    [
87
                        'type' => 'artifact',
88
                        'url' => $this->tempArtifact,
89
                    ],
90
                ],
91
            ],
92
            $this->tempGlobalComposerHome
93
        );
94
95
        $this->execComposerInDir('global update', $this->tempGlobalComposerHome);
96
97
        $this->createArtifact();
98
        $this->writeComposerJsonFile(
99
            [
100
                'name'         => 'package-versions/e2e-local',
101
                'require'      => ['test/package' => '2.0.0'],
102
                'repositories' => [
103
                    ['packagist' => false],
104
                    [
105
                        'type' => 'artifact',
106
                        'url' => $this->tempArtifact,
107
                    ],
108
                ],
109
            ],
110
            $this->tempLocalComposerHome
111
        );
112
113
        $this->execComposerInDir('update', $this->tempLocalComposerHome);
114
        $this->assertFileNotExists(
115
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
116
        );
117
    }
118
119
    public function testRemovingPluginDoesNotAttemptToGenerateVersions() : void
120
    {
121
        $this->createPackageVersionsArtifact();
122
        $this->createArtifact();
123
124
        $this->writeComposerJsonFile(
125
            [
126
                'name'         => 'package-versions/e2e-local',
127
                'require'      => [
128
                    'test/package' => '2.0.0',
129
                    'ocramius/package-versions' => '1.0.0',
130
                ],
131
                'repositories' => [
132
                    ['packagist' => false],
133
                    [
134
                        'type' => 'artifact',
135
                        'url' => $this->tempArtifact,
136
                    ],
137
                ],
138
            ],
139
            $this->tempLocalComposerHome
140
        );
141
142
        $this->execComposerInDir('update', $this->tempLocalComposerHome);
143
        $this->assertFileExists(
144
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
145
        );
146
147
        $this->execComposerInDir('remove ocramius/package-versions', $this->tempLocalComposerHome);
148
149
        $this->assertFileNotExists(
150
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
151
        );
152
    }
153
154
    /**
155
     * @group #41
156
     * @group #46
157
     */
158
    public function testRemovingPluginWithNoDevDoesNotAttemptToGenerateVersions() : void
159
    {
160
        $this->createPackageVersionsArtifact();
161
        $this->createArtifact();
162
163
        $this->writeComposerJsonFile(
164
            [
165
                'name'         => 'package-versions/e2e-local',
166
                'require-dev'      => ['ocramius/package-versions' => '1.0.0'],
167
                'repositories' => [
168
                    ['packagist' => false],
169
                    [
170
                        'type' => 'artifact',
171
                        'url' => $this->tempArtifact,
172
                    ],
173
                ],
174
            ],
175
            $this->tempLocalComposerHome
176
        );
177
178
        $this->execComposerInDir('update', $this->tempLocalComposerHome);
179
        $this->assertFileExists(
180
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
181
        );
182
183
        $this->execComposerInDir('install --no-dev', $this->tempLocalComposerHome);
184
185
        $this->assertFileNotExists(
186
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
187
        );
188
    }
189
190
    /**
191
     * @group 101
192
     */
193
    public function testInstallingPluginWithNoScriptsLeadsToUsableVersionsClass() : void
194
    {
195
        $this->createPackageVersionsArtifact();
196
        $this->createArtifact();
197
198
        $this->writeComposerJsonFile(
199
            [
200
                'name'         => 'package-versions/e2e-local',
201
                'require'      => ['ocramius/package-versions' => '1.0.0'],
202
                'repositories' => [
203
                    ['packagist' => false],
204
                    [
205
                        'type' => 'artifact',
206
                        'url' => $this->tempArtifact,
207
                    ],
208
                ],
209
            ],
210
            $this->tempLocalComposerHome
211
        );
212
213
        $this->execComposerInDir('install --no-scripts', $this->tempLocalComposerHome);
214
        $this->assertFileExists(
215
            $this->tempLocalComposerHome . '/vendor/ocramius/package-versions/src/PackageVersions/Versions.php'
216
        );
217
218
        $this->writePackageVersionUsingFile($this->tempLocalComposerHome);
219
        $this->assertPackageVersionsIsUsable($this->tempLocalComposerHome);
220
    }
221
222
    private function createPackageVersionsArtifact() : void
223
    {
224
        $zip = new ZipArchive();
225
226
        $zip->open($this->tempArtifact . '/ocramius-package-versions-1.0.0.zip', ZipArchive::CREATE);
227
228
        $files = array_filter(
229
            iterator_to_array(new RecursiveIteratorIterator(
230
                new RecursiveCallbackFilterIterator(
231
                    new RecursiveDirectoryIterator(realpath(__DIR__ . '/../../'), RecursiveDirectoryIterator::SKIP_DOTS),
232
                    static function (SplFileInfo $file, string $key, RecursiveDirectoryIterator $iterator) {
233
                        return $iterator->getSubPathname()[0]  !== '.' && $iterator->getSubPathname() !== 'vendor';
234
                    }
235
                ),
236
                RecursiveIteratorIterator::LEAVES_ONLY
237
            )),
238
            static function (SplFileInfo $file) {
239
                return ! $file->isDir();
240
            }
241
        );
242
243
        array_walk(
244
            $files,
245
            static function (SplFileInfo $file) use ($zip) {
246
                if ($file->getFilename() === 'composer.json') {
247
                    $contents            = json_decode(file_get_contents($file->getRealPath()), true);
248
                    $contents['version'] = '1.0.0';
249
250
                    return $zip->addFromString('composer.json', json_encode($contents));
251
                }
252
253
                $zip->addFile(
254
                    $file->getRealPath(),
255
                    substr($file->getRealPath(), strlen(realpath(__DIR__ . '/../../')) + 1)
256
                );
257
            }
258
        );
259
260
        $zip->close();
261
    }
262
263
    private function createArtifact() : void
264
    {
265
        $zip = new ZipArchive();
266
267
        $zip->open($this->tempArtifact . '/test-package-2.0.0.zip', ZipArchive::CREATE);
268
        $zip->addFromString(
269
            'composer.json',
270
            json_encode(
271
                [
272
                    'name'    => 'test/package',
273
                    'version' => '2.0.0',
274
                ],
275
                JSON_PRETTY_PRINT
276
            )
277
        );
278
        $zip->close();
279
    }
280
281
    /**
282
     * @param mixed[] $config
283
     */
284
    private function writeComposerJsonFile(array $config, string $directory) : void
285
    {
286
        file_put_contents(
287
            $directory . '/composer.json',
288
            json_encode($config, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)
289
        );
290
    }
291
292
    private function writePackageVersionUsingFile(string $directory) : void
293
    {
294
        file_put_contents(
295
            $directory . '/use-package-versions.php',
296
            <<<'PHP'
297
<?php
298
299
require_once __DIR__ . '/vendor/autoload.php';
300
301
echo \PackageVersions\Versions::getVersion('ocramius/package-versions');
302
PHP
303
        );
304
    }
305
306
    private function assertPackageVersionsIsUsable(string $directory) : void
307
    {
308
        exec(PHP_BINARY . ' ' . escapeshellarg($directory . '/use-package-versions.php'), $output, $exitCode);
309
310
        self::assertSame(0, $exitCode);
311
        self::assertCount(1, $output);
0 ignored issues
show
Documentation introduced by
$output is of type null|array, but the function expects a object<Countable>|object...nit\Framework\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
312
        self::assertRegExp('/^1\\..*\\@[a-f0-9]*$/', $output[0]);
313
    }
314
315
    /**
316
     * @return mixed[]
317
     */
318
    private function execComposerInDir(string $command, string $dir) : array
319
    {
320
        $currentDir = getcwd();
321
        chdir($dir);
322
        exec(__DIR__ . '/../../vendor/bin/composer ' . $command . ' 2> /dev/null', $output, $exitCode);
323
        $this->assertEquals(0, $exitCode);
324
        chdir($currentDir);
325
326
        return $output;
327
    }
328
329
    private function rmDir(string $directory) : void
330
    {
331
        if (! is_dir($directory)) {
332
            unlink($directory);
333
334
            return;
335
        }
336
337
        array_map(
338
            function ($item) use ($directory) : void {
339
                $this->rmDir($directory . '/' . $item);
340
            },
341
            array_filter(
342
                scandir($directory),
343
                static function (string $dirItem) {
344
                    return ! in_array($dirItem, ['.', '..'], true);
345
                }
346
            )
347
        );
348
349
        rmdir($directory);
350
    }
351
}
352