Passed
Push — master ( f5dfbe...1545ea )
by Doug
10:29
created

Extension::initCodeCoverage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.3149

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 8
ccs 4
cts 7
cp 0.5714
crap 2.3149
rs 10
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\Subscriber\EventSubscriber;
17
use SebastianBergmann\CodeCoverage\CodeCoverage;
18
use SebastianBergmann\CodeCoverage\Driver\Driver;
19
use SebastianBergmann\CodeCoverage\Filter;
20
use SebastianBergmann\CodeCoverage\NoCodeCoverageDriverAvailableException;
21
use SebastianBergmann\CodeCoverage\NoCodeCoverageDriverWithPathCoverageSupportAvailableException;
22
use SebastianBergmann\CodeCoverage\RuntimeException;
0 ignored issues
show
Bug introduced by
The type SebastianBergmann\CodeCoverage\RuntimeException 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...
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\OutputInterface;
27
use Symfony\Component\DependencyInjection\ContainerBuilder;
28
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
29
use Symfony\Component\DependencyInjection\Reference;
30
31
/**
32
 * Code coverage extension.
33
 *
34
 * @author Anthon Pang <[email protected]>
35
 */
36
class Extension implements ExtensionInterface
37
{
38
    /**
39
     * {@inheritdoc}
40
     */
41 24
    public function initialize(ExtensionManager $extensionManager): void
42
    {
43 24
    }
44
45
    /**
46
     * {@inheritdoc}
47
     */
48 24
    public function load(ContainerBuilder $container, array $config): void
49
    {
50 24
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/Resources/config'));
51
52 24
        $servicesFile = 'services.xml';
53 24
        $loader->load($servicesFile);
54
55 24
        $container->setParameter('behat.code_coverage.config.filter', $config['filter']);
56 24
        $container->setParameter('behat.code_coverage.config.reports', $config['reports'] ?? []);
57 24
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62 48
    public function configure(ArrayNodeDefinition $builder): void
63
    {
64
        $builder
65 48
            ->children()
66 48
                ->arrayNode('filter')
67 48
                    ->addDefaultsIfNotSet()
68 48
                    ->children()
69 48
                        ->scalarNode('includeUncoveredFiles')
70 48
                            ->defaultTrue()
71 48
                        ->end()
72 48
                        ->scalarNode('processUncoveredFiles')
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

72
                        ->/** @scrutinizer ignore-call */ scalarNode('processUncoveredFiles')
Loading history...
73 48
                            ->defaultFalse()
74 48
                        ->end()
75 48
                        ->arrayNode('include')
76 48
                            ->addDefaultsIfNotSet()
77 48
                            ->children()
78 48
                                ->arrayNode('directories')
79 48
                                   ->useAttributeAsKey('name')
80 48
                                   ->normalizeKeys(false)
81 48
                                   ->prototype('array')
82 48
                                       ->children()
83 48
                                           ->scalarNode('prefix')->defaultValue('')->end()
84 48
                                           ->scalarNode('suffix')->defaultValue('.php')->end()
85 48
                                       ->end()
86 48
                                   ->end()
87 48
                                ->end()
88 48
                                ->arrayNode('files')
89 48
                                   ->prototype('scalar')->end()
90 48
                                ->end()
91 48
                            ->end()
92 48
                        ->end()
93 48
                        ->arrayNode('exclude')
94 48
                            ->addDefaultsIfNotSet()
95 48
                            ->children()
96 48
                                ->arrayNode('directories')
97 48
                                   ->useAttributeAsKey('name')
98 48
                                   ->normalizeKeys(false)
99 48
                                   ->prototype('array')
100 48
                                       ->children()
101 48
                                           ->scalarNode('prefix')->defaultValue('')->end()
102 48
                                           ->scalarNode('suffix')->defaultValue('.php')->end()
103 48
                                       ->end()
104 48
                                   ->end()
105 48
                                ->end()
106 48
                                ->arrayNode('files')
107 48
                                   ->prototype('scalar')->end()
108 48
                                ->end()
109 48
                            ->end()
110 48
                        ->end()
111 48
                    ->end()
112 48
                ->end()
113 48
                ->arrayNode('reports')
114 48
                    ->children()
115 48
                        ->arrayNode('clover')
116 48
                            ->children()
117 48
                                ->scalarNode('name')->defaultNull()->end()
118 48
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
119 48
                            ->end()
120 48
                        ->end()
121 48
                        ->arrayNode('crap4j')
122 48
                            ->children()
123 48
                                ->scalarNode('name')->defaultNull()->end()
124 48
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
125 48
                            ->end()
126 48
                        ->end()
127 48
                        ->arrayNode('html')
128 48
                            ->children()
129 48
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
130 48
                                ->scalarNode('lowUpperBound')->defaultValue(50)->end()
131 48
                                ->scalarNode('highLowerBound')->defaultValue(90)->end()
132 48
                            ->end()
133 48
                        ->end()
134 48
                        ->arrayNode('php')
135 48
                            ->children()
136 48
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
137 48
                            ->end()
138 48
                        ->end()
139 48
                        ->arrayNode('text')
140 48
                            ->children()
141 48
                                ->booleanNode('showColors')->defaultValue(false)->end()
142 48
                                ->scalarNode('lowUpperBound')->defaultValue(50)->end()
143 48
                                ->scalarNode('highLowerBound')->defaultValue(90)->end()
144 48
                                ->booleanNode('showOnlySummary')->defaultValue(false)->end()
145 48
                                ->booleanNode('showUncoveredFiles')->defaultValue(false)->end()
146 48
                            ->end()
147 48
                        ->end()
148 48
                        ->arrayNode('xml')
149 48
                            ->children()
150 48
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
151 48
                            ->end()
152 48
                        ->end()
153 48
                    ->end()
154 48
                ->end()
155 48
            ->end()
156 48
        ->end();
157 48
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162 48
    public function getConfigKey()
163
    {
164 48
        return 'code_coverage';
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170 96
    public function process(ContainerBuilder $container): void
171
    {
172
        /** @var InputInterface $input */
173 96
        $input = $container->get('cli.input');
174
175
        /** @var OutputInterface $output */
176 96
        $output = $container->get('cli.output');
177
178 96
        $config = $container->getParameter('behat.code_coverage.config.filter');
179
180 96
        $canCollectCodeCoverage = true;
181
        try {
182 96
            $this->initCodeCoverage(new Filter(), $config);
183
184 72
            $codeCoverage = $container->getDefinition(CodeCoverage::class);
185 72
            $filter = $container->getDefinition(Filter::class);
186 72
            $codeCoverage->setFactory([new Reference(self::class), 'initCodeCoverage']);
187 72
            $codeCoverage->setArguments([$filter, $config]);
188 24
        } catch (NoCodeCoverageDriverAvailableException | RuntimeException $e) {
189 24
            $output->writeln('<comment>No code coverage driver is available</comment>');
190 24
            $canCollectCodeCoverage = false;
191
        }
192
193 96
        if (!$canCollectCodeCoverage || $input->hasParameterOption('--no-coverage')) {
194 48
            $container->getDefinition(EventSubscriber::class)->setArgument('$coverage', null);
195
        }
196 96
    }
197
198 72
    public function initCodeCoverage(Filter $filter, array $config): CodeCoverage
199
    {
200 72
        $driverClassReflection = new \ReflectionClass(Driver::class);
201 72
        if ($driverClassReflection->isInterface()) {
202 72
            return $this->initCodeCoverageV678($filter, $config);
203
        }
204
205
        return $this->initCodeCoverageV9($filter, $config);
206
    }
207
208
    public function initCodeCoverageV9(Filter $filter, array $config): CodeCoverage
209
    {
210
        // set up filter
211
        array_walk($config['include']['directories'], static function (array $dir, string $path, Filter $filter): void {
212
            $filter->includeDirectory($path, $dir['suffix'], $dir['prefix']);
213
        }, $filter);
214
215
        array_walk($config['include']['files'], static function (string $file, string $key, Filter $filter): void {
216
            $filter->includeFile($file);
217
        }, $filter);
218
219
        array_walk($config['exclude']['directories'], static function (array $dir, string $path, Filter $filter): void {
220
            $filter->excludeDirectory($path, $dir['suffix'], $dir['prefix']);
221
        }, $filter);
222
223
        array_walk($config['exclude']['files'], static function (string $file, string $key, Filter $filter): void {
224
            $filter->excludeFile($file);
225
        }, $filter);
226
227
        // see if we can get a driver
228
        try {
229
            $driver = Driver::forLineAndPathCoverage($filter);
230
        } catch (NoCodeCoverageDriverWithPathCoverageSupportAvailableException $e) {
231
            $driver = Driver::forLineCoverage($filter);
232
        }
233
234
        // and init coverage
235
        $codeCoverage = new CodeCoverage($driver, $filter);
236
237
        if ($config['includeUncoveredFiles']) {
238
            $codeCoverage->includeUncoveredFiles();
239
        } else {
240
            $codeCoverage->excludeUncoveredFiles();
241
        }
242
243
        if ($config['processUncoveredFiles']) {
244
            $codeCoverage->processUncoveredFiles();
245
        } else {
246
            $codeCoverage->doNotProcessUncoveredFiles();
247
        }
248
249
        return $codeCoverage;
250
    }
251
252 63
    public function initCodeCoverageV678(Filter $filter, array $config): CodeCoverage
253
    {
254
        // set up filter
255 21
        array_walk($config['include']['directories'], static function (array $dir, string $path, Filter $filter): void {
256 72
            $filter->addDirectoryToWhitelist($path, $dir['suffix'], $dir['prefix']);
0 ignored issues
show
Bug introduced by
The method addDirectoryToWhitelist() does not exist on SebastianBergmann\CodeCoverage\Filter. ( Ignorable by Annotation )

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

256
            $filter->/** @scrutinizer ignore-call */ 
257
                     addDirectoryToWhitelist($path, $dir['suffix'], $dir['prefix']);

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...
257 72
        }, $filter);
258
259 21
        array_walk($config['include']['files'], static function (string $file, string $key, Filter $filter): void {
260 72
            $filter->addFileToWhitelist($file);
0 ignored issues
show
Bug introduced by
The method addFileToWhitelist() does not exist on SebastianBergmann\CodeCoverage\Filter. ( Ignorable by Annotation )

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

260
            $filter->/** @scrutinizer ignore-call */ 
261
                     addFileToWhitelist($file);

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...
261 72
        }, $filter);
262
263 21
        array_walk($config['exclude']['directories'], static function (array $dir, string $path, Filter $filter): void {
264 72
            $filter->removeDirectoryFromWhitelist($path, $dir['suffix'], $dir['prefix']);
0 ignored issues
show
Bug introduced by
The method removeDirectoryFromWhitelist() does not exist on SebastianBergmann\CodeCoverage\Filter. ( Ignorable by Annotation )

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

264
            $filter->/** @scrutinizer ignore-call */ 
265
                     removeDirectoryFromWhitelist($path, $dir['suffix'], $dir['prefix']);

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...
265 72
        }, $filter);
266
267 21
        array_walk($config['exclude']['files'], static function (string $file, string $key, Filter $filter): void {
268 72
            $filter->removeFileFromWhitelist($file);
0 ignored issues
show
Bug introduced by
The method removeFileFromWhitelist() does not exist on SebastianBergmann\CodeCoverage\Filter. ( Ignorable by Annotation )

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

268
            $filter->/** @scrutinizer ignore-call */ 
269
                     removeFileFromWhitelist($file);

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...
269 72
        }, $filter);
270
271
        // and init coverage
272 72
        $codeCoverage = new CodeCoverage(null, $filter);
0 ignored issues
show
Bug introduced by
null of type null is incompatible with the type SebastianBergmann\CodeCoverage\Driver\Driver expected by parameter $driver of SebastianBergmann\CodeCo...Coverage::__construct(). ( Ignorable by Annotation )

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

272
        $codeCoverage = new CodeCoverage(/** @scrutinizer ignore-type */ null, $filter);
Loading history...
273
274 72
        $codeCoverage->setAddUncoveredFilesFromWhitelist($config['includeUncoveredFiles']);
0 ignored issues
show
Bug introduced by
The method setAddUncoveredFilesFromWhitelist() 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

274
        $codeCoverage->/** @scrutinizer ignore-call */ 
275
                       setAddUncoveredFilesFromWhitelist($config['includeUncoveredFiles']);

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...
275 72
        $codeCoverage->setProcessUncoveredFilesFromWhitelist($config['processUncoveredFiles']);
0 ignored issues
show
Bug introduced by
The method setProcessUncoveredFilesFromWhitelist() 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

275
        $codeCoverage->/** @scrutinizer ignore-call */ 
276
                       setProcessUncoveredFilesFromWhitelist($config['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...
276
277 72
        return $codeCoverage;
278
    }
279
}
280