Passed
Push — main ( 907dc9...0ef454 )
by Sebastian
03:44
created

testBrokenSymlinkDetectionOnBrokenRelativeSymlink()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
nc 1
nop 0
dl 0
loc 18
rs 9.8666
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of CaptainHook
5
 *
6
 * (c) Sebastian Feldmann <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace CaptainHook\App\Runner;
13
14
use CaptainHook\App\Config\Mockery as ConfigMockery;
15
use CaptainHook\App\Console\IO\DefaultIO;
16
use CaptainHook\App\Console\IO\Mockery as IOMockery;
17
use CaptainHook\App\Exception\InvalidHookName;
18
use CaptainHook\App\Git\DummyRepo;
19
use CaptainHook\App\Hook\Mockery as HookMockery;
20
use CaptainHook\App\Mockery as CHMockery;
21
use CaptainHook\App\Storage\File;
22
use Exception;
23
use org\bovigo\vfs\vfsStream;
24
use PHPUnit\Framework\TestCase;
25
use RuntimeException;
26
use SebastianFeldmann\Git\Repository;
27
28
class InstallerTest extends TestCase
29
{
30
    use ConfigMockery;
31
    use IOMockery;
32
    use CHMockery;
33
    use HookMockery;
34
35
    /**
36
     * Tests Installer::setHook
37
     *
38
     * @throws \CaptainHook\App\Exception\InvalidHookName
39
     */
40
    public function testSetInvalidHook(): void
41
    {
42
        $this->expectException(InvalidHookName::class);
43
44
        $io       = $this->createIOMock();
45
        $config   = $this->createConfigMock();
46
        $repo     = $this->createRepositoryMock();
47
        $template = $this->createTemplateMock();
48
49
        $runner = new Installer($io, $config, $repo, $template);
50
        $runner->setHook('itDoNotExist');
51
    }
52
53
    /**
54
     * Tests Installer::setHook
55
     *
56
     * @throws \CaptainHook\App\Exception\InvalidHookName
57
     */
58
    public function testSetMultipleInvalidHooks(): void
59
    {
60
        $this->expectException(InvalidHookName::class);
61
62
        $io       = $this->createIOMock();
63
        $config   = $this->createConfigMock();
64
        $repo     = $this->createRepositoryMock();
65
        $template = $this->createTemplateMock();
66
67
        $runner = new Installer($io, $config, $repo, $template);
68
        $runner->setHook('itDoNotExist1,itDoNotExist2,itDontExist3');
69
    }
70
71
    /**
72
     * Tests Installer::setHook
73
     *
74
     * @throws \CaptainHook\App\Exception\InvalidHookName
75
     */
76
    public function testSetHookAndEnabledOnly(): void
77
    {
78
        $this->expectException(Exception::class);
79
80
        $io       = $this->createIOMock();
81
        $config   = $this->createConfigMock();
82
        $repo     = $this->createRepositoryMock();
83
        $template = $this->createTemplateMock();
84
85
        $runner = new Installer($io, $config, $repo, $template);
86
        $runner->setOnlyEnabled(true);
87
        $runner->setHook('pre-push');
88
    }
89
90
    /**
91
     * Tests Installer::setHook
92
     *
93
     * @throws \CaptainHook\App\Exception\InvalidHookName
94
     */
95
    public function testMoveAfterSkippingFail(): void
96
    {
97
        $this->expectException(RuntimeException::class);
98
99
        $io       = $this->createIOMock();
100
        $config   = $this->createConfigMock();
101
        $repo     = $this->createRepositoryMock();
102
        $template = $this->createTemplateMock();
103
104
        $runner = new Installer($io, $config, $repo, $template);
105
        $runner->setHook('pre-commit');
106
        $runner->setSkipExisting(true);
107
        $runner->setMoveExistingTo('/tmp/');
108
    }
109
110
    /**
111
     * Tests Installer::setHook
112
     *
113
     * @throws \CaptainHook\App\Exception\InvalidHookName
114
     */
115
    public function testSkipAfterMovingFail(): void
116
    {
117
        $this->expectException(RuntimeException::class);
118
119
        $io       = $this->createIOMock();
120
        $config   = $this->createConfigMock();
121
        $repo     = $this->createRepositoryMock();
122
        $template = $this->createTemplateMock();
123
124
        $runner = new Installer($io, $config, $repo, $template);
125
        $runner->setHook('pre-commit');
126
        $runner->setMoveExistingTo('/tmp/');
127
        $runner->setSkipExisting(true);
128
    }
129
130
    /**
131
     * Tests Installer::run
132
     */
133
    public function testHookInstallationDeclined(): void
134
    {
135
        $fakeRepo = new DummyRepo();
136
137
        $io       = $this->createIOMock();
138
        $config   = $this->createConfigMock();
139
        $repo     = $this->createRepositoryMock($fakeRepo->getRoot());
140
        $template = $this->createTemplateMock();
141
142
        $io->expects($this->atLeast(5))->method('ask')->willReturn('n');
143
144
        $runner = new Installer($io, $config, $repo, $template);
145
        $runner->setHook('');
146
        $runner->run();
147
148
        $this->assertFileDoesNotExist($fakeRepo->getHookDir() . '/pre-commit');
149
        $this->assertFileDoesNotExist($fakeRepo->getHookDir() . '/pre-push');
150
    }
151
152
    /**
153
     * Tests Installer::run
154
     */
155
    public function testWriteHook(): void
156
    {
157
        $fakeRepo = new DummyRepo();
158
159
        $io       = $this->createIOMock();
160
        $config   = $this->createConfigMock();
161
        $repo     = $this->createRepositoryMock($fakeRepo->getRoot());
162
        $template = $this->createTemplateMock();
163
164
        $template->expects($this->once())
165
                 ->method('getCode')
166
                 ->with('pre-commit')
167
                 ->willReturn('');
168
169
        $runner = new Installer($io, $config, $repo, $template);
170
        $runner->setHook('pre-commit');
171
        $runner->run();
172
173
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-commit');
174
    }
175
176
    /**
177
     * Tests Installer::checkForBrokenSymlinks
178
     */
179
    public function testBrokenSymlinkDetectionOnExistingFile(): void
180
    {
181
        $io       = $this->createIOMock();
182
        $config   = $this->createConfigMock();
183
        $repo     = $this->createRepositoryMock();
184
        $template = $this->createTemplateMock();
185
186
        $file = $this->getMockBuilder(File::class)
187
                     ->disableOriginalConstructor()
188
                     ->getMock();
189
190
        $runner = new FakeInstaller($io, $config, $repo, $template);
191
        $file->method('isLink')->willReturn(true);
192
        $file->method('linkTarget')->willReturn(__FILE__);
193
194
        $runner->checkSymlink($file);
195
        $this->assertTrue(true);
196
    }
197
198
    /**
199
     * Tests Installer::checkForBrokenSymlinks
200
     */
201
    public function testBrokenSymlinkDetectionOnBrokenAbsoluteSymlink(): void
202
    {
203
        $this->expectException(Exception::class);
204
205
        $io       = $this->createIOMock();
206
        $config   = $this->createConfigMock();
207
        $repo     = $this->createRepositoryMock();
208
        $template = $this->createTemplateMock();
209
210
        $file = $this->getMockBuilder(File::class)
211
                     ->disableOriginalConstructor()
212
                     ->getMock();
213
214
        $runner = new FakeInstaller($io, $config, $repo, $template);
215
        $file->method('isLink')->willReturn(true);
216
        $file->method('linkTarget')->willReturn('/foo/bar/baz');
217
218
        $runner->checkSymlink($file);
219
    }
220
221
    /**
222
     * Tests Installer::checkForBrokenSymlinks
223
     */
224
    public function testBrokenSymlinkDetectionOnBrokenRelativeSymlink(): void
225
    {
226
        $this->expectException(Exception::class);
227
228
        $io       = $this->createIOMock();
229
        $config   = $this->createConfigMock();
230
        $repo     = $this->createRepositoryMock();
231
        $template = $this->createTemplateMock();
232
233
        $file = $this->getMockBuilder(File::class)
234
            ->disableOriginalConstructor()
235
            ->getMock();
236
237
        $runner = new FakeInstaller($io, $config, $repo, $template);
238
        $file->method('isLink')->willReturn(true);
239
        $file->method('linkTarget')->willReturn('../../foo/bar/baz');
240
241
        $runner->checkSymlink($file);
242
    }
243
244
    /**
245
     * Tests Installer::run
246
     */
247
    public function testWriteMultipleHooks(): void
248
    {
249
        $fakeRepo = new DummyRepo();
250
251
        $io       = $this->createIOMock();
252
        $config   = $this->createConfigMock();
253
        $repo     = $this->createRepositoryMock($fakeRepo->getRoot());
254
        $template = $this->createTemplateMock();
255
256
        $runner = new Installer($io, $config, $repo, $template);
257
        $runner->setHook('pre-commit,pre-push,post-checkout');
258
        $runner->run();
259
260
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-commit');
261
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-push');
262
        $this->assertFileExists($fakeRepo->getHookDir() . '/post-checkout');
263
    }
264
265
    /**
266
     * Tests Installer::run
267
     */
268
    public function testMoveExistingHook(): void
269
    {
270
        $fakeRepo = new DummyRepo(
271
            // git repo
272
            [
273
                'config' => '# fake git config',
274
                'hooks'  => [
275
                    'pre-commit' => '# fake pre-commit file',
276
                    'pre-push'   => '# fake pre-push file',
277
                ]
278
            ],
279
            // files
280
            [
281
                'foo' => []
282
            ]
283
        );
284
285
        $io       = $this->createIOMock();
286
        $config   = $this->createConfigMock(true, $fakeRepo->getRoot() . '/captainhook.json');
287
        $template = $this->createTemplateMock();
288
        $repo     = new Repository($fakeRepo->getRoot());
289
290
        $template->expects($this->once())
291
                 ->method('getCode')
292
                 ->with('pre-commit')
293
                 ->willReturn('');
294
295
        $runner = new Installer($io, $config, $repo, $template);
296
        $runner->setHook('pre-commit')
297
               ->setMoveExistingTo('foo/bar/')
298
               ->run();
299
300
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-commit');
301
        $this->assertFileExists($fakeRepo->getRoot() . '/foo/bar/pre-commit');
302
    }
303
304
    /**
305
     * Tests Installer::run
306
     */
307
    public function testMoveNotExistingHook(): void
308
    {
309
        $fakeRepo = new DummyRepo(
310
            // git repo
311
            [
312
                'config' => '# fake git config',
313
                'hooks'  => [
314
                    'pre-push' => '# fake pre-push file',
315
                ]
316
            ],
317
            // files
318
            [
319
                'foo' => []
320
            ]
321
        );
322
323
        $io       = $this->createIOMock();
324
        $config   = $this->createConfigMock(true, $fakeRepo->getRoot() . '/captainhook.json');
325
        $template = $this->createTemplateMock();
326
        $repo     = new Repository($fakeRepo->getRoot());
327
328
        $template->expects($this->once())
329
                 ->method('getCode')
330
                 ->with('pre-commit')
331
                 ->willReturn('');
332
333
        $runner = new Installer($io, $config, $repo, $template);
334
        $runner->setHook('pre-commit')
335
               ->setMoveExistingTo('foo/bar/')
336
               ->run();
337
338
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-commit');
339
    }
340
341
    /**
342
     * Tests Installer::run
343
     */
344
    public function testMoveExistingHookTargetIsFile(): void
345
    {
346
        $this->expectException(RuntimeException::class);
347
348
        $fakeRepo = new DummyRepo(
349
            // git repo
350
            [
351
                'config' => '# fake git config',
352
                'hooks'  => [
353
                    'pre-commit' => '# fake pre-commit file',
354
                    'pre-push'   => '# fake pre-push file',
355
                ]
356
            ],
357
            // files
358
            [
359
                'foo' => '# some random file'
360
            ]
361
        );
362
363
        $io       = $this->createIOMock();
364
        $config   = $this->createConfigMock(true, $fakeRepo->getRoot() . '/captainhook.json');
365
        $template = $this->createTemplateMock();
366
        $repo     = new Repository($fakeRepo->getRoot());
367
368
        $runner = new Installer($io, $config, $repo, $template);
369
        $runner->setHook('pre-commit')
370
               ->setMoveExistingTo('foo')
371
               ->run();
372
    }
373
374
    /**
375
     * Tests Installer::writeHookFile
376
     */
377
    public function testSkipExisting(): void
378
    {
379
        $io       = $this->createIOMock();
380
        $config   = $this->createConfigMock();
381
        $repo     = $this->createRepositoryMock();
382
        $template = $this->createTemplateMock();
383
384
        $io->expects($this->atLeast(1))->method('write');
385
        $repo->expects($this->once())->method('hookExists')->willReturn(true);
386
387
        $runner = new Installer($io, $config, $repo, $template);
388
        $runner->setSkipExisting(true);
389
        $runner->setHook('pre-commit');
390
        $runner->run();
391
    }
392
393
    /**
394
     * Tests Installer::writeHookFile
395
     */
396
    public function testOnlyEnabledAndHooksToHandle(): void
397
    {
398
        $this->expectException(Exception::class);
399
400
        $io       = $this->createIOMock();
401
        $config   = $this->createConfigMock();
402
        $repo     = $this->createRepositoryMock();
403
        $template = $this->createTemplateMock();
404
405
        $runner = new Installer($io, $config, $repo, $template);
406
        $runner->setHook('pre-commit');
407
        $runner->setOnlyEnabled(true);
408
    }
409
410
    /**
411
     * Tests Installer::writeHookFile
412
     */
413
    public function testDeclineOverwrite(): void
414
    {
415
        $io       = $this->createIOMock();
416
        $config   = $this->createConfigMock();
417
        $repo     = $this->createRepositoryMock();
418
        $template = $this->createTemplateMock();
419
420
        $io->expects($this->once())->method('ask')->willReturn('n');
421
        $repo->expects($this->once())->method('hookExists')->willReturn(true);
422
423
        $runner = new Installer($io, $config, $repo, $template);
424
        $runner->setHook('pre-commit');
425
        $runner->run();
426
    }
427
428
    public function testMoveExistingHookWhenMoveExistingIsAnAbsolutePath(): void
429
    {
430
        $virtualFs = vfsStream::setup('root');
431
432
        $fakeRepo = new DummyRepo(
433
        // git repo
434
            [
435
                'config' => '# fake git config',
436
                'hooks'  => [
437
                    'pre-commit' => '# fake pre-commit file',
438
                    'pre-push'   => '# fake pre-push file',
439
                ]
440
            ],
441
            // files
442
            [
443
                'foo' => []
444
            ]
445
        );
446
447
        $io       = $this->createIOMock();
448
        $config   = $this->createConfigMock(true, $fakeRepo->getRoot() . '/captainhook.json');
449
        $template = $this->createTemplateMock();
450
        $repo     = new Repository($fakeRepo->getRoot());
451
452
        $template->expects($this->once())
453
            ->method('getCode')
454
            ->with('pre-commit')
455
            ->willReturn('');
456
457
        $runner = new Installer($io, $config, $repo, $template);
458
        $runner->setHook('pre-commit')
459
            ->setMoveExistingTo($virtualFs->url() . '/foo/bar')
460
            ->run();
461
462
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-commit');
463
        $this->assertFileExists($fakeRepo->getRoot() . '/foo/bar/pre-commit');
464
    }
465
}
466