HookTest::testShouldSkipActionsCanBeSetToTrue()
last analyzed

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 12
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;
15
use CaptainHook\App\Config\Mockery as ConfigMockery;
16
use CaptainHook\App\Console\IO\Mockery as IOMockery;
17
use CaptainHook\App\Console\IO\TestIO;
18
use CaptainHook\App\Git\DummyRepo;
19
use CaptainHook\App\Hook\Restriction;
20
use CaptainHook\App\Hooks;
21
use CaptainHook\App\Mockery as CHMockery;
22
use CaptainHook\App\Plugin\DummyConstrainedPlugin;
23
use CaptainHook\App\Plugin\DummyConstrainedHookPlugin;
24
use CaptainHook\App\Plugin\DummyConstrainedHookPluginAlt;
25
use CaptainHook\App\Plugin\DummyPlugin;
26
use CaptainHook\App\Plugin\DummyHookPlugin;
27
use CaptainHook\App\Plugin\DummyHookPluginSkipsActions;
28
use Exception;
29
use PHPUnit\Framework\TestCase;
30
31
class HookTest extends TestCase
32
{
33
    use ConfigMockery;
34
    use IOMockery;
35
    use CHMockery;
36
37
    protected function setUp(): void
38
    {
39
        // Ensure the static properties on dummy plugins are all set to their defaults.
40
        DummyHookPlugin::$beforeHookCalled = 0;
41
        DummyHookPlugin::$beforeActionCalled = 0;
42
        DummyHookPlugin::$afterActionCalled = 0;
43
        DummyHookPlugin::$afterHookCalled = 0;
44
        DummyHookPluginSkipsActions::$skipStartIn = 'beforeHook';
45
        DummyHookPluginSkipsActions::$skipStartAt = 1;
46
        DummyConstrainedHookPlugin::$restriction = null;
47
        DummyConstrainedHookPluginAlt::$restriction = null;
48
        DummyConstrainedPlugin::$restriction = null;
49
    }
50
51
    protected function tearDown(): void
52
    {
53
        // Reset the static properties on dummy plugins to their defaults.
54
        DummyHookPlugin::$beforeHookCalled = 0;
55
        DummyHookPlugin::$beforeActionCalled = 0;
56
        DummyHookPlugin::$afterActionCalled = 0;
57
        DummyHookPlugin::$afterHookCalled = 0;
58
        DummyHookPluginSkipsActions::$skipStartIn = 'beforeHook';
59
        DummyHookPluginSkipsActions::$skipStartAt = 1;
60
        DummyConstrainedHookPlugin::$restriction = null;
61
        DummyConstrainedHookPluginAlt::$restriction = null;
62
        DummyConstrainedPlugin::$restriction = null;
63
    }
64
65
    public function testGetName(): void
66
    {
67
        $io = $this->createIOMock();
68
        $config = $this->createConfigMock();
69
        $repo = $this->createRepositoryMock();
70
71
        $runner = new class ($io, $config, $repo) extends Hook {
72
            protected string $hook = Hooks::PRE_COMMIT;
73
        };
74
75
        $this->assertSame('pre-commit', $runner->getName());
76
    }
77
78
    public function testShouldSkipActionsIsFalseByDefault(): void
79
    {
80
        $io = $this->createIOMock();
81
        $config = $this->createConfigMock();
82
        $repo = $this->createRepositoryMock();
83
84
        $runner = new class ($io, $config, $repo) extends Hook {
85
            protected string $hook = Hooks::PRE_COMMIT;
86
        };
87
88
        $this->assertFalse($runner->shouldSkipActions());
89
    }
90
91
    public function testShouldSkipActionsCanBeSetToTrue(): void
92
    {
93
        $io = $this->createIOMock();
94
        $config = $this->createConfigMock();
95
        $repo = $this->createRepositoryMock();
96
97
        $runner = new class ($io, $config, $repo) extends Hook {
98
            protected string $hook = Hooks::PRE_COMMIT;
99
        };
100
101
        $this->assertTrue($runner->shouldSkipActions(true));
102
        $this->assertTrue($runner->shouldSkipActions());
103
    }
104
105
    public function testShouldSkipActionsCanBeSetToFalse(): void
106
    {
107
        $io = $this->createIOMock();
108
        $config = $this->createConfigMock();
109
        $repo = $this->createRepositoryMock();
110
111
        $runner = new class ($io, $config, $repo) extends Hook {
112
            protected string $hook = Hooks::PRE_COMMIT;
113
        };
114
115
        $runner->shouldSkipActions(true);
116
117
        $this->assertFalse($runner->shouldSkipActions(false));
118
        $this->assertFalse($runner->shouldSkipActions());
119
    }
120
121
    public function testActionNotApplicable(): void
122
    {
123
        $config = $this->createConfigMock();
124
        $config->method('failOnFirstError')->willReturn(true);
125
        $dummy = new DummyRepo(['hooks' => ['pre-commit' => '# hook script']]);
126
        $repo  = $this->createRepositoryMock($dummy->getRoot());
127
        $repo->method('getHooksDir')->willReturn($dummy->getHookDir());
128
129
        $io           = new TestIO();
130
        $hookConfig   = $this->createHookConfigMock();
131
        $actionConfig = $this->createActionConfigMock();
132
        $actionConfig->method('getAction')->willReturn("\\CaptainHook\\App\\Hook\\Message\\Action\\Beams");
133
        $hookConfig->method('isEnabled')->willReturn(true);
134
        $hookConfig->expects($this->once())->method('getActions')->willReturn([$actionConfig]);
135
        $config->expects($this->once())->method('getHookConfigToExecute')->willReturn($hookConfig);
136
        $config->expects($this->atLeastOnce())->method('isHookEnabled')->willReturn(true);
137
138
        $runner = new class ($io, $config, $repo) extends Hook {
139
            protected string $hook = Hooks::PRE_PUSH;
140
        };
141
        $runner->run();
142
143
        $this->assertStringContainsString('skipped', implode($io->getLog()));
144
    }
145
146
    public function testRunHookWithPlugins(): void
147
    {
148
        if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
149
            $this->markTestSkipped('not tested on windows');
150
        }
151
152
        $restriction1 = new Restriction(Hooks::POST_CHECKOUT);
153
        DummyConstrainedPlugin::$restriction = $restriction1;
154
        DummyConstrainedHookPluginAlt::$restriction = $restriction1;
155
156
        $restriction2 = new Restriction(Hooks::PRE_COMMIT);
157
        DummyConstrainedHookPlugin::$restriction = $restriction2;
158
159
        $pluginConfig1 = new Config\Plugin(DummyPlugin::class);
160
        $pluginConfig2 = new Config\Plugin(DummyHookPlugin::class);
161
        $pluginConfig3 = new Config\Plugin(DummyConstrainedPlugin::class);
162
        $pluginConfig4 = new Config\Plugin(DummyConstrainedHookPlugin::class);
163
        $pluginConfig5 = new Config\Plugin(DummyConstrainedHookPluginAlt::class);
164
165
        $config = $this->createConfigMock();
166
        $config->method('failOnFirstError')->willReturn(true);
167
        $config->method('getPlugins')->willReturn([
168
            $pluginConfig1,
169
            $pluginConfig2,
170
            $pluginConfig3,
171
            $pluginConfig4,
172
            $pluginConfig5,
173
        ]);
174
        $dummy = new DummyRepo(['hooks' => ['pre-commit' => '# hook script']]);
175
        $repo  = $this->createRepositoryMock($dummy->getRoot());
176
        $repo->method('getHooksDir')->willReturn($dummy->getHookDir());
177
178
        $io           = $this->createIOMock();
179
        $hookConfig   = $this->createHookConfigMock();
180
        $actionConfig = $this->createActionConfigMock();
181
        $actionConfig->method('getAction')->willReturn(CH_PATH_FILES . '/bin/success');
182
        $hookConfig->method('isEnabled')->willReturn(true);
183
        $hookConfig->expects($this->once())->method('getActions')->willReturn([$actionConfig, $actionConfig]);
184
        $config->expects($this->once())->method('getHookConfigToExecute')->willReturn($hookConfig);
185
        $config->expects($this->atLeastOnce())->method('isHookEnabled')->willReturn(true);
186
        $io->expects($this->atLeast(1))->method('write');
187
188
        $runner = new class ($io, $config, $repo) extends Hook {
189
            protected string $hook = Hooks::PRE_COMMIT;
190
        };
191
        $runner->run();
192
193
        $this->assertSame(2, DummyHookPlugin::$beforeHookCalled);
194
        $this->assertSame(4, DummyHookPlugin::$beforeActionCalled);
195
        $this->assertSame(4, DummyHookPlugin::$afterActionCalled);
196
        $this->assertSame(2, DummyHookPlugin::$afterHookCalled);
197
    }
198
199
    public function testRunHookSkipsActionsFromPluginBeforeHook(): void
200
    {
201
        DummyHookPluginSkipsActions::$skipStartAt = 1;
202
203
        $pluginConfig = new Config\Plugin(DummyHookPluginSkipsActions::class);
204
205
        $dummy = new DummyRepo(['hooks' => ['pre-commit' => '# hook script']]);
206
        $repo  = $this->createRepositoryMock($dummy->getRoot());
207
        $repo->method('getHooksDir')->willReturn($dummy->getHookDir());
208
209
        $config = $this->createConfigMock();
210
        $config->method('failOnFirstError')->willReturn(true);
211
        $config->method('getPlugins')->willReturn([$pluginConfig]);
212
213
        $io = $this->createIOMock();
214
        $hookConfig = $this->createHookConfigMock();
215
        $actionConfig = $this->createActionConfigMock();
216
        $hookConfig->method('isEnabled')->willReturn(true);
217
        $hookConfig->expects($this->once())->method('getActions')->willReturn([
218
            $actionConfig,
219
            $actionConfig,
220
        ]);
221
        $config->expects($this->once())->method('getHookConfigToExecute')->willReturn($hookConfig);
222
        $config->expects($this->atLeastOnce())->method('isHookEnabled')->willReturn(true);
223
        $io->expects($this->atLeast(1))->method('write');
224
225
        $runner = new class ($io, $config, $repo) extends Hook {
226
            protected string $hook = Hooks::PRE_COMMIT;
227
        };
228
        $runner->run();
229
230
        $this->assertSame(1, DummyHookPlugin::$beforeHookCalled);
231
        $this->assertSame(0, DummyHookPlugin::$beforeActionCalled);
232
        $this->assertSame(0, DummyHookPlugin::$afterActionCalled);
233
        $this->assertSame(1, DummyHookPlugin::$afterHookCalled);
234
    }
235
236
    public function testRunHookSkipsActionsFromPluginBeforeAction(): void
237
    {
238
        if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
239
            $this->markTestSkipped('not tested on windows');
240
        }
241
242
        DummyHookPluginSkipsActions::$skipStartIn = 'beforeAction';
243
        DummyHookPluginSkipsActions::$skipStartAt = 3;
244
245
        $pluginConfig = new Config\Plugin(DummyHookPluginSkipsActions::class);
246
247
        $dummy = new DummyRepo(['hooks' => ['pre-commit' => '# hook script']]);
248
        $repo  = $this->createRepositoryMock($dummy->getRoot());
249
        $repo->method('getHooksDir')->willReturn($dummy->getHookDir());
250
251
        $config = $this->createConfigMock();
252
        $config->method('failOnFirstError')->willReturn(true);
253
        $config->method('getPlugins')->willReturn([$pluginConfig]);
254
255
        $io = $this->createIOMock();
256
        $hookConfig = $this->createHookConfigMock();
257
        $actionConfig = $this->createActionConfigMock();
258
        $actionConfig->method('getAction')->willReturn(CH_PATH_FILES . '/bin/success');
259
        $hookConfig->method('isEnabled')->willReturn(true);
260
        $hookConfig->expects($this->once())->method('getActions')->willReturn([
261
            $actionConfig,
262
            $actionConfig,
263
            $actionConfig,
264
            $actionConfig,
265
            $actionConfig,
266
        ]);
267
        $config->expects($this->once())->method('getHookConfigToExecute')->willReturn($hookConfig);
268
        $config->expects($this->atLeastOnce())->method('isHookEnabled')->willReturn(true);
269
        $io->expects($this->atLeast(1))->method('write');
270
271
        $runner = new class ($io, $config, $repo) extends Hook {
272
            protected string $hook = Hooks::PRE_COMMIT;
273
        };
274
        $runner->run();
275
276
        $this->assertSame(1, DummyHookPlugin::$beforeHookCalled);
277
        $this->assertSame(3, DummyHookPlugin::$beforeActionCalled);
278
        $this->assertSame(3, DummyHookPlugin::$afterActionCalled);
279
        $this->assertSame(1, DummyHookPlugin::$afterHookCalled);
280
    }
281
282
    public function testRunHookWhenPluginsAreDisabled(): void
283
    {
284
        $pluginConfig1 = new Config\Plugin(DummyHookPlugin::class);
285
        $pluginConfig2 = new Config\Plugin(DummyHookPlugin::class);
286
287
        $config = $this->createConfigMock();
288
        $config->method('failOnFirstError')->willReturn(false);
289
        $config->method('getPlugins')->willReturn([$pluginConfig1, $pluginConfig2]);
290
291
        $io           = $this->createIOMock();
292
        $repo         = $this->createRepositoryMock();
293
        $hookConfig   = $this->createHookConfigMock();
294
        $actionConfig = $this->createActionConfigMock();
295
        $actionConfig->expects($this->atLeastOnce())->method('getAction')->willReturn(CH_PATH_FILES . '/bin/success');
296
        $hookConfig->method('isEnabled')->willReturn(true);
297
        $hookConfig->expects($this->once())->method('getActions')->willReturn([$actionConfig, clone $actionConfig]);
298
        $config->method('isHookEnabled')->willReturn(true);
299
        $config->expects($this->once())->method('getHookConfigToExecute')->willReturn($hookConfig);
300
301
        $runner = new class ($io, $config, $repo) extends Hook {
302
            protected string $hook = Hooks::PRE_COMMIT;
303
        };
304
        $runner->setPluginsDisabled(true);
305
        $runner->run();
306
307
        $this->assertSame(0, DummyHookPlugin::$beforeHookCalled);
308
        $this->assertSame(0, DummyHookPlugin::$beforeActionCalled);
309
        $this->assertSame(0, DummyHookPlugin::$afterActionCalled);
310
        $this->assertSame(0, DummyHookPlugin::$afterHookCalled);
311
    }
312
}
313