Extension::initCodeCoverage()   F
last analyzed

Complexity

Conditions 12
Paths 576

Size

Total Lines 54
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 12.0585

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 12
eloc 28
c 5
b 0
f 0
nc 576
nop 5
dl 0
loc 54
ccs 25
cts 27
cp 0.9259
crap 12.0585
rs 3.3888

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Behat Code Coverage
4
 */
5
declare(strict_types=1);
6
7
namespace DVDoug\Behat\CodeCoverage;
8
9
use Behat\Testwork\Cli\Controller;
10
use Behat\Testwork\Cli\ServiceContainer\CliExtension;
11
use Behat\Testwork\EventDispatcher\ServiceContainer\EventDispatcherExtension;
12
use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface;
13
use Behat\Testwork\ServiceContainer\ExtensionManager;
14
use DVDoug\Behat\CodeCoverage\Subscriber\EventSubscriber;
15
use SebastianBergmann\CodeCoverage\CodeCoverage;
16
use SebastianBergmann\CodeCoverage\Driver\Selector;
17
use SebastianBergmann\CodeCoverage\Driver\XdebugNotAvailableException;
18
use SebastianBergmann\CodeCoverage\Driver\XdebugNotEnabledException;
19
use SebastianBergmann\CodeCoverage\Filter;
20
use SebastianBergmann\CodeCoverage\NoCodeCoverageDriverAvailableException;
21
use SebastianBergmann\CodeCoverage\NoCodeCoverageDriverWithPathCoverageSupportAvailableException;
22
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
23
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
24
use Symfony\Component\Config\FileLocator;
25
use Symfony\Component\Console\Input\InputInterface;
26
use Symfony\Component\Console\Output\ConsoleOutputInterface;
27
use Symfony\Component\Console\Output\OutputInterface;
28
use Symfony\Component\DependencyInjection\ContainerBuilder;
29
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
30
use Symfony\Component\DependencyInjection\Reference;
31
32
use function sprintf;
33
use function sys_get_temp_dir;
34
use function realpath;
35
36
class Extension implements ExtensionInterface
37
{
38 37
    public function initialize(ExtensionManager $extensionManager): void
39
    {
40 37
    }
41
42 37
    public function load(ContainerBuilder $container, array $config): void
43
    {
44 37
        $container->registerForAutoconfiguration(Controller::class)->addTag(CliExtension::CONTROLLER_TAG);
45 37
        $container->registerForAutoconfiguration(EventSubscriber::class)->addTag(EventDispatcherExtension::SUBSCRIBER_TAG);
46
47 37
        $loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../config'));
48 37
        $loader->load('services.php');
49
50 37
        $container->setParameter('behat.code_coverage.config.filter', $config['filter']);
51 37
        $container->setParameter('behat.code_coverage.config.branchAndPathCoverage', $config['branchAndPathCoverage']);
52 37
        $container->setParameter('behat.code_coverage.config.reports', $config['reports'] ?? []);
53 37
        $container->setParameter('behat.code_coverage.config.cache', $config['cache']);
54
    }
55
56 74
    public function configure(ArrayNodeDefinition $builder): void
57
    {
58 74
        $builder
59 74
            ->children()
60 74
                ->scalarNode('cache')
61 74
                    ->defaultValue(sys_get_temp_dir() . '/behat-code-coverage-cache')
62 74
                ->end()
63 74
                ->booleanNode('branchAndPathCoverage')
0 ignored issues
show
Bug introduced by
The method booleanNode() 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

63
                ->/** @scrutinizer ignore-call */ booleanNode('branchAndPathCoverage')
Loading history...
64 74
                  ->defaultNull() // use null to mean auto
65 74
                ->end()
66 74
                ->arrayNode('filter')
67 74
                    ->addDefaultsIfNotSet()
68 74
                    ->children()
69 74
                        ->scalarNode('includeUncoveredFiles')
70 74
                            ->defaultTrue()
71 74
                        ->end()
72 74
                        ->scalarNode('processUncoveredFiles')
73 74
                            ->defaultFalse()
74 74
                            ->setDeprecated('dvdoug/behat-code-coverage', '5.3', 'the processUncoveredFiles setting is deprecated, it has been removed from php-code-coverage v10')
75 74
                        ->end()
76 74
                        ->arrayNode('include')
77 74
                            ->addDefaultsIfNotSet()
78 74
                            ->children()
79 74
                                ->arrayNode('directories')
80 74
                                   ->useAttributeAsKey('name')
81 74
                                   ->normalizeKeys(false)
82 74
                                   ->prototype('array')
83 74
                                       ->children()
84 74
                                           ->scalarNode('prefix')->defaultValue('')->end()
85 74
                                           ->scalarNode('suffix')->defaultValue('.php')->end()
86 74
                                       ->end()
87 74
                                   ->end()
88 74
                                ->end()
89 74
                                ->arrayNode('files')
90 74
                                   ->prototype('scalar')->end()
91 74
                                ->end()
92 74
                            ->end()
93 74
                        ->end()
94 74
                        ->arrayNode('exclude')
95 74
                            ->addDefaultsIfNotSet()
96 74
                            ->children()
97 74
                                ->arrayNode('directories')
98 74
                                   ->useAttributeAsKey('name')
99 74
                                   ->normalizeKeys(false)
100 74
                                   ->prototype('array')
101 74
                                       ->children()
102 74
                                           ->scalarNode('prefix')->defaultValue('')->end()
103 74
                                           ->scalarNode('suffix')->defaultValue('.php')->end()
104 74
                                       ->end()
105 74
                                   ->end()
106 74
                                ->end()
107 74
                                ->arrayNode('files')
108 74
                                   ->prototype('scalar')->end()
109 74
                                ->end()
110 74
                            ->end()
111 74
                        ->end()
112 74
                    ->end()
113 74
                ->end()
114 74
                ->arrayNode('reports')
115 74
                    ->children()
116 74
                        ->arrayNode('cobertura')
117 74
                            ->children()
118 74
                                ->scalarNode('name')->defaultNull()->end()
119 74
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
120 74
                            ->end()
121 74
                        ->end()
122 74
                        ->arrayNode('clover')
123 74
                            ->children()
124 74
                                ->scalarNode('name')->defaultNull()->end()
125 74
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
126 74
                            ->end()
127 74
                        ->end()
128 74
                        ->arrayNode('crap4j')
129 74
                            ->children()
130 74
                                ->scalarNode('name')->defaultNull()->end()
131 74
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
132 74
                            ->end()
133 74
                        ->end()
134 74
                        ->arrayNode('html')
135 74
                            ->children()
136 74
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
137 74
                                ->scalarNode('lowUpperBound')->defaultValue(50)->end()
138 74
                                ->scalarNode('highLowerBound')->defaultValue(90)->end()
139 74
                                ->arrayNode('colors')
140 74
                                    ->addDefaultsIfNotSet()
141 74
                                    ->children()
142 74
                                        ->scalarNode('successLow')->defaultValue('#dff0d8')->end()
143 74
                                        ->scalarNode('successMedium')->defaultValue('#c3e3b5')->end()
144 74
                                        ->scalarNode('successHigh')->defaultValue('#99cb84')->end()
145 74
                                        ->scalarNode('warning')->defaultValue('#fcf8e3')->end()
146 74
                                        ->scalarNode('danger')->defaultValue('#f2dede')->end()
147 74
                                    ->end()
148 74
                                ->end()
149 74
                                ->scalarNode('customCSSFile')->defaultNull()->end()
150 74
                            ->end()
151 74
                        ->end()
152 74
                        ->arrayNode('php')
153 74
                            ->children()
154 74
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
155 74
                            ->end()
156 74
                        ->end()
157 74
                        ->arrayNode('text')
158 74
                            ->children()
159 74
                                ->booleanNode('showColors')->defaultValue(false)->end()
160 74
                                ->scalarNode('lowUpperBound')->defaultValue(50)->end()
161 74
                                ->scalarNode('highLowerBound')->defaultValue(90)->end()
162 74
                                ->booleanNode('showOnlySummary')->defaultValue(false)->end()
163 74
                                ->booleanNode('showUncoveredFiles')->defaultValue(false)->end()
164 74
                            ->end()
165 74
                        ->end()
166 74
                        ->arrayNode('xml')
167 74
                            ->children()
168 74
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
169 74
                            ->end()
170 74
                        ->end()
171 74
                    ->end()
172 74
                ->end()
173 74
            ->end()
174 74
        ->end();
175
    }
176
177 74
    public function getConfigKey()
178
    {
179 74
        return 'code_coverage';
180
    }
181
182 148
    public function process(ContainerBuilder $container): void
183
    {
184
        /** @var InputInterface $input */
185 148
        $input = $container->get(CliExtension::INPUT_ID);
186
187
        /** @var OutputInterface $output */
188 148
        $output = $container->get(CliExtension::OUTPUT_ID);
189
190 148
        if ($output instanceof ConsoleOutputInterface) {
191
            $output = $output->getErrorOutput();
192
        }
193
194 148
        $filterConfig = $container->getParameter('behat.code_coverage.config.filter');
195 148
        $branchPathConfig = $container->getParameter('behat.code_coverage.config.branchAndPathCoverage');
196 148
        $cacheDir = $container->getParameter('behat.code_coverage.config.cache');
197
198 148
        $canCollectCodeCoverage = !$input->hasParameterOption('--no-coverage');
199 148
        if ($canCollectCodeCoverage) {
200
            try {
201 111
                $this->initCodeCoverage(new Filter(), $filterConfig, $branchPathConfig, $cacheDir, $output);
202
203 74
                $codeCoverageDefinition = $container->getDefinition(CodeCoverage::class);
204 74
                $filterDefinition = $container->getDefinition(Filter::class);
205 74
                $codeCoverageDefinition->setFactory([new Reference(self::class), 'initCodeCoverage']);
206 74
                $codeCoverageDefinition->setArguments([$filterDefinition, $filterConfig, $branchPathConfig, $cacheDir, $output]);
207 37
            } catch (NoCodeCoverageDriverAvailableException|XdebugNotEnabledException|XdebugNotAvailableException $e) {
208 37
                $output->writeln("<comment>{$e->getMessage()}</comment>");
209 37
                $canCollectCodeCoverage = false;
210
            }
211
        }
212
213 148
        if (!$canCollectCodeCoverage) {
214 74
            $container->getDefinition(EventSubscriber::class)->setArgument('$coverage', null);
215
        }
216
    }
217
218 74
    public function initCodeCoverage(Filter $filter, array $filterConfig, ?bool $branchPathConfig, string $cacheDir, OutputInterface $output): CodeCoverage
219
    {
220
        // set up filter
221 74
        $files = [];
222
223 74
        foreach ($filterConfig['include']['directories'] as $directoryToInclude => $details) {
224 74
            foreach ((new FileIteratorFacade())->getFilesAsArray($directoryToInclude, $details['suffix'], $details['prefix']) as $fileToInclude) {
225
                $files[realpath($fileToInclude)] = realpath($fileToInclude);
226
            }
227
        }
228
229 74
        foreach ($filterConfig['include']['files'] as $fileToInclude) {
230 74
            $files[$fileToInclude] = $fileToInclude;
231
        }
232
233 74
        foreach ($filterConfig['exclude']['directories'] as $directoryToExclude => $details) {
234 74
            foreach ((new FileIteratorFacade())->getFilesAsArray($directoryToExclude, $details['suffix'], $details['prefix']) as $fileToExclude) {
235
                unset($files[$fileToExclude]);
236
            }
237
        }
238
239 74
        foreach ($filterConfig['exclude']['files'] as $fileToExclude) {
240 74
            unset($files[realpath($fileToExclude)]);
241
        }
242
243 74
        foreach ($files as $file) {
244 74
            $filter->includeFile($file);
245
        }
246
247
        // see if we can get a driver
248 74
        $selector = new Selector();
249 74
        $driver = $selector->forLineCoverage($filter);
250 74
        if ($branchPathConfig !== false) {
251
            try {
252 37
                $driver = $selector->forLineAndPathCoverage($filter);
253 19
            } catch (NoCodeCoverageDriverWithPathCoverageSupportAvailableException|XdebugNotAvailableException|XdebugNotEnabledException $e) {
254
                // fallback driver is already set
255 19
                if ($branchPathConfig === true) { // only warn if explicitly enabled
0 ignored issues
show
introduced by
The condition $branchPathConfig === true is always true.
Loading history...
256 19
                    $output->writeln(sprintf('<info>%s does not support collecting branch and path data</info>', $driver->nameAndVersion()));
257
                }
258
            }
259
        }
260
261
        // and init coverage
262 74
        $codeCoverage = new CodeCoverage($driver, $filter);
263 74
        $codeCoverage->cacheStaticAnalysis($cacheDir);
264
265 74
        if ($filterConfig['includeUncoveredFiles']) {
266 37
            $codeCoverage->includeUncoveredFiles();
267
        } else {
268 37
            $codeCoverage->excludeUncoveredFiles();
269
        }
270
271 74
        return $codeCoverage;
272
    }
273
}
274