Passed
Push — master ( e2b89d...ef15a2 )
by Doug
08:56
created

Extension::setupCodeCoverage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 16
c 0
b 0
f 0
dl 0
loc 23
ccs 0
cts 16
cp 0
rs 9.7333
cc 2
nc 2
nop 1
crap 6
1
<?php
2
3
declare(strict_types=1);
4
/**
5
 * Code Coverage Extension for Behat.
6
 *
7
 * @copyright 2013 Anthon Pang
8
 *
9
 * @license BSD-2-Clause
10
 */
11
12
namespace DVDoug\Behat\CodeCoverage;
13
14
use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface;
15
use Behat\Testwork\ServiceContainer\ExtensionManager;
16
use DVDoug\Behat\CodeCoverage\Driver\RemoteXdebug;
17
use DVDoug\Behat\CodeCoverage\Listener\EventListener;
18
use SebastianBergmann\CodeCoverage\CodeCoverage;
19
use SebastianBergmann\CodeCoverage\Filter;
20
use SebastianBergmann\Environment\Runtime;
21
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
22
use Symfony\Component\Config\FileLocator;
23
use Symfony\Component\Console\Input\InputInterface;
24
use Symfony\Component\Console\Output\OutputInterface;
25
use Symfony\Component\DependencyInjection\ContainerBuilder;
26
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
27
28
/**
29
 * Code coverage extension.
30
 *
31
 * @author Anthon Pang <[email protected]>
32
 */
33
class Extension implements ExtensionInterface
34
{
35
    /**
36
     * @var string
37
     */
38
    private $configFolder;
39
40
    /**
41
     * Constructor.
42
     *
43
     * @param string $configFolder
44
     */
45
    public function __construct($configFolder = null)
46
    {
47
        $this->configFolder = $configFolder ?: __DIR__ . '/Resources/config';
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function initialize(ExtensionManager $extensionManager): void
54
    {
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60
    public function load(ContainerBuilder $container, array $config): void
61
    {
62
        $loader = new XmlFileLoader($container, new FileLocator($this->configFolder));
63
64
        $servicesFile = 'services.xml';
65
        $loader->load($servicesFile);
66
67
        if (!isset($config['auth']['user']) || !isset($config['auth']['password'])) {
68
            $config['auth'] = null;
69
        }
70
71
        if (count($config['drivers'])) {
72
            $config['driver'] = $config['drivers'][0];
73
        }
74
75
        if (!count($config['report']['options'])) {
76
            $config['report']['options'] = [
77
                'target' => '/tmp',
78
            ];
79
        }
80
81
        if (!$container->hasParameter('mink.base_url')) {
82
            $container->setParameter('mink.base_url', null);
83
        }
84
85
        $container->setParameter('behat.code_coverage.config.auth', $config['auth']);
86
        $container->setParameter('behat.code_coverage.config.create', $config['create']);
87
        $container->setParameter('behat.code_coverage.config.read', $config['read']);
88
        $container->setParameter('behat.code_coverage.config.delete', $config['delete']);
89
        $container->setParameter('behat.code_coverage.config.driver', $config['driver']);
90
        $container->setParameter('behat.code_coverage.config.drivers', $config['drivers']);
91
        $container->setParameter('behat.code_coverage.config.filter', $config['filter']);
92
        $container->setParameter('behat.code_coverage.config.report', $config['report'] ?? []);
93
        $container->setParameter('behat.code_coverage.config.reports', $config['reports'] ?? []);
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99
    public function configure(ArrayNodeDefinition $builder): void
100
    {
101
        $builder
102
            ->children()
103
                ->arrayNode('auth')
104
                    ->children()
105
                        ->scalarNode('user')->end()
106
                        ->scalarNode('password')->end()
0 ignored issues
show
Bug introduced by
The method scalarNode() does not exist on Symfony\Component\Config...der\NodeParentInterface. It seems like you code against a sub-type of Symfony\Component\Config...der\NodeParentInterface such as Symfony\Component\Config...ion\Builder\NodeBuilder. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

106
                        ->/** @scrutinizer ignore-call */ scalarNode('password')->end()
Loading history...
107
                    ->end()
108
                ->end()
109
                ->arrayNode('create')
110
                    ->addDefaultsIfNotSet()
111
                    ->children()
112
                        ->scalarNode('method')->defaultValue('POST')->end()
113
                        ->scalarNode('path')->defaultValue('/')->end()
114
                    ->end()
115
                ->end()
116
                ->arrayNode('read')
117
                    ->addDefaultsIfNotSet()
118
                    ->children()
119
                        ->scalarNode('method')->defaultValue('GET')->end()
120
                        ->scalarNode('path')->defaultValue('/')->end()
121
                    ->end()
122
                ->end()
123
                ->arrayNode('delete')
124
                    ->addDefaultsIfNotSet()
125
                    ->children()
126
                        ->scalarNode('method')->defaultValue('DELETE')->end()
127
                        ->scalarNode('path')->defaultValue('/')->end()
128
                    ->end()
129
                ->end()
130
                ->arrayNode('drivers')
131
                    ->setDeprecated('The "drivers" option is deprecated. Use "driver" instead.')
132
                    ->prototype('scalar')->end()
133
                ->end()
134
                ->enumNode('driver')
135
                    ->values(['local', 'remote'])
136
                    ->defaultValue('local')
137
                ->end()
138
                ->arrayNode('filter')
139
                    ->addDefaultsIfNotSet()
140
                    ->children()
141
                        ->arrayNode('whitelist')
142
                            ->addDefaultsIfNotSet()
143
                            ->children()
144
                                ->scalarNode('addUncoveredFilesFromWhitelist')
145
                                    ->defaultTrue()
146
                                ->end()
147
                                ->scalarNode('processUncoveredFilesFromWhitelist')
148
                                    ->defaultFalse()
149
                                ->end()
150
                                ->arrayNode('include')
151
                                    ->addDefaultsIfNotSet()
152
                                    ->children()
153
                                        ->arrayNode('directories')
154
                                           ->useAttributeAsKey('name')
155
                                           ->normalizeKeys(false)
156
                                           ->prototype('array')
157
                                               ->children()
158
                                                   ->scalarNode('prefix')->defaultValue('')->end()
159
                                                   ->scalarNode('suffix')->defaultValue('.php')->end()
160
                                               ->end()
161
                                           ->end()
162
                                        ->end()
163
                                        ->arrayNode('files')
164
                                           ->prototype('scalar')->end()
165
                                        ->end()
166
                                    ->end()
167
                                ->end()
168
                                ->arrayNode('exclude')
169
                                    ->addDefaultsIfNotSet()
170
                                    ->children()
171
                                        ->arrayNode('directories')
172
                                           ->useAttributeAsKey('name')
173
                                           ->normalizeKeys(false)
174
                                           ->prototype('array')
175
                                               ->children()
176
                                                   ->scalarNode('prefix')->defaultValue('')->end()
177
                                                   ->scalarNode('suffix')->defaultValue('.php')->end()
178
                                               ->end()
179
                                           ->end()
180
                                        ->end()
181
                                        ->arrayNode('files')
182
                                           ->prototype('scalar')->end()
183
                                        ->end()
184
                                    ->end()
185
                                ->end()
186
                            ->end()
187
                        ->end()
188
                    ->end()
189
                ->end()
190
                ->arrayNode('report')
191
                    ->setDeprecated('The "report" option is deprecated. Use "reports" instead.')
192
                    ->children()
193
                        ->scalarNode('format')->defaultValue('html')->end()
194
                        ->arrayNode('options')
195
                            ->useAttributeAsKey('name')
196
                            ->prototype('scalar')->end()
197
                        ->end()
198
                    ->end()
199
                ->end()
200
                ->arrayNode('reports')
201
                    ->children()
202
                        ->arrayNode('clover')
203
                            ->children()
204
                                ->scalarNode('name')->end()
205
                                ->scalarNode('target')->end()
206
                            ->end()
207
                        ->end()
208
                        ->arrayNode('crap4j')
209
                            ->children()
210
                                ->scalarNode('name')->end()
211
                                ->scalarNode('target')->end()
212
                            ->end()
213
                        ->end()
214
                        ->arrayNode('html')
215
                            ->children()
216
                                ->scalarNode('target')->end()
217
                                ->scalarNode('lowUpperBound')->end()
218
                                ->scalarNode('highLowerBound')->end()
219
                            ->end()
220
                        ->end()
221
                        ->arrayNode('php')
222
                            ->children()
223
                                ->scalarNode('target')->end()
224
                            ->end()
225
                        ->end()
226
                        ->arrayNode('text')
227
                            ->children()
228
                                ->booleanNode('showColors')->end()
229
                                ->scalarNode('lowUpperBound')->end()
230
                                ->scalarNode('highLowerBound')->end()
231
                                ->booleanNode('showOnlySummary')->end()
232
                                ->booleanNode('showUncoveredFiles')->end()
233
                            ->end()
234
                        ->end()
235
                        ->arrayNode('xml')
236
                            ->children()
237
                                ->scalarNode('target')->end()
238
                            ->end()
239
                        ->end()
240
                    ->end()
241
                ->end()
242
            ->end()
243
        ->end();
244
    }
245
246
    /**
247
     * {@inheritdoc}
248
     */
249
    public function getConfigKey()
250
    {
251
        return 'code_coverage';
252
    }
253
254
    /**
255
     * {@inheritdoc}
256
     */
257
    public function process(ContainerBuilder $container): void
258
    {
259
        /** @var InputInterface $input */
260
        $input = $container->get('cli.input');
261
262
        /** @var OutputInterface $output */
263
        $output = $container->get('cli.output');
264
265
        $runtime = new Runtime();
266
        $canCollectCodeCoverage = $runtime->canCollectCodeCoverage();
267
268
        if (!$canCollectCodeCoverage) {
269
            $output->writeln('<comment>No code coverage driver is available</comment>');
270
        }
271
272
        if (!$canCollectCodeCoverage || $input->hasParameterOption('--no-coverage')) {
273
            $container->getDefinition(EventListener::class)->setArgument('$coverage', null);
274
        }
275
276
        $this->setupCodeCoverageFilter($container);
277
        $this->setupCodeCoverage($container);
278
    }
279
280
    private function setupCodeCoverage(ContainerBuilder $container): void
281
    {
282
        $codeCoverage = $container->getDefinition(CodeCoverage::class);
283
        $filter = $container->getDefinition(Filter::class);
284
        $driverChoice = $container->getParameter('behat.code_coverage.config.driver');
285
286
        if ($driverChoice === 'remote') {
287
            $codeCoverage->setFactory([CodeCoverage::class, 'createWithDriverAndFilter']);
288
            $codeCoverage->setArguments([$container->getDefinition(RemoteXdebug::class), $filter]);
289
        } else {
290
            $codeCoverage->setFactory([CodeCoverage::class, 'createWithFilter']);
291
            $codeCoverage->setArguments([$filter]);
292
        }
293
294
        $config = $container->getParameter('behat.code_coverage.config.filter');
295
296
        $codeCoverage->addMethodCall(
297
            'includeUncoveredFiles',
298
            [$config['whitelist']['addUncoveredFilesFromWhitelist']]
299
        );
300
        $codeCoverage->addMethodCall(
301
            'processUncoveredFiles',
302
            [$config['whitelist']['processUncoveredFilesFromWhitelist']]
303
        );
304
    }
305
306
    private function setupCodeCoverageFilter(ContainerBuilder $container): void
307
    {
308
        $filter = $container->getDefinition(Filter::class);
309
        $config = $container->getParameter('behat.code_coverage.config.filter');
310
311
        $dirs = [
312
            'includeDirectory' => ['whitelist', 'include', 'directories'],
313
            'excludeDirectory' => ['whitelist', 'exclude', 'directories'],
314
        ];
315
316
        foreach ($dirs as $method => $hiera) {
317
            foreach ($config[$hiera[0]][$hiera[1]][$hiera[2]] as $path => $dir) {
318
                $filter->addMethodCall($method, [$path, $dir['suffix'], $dir['prefix']]);
319
            }
320
        }
321
322
        $files = [
323
            'addFileToWhiteList' => ['whitelist', 'include', 'files'],
324
            'removeFileFromWhiteList' => ['whitelist', 'exclude', 'files'],
325
        ];
326
327
        foreach ($files as $method => $hiera) {
328
            foreach ($config[$hiera[0]][$hiera[1]][$hiera[2]] as $file) {
329
                $filter->addMethodCall($method, [$file]);
330
            }
331
        }
332
    }
333
}
334