Passed
Push — main ( 36f773...e1b064 )
by Sebastian
03:34
created

testBrokenSymlinkDetectionOnExistingFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
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 17
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 testBrokenSymlinkDetectionOnBrokenSymlink(): 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::run
223
     */
224
    public function testWriteMultipleHooks(): void
225
    {
226
        $fakeRepo = new DummyRepo();
227
228
        $io       = $this->createIOMock();
229
        $config   = $this->createConfigMock();
230
        $repo     = $this->createRepositoryMock($fakeRepo->getRoot());
231
        $template = $this->createTemplateMock();
232
233
        $runner = new Installer($io, $config, $repo, $template);
234
        $runner->setHook('pre-commit,pre-push,post-checkout');
235
        $runner->run();
236
237
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-commit');
238
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-push');
239
        $this->assertFileExists($fakeRepo->getHookDir() . '/post-checkout');
240
    }
241
242
    /**
243
     * Tests Installer::run
244
     */
245
    public function testMoveExistingHook(): void
246
    {
247
        $fakeRepo = new DummyRepo(
248
            // git repo
249
            [
250
                'config' => '# fake git config',
251
                'hooks'  => [
252
                    'pre-commit' => '# fake pre-commit file',
253
                    'pre-push'   => '# fake pre-push file',
254
                ]
255
            ],
256
            // files
257
            [
258
                'foo' => []
259
            ]
260
        );
261
262
        $io       = $this->createIOMock();
263
        $config   = $this->createConfigMock(true, $fakeRepo->getRoot() . '/captainhook.json');
264
        $template = $this->createTemplateMock();
265
        $repo     = new Repository($fakeRepo->getRoot());
266
267
        $template->expects($this->once())
268
                 ->method('getCode')
269
                 ->with('pre-commit')
270
                 ->willReturn('');
271
272
        $runner = new Installer($io, $config, $repo, $template);
273
        $runner->setHook('pre-commit')
274
               ->setMoveExistingTo('foo/bar/')
275
               ->run();
276
277
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-commit');
278
        $this->assertFileExists($fakeRepo->getRoot() . '/foo/bar/pre-commit');
279
    }
280
281
    /**
282
     * Tests Installer::run
283
     */
284
    public function testMoveNotExistingHook(): void
285
    {
286
        $fakeRepo = new DummyRepo(
287
            // git repo
288
            [
289
                'config' => '# fake git config',
290
                'hooks'  => [
291
                    'pre-push' => '# fake pre-push file',
292
                ]
293
            ],
294
            // files
295
            [
296
                'foo' => []
297
            ]
298
        );
299
300
        $io       = $this->createIOMock();
301
        $config   = $this->createConfigMock(true, $fakeRepo->getRoot() . '/captainhook.json');
302
        $template = $this->createTemplateMock();
303
        $repo     = new Repository($fakeRepo->getRoot());
304
305
        $template->expects($this->once())
306
                 ->method('getCode')
307
                 ->with('pre-commit')
308
                 ->willReturn('');
309
310
        $runner = new Installer($io, $config, $repo, $template);
311
        $runner->setHook('pre-commit')
312
               ->setMoveExistingTo('foo/bar/')
313
               ->run();
314
315
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-commit');
316
    }
317
318
    /**
319
     * Tests Installer::run
320
     */
321
    public function testMoveExistingHookTargetIsFile(): void
322
    {
323
        $this->expectException(RuntimeException::class);
324
325
        $fakeRepo = new DummyRepo(
326
            // git repo
327
            [
328
                'config' => '# fake git config',
329
                'hooks'  => [
330
                    'pre-commit' => '# fake pre-commit file',
331
                    'pre-push'   => '# fake pre-push file',
332
                ]
333
            ],
334
            // files
335
            [
336
                'foo' => '# some random file'
337
            ]
338
        );
339
340
        $io       = $this->createIOMock();
341
        $config   = $this->createConfigMock(true, $fakeRepo->getRoot() . '/captainhook.json');
342
        $template = $this->createTemplateMock();
343
        $repo     = new Repository($fakeRepo->getRoot());
344
345
        $runner = new Installer($io, $config, $repo, $template);
346
        $runner->setHook('pre-commit')
347
               ->setMoveExistingTo('foo')
348
               ->run();
349
    }
350
351
    /**
352
     * Tests Installer::writeHookFile
353
     */
354
    public function testSkipExisting(): void
355
    {
356
        $io       = $this->createIOMock();
357
        $config   = $this->createConfigMock();
358
        $repo     = $this->createRepositoryMock();
359
        $template = $this->createTemplateMock();
360
361
        $io->expects($this->atLeast(1))->method('write');
362
        $repo->expects($this->once())->method('hookExists')->willReturn(true);
363
364
        $runner = new Installer($io, $config, $repo, $template);
365
        $runner->setSkipExisting(true);
366
        $runner->setHook('pre-commit');
367
        $runner->run();
368
    }
369
370
    /**
371
     * Tests Installer::writeHookFile
372
     */
373
    public function testOnlyEnabledAndHooksToHandle(): void
374
    {
375
        $this->expectException(Exception::class);
376
377
        $io       = $this->createIOMock();
378
        $config   = $this->createConfigMock();
379
        $repo     = $this->createRepositoryMock();
380
        $template = $this->createTemplateMock();
381
382
        $runner = new Installer($io, $config, $repo, $template);
383
        $runner->setHook('pre-commit');
384
        $runner->setOnlyEnabled(true);
385
    }
386
387
    /**
388
     * Tests Installer::writeHookFile
389
     */
390
    public function testDeclineOverwrite(): void
391
    {
392
        $io       = $this->createIOMock();
393
        $config   = $this->createConfigMock();
394
        $repo     = $this->createRepositoryMock();
395
        $template = $this->createTemplateMock();
396
397
        $io->expects($this->once())->method('ask')->willReturn('n');
398
        $repo->expects($this->once())->method('hookExists')->willReturn(true);
399
400
        $runner = new Installer($io, $config, $repo, $template);
401
        $runner->setHook('pre-commit');
402
        $runner->run();
403
    }
404
405
    public function testMoveExistingHookWhenMoveExistingIsAnAbsolutePath(): void
406
    {
407
        $virtualFs = vfsStream::setup('root');
408
409
        $fakeRepo = new DummyRepo(
410
        // git repo
411
            [
412
                'config' => '# fake git config',
413
                'hooks'  => [
414
                    'pre-commit' => '# fake pre-commit file',
415
                    'pre-push'   => '# fake pre-push file',
416
                ]
417
            ],
418
            // files
419
            [
420
                'foo' => []
421
            ]
422
        );
423
424
        $io       = $this->createIOMock();
425
        $config   = $this->createConfigMock(true, $fakeRepo->getRoot() . '/captainhook.json');
426
        $template = $this->createTemplateMock();
427
        $repo     = new Repository($fakeRepo->getRoot());
428
429
        $template->expects($this->once())
430
            ->method('getCode')
431
            ->with('pre-commit')
432
            ->willReturn('');
433
434
        $runner = new Installer($io, $config, $repo, $template);
435
        $runner->setHook('pre-commit')
436
            ->setMoveExistingTo($virtualFs->url() . '/foo/bar')
437
            ->run();
438
439
        $this->assertFileExists($fakeRepo->getHookDir() . '/pre-commit');
440
        $this->assertFileExists($fakeRepo->getRoot() . '/foo/bar/pre-commit');
441
    }
442
}
443