Passed
Push — master ( 1e5789...d61c3b )
by Doug
03:37
created

Extension::setupCodeCoverage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 1

Importance

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