Passed
Push — master ( 81cf57...885f0c )
by Doug
03:23
created

Extension::getConfigKey()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
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 Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
23
use Symfony\Component\Config\FileLocator;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Output\OutputInterface;
26
use Symfony\Component\DependencyInjection\ContainerBuilder;
27
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
28
use Symfony\Component\DependencyInjection\Reference;
29
30
/**
31
 * Code coverage extension.
32
 *
33
 * @author Anthon Pang <[email protected]>
34
 */
35
class Extension implements ExtensionInterface
36
{
37
    /**
38
     * {@inheritdoc}
39
     */
40 4
    public function initialize(ExtensionManager $extensionManager): void
41
    {
42 4
    }
43
44
    /**
45
     * {@inheritdoc}
46
     */
47 4
    public function load(ContainerBuilder $container, array $config): void
48
    {
49 4
        $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/Resources/config'));
50
51 4
        $servicesFile = 'services.xml';
52 4
        $loader->load($servicesFile);
53
54 4
        $container->setParameter('behat.code_coverage.config.filter', $config['filter']);
55 4
        $container->setParameter('behat.code_coverage.config.branchAndPathCoverage', $config['branchAndPathCoverage']);
56 4
        $container->setParameter('behat.code_coverage.config.reports', $config['reports'] ?? []);
57 4
        $container->setParameter('behat.code_coverage.config.cache', $config['cache']);
58 4
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63 8
    public function configure(ArrayNodeDefinition $builder): void
64
    {
65
        $builder
66 8
            ->children()
67 8
                ->scalarNode('cache')
68 8
                    ->defaultValue(sys_get_temp_dir() . '/behat-code-coverage-cache')
69 8
                ->end()
70 8
                ->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

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