Passed
Push — master ( d70078...23458e )
by Doug
03:21
created

Extension::process()   A

Complexity

Conditions 4
Paths 12

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 4.074

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 15
nc 12
nop 1
dl 0
loc 25
ccs 15
cts 18
cp 0.8333
crap 4.074
rs 9.7666
c 1
b 0
f 0
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 1
class Extension implements ExtensionInterface
37
{
38
    /**
39
     * {@inheritdoc}
40
     */
41 4
    public function initialize(ExtensionManager $extensionManager): void
42
    {
43 4
    }
44
45
    /**
46
     * {@inheritdoc}
47
     */
48 4
    public function load(ContainerBuilder $container, array $config): void
49
    {
50 4
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/Resources/config'));
51
52 4
        $servicesFile = 'services.xml';
53 4
        $loader->load($servicesFile);
54
55 4
        $container->setParameter('behat.code_coverage.config.filter', $config['filter']);
56 4
        $container->setParameter('behat.code_coverage.config.reports', $config['reports'] ?? []);
57 4
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62 8
    public function configure(ArrayNodeDefinition $builder): void
63
    {
64
        $builder
65 8
            ->children()
66 8
                ->arrayNode('filter')
67 8
                    ->addDefaultsIfNotSet()
68 8
                    ->children()
69 8
                        ->scalarNode('includeUncoveredFiles')
70 8
                            ->defaultTrue()
71 8
                        ->end()
72 8
                        ->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 8
                            ->defaultFalse()
74 8
                        ->end()
75 8
                        ->arrayNode('include')
76 8
                            ->addDefaultsIfNotSet()
77 8
                            ->children()
78 8
                                ->arrayNode('directories')
79 8
                                   ->useAttributeAsKey('name')
80 8
                                   ->normalizeKeys(false)
81 8
                                   ->prototype('array')
82 8
                                       ->children()
83 8
                                           ->scalarNode('prefix')->defaultValue('')->end()
84 8
                                           ->scalarNode('suffix')->defaultValue('.php')->end()
85 8
                                       ->end()
86 8
                                   ->end()
87 8
                                ->end()
88 8
                                ->arrayNode('files')
89 8
                                   ->prototype('scalar')->end()
90 8
                                ->end()
91 8
                            ->end()
92 8
                        ->end()
93 8
                        ->arrayNode('exclude')
94 8
                            ->addDefaultsIfNotSet()
95 8
                            ->children()
96 8
                                ->arrayNode('directories')
97 8
                                   ->useAttributeAsKey('name')
98 8
                                   ->normalizeKeys(false)
99 8
                                   ->prototype('array')
100 8
                                       ->children()
101 8
                                           ->scalarNode('prefix')->defaultValue('')->end()
102 8
                                           ->scalarNode('suffix')->defaultValue('.php')->end()
103 8
                                       ->end()
104 8
                                   ->end()
105 8
                                ->end()
106 8
                                ->arrayNode('files')
107 8
                                   ->prototype('scalar')->end()
108 8
                                ->end()
109 8
                            ->end()
110 8
                        ->end()
111 8
                    ->end()
112 8
                ->end()
113 8
                ->arrayNode('reports')
114 8
                    ->children()
115 8
                        ->arrayNode('clover')
116 8
                            ->children()
117 8
                                ->scalarNode('name')->defaultNull()->end()
118 8
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
119 8
                            ->end()
120 8
                        ->end()
121 8
                        ->arrayNode('crap4j')
122 8
                            ->children()
123 8
                                ->scalarNode('name')->defaultNull()->end()
124 8
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
125 8
                            ->end()
126 8
                        ->end()
127 8
                        ->arrayNode('html')
128 8
                            ->children()
129 8
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
130 8
                                ->scalarNode('lowUpperBound')->defaultValue(50)->end()
131 8
                                ->scalarNode('highLowerBound')->defaultValue(90)->end()
132 8
                            ->end()
133 8
                        ->end()
134 8
                        ->arrayNode('php')
135 8
                            ->children()
136 8
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
137 8
                            ->end()
138 8
                        ->end()
139 8
                        ->arrayNode('text')
140 8
                            ->children()
141 8
                                ->booleanNode('showColors')->defaultValue(false)->end()
142 8
                                ->scalarNode('lowUpperBound')->defaultValue(50)->end()
143 8
                                ->scalarNode('highLowerBound')->defaultValue(90)->end()
144 8
                                ->booleanNode('showOnlySummary')->defaultValue(false)->end()
145 8
                                ->booleanNode('showUncoveredFiles')->defaultValue(false)->end()
146 8
                            ->end()
147 8
                        ->end()
148 8
                        ->arrayNode('xml')
149 8
                            ->children()
150 8
                                ->scalarNode('target')->isRequired()->cannotBeEmpty()->end()
151 8
                            ->end()
152 8
                        ->end()
153 8
                    ->end()
154 8
                ->end()
155 8
            ->end()
156 8
        ->end();
157 8
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162 8
    public function getConfigKey()
163
    {
164 8
        return 'code_coverage';
165
    }
166
167
    /**
168
     * {@inheritdoc}
169
     */
170 16
    public function process(ContainerBuilder $container): void
171
    {
172
        /** @var InputInterface $input */
173 16
        $input = $container->get('cli.input');
174
175
        /** @var OutputInterface $output */
176 16
        $output = $container->get('cli.output');
177
178 16
        $config = $container->getParameter('behat.code_coverage.config.filter');
179
180 16
        $canCollectCodeCoverage = true;
181
        try {
182 16
            $this->initCodeCoverage(new Filter(), $config);
183
184 12
            $codeCoverage = $container->getDefinition(CodeCoverage::class);
185 12
            $filter = $container->getDefinition(Filter::class);
186 12
            $codeCoverage->setFactory([new Reference(self::class), 'initCodeCoverage']);
187 12
            $codeCoverage->setArguments([$filter, $config]);
188 4
        } catch (NoCodeCoverageDriverAvailableException | RuntimeException $e) {
189 4
            $output->writeln('<comment>No code coverage driver is available</comment>');
190 4
            $canCollectCodeCoverage = false;
191
        }
192
193 16
        if (!$canCollectCodeCoverage || $input->hasParameterOption('--no-coverage')) {
194 8
            $container->getDefinition(EventSubscriber::class)->setArgument('$coverage', null);
195
        }
196 16
    }
197
198 12
    public function initCodeCoverage(Filter $filter, array $config): CodeCoverage
199
    {
200 12
        $driverClassReflection = new \ReflectionClass(Driver::class);
201 12
        if ($driverClassReflection->isInterface()) {
202 6
            return $this->initCodeCoverageV678($filter, $config);
203
        }
204
205 6
        return $this->initCodeCoverageV9($filter, $config);
206
    }
207
208 6
    public function initCodeCoverageV9(Filter $filter, array $config): CodeCoverage
209
    {
210
        // set up filter
211 6
        array_walk($config['include']['directories'], static function (array $dir, string $path, Filter $filter): void {
212 6
            $filter->includeDirectory($path, $dir['suffix'], $dir['prefix']);
213 6
        }, $filter);
214
215 6
        array_walk($config['include']['files'], static function (string $file, string $key, Filter $filter): void {
216 6
            $filter->includeFile($file);
217 6
        }, $filter);
218
219 6
        array_walk($config['exclude']['directories'], static function (array $dir, string $path, Filter $filter): void {
220 6
            $filter->excludeDirectory($path, $dir['suffix'], $dir['prefix']);
221 6
        }, $filter);
222
223 6
        array_walk($config['exclude']['files'], static function (string $file, string $key, Filter $filter): void {
224 6
            $filter->excludeFile($file);
225 6
        }, $filter);
226
227
        // see if we can get a driver
228
        try {
229 6
            $driver = Driver::forLineAndPathCoverage($filter);
230 3
        } catch (NoCodeCoverageDriverWithPathCoverageSupportAvailableException $e) {
231 3
            $driver = Driver::forLineCoverage($filter);
232
        }
233
234
        // and init coverage
235 6
        $codeCoverage = new CodeCoverage($driver, $filter);
236
237 6
        if ($config['includeUncoveredFiles']) {
238 2
            $codeCoverage->includeUncoveredFiles();
239
        } else {
240 4
            $codeCoverage->excludeUncoveredFiles();
241
        }
242
243 6
        if ($config['processUncoveredFiles']) {
244 2
            $codeCoverage->processUncoveredFiles();
245
        } else {
246 4
            $codeCoverage->doNotProcessUncoveredFiles();
247
        }
248
249 6
        return $codeCoverage;
250
    }
251
252 6
    public function initCodeCoverageV678(Filter $filter, array $config): CodeCoverage
253
    {
254
        // set up filter
255
        array_walk($config['include']['directories'], static function (array $dir, string $path, Filter $filter): void {
256 6
            $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 6
        }, $filter);
258
259
        array_walk($config['include']['files'], static function (string $file, string $key, Filter $filter): void {
260 6
            $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 6
        }, $filter);
262
263
        array_walk($config['exclude']['directories'], static function (array $dir, string $path, Filter $filter): void {
264 6
            $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 6
        }, $filter);
266
267
        array_walk($config['exclude']['files'], static function (string $file, string $key, Filter $filter): void {
268 6
            $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 6
        }, $filter);
270
271
        // and init coverage
272 6
        $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 6
        $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 6
        $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 6
        return $codeCoverage;
278
    }
279
}
280