Passed
Push — master ( bf01cc...1280f5 )
by Doug
04:24
created

Extension::initCodeCoverage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 9
ccs 0
cts 5
cp 0
rs 10
cc 2
nc 2
nop 1
crap 6
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\NoCodeCoverageDriverWithPathCoverageSupportAvailableException;
21
use SebastianBergmann\Environment\Runtime;
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
29
/**
30
 * Code coverage extension.
31
 *
32
 * @author Anthon Pang <[email protected]>
33
 */
34
class Extension implements ExtensionInterface
35
{
36
    /**
37
     * @var string
38
     */
39
    private $configFolder;
40
41 8
    public function __construct()
42
    {
43 8
        $this->configFolder = __DIR__ . '/Resources/config';
44 8
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49 2
    public function initialize(ExtensionManager $extensionManager): void
50
    {
51 2
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56 2
    public function load(ContainerBuilder $container, array $config): void
57
    {
58 2
        $loader = new XmlFileLoader($container, new FileLocator($this->configFolder));
59
60 2
        $servicesFile = 'services.xml';
61 2
        $loader->load($servicesFile);
62
63 2
        $container->setParameter('behat.code_coverage.config.filter', $config['filter']);
64 2
        $container->setParameter('behat.code_coverage.config.reports', $config['reports'] ?? []);
65 2
    }
66
67
    /**
68
     * {@inheritdoc}
69
     */
70 4
    public function configure(ArrayNodeDefinition $builder): void
71
    {
72
        $builder
73 4
            ->children()
74 4
                ->arrayNode('filter')
75 4
                    ->addDefaultsIfNotSet()
76 4
                    ->children()
77 4
                        ->scalarNode('includeUncoveredFiles')
78 4
                            ->defaultTrue()
79 4
                        ->end()
80 4
                        ->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

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