Passed
Pull Request — master (#22)
by
unknown
14:48 queued 12:08
created

Extension::initCodeCoverage()   F

Complexity

Conditions 14
Paths 1728

Size

Total Lines 62
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 28
CRAP Score 15.0776

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 14
eloc 33
c 4
b 0
f 0
nc 1728
nop 5
dl 0
loc 62
ccs 28
cts 34
cp 0.8235
crap 15.0776
rs 2.1

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 Composer\InstalledVersions;
15
use Composer\Semver\VersionParser;
16
use DVDoug\Behat\CodeCoverage\Subscriber\EventSubscriber;
17
use SebastianBergmann\CodeCoverage\CodeCoverage;
18
use SebastianBergmann\CodeCoverage\Driver\Selector;
19
use SebastianBergmann\CodeCoverage\Driver\Xdebug2NotEnabledException;
0 ignored issues
show
Bug introduced by
The type SebastianBergmann\CodeCo...bug2NotEnabledException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use SebastianBergmann\CodeCoverage\Driver\Xdebug3NotEnabledException;
0 ignored issues
show
Bug introduced by
The type SebastianBergmann\CodeCo...bug3NotEnabledException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use SebastianBergmann\CodeCoverage\Driver\XdebugNotAvailableException;
22
use SebastianBergmann\CodeCoverage\Driver\XdebugNotEnabledException;
23
use SebastianBergmann\CodeCoverage\Filter;
24
use SebastianBergmann\CodeCoverage\NoCodeCoverageDriverAvailableException;
25
use SebastianBergmann\CodeCoverage\NoCodeCoverageDriverWithPathCoverageSupportAvailableException;
26
use SebastianBergmann\FileIterator\Facade as FileIteratorFacade;
27
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
28
use Symfony\Component\Config\FileLocator;
29
use Symfony\Component\Console\Input\InputInterface;
30
use Symfony\Component\Console\Output\OutputInterface;
31
use Symfony\Component\DependencyInjection\ContainerBuilder;
32
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
33
use Symfony\Component\DependencyInjection\Reference;
34
35
use function sprintf;
36
use function sys_get_temp_dir;
37
38
class Extension implements ExtensionInterface
39
{
40 27
    public function initialize(ExtensionManager $extensionManager): void
41
    {
42 27
    }
43
44 35
    public function load(ContainerBuilder $container, array $config): void
45
    {
46 35
        $container->registerForAutoconfiguration(Controller::class)->addTag(CliExtension::CONTROLLER_TAG);
47 35
        $container->registerForAutoconfiguration(EventSubscriber::class)->addTag(EventDispatcherExtension::SUBSCRIBER_TAG);
48
49 35
        $loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../config'));
50 35
        $loader->load('services.php');
51
52 35
        $container->setParameter('behat.code_coverage.config.filter', $config['filter']);
53 35
        $container->setParameter('behat.code_coverage.config.branchAndPathCoverage', $config['branchAndPathCoverage']);
54 35
        $container->setParameter('behat.code_coverage.config.reports', $config['reports'] ?? []);
55 35
        $container->setParameter('behat.code_coverage.config.cache', $config['cache']);
56
    }
57
58 70
    public function configure(ArrayNodeDefinition $builder): void
59
    {
60 54
        $builder
61 70
            ->children()
62 70
                ->scalarNode('cache')
63 70
                    ->defaultValue(sys_get_temp_dir() . '/behat-code-coverage-cache')
64 70
                ->end()
65 70
                ->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

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

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

269
                $codeCoverage->/** @scrutinizer ignore-call */ 
270
                               processUncoveredFiles();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
270
            } else {
271 44
                $codeCoverage->doNotProcessUncoveredFiles();
0 ignored issues
show
Bug introduced by
The method doNotProcessUncoveredFiles() does not exist on SebastianBergmann\CodeCoverage\CodeCoverage. ( Ignorable by Annotation )

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

271
                $codeCoverage->/** @scrutinizer ignore-call */ 
272
                               doNotProcessUncoveredFiles();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
272
            }
273
        }
274
275 105
        return $codeCoverage;
276
    }
277
}
278