├── .gitignore
├── features
├── test.feature
└── bootstrap
│ └── FeatureContext.php
├── .travis.yml
├── .editorconfig
├── init.php
├── behat.yml.dist
├── phpcs.xml
├── src
├── Common
│ ├── ReportInterface.php
│ ├── Report
│ │ ├── Factory.php
│ │ ├── Php.php
│ │ ├── Clover.php
│ │ ├── Xml.php
│ │ ├── Crap4j.php
│ │ ├── Html.php
│ │ └── Text.php
│ ├── Driver
│ │ ├── Factory.php
│ │ ├── Stub.php
│ │ ├── HHVM.php
│ │ └── XCache.php
│ └── Model
│ │ └── Aggregate.php
├── Controller
│ └── Cli
│ │ └── CodeCoverageController.php
├── Compiler
│ ├── FactoryPass.php
│ ├── DriverPass.php
│ └── FilterPass.php
├── Service
│ └── ReportService.php
├── Driver
│ ├── Proxy.php
│ └── RemoteXdebug.php
├── Listener
│ └── EventListener.php
├── Resources
│ └── config
│ │ ├── services.xml
│ │ └── services-2.3.xml
└── Extension.php
├── autoload.php
├── phpunit.xml.dist
├── tests
├── Common
│ ├── Report
│ │ ├── CloverTest.php
│ │ ├── TextTest.php
│ │ ├── PhpTest.php
│ │ ├── Crap4jTest.php
│ │ ├── HtmlTest.php
│ │ ├── XmlTest.php
│ │ └── FactoryTest.php
│ ├── Driver
│ │ ├── HHVMTest.php
│ │ ├── FactoryTest.php
│ │ ├── StubTest.php
│ │ └── XCacheTest.php
│ └── Model
│ │ └── AggregateTest.php
├── Service
│ └── ReportServiceTest.php
├── Driver
│ ├── ProxyTest.php
│ └── RemoteXdebugTest.php
├── Compiler
│ ├── DriverPassTest.php
│ ├── FactoryPassTest.php
│ └── FilterPassTest.php
├── VIPSoft
│ └── TestCase.php
├── Listener
│ └── EventListenerTest.php
└── ExtensionTest.php
├── LICENSE
├── composer.json
├── .appveyor.yml
├── CHANGELOG.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | bin/
2 | nbproject/
3 | vendor/
4 | build/
5 | composer.phar
6 | **/*.dbf
7 | /composer.lock
8 |
--------------------------------------------------------------------------------
/features/test.feature:
--------------------------------------------------------------------------------
1 | Feature: Listing command
2 | In order to change the structure of the folder I am currently in
3 | As a UNIX user
4 | I need to be able see the currently available files and folders there
5 |
6 | Scenario: Listing two files in a directory
7 | Given I am in a directory "test"
8 | When I run "ls"
9 | Then I should get "bla"
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | matrix:
4 | include:
5 | - php: 7.1
6 | - php: 7.1
7 | deps: low
8 | - php: 7.2
9 | - php: 7.2
10 | deps: low
11 |
12 | before_script:
13 | - composer validate
14 | - if [[ $deps = low ]]; then composer update --prefer-lowest --prefer-stable; else composer update; fi
15 |
16 | script:
17 | - ./bin/phpcs
18 | - ./bin/phpunit -vvv
19 |
20 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 |
11 | # Matches multiple files with brace expansion notation
12 | # Set default charset
13 | [*.{json,php}]
14 | charset = utf-8
15 | indent_style = space
16 | indent_size = 4
17 |
18 | [*.{yml,yaml}]
19 | indent_style = space
20 | indent_size = 2
21 |
22 |
--------------------------------------------------------------------------------
/init.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * This source file is subject to the MIT license that is bundled
9 | * with this source code in the file LICENSE.
10 | */
11 |
12 | spl_autoload_register(function($class) {
13 | if (false !== strpos($class, 'LeanPHP\\Behat\\CodeCoverage')) {
14 | require_once(__DIR__.'/src/'.str_replace('\\', '/', $class).'.php');
15 |
16 | return true;
17 | }
18 | }, true, false);
19 |
20 | return new LeanPHP\Behat\CodeCoverage\Extension;
21 |
--------------------------------------------------------------------------------
/behat.yml.dist:
--------------------------------------------------------------------------------
1 | default:
2 | extensions:
3 | LeanPHP\Behat\CodeCoverage\Extension:
4 | filter:
5 | whitelist:
6 | include:
7 | directories:
8 | 'src': ~
9 | report:
10 | format: html
11 | options:
12 | target: build/coverage-behat
13 | html:
14 | options:
15 | target: build/coverage-behat
16 | php:
17 | options:
18 | target: build/coverage-behat.php
19 | crap4j:
20 | options:
21 | target: build/coverage-behat.crap4j
22 |
23 |
--------------------------------------------------------------------------------
/features/bootstrap/FeatureContext.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | LeanPHP Coding Standard
5 |
6 |
7 | src
8 |
9 |
10 | test
11 | tests
12 | *Spec.php
13 |
14 |
15 |
16 | >
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Common/ReportInterface.php:
--------------------------------------------------------------------------------
1 |
18 | */
19 | interface ReportInterface
20 | {
21 | /**
22 | * Constructor
23 | *
24 | * @param array $options
25 | */
26 | public function __construct(array $options);
27 |
28 | /**
29 | * Generate report
30 | *
31 | * @param CodeCoverage $coverage
32 | *
33 | * @return string|null
34 | */
35 | public function process(CodeCoverage $coverage);
36 | }
37 |
--------------------------------------------------------------------------------
/autoload.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | class Bootstrap
18 | {
19 | /**
20 | * Load class
21 | *
22 | * @param string $class Class name
23 | */
24 | public static function autoload($class)
25 | {
26 | $file = str_replace(array('\\', '_'), '/', $class);
27 | $path = __DIR__ . '/src/' . $file . '.php';
28 |
29 | if (file_exists($path)) {
30 | include_once $path;
31 | }
32 | }
33 | }
34 |
35 | spl_autoload_register('VIPSoft\Bootstrap::autoload');
36 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 | tests
18 |
19 |
20 |
21 |
22 |
23 | src
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/Common/Report/Factory.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | class Factory
18 | {
19 | /**
20 | * Creation method
21 | *
22 | * @param string $reportType
23 | * @param array $options
24 | *
25 | * @return \LeanPHP\Behat\CodeCoverage\Common\ReportInterface|null
26 | */
27 | public function create($reportType, array $options)
28 | {
29 | if (in_array($reportType, array('clover', 'crap4j', 'html', 'php', 'text', 'xml'))) {
30 | $className = '\LeanPHP\Behat\CodeCoverage\Common\Report\\'.ucfirst($reportType);
31 |
32 | return new $className($options);
33 | }
34 |
35 | return null;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/Common/Report/CloverTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder('SebastianBergmann\CodeCoverage\Node\File')
27 | ->disableOriginalConstructor()
28 | ->getMock();
29 |
30 | $coverage = $this->createMock('SebastianBergmann\CodeCoverage\CodeCoverage');
31 | $coverage->expects($this->once())
32 | ->method('getReport')
33 | ->will($this->returnValue($report));
34 |
35 | $report = new Clover(array());
36 | $result = $report->process($coverage);
37 |
38 | $this->assertTrue(strpos($result, '') === 0);
39 | }
40 | }*/
41 |
--------------------------------------------------------------------------------
/src/Common/Driver/Factory.php:
--------------------------------------------------------------------------------
1 |
18 | */
19 | class Factory
20 | {
21 | /**
22 | * @var array
23 | */
24 | private $driverClasses;
25 |
26 | /**
27 | * Constructor
28 | *
29 | * @param array $driverClasses List of namespaced driver classes
30 | */
31 | public function __construct(array $driverClasses)
32 | {
33 | $this->driverClasses = $driverClasses;
34 | }
35 |
36 | /**
37 | * Create driver
38 | *
39 | * @return DriverInterface
40 | */
41 | public function create()
42 | {
43 | foreach ($this->driverClasses as $driverClass) {
44 | try {
45 | $driver = new $driverClass();
46 |
47 | return $driver;
48 | } catch (\Exception $e) {
49 | }
50 | }
51 |
52 | return null;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Controller/Cli/CodeCoverageController.php:
--------------------------------------------------------------------------------
1 |
6 | *
7 | * @license BSD-2-Clause
8 | *
9 | * For the full copyright and license information, please see the LICENSE file
10 | * that was distributed with this source code.
11 | */
12 |
13 | namespace LeanPHP\Behat\CodeCoverage\Controller\Cli;
14 |
15 | use Behat\Testwork\Cli\Controller;
16 | use Symfony\Component\Console\Command\Command;
17 | use Symfony\Component\Console\Input\InputInterface;
18 | use Symfony\Component\Console\Input\InputOption;
19 | use Symfony\Component\Console\Output\OutputInterface;
20 | use Symfony\Component\DependencyInjection\ContainerBuilder;
21 |
22 | /**
23 | * Code Coverage Cli Controller
24 | *
25 | * @author Danny Lewis
26 | */
27 | class CodeCoverageController implements Controller
28 | {
29 | /**
30 | * {@inheritdoc}
31 | */
32 | public function configure(Command $command)
33 | {
34 | $command->addOption('no-coverage', null, InputOption::VALUE_NONE, 'Skip Code Coverage generation');
35 | }
36 |
37 | /**
38 | * {@inheritdoc}
39 | */
40 | public function execute(InputInterface $input, OutputInterface $output)
41 | {
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Compiler/FactoryPass.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class FactoryPass implements CompilerPassInterface
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function process(ContainerBuilder $container)
27 | {
28 | if (! $container->hasDefinition('vipsoft.code_coverage.driver.factory')) {
29 | return;
30 | }
31 |
32 | $factory = $container->getDefinition('vipsoft.code_coverage.driver.factory');
33 | $drivers = array();
34 | $ids = $container->findTaggedServiceIds('vipsoft.code_coverage.driver');
35 |
36 | foreach ($ids as $id => $attributes) {
37 | $drivers[] = $container->getDefinition($id)->getClass();
38 | }
39 |
40 | $factory->setArguments(array($drivers));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/Common/Report/TextTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder('SebastianBergmann\CodeCoverage\Node\File')
31 | ->disableOriginalConstructor()
32 | ->getMock();
33 |
34 | $coverage = $this->createMock('SebastianBergmann\CodeCoverage\CodeCoverage');
35 | $coverage->expects($this->once())
36 | ->method('getReport')
37 | ->will($this->returnValue($report));
38 |
39 | $report = new Text(array());
40 | ob_start();
41 | $report->process($coverage);
42 | $result = ob_get_clean();
43 |
44 | $this->assertTrue($result === '');
45 | }
46 | }*/
47 |
--------------------------------------------------------------------------------
/src/Common/Driver/Stub.php:
--------------------------------------------------------------------------------
1 |
18 | */
19 | class Stub implements DriverInterface
20 | {
21 | private $driver;
22 |
23 | /**
24 | * Register driver
25 | *
26 | * @param DriverInterface $driver
27 | */
28 | public function setDriver(DriverInterface $driver)
29 | {
30 | $this->driver = $driver;
31 | }
32 |
33 | /**
34 | * Get driver
35 | *
36 | * @return DriverInterface $driver
37 | */
38 | public function getDriver()
39 | {
40 | return $this->driver;
41 | }
42 |
43 | /**
44 | * {@inheritdoc}
45 | */
46 | public function start(bool $determineUnusedAndDead = true): void
47 | {
48 | if ($this->driver) {
49 | $this->driver->start();
50 | }
51 | }
52 |
53 | /**
54 | * {@inheritdoc}
55 | */
56 | public function stop(): array
57 | {
58 | return $this->driver ? $this->driver->stop() : false;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Common/Report/Php.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class Php implements ReportInterface
22 | {
23 | /**
24 | * @var \SebastianBergmann\CodeCoverage\Report\Clover
25 | */
26 | private $report;
27 |
28 | /**
29 | * @var array
30 | */
31 | private $options;
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function __construct(array $options)
37 | {
38 | if (! isset($options['target'])) {
39 | $options['target'] = null;
40 | }
41 |
42 | $this->report = new PHPReport();
43 | $this->options = $options;
44 | }
45 |
46 | /**
47 | * {@inheritdoc}
48 | */
49 | public function process(CodeCoverage $coverage)
50 | {
51 | return $this->report->process(
52 | $coverage,
53 | $this->options['target']
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Common/Model/Aggregate.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | class Aggregate
18 | {
19 | /**
20 | * @var array
21 | */
22 | private $coverage = [];
23 |
24 | /**
25 | * Update aggregated coverage
26 | *
27 | * @param string $class
28 | * @param array $counts
29 | */
30 | public function update($class, array $counts)
31 | {
32 | if (! isset($this->coverage[$class])) {
33 | $this->coverage[$class] = $counts;
34 |
35 | return;
36 | }
37 |
38 | foreach ($counts as $line => $status) {
39 | if (! isset($this->coverage[$class][$line]) || $status > 0) {
40 | // converts "hits" to "status"
41 | $status = ! $status ? -1 : ($status > 1 ? 1 : $status);
42 |
43 | $this->coverage[$class][$line] = $status;
44 | }
45 | }
46 | }
47 |
48 | /**
49 | * Get coverage
50 | *
51 | * @return array
52 | */
53 | public function getCoverage()
54 | {
55 | return $this->coverage;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/tests/Common/Report/PhpTest.php:
--------------------------------------------------------------------------------
1 | createMock('SebastianBergmann\CodeCoverage\CodeCoverage');
33 | $filter = $this->createMock('SebastianBergmann\CodeCoverage\Filter');
34 | $filter
35 | ->expects($this->once())
36 | ->method('getWhitelistedFiles')
37 | ->will($this->returnValue(array()));
38 | $coverage->expects($this->once())
39 | ->method('filter')
40 | ->will($this->returnValue($filter));
41 |
42 |
43 | $report = new Php(array());
44 | $result = $report->process($coverage);
45 |
46 | $this->assertTrue(strncmp($result, ' (https://ek9.co).
2 | Copyright (c) 2013-2016 Anthon Pang.
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 |
--------------------------------------------------------------------------------
/tests/Common/Report/Crap4jTest.php:
--------------------------------------------------------------------------------
1 | markTestSkipped();
33 |
34 | return;
35 | }
36 |
37 | $report = $this->getMockBuilder('SebastianBergmann\CodeCoverage\Report\Crap4j')
38 | ->disableOriginalConstructor()
39 | ->getMock();
40 |
41 | $coverage = $this->createMock('SebastianBergmann\CodeCoverage\CodeCoverage');
42 | $coverage->expects($this->once())
43 | ->method('getReport')
44 | ->will($this->returnValue($report));
45 |
46 | $report = new Crap4j();
47 | $result = $report->process($coverage);
48 |
49 | $this->assertTrue(strpos($result, '') === 0);
50 |
51 | }
52 | }*/
53 |
--------------------------------------------------------------------------------
/src/Common/Report/Clover.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class Clover implements ReportInterface
22 | {
23 | /**
24 | * @var \SebastianBergmann\CodeCoverage\Report\Clover
25 | */
26 | private $report;
27 |
28 | /**
29 | * @var array
30 | */
31 | private $options;
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function __construct(array $options)
37 | {
38 | if (! isset($options['target'])) {
39 | $options['target'] = null;
40 | }
41 |
42 | if (! isset($options['name'])) {
43 | $options['name'] = null;
44 | }
45 |
46 | $this->report = new CloverReport();
47 | $this->options = $options;
48 | }
49 |
50 | /**
51 | * {@inheritdoc}
52 | */
53 | public function process(CodeCoverage $coverage)
54 | {
55 | return $this->report->process(
56 | $coverage,
57 | $this->options['target'],
58 | $this->options['name']
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Common/Report/Xml.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class Xml implements ReportInterface
22 | {
23 | /**
24 | * @var \SebastianBergmann\CodeCoverage\Report\XML
25 | */
26 | private $report;
27 |
28 | /**
29 | * @var array
30 | */
31 | private $options;
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function __construct(array $options)
37 | {
38 | if (! class_exists('SebastianBergmann\CodeCoverage\Report\Xml\Facade')) {
39 | throw new \Exception('XML requires CodeCoverage 4.0+');
40 | }
41 |
42 | if (! isset($options['target'])) {
43 | $options['target'] = null;
44 | }
45 |
46 | $this->report = new Facade('');
47 | $this->options = $options;
48 | }
49 |
50 | /**
51 | * {@inheritdoc}
52 | */
53 | public function process(CodeCoverage $coverage)
54 | {
55 | return $this->report->process(
56 | $coverage,
57 | $this->options['target']
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Compiler/DriverPass.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class DriverPass implements CompilerPassInterface
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function process(ContainerBuilder $container)
27 | {
28 | if (! $container->hasDefinition('behat.code_coverage.driver.proxy')) {
29 | return;
30 | }
31 |
32 | $proxy = $container->getDefinition('behat.code_coverage.driver.proxy');
33 | $enabled = $container->getParameter('behat.code_coverage.config.drivers');
34 |
35 | foreach ($container->findTaggedServiceIds('behat.code_coverage.driver') as $id => $tagAttributes) {
36 | foreach ($tagAttributes as $attributes) {
37 | if (isset($attributes['alias'])
38 | && in_array($attributes['alias'], $enabled)
39 | ) {
40 | $proxy->addMethodCall('addDriver', array(new Reference($id)));
41 | }
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Common/Driver/HHVM.php:
--------------------------------------------------------------------------------
1 |
21 | */
22 | class HHVM implements DriverInterface
23 | {
24 | /**
25 | * Constructor
26 | *
27 | * @throws SebastianBergmann\CodeCoverage\RuntimeException if PHP code coverage not enabled
28 | */
29 | public function __construct()
30 | {
31 | if (! defined('HPHP_VERSION')) {
32 | throw new \SebastianBergmann\CodeCoverage\RuntimeException('This driver requires HHVM');
33 | }
34 | }
35 |
36 | /**
37 | * {@inheritdoc}
38 | */
39 | public function start(bool $determineUnusedAndDead = true): void
40 | {
41 | fb_enable_code_coverage();
42 | }
43 |
44 | /**
45 | * {@inheritdoc}
46 | */
47 | public function stop(): array
48 | {
49 | $codeCoverage = fb_get_code_coverage(true);
50 |
51 | if (null === $codeCoverage) {
52 | $codeCoverage = [];
53 | }
54 |
55 | fb_disable_code_coverage();
56 |
57 | return $codeCoverage;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tests/Common/Report/HtmlTest.php:
--------------------------------------------------------------------------------
1 | addFile('file', array('class' => array(1 => 1)), array(), false);
39 |
40 | $coverage = $this->createMock('SebastianBergmann\CodeCoverage\CodeCoverage');
41 | $coverage->expects($this->once())
42 | ->method('getReport')
43 | ->will($this->returnValue($report));
44 |
45 | $report = new Html(array(
46 | 'target' => $target,
47 | ));
48 |
49 | try {
50 | $result = $report->process($coverage);
51 | } catch (\Exception $e) {
52 | print_r($e->getMessage());
53 | $this->fail();
54 | }
55 | }
56 | }*/
57 |
--------------------------------------------------------------------------------
/src/Service/ReportService.php:
--------------------------------------------------------------------------------
1 |
19 | */
20 | class ReportService
21 | {
22 | /**
23 | * @var array
24 | */
25 | private $config;
26 |
27 | /**
28 | * @var \LeanPHP\Behat\CodeCoverage\Common\Report\Factory
29 | */
30 | private $factory;
31 |
32 | /**
33 | * Constructor
34 | *
35 | * @param array $config
36 | * @param \LeanPHP\Behat\CodeCoverage\Common\Report\Factory $factory
37 | */
38 | public function __construct(array $config, Factory $factory)
39 | {
40 | $this->config = $config;
41 | $this->factory = $factory;
42 | }
43 |
44 | /**
45 | * Generate report
46 | *
47 | * @param CodeCoverage $coverage
48 | */
49 | public function generateReport(CodeCoverage $coverage)
50 | {
51 | $format = $this->config['report']['format'];
52 | $options = $this->config['report']['options'];
53 |
54 | $report = $this->factory->create($format, $options);
55 | $output = $report->process($coverage);
56 |
57 | if ('text' === $format) {
58 | print_r($output);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/Common/Report/Crap4j.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class Crap4j implements ReportInterface
22 | {
23 | /**
24 | * @var SebastianBergmann\CodeCoverage\Report\Crap4j
25 | */
26 | private $report;
27 |
28 | /**
29 | * @var array
30 | */
31 | private $options;
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function __construct(array $options)
37 | {
38 | if (! class_exists('SebastianBergmann\CodeCoverage\Report\Crap4j')) {
39 | throw new \Exception('Crap4j requires CodeCoverage 4.0+');
40 | }
41 |
42 | if (! isset($options['target'])) {
43 | $options['target'] = null;
44 | }
45 |
46 | if (! isset($options['name'])) {
47 | $options['name'] = null;
48 | }
49 |
50 | $this->report = new Crap4jReport();
51 | $this->options = $options;
52 | }
53 |
54 | /**
55 | * {@inheritdoc}
56 | */
57 | public function process(CodeCoverage $coverage)
58 | {
59 | return $this->report->process(
60 | $coverage,
61 | $this->options['target'],
62 | $this->options['name']
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/tests/Common/Report/XmlTest.php:
--------------------------------------------------------------------------------
1 | addFile('file', array('class' => array(1 => 1)), array(), false);
38 |
39 | $coverage = $this->createMock('SebastianBergmann\CodeCoverage\CodeCoverage');
40 | $coverage->expects($this->atLeast(1))
41 | ->method('getReport')
42 | ->will($this->returnValue($report));
43 | $coverage->expects($this->once())
44 | ->method('getTests')
45 | ->will($this->returnValue(array()));
46 |
47 |
48 |
49 | $report = new Xml(array(
50 | 'target' => $target,
51 | ));
52 |
53 | try {
54 | $result = $report->process($coverage);
55 | } catch (\Exception $e) {
56 | echo 'aaaa';
57 | echo($e->getMessage());
58 | $this->fail();
59 | }
60 | }
61 | }*/
62 |
--------------------------------------------------------------------------------
/src/Common/Driver/XCache.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class XCache implements DriverInterface
22 | {
23 | /**
24 | * Constructor
25 | *
26 | * @throws \SebastianBergmann\CodeCoverage\RuntimeException if PHP code coverage not enabled
27 | */
28 | public function __construct()
29 | {
30 | if (! extension_loaded('xcache')) {
31 | throw new \SebastianBergmann\CodeCoverage\RuntimeException('This driver requires XCache');
32 | }
33 |
34 | if (version_compare(phpversion('xcache'), '1.2.0', '<') ||
35 | ! ini_get('xcache.coverager')
36 | ) {
37 | throw new \SebastianBergmann\CodeCoverage\RuntimeException('xcache.coverager=On has to be set in php.ini');
38 | }
39 | }
40 |
41 | /**
42 | * {@inheritdoc}
43 | */
44 | public function start(bool $determineUnusedAndDead = true): void
45 | {
46 | xcache_coverager_start();
47 | }
48 |
49 | /**
50 | * {@inheritdoc}
51 | */
52 | public function stop(): array
53 | {
54 | $codeCoverage = xcache_coverager_get();
55 |
56 | if (null === $codeCoverage) {
57 | $codeCoverage = [];
58 | }
59 |
60 | xcache_coverager_stop(true);
61 |
62 | return $codeCoverage;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Driver/Proxy.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class Proxy implements DriverInterface
22 | {
23 | /**
24 | * @var array
25 | */
26 | private $drivers = array();
27 |
28 | /**
29 | * Register driver
30 | *
31 | * @param DriverInterface|null $driver
32 | */
33 | public function addDriver(DriverInterface $driver = null)
34 | {
35 | if ($driver) {
36 | $this->drivers[] = $driver;
37 | }
38 | }
39 |
40 | /**
41 | * {@inheritdoc}
42 | */
43 | public function start(bool $determineUnusedAndDead = true): void
44 | {
45 | foreach ($this->drivers as $driver) {
46 | $driver->start($determineUnusedAndDead);
47 | }
48 | }
49 |
50 | /**
51 | * {@inheritdoc}
52 | */
53 | public function stop(): array
54 | {
55 | $aggregate = new Aggregate();
56 |
57 | foreach ($this->drivers as $driver) {
58 | $coverage = $driver->stop();
59 |
60 | if (! $coverage) {
61 | continue;
62 | }
63 |
64 | foreach ($coverage as $class => $counts) {
65 | $aggregate->update($class, $counts);
66 | }
67 | }
68 |
69 | return $aggregate->getCoverage();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/tests/Service/ReportServiceTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder('LeanPHP\Behat\CodeCoverage\Common\Report\Html')
45 | ->disableOriginalConstructor()
46 | ->getMock();
47 |
48 | $factory = $this->createMock('LeanPHP\Behat\CodeCoverage\Common\Report\Factory');
49 | $factory->expects($this->once())
50 | ->method('create')
51 | ->will($this->returnValue($report));
52 |
53 | $coverage = $this->createMock('SebastianBergmann\CodeCoverage\CodeCoverage');
54 |
55 | $service = new ReportService(array('report' => array('format' => 'html', 'options' => array())), $factory);
56 | $service->generateReport($coverage);
57 | }
58 | }*/
59 |
--------------------------------------------------------------------------------
/tests/Common/Driver/HHVMTest.php:
--------------------------------------------------------------------------------
1 | getMockFunction('defined', function () {
24 | return false;
25 | });
26 |
27 | try {
28 | new HHVM();
29 |
30 | $this->fail();
31 | } catch (\Exception $e) {
32 | $this->assertTrue($e instanceof \SebastianBergmann\CodeCoverage\RuntimeException);
33 | $this->assertEquals('This driver requires HHVM', $e->getMessage());
34 | }
35 | }
36 |
37 | public function testConstructXCache()
38 | {
39 | $this->getMockFunction('defined', function () {
40 | return true;
41 | });
42 |
43 | new HHVM();
44 | }
45 |
46 | public function testStartXCache()
47 | {
48 | $this->getMockFunction('defined', function () {
49 | return true;
50 | });
51 |
52 | $this->getMockFunction('fb_enable_code_coverage', null);
53 |
54 | $driver = new HHVM();
55 | $driver->start();
56 | }
57 |
58 | public function testStopXCache()
59 | {
60 | $this->getMockFunction('defined', function () {
61 | return true;
62 | });
63 |
64 | $function = $this->createMock('VIPSoft\Test\FunctionProxy');
65 | $function->expects($this->exactly(2))
66 | ->method('invokeFunction');
67 |
68 | $this->getMockFunction('fb_get_code_coverage', $function);
69 | $this->getMockFunction('fb_disable_code_coverage', $function);
70 |
71 | $driver = new HHVM();
72 | $driver->stop();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Common/Report/Html.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class Html implements ReportInterface
22 | {
23 | /**
24 | * @var Facade
25 | */
26 | private $report;
27 |
28 | /**
29 | * @var array
30 | */
31 | private $options;
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function __construct(array $options)
37 | {
38 | if (! isset($options['target'])) {
39 | $options['target'] = null;
40 | }
41 |
42 | if (! isset($options['charset'])) {
43 | $options['charset'] = 'UTF-8';
44 | }
45 |
46 | if (! isset($options['highlight'])) {
47 | $options['highlight'] = false;
48 | }
49 |
50 | if (! isset($options['lowUpperBound'])) {
51 | $options['lowUpperBound'] = 35;
52 | }
53 |
54 | if (! isset($options['highUpperBound'])) {
55 | $options['highUpperBound'] = 70;
56 | }
57 |
58 | if (! isset($options['generator'])) {
59 | $options['generator'] = '';
60 | }
61 |
62 | $this->report = new Facade(
63 | $options['lowUpperBound'],
64 | $options['highUpperBound'],
65 | $options['generator']
66 | );
67 |
68 | $this->options = $options;
69 | }
70 |
71 | /**
72 | * {@inheritdoc}
73 | */
74 | public function process(CodeCoverage $coverage)
75 | {
76 | return $this->report->process(
77 | $coverage,
78 | $this->options['target']
79 | );
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "leanphp/behat-code-coverage",
3 | "description": "Generate Code Coverage reports for Behat tests",
4 | "type": "library",
5 | "keywords": [
6 | "behat", "code", "coverage", "generate", "generation", "build",
7 | "report", "test", "tests", "code-coverage", "reports", "clover",
8 | "scenario", "bdd"
9 | ],
10 | "license": "BSD-2-Clause",
11 | "authors": [
12 | {
13 | "name": "ek9",
14 | "email": "dev@ek9.co",
15 | "homepage": "https://ek9.co"
16 | },
17 | {
18 | "name": "Anthon Pang",
19 | "email": "apang@softwaredevelopment.ca"
20 | }
21 | ],
22 | "support": {
23 | "issues": "https://github.com/leanphp/behat-code-coverage/issues",
24 | "source": "https://github.com/leanphp/behat-code-coverage",
25 | "docs": "https://github.com/leanphp/behat-code-coverage#behat-code-coverage"
26 | },
27 | "require": {
28 | "php": ">=5.6",
29 | "phpunit/php-code-coverage": "^6.0",
30 | "behat/behat": "^3.0",
31 | "guzzlehttp/guzzle": "^6.0",
32 | "symfony/config": "^2.3||^3.0||^4.0",
33 | "symfony/dependency-injection": "^2.2||^3.0||^4.0",
34 | "symfony/expression-language": "^2.2||^3.0||^4.0",
35 | "symfony/http-kernel": "^2.3||^3.0||^4.0",
36 | "symfony/http-foundation": "^2.3||^3.0||^4.0"
37 | },
38 | "require-dev": {
39 | "phpunit/phpunit": "^7.0",
40 | "mikey179/vfsStream": "1.6.*",
41 | "squizlabs/php_codesniffer": "^3.2",
42 | "escapestudios/symfony2-coding-standard": "^3.1"
43 | },
44 | "suggest": {
45 | "ext-xdebug": "Xdebug extension is required to collect coverage via Xdebug driver and run tests",
46 | "ext-phpdbg": "PHPDBG extension allows you to collect coverage faster than Xdebug (PHP 7.0+)"
47 | },
48 | "autoload": {
49 | "psr-4": { "LeanPHP\\Behat\\CodeCoverage\\": "src/" }
50 | },
51 | "config": {
52 | "bin-dir": "bin"
53 | },
54 | "extra": {
55 | "branch-alias": {
56 | "dev-master": "3.2.x-dev",
57 | "dev-develop": "4.x-dev",
58 | "dev-v3.1": "3.1.x-dev"
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/tests/Driver/ProxyTest.php:
--------------------------------------------------------------------------------
1 | localDriver = $this->createMock('LeanPHP\Behat\CodeCoverage\Common\Driver\Stub');
30 |
31 | $this->remoteDriver = $this->getMockBuilder('LeanPHP\Behat\CodeCoverage\Driver\RemoteXdebug')
32 | ->disableOriginalConstructor()
33 | ->getMock();
34 |
35 | $this->driver = new Proxy();
36 | $this->driver->addDriver($this->localDriver);
37 | $this->driver->addDriver($this->remoteDriver);
38 | }
39 |
40 | public function testStart()
41 | {
42 | $this->localDriver->expects($this->once())
43 | ->method('start');
44 |
45 | $this->remoteDriver->expects($this->once())
46 | ->method('start');
47 |
48 | $this->driver->start();
49 | }
50 |
51 | public function testStop()
52 | {
53 | $coverage = array(
54 | 'SomeClass' => array(
55 | 1 => 1,
56 | 2 => -1,
57 | 3 => -2,
58 | )
59 | );
60 |
61 | $this->localDriver->expects($this->once())
62 | ->method('stop')
63 | ->will($this->returnValue($coverage));
64 |
65 | $this->remoteDriver->expects($this->once())
66 | ->method('stop')
67 | ->will($this->returnValue([]));
68 |
69 | $coverage = $this->driver->stop();
70 |
71 | $this->assertEquals(
72 | array(
73 | 'SomeClass' => array(
74 | 1 => 1,
75 | 2 => -1,
76 | 3 => -2,
77 | )
78 | ),
79 | $coverage
80 | );
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/tests/Compiler/DriverPassTest.php:
--------------------------------------------------------------------------------
1 | createMock('Symfony\Component\DependencyInjection\ContainerBuilder');
24 | $container->expects($this->once())
25 | ->method('hasDefinition')
26 | ->will($this->returnValue(false));
27 |
28 | $pass = new DriverPass();
29 | $pass->process($container);
30 | }
31 |
32 | public function testProcess()
33 | {
34 | $proxy = $this->createMock('Symfony\Component\DependencyInjection\Definition');
35 | $proxy->expects($this->exactly(2))
36 | ->method('addMethodCall');
37 |
38 | $container = $this->createMock('Symfony\Component\DependencyInjection\ContainerBuilder');
39 | $container->expects($this->once())
40 | ->method('hasDefinition')
41 | ->with('behat.code_coverage.driver.proxy')
42 | ->will($this->returnValue(true));
43 |
44 | $container->expects($this->once())
45 | ->method('getDefinition')
46 | ->with('behat.code_coverage.driver.proxy')
47 | ->will($this->returnValue($proxy));
48 |
49 | $container->expects($this->once())
50 | ->method('getParameter')
51 | ->with('behat.code_coverage.config.drivers')
52 | ->will($this->returnValue(array('local', 'remote')));
53 |
54 | $container->expects($this->once())
55 | ->method('findTaggedServiceIds')
56 | ->with('behat.code_coverage.driver')
57 | ->will($this->returnValue(array(
58 | 'behat.code_coverage.driver.local' => array(array(
59 | 'alias' => 'local'
60 | )),
61 | 'behat.code_coverage.driver.remote' => array(array(
62 | 'alias' => 'remote'
63 | )),
64 | )));
65 |
66 | $pass = new DriverPass();
67 | $pass->process($container);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/tests/Common/Report/FactoryTest.php:
--------------------------------------------------------------------------------
1 | assertEquals($expected, get_class($factory->create($reportType, array())));
35 | }
36 |
37 | public function legacyCreateProvider()
38 | {
39 | return array(
40 | array(
41 | 'LeanPHP\Behat\CodeCoverage\Common\Report\Clover',
42 | 'clover',
43 | ),
44 | array(
45 | 'LeanPHP\Behat\CodeCoverage\Common\Report\Html',
46 | 'html',
47 | ),
48 | array(
49 | 'LeanPHP\Behat\CodeCoverage\Common\Report\Php',
50 | 'php',
51 | ),
52 | array(
53 | 'LeanPHP\Behat\CodeCoverage\Common\Report\Text',
54 | 'text',
55 | ),
56 | );
57 | }
58 |
59 | /**
60 | * @dataProvider createProvider
61 | public function testCreate($expected, $reportType)
62 | {
63 | $factory = new Factory();
64 |
65 | try {
66 | $this->assertEquals($expected, get_class($factory->create($reportType, array())));
67 | } catch (\Exception $e) {
68 | $this->assertTrue(strpos($e->getMessage(), 'requires CodeCoverage 4.0+') !== false);
69 | }
70 | }
71 |
72 | public function createProvider()
73 | {
74 | return array(
75 | array(
76 | 'LeanPHP\Behat\CodeCoverage\Common\Report\Crap4j',
77 | 'crap4j',
78 | ),
79 | array(
80 | 'LeanPHP\Behat\CodeCoverage\Common\Report\Xml',
81 | 'xml',
82 | ),
83 | );
84 | }
85 |
86 | public function testCreateInvalid()
87 | {
88 | $factory = new Factory();
89 |
90 | $this->assertTrue($factory->create('HTML', array()) === null);
91 | }
92 | }*/
93 |
--------------------------------------------------------------------------------
/tests/Common/Driver/FactoryTest.php:
--------------------------------------------------------------------------------
1 | create();
26 |
27 | $this->assertTrue($driver === null);
28 | }
29 |
30 | public function testCreate()
31 | {
32 | if ( ! class_exists('LeanPHP\Behat\CodeCoverage\Common\Driver\Factory\GoodDriver')) {
33 | eval(<<create();
61 |
62 | $this->assertTrue($driver !== null);
63 | }
64 |
65 | public function testCreateException()
66 | {
67 | if ( ! class_exists('LeanPHP\Behat\CodeCoverage\Common\Driver\Factory\BadDriver')) {
68 | eval(<<create();
97 |
98 | $this->assertTrue($driver === null);
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/tests/Common/Model/AggregateTest.php:
--------------------------------------------------------------------------------
1 | getCoverage();
25 |
26 | $this->assertTrue(is_array($coverage));
27 | $this->assertCount(0, $coverage);
28 | }
29 |
30 | public function testUpdateWhenEmpty()
31 | {
32 | $aggregate = new Aggregate();
33 | $aggregate->update('test', array(2 => 1));
34 |
35 | $coverage = $aggregate->getCoverage();
36 |
37 | $this->assertTrue(is_array($coverage));
38 | $this->assertCount(1, $coverage);
39 | $this->assertEquals(array(2 => 1), $coverage['test']);
40 | }
41 |
42 | public function testUpdateForCollision()
43 | {
44 | $aggregate = new Aggregate();
45 | $aggregate->update('first', array(2 => 1));
46 | $aggregate->update('second', array(1 => -1));
47 |
48 | $coverage = $aggregate->getCoverage();
49 |
50 | $this->assertTrue(is_array($coverage));
51 | $this->assertCount(2, $coverage);
52 | $this->assertEquals(array(2 => 1), $coverage['first']);
53 | $this->assertEquals(array(1 => -1), $coverage['second']);
54 | }
55 |
56 | /**
57 | * @dataProvider updateDataProvider
58 | */
59 | public function testUpdate($first, $second, $expected)
60 | {
61 | $aggregate = new Aggregate();
62 | $aggregate->update('test', $first);
63 | $aggregate->update('test', $second);
64 |
65 | $coverage = $aggregate->getCoverage();
66 |
67 | $this->assertTrue(is_array($coverage));
68 | $this->assertCount(1, $coverage);
69 | $this->assertEquals($expected, $coverage['test']);
70 | }
71 |
72 | public function updateDataProvider()
73 | {
74 | return array(
75 | array(
76 | array(1 => 1),
77 | array(1 => 1),
78 | array(1 => 1),
79 | ),
80 | array(
81 | array(1 => 1),
82 | array(2 => 1),
83 | array(1 => 1, 2 => 1),
84 | ),
85 | array(
86 | array(1 => -1),
87 | array(1 => 1),
88 | array(1 => 1),
89 | ),
90 | array(
91 | array(1 => 1),
92 | array(1 => -1),
93 | array(1 => 1),
94 | ),
95 | );
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/tests/Common/Driver/StubTest.php:
--------------------------------------------------------------------------------
1 | createMock('SebastianBergmann\CodeCoverage\Driver\Xdebug');
29 |
30 | $driver = new Stub();
31 | $this->assertTrue($driver->getDriver() === null);
32 |
33 | $driver->setDriver($mock);
34 | $this->assertTrue($driver->getDriver() === $mock);
35 | }
36 |
37 | /**
38 | * @requires extension xdebug
39 | public function testStartXdebug()
40 | {
41 | $mock = $this->createMock('SebastianBergmann\CodeCoverage\Driver\Xdebug');
42 | $mock->expects($this->once())
43 | ->method('start');
44 |
45 | $driver = new Stub();
46 | $driver->setDriver($mock);
47 | $driver->start();
48 | }
49 |
50 | /**
51 | * @requires extension xdebug
52 | public function testStopXdebug()
53 | {
54 | $mock = $this->createMock('SebastianBergmann\CodeCoverage\Driver\Xdebug');
55 | $mock->expects($this->once())
56 | ->method('stop');
57 |
58 | $driver = new Stub();
59 | $driver->setDriver($mock);
60 | $driver->stop();
61 | }
62 |
63 | /**
64 | * @requires extension phpdbg
65 | public function testGetterSetterPHPDBG()
66 | {
67 | $mock = $this->createMock('SebastianBergmann\CodeCoverage\Driver\PHPDBG');
68 |
69 | $driver = new Stub();
70 | $this->assertTrue($driver->getDriver() === null);
71 |
72 | $driver->setDriver($mock);
73 | $this->assertTrue($driver->getDriver() === $mock);
74 | }
75 |
76 | /**
77 | * @requires extension phpdbg
78 | public function testStartPHPDBG()
79 | {
80 | $mock = $this->createMock('SebastianBergmann\CodeCoverage\Driver\PHPDBG');
81 | $mock->expects($this->once())
82 | ->method('start');
83 |
84 | $driver = new Stub();
85 | $driver->setDriver($mock);
86 | $driver->start();
87 | }
88 |
89 | /**
90 | * @requires extension phpdbg
91 | public function testStopPHPDBG()
92 | {
93 | $mock = $this->createMock('SebastianBergmann\CodeCoverage\Driver\PHPDBG');
94 | $mock->expects($this->once())
95 | ->method('stop');
96 |
97 | $driver = new Stub();
98 | $driver->setDriver($mock);
99 | $driver->stop();
100 | }
101 |
102 | }*/
103 |
--------------------------------------------------------------------------------
/tests/Compiler/FactoryPassTest.php:
--------------------------------------------------------------------------------
1 | createMock('Symfony\Component\DependencyInjection\ContainerBuilder');
25 | $container->expects($this->once())
26 | ->method('hasDefinition')
27 | ->will($this->returnValue(false));
28 |
29 | $pass = new FactoryPass();
30 | $pass->process($container);
31 | }
32 |
33 | public function testProcess()
34 | {
35 | $factory = $this->createMock('Symfony\Component\DependencyInjection\Definition');
36 | $factory->expects($this->once())
37 | ->method('setArguments');
38 |
39 | $xcache = $this->createMock('Symfony\Component\DependencyInjection\Definition');
40 | $xcache->expects($this->once())
41 | ->method('getClass')
42 | ->will($this->returnValue('LeanPHP\Behat\CodeCoverage\Common\Driver\XCache'));
43 |
44 | $xdebug = $this->createMock('Symfony\Component\DependencyInjection\Definition');
45 | $xdebug->expects($this->once())
46 | ->method('getClass')
47 | ->will($this->returnValue('Xdebug'));
48 |
49 | $container = $this->createMock('Symfony\Component\DependencyInjection\ContainerBuilder');
50 |
51 | $container->expects($this->at(0))
52 | ->method('hasDefinition')
53 | ->with('vipsoft.code_coverage.driver.factory')
54 | ->will($this->returnValue(true));
55 |
56 | $container->expects($this->at(1))
57 | ->method('getDefinition')
58 | ->with('vipsoft.code_coverage.driver.factory')
59 | ->will($this->returnValue($factory));
60 |
61 | $container->expects($this->at(2))
62 | ->method('findTaggedServiceIds')
63 | ->with('vipsoft.code_coverage.driver')
64 | ->will($this->returnValue(array(
65 | 'vipsoft.code_coverage.driver.xcache' => array(),
66 | 'vipsoft.code_coverage.driver.xdebug' => array(),
67 | )));
68 |
69 | $container->expects($this->at(3))
70 | ->method('getDefinition')
71 | ->with('vipsoft.code_coverage.driver.xcache')
72 | ->will($this->returnValue($xcache));
73 |
74 | $container->expects($this->at(4))
75 | ->method('getDefinition')
76 | ->with('vipsoft.code_coverage.driver.xdebug')
77 | ->will($this->returnValue($xdebug));
78 |
79 | $pass = new FactoryPass();
80 | $pass->process($container);
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Common/Report/Text.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class Text implements ReportInterface
22 | {
23 | /**
24 | * @var \SebastianBergmann\CodeCoverage\Report\Text
25 | */
26 | private $report;
27 |
28 | /**
29 | * @var array
30 | */
31 | private $options;
32 |
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function __construct(array $options)
37 | {
38 | if (! isset($options['showColors'])) {
39 | $options['showColors'] = false;
40 | }
41 |
42 | if (! isset($options['printer'])) {
43 | $options['printer'] = null;
44 | }
45 |
46 | if (! isset($options['lowUpperBound'])) {
47 | $options['lowUpperBound'] = 35;
48 | }
49 |
50 | if (! isset($options['highUpperBound'])) {
51 | $options['highUpperBound'] = 70;
52 | }
53 |
54 | if (! isset($options['showUncoveredFiles'])) {
55 | $options['showUncoveredFiles'] = false;
56 | }
57 |
58 | if ($this->getVersion() === '1.2') {
59 | $outputStream = new \PHPUnit_Util_Printer($options['printer']);
60 |
61 | $this->report = new TextReport(
62 | $outputStream,
63 | $options['lowUpperBound'],
64 | $options['highUpperBound'],
65 | $options['showUncoveredFiles']
66 | );
67 | } else {
68 | if (! isset($options['showOnlySummary'])) {
69 | $options['showOnlySummary'] = false;
70 | }
71 |
72 | $this->report = new TextReport(
73 | $options['lowUpperBound'],
74 | $options['highUpperBound'],
75 | $options['showUncoveredFiles'],
76 | $options['showOnlySummary']
77 | );
78 | }
79 |
80 | $this->options = $options;
81 | }
82 |
83 | /**
84 | * {@inheritdoc}
85 | */
86 | public function process(CodeCoverage $coverage)
87 | {
88 | return $this->report->process(
89 | $coverage,
90 | $this->options['showColors']
91 | );
92 | }
93 |
94 | /**
95 | * return version of CodeCoverage
96 | *
97 | * @return string
98 | */
99 | private function getVersion()
100 | {
101 | $reflectionMethod = new \ReflectionMethod('SebastianBergmann\CodeCoverage\Report\Text', '__construct');
102 | $parameters = $reflectionMethod->getParameters();
103 |
104 | if (reset($parameters)->name === 'outputStream') {
105 | return '1.2';
106 | }
107 |
108 | return '1.3';
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/Compiler/FilterPass.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class FilterPass implements CompilerPassInterface
22 | {
23 | /**
24 | * {@inheritdoc}
25 | */
26 | public function process(ContainerBuilder $container)
27 | {
28 | $this->processCodeCoverage($container);
29 | $this->processCodeCoverageFilter($container);
30 | }
31 |
32 | /**
33 | * @param ContainerBuilder $container
34 | */
35 | private function processCodeCoverage(ContainerBuilder $container)
36 | {
37 | if (! $container->hasDefinition('behat.code_coverage.php_code_coverage')) {
38 | return;
39 | }
40 |
41 | $coverage = $container->getDefinition('behat.code_coverage.php_code_coverage');
42 | $config = $container->getParameter('behat.code_coverage.config.filter');
43 |
44 | $coverage->addMethodCall(
45 | 'setAddUncoveredFilesFromWhitelist',
46 | array($config['whitelist']['addUncoveredFilesFromWhitelist'])
47 | );
48 | $coverage->addMethodCall(
49 | 'setProcessUncoveredFilesFromWhiteList',
50 | array($config['whitelist']['processUncoveredFilesFromWhitelist'])
51 | );
52 | $coverage->addMethodCall(
53 | 'setForceCoversAnnotation',
54 | array($config['forceCoversAnnotation'])
55 | );
56 | }
57 |
58 | /**
59 | * @param ContainerBuilder $container
60 | */
61 | private function processCodeCoverageFilter(ContainerBuilder $container)
62 | {
63 | if (! $container->hasDefinition('behat.code_coverage.php_code_coverage_filter')) {
64 | return;
65 | }
66 |
67 | $filter = $container->getDefinition('behat.code_coverage.php_code_coverage_filter');
68 | $config = $container->getParameter('behat.code_coverage.config.filter');
69 |
70 | $dirs = array(
71 | 'addDirectoryToWhiteList' => array('whitelist', 'include', 'directories'),
72 | 'removeDirectoryFromWhiteList' => array('whitelist', 'exclude', 'directories'),
73 | );
74 |
75 | foreach ($dirs as $method => $hiera) {
76 | foreach ($config[$hiera[0]][$hiera[1]][$hiera[2]] as $path => $dir) {
77 | $filter->addMethodCall($method, array($path, $dir['suffix'], $dir['prefix']));
78 | }
79 | }
80 |
81 | $files = array(
82 | 'addFileToWhiteList' => array('whitelist', 'include', 'files'),
83 | 'removeFileFromWhiteList' => array('whitelist', 'exclude', 'files'),
84 | );
85 |
86 | foreach ($files as $method => $hiera) {
87 | foreach ($config[$hiera[0]][$hiera[1]][$hiera[2]] as $file) {
88 | $filter->addMethodCall($method, array($file));
89 | }
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/.appveyor.yml:
--------------------------------------------------------------------------------
1 | version: '{branch}-{build}'
2 | build: false
3 | shallow_clone: false
4 | platform: x64
5 | clone_folder: c:\projects\behat-code-coverage
6 | pull_requests:
7 | do_not_increment_build_number: true
8 |
9 | environment:
10 | COMPOSER_ROOT_VERSION: '7.0-dev'
11 | matrix:
12 | - PHP_VERSION: '7.2.0-Win32-VC15-x86'
13 | DEPENDENCIES: ''
14 | XDEBUG_VERSION: '2.6.0-7.2-vc15'
15 | - PHP_VERSION: '7.2.0-Win32-VC15-x86'
16 | DEPENDENCIES: '--prefer-lowest'
17 | XDEBUG_VERSION: '2.6.0-7.2-vc15'
18 | - PHP_VERSION: '7.1.12-Win32-VC14-x86'
19 | DEPENDENCIES: ''
20 | XDEBUG_VERSION: '2.6.0-7.1-vc14'
21 | - PHP_VERSION: '7.1.12-Win32-VC14-x86'
22 | DEPENDENCIES: '--prefer-lowest'
23 | XDEBUG_VERSION: '2.6.0-7.1-vc14'
24 |
25 | matrix:
26 | fast_finish: true
27 |
28 | #branches:
29 | #only:
30 | #- master
31 |
32 | skip_commits:
33 | message: /\[ci skip\]/
34 |
35 | cache:
36 | - c:\php -> appveyor.yml
37 | - c:\projects\behat-code-coverage\vendor
38 | - '%LOCALAPPDATA%\Composer\files'
39 |
40 | init:
41 | - SET PATH=c:\php\%PHP_VERSION%;%PATH%
42 | - SET COMPOSER_NO_INTERACTION=1
43 | - SET PHP=1
44 | - SET ANSICON=121x90 (121x90)
45 | - git config --global core.autocrlf input
46 |
47 | install:
48 | - IF NOT EXIST c:\php mkdir c:\php
49 | - IF NOT EXIST c:\php\%PHP_VERSION% mkdir c:\php\%PHP_VERSION%
50 | - cd c:\php\%PHP_VERSION%
51 | - IF NOT EXIST php-installed.txt curl -fsS -o php-%PHP_VERSION%.zip https://windows.php.net/downloads/releases/archives/php-%PHP_VERSION%.zip
52 | - IF NOT EXIST php-installed.txt 7z x php-%PHP_VERSION%.zip -y >nul
53 | - IF NOT EXIST php-installed.txt del /Q *.zip
54 | - IF NOT EXIST php-installed.txt copy /Y php.ini-development php.ini
55 | - IF NOT EXIST php-installed.txt echo max_execution_time=1200 >> php.ini
56 | - IF NOT EXIST php-installed.txt echo date.timezone="UTC" >> php.ini
57 | - IF NOT EXIST php-installed.txt echo extension_dir=ext >> php.ini
58 | - IF NOT EXIST php-installed.txt echo extension=php_curl.dll >> php.ini
59 | - IF NOT EXIST php-installed.txt echo extension=php_openssl.dll >> php.ini
60 | - IF NOT EXIST php-installed.txt echo extension=php_mbstring.dll >> php.ini
61 | - IF NOT EXIST php-installed.txt echo extension=php_fileinfo.dll >> php.ini
62 | - IF NOT EXIST php-installed.txt echo extension=php_mysqli.dll >> php.ini
63 | - IF NOT EXIST php-installed.txt echo extension=php_pdo_sqlite.dll >> php.ini
64 | - IF NOT EXIST php-installed.txt echo zend.assertions=1 >> php.ini
65 | - IF NOT EXIST php-installed.txt echo assert.exception=On >> php.ini
66 | - IF NOT EXIST php-installed.txt appveyor DownloadFile https://getcomposer.org/composer.phar
67 | - IF NOT EXIST php-installed.txt echo @php %%~dp0composer.phar %%* > composer.bat
68 | - IF NOT EXIST php-installed.txt type nul >> php-installed.txt
69 | - IF %PHP%==1 appveyor DownloadFile https://xdebug.org/files/php_xdebug-%XDEBUG_VERSION%.dll
70 | - mv php_xdebug-%XDEBUG_VERSION%.dll ext\
71 | - echo zend_extension="php_xdebug-%XDEBUG_VERSION%.dll" >> php.ini
72 | - echo xdebug.remote_enable=true >> php.ini
73 | - echo xdebug.remote_autostart=true >> php.ini
74 | - cd c:\projects\behat-code-coverage
75 | - composer self-update
76 | - composer update --no-progress --no-ansi --no-interaction --no-suggest --optimize-autoloader --prefer-stable %DEPENDENCIES%
77 |
78 | test_script:
79 | - cd c:\projects\behat-code-coverage
80 | - bin\phpcs
81 | - phpdbg -qrr vendor\phpunit\phpunit\phpunit -vvv
82 |
83 |
--------------------------------------------------------------------------------
/src/Listener/EventListener.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | class EventListener implements EventSubscriberInterface
26 | {
27 | /**
28 | * @var CodeCoverage
29 | */
30 | private $coverage;
31 |
32 | /**
33 | * @var \LeanPHP\Behat\CodeCoverage\Service\ReportService
34 | */
35 | private $reportService;
36 |
37 | /**
38 | * @var bool
39 | */
40 | private $skipCoverage;
41 |
42 | /**
43 | * Constructor
44 | *
45 | * @param CodeCoverage $coverage
46 | * @param \LeanPHP\Behat\CodeCoverage\Service\ReportService $reportService
47 | * @param boolean $skipCoverage
48 | */
49 | public function __construct(CodeCoverage $coverage, ReportService $reportService, $skipCoverage = false)
50 | {
51 | $this->coverage = $coverage;
52 | $this->reportService = $reportService;
53 | $this->skipCoverage = $skipCoverage;
54 | }
55 |
56 | /**
57 | * {@inheritdoc}
58 | */
59 | public static function getSubscribedEvents()
60 | {
61 | return array(
62 | ExerciseCompleted::BEFORE => 'beforeExercise',
63 | ScenarioTested::BEFORE => 'beforeScenario',
64 | ExampleTested::BEFORE => 'beforeScenario',
65 | ScenarioTested::AFTER => 'afterScenario',
66 | ExampleTested::AFTER => 'afterScenario',
67 | ExerciseCompleted::AFTER => 'afterExercise',
68 | );
69 | }
70 |
71 | /**
72 | * Before Exercise hook
73 | *
74 | * @param \Behat\Testwork\EventDispatcher\Event\ExerciseCompleted $event
75 | */
76 | public function beforeExercise(ExerciseCompleted $event)
77 | {
78 | if ($this->skipCoverage) {
79 | return;
80 | }
81 |
82 | $this->coverage->clear();
83 | }
84 |
85 | /**
86 | * Before Scenario/Outline Example hook
87 | *
88 | * @param \Behat\Behat\EventDispatcher\Event\ScenarioTested $event
89 | */
90 | public function beforeScenario(ScenarioTested $event)
91 | {
92 | if ($this->skipCoverage) {
93 | return;
94 | }
95 |
96 | $node = $event->getScenario();
97 | $id = $event->getFeature()->getFile().':'.$node->getLine();
98 |
99 | $this->coverage->start($id);
100 | }
101 |
102 | /**
103 | * After Scenario/Outline Example hook
104 | *
105 | * @param \Behat\Behat\EventDispatcher\Event\ScenarioTested $event
106 | */
107 | public function afterScenario(ScenarioTested $event)
108 | {
109 | if ($this->skipCoverage) {
110 | return;
111 | }
112 |
113 | $this->coverage->stop();
114 | }
115 |
116 | /**
117 | * After Exercise hook
118 | *
119 | * @param \Behat\Testwork\Tester\Event\ExerciseCompleted $event
120 | */
121 | public function afterExercise(ExerciseCompleted $event)
122 | {
123 | if ($this->skipCoverage) {
124 | return;
125 | }
126 |
127 | $this->reportService->generateReport($this->coverage);
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/Driver/RemoteXdebug.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class RemoteXdebug implements DriverInterface
22 | {
23 | /**
24 | * @var array
25 | */
26 | private $config;
27 |
28 | /**
29 | * @var GuzzleHttp\Client
30 | */
31 | private $client;
32 |
33 | /**
34 | * Constructor
35 | *
36 | * [
37 | * 'base_uri' => 'http://api.example.com/1.0/coverage',
38 | * 'auth' => [
39 | * 'user' => 'user name',
40 | * 'password' => 'password',
41 | * ],
42 | * 'create' => [
43 | * 'method' => 'POST',
44 | * 'path' => '/',
45 | * ],
46 | * 'read' => [
47 | * 'method' => 'GET',
48 | * 'path' => '/',
49 | * ],
50 | * 'delete' => [
51 | * 'method' => 'DELETE',
52 | * 'path' => '/',
53 | * ],
54 | * ]
55 | *
56 | * @param array $config Configuration
57 | * @param GuzzleHttp\Client $client HTTP client
58 | */
59 | public function __construct(array $config, Client $client)
60 | {
61 | $this->config = $config;
62 |
63 | $this->client = $client;
64 | //$this->client->setBaseUrl($config['base_url']);
65 | }
66 |
67 | /**
68 | * {@inheritdoc}
69 | */
70 | public function start(bool $determineUnusedAndDead = true): void
71 | {
72 | $response = $this->sendRequest('create');
73 |
74 | if ($response->getStatusCode() !== 200) {
75 | throw new \Exception(sprintf('remote driver start failed: %s', $response->getReasonPhrase()));
76 | }
77 | }
78 |
79 | /**
80 | * {@inheritdoc}
81 | */
82 | public function stop(): array
83 | {
84 | $response = $this->sendRequest('read', ['headers' => ['Accept' => 'application/json']]);
85 |
86 | if ($response->getStatusCode() !== 200) {
87 | throw new \Exception(sprintf('remote driver fetch failed: %s', $response->getReasonPhrase()));
88 | }
89 |
90 | $response = $this->sendRequest('delete');
91 |
92 | return json_decode($response->getBody(true), true);
93 | }
94 |
95 | /**
96 | * Construct request
97 | *
98 | * @param string $endpoint
99 | * @param array $headers
100 | *
101 | * @return GuzzleHttp\Psr7\Response
102 | */
103 | private function sendRequest($endpoint, $headers = array())
104 | {
105 | $method = strtolower($this->config[$endpoint]['method']);
106 |
107 | if (! in_array($method, array('get', 'post', 'put', 'delete'))) {
108 | throw new \Exception(sprintf('%s method must be GET, POST, PUT, or DELETE', $endpoint));
109 | }
110 |
111 | if (isset($this->config['auth'])) {
112 | $response = $this->client->request(
113 | $method,
114 | $this->config[$endpoint]['path'],
115 | [
116 | 'auth' => [$this->config['auth']['user'], $this->config['auth']['password']],
117 | 'headers' => $headers,
118 | ]
119 | );
120 | } else {
121 | $response = $this->client->request(
122 | $method,
123 | $this->config[$endpoint]['path'],
124 | [
125 | 'headers' => $headers,
126 | ]
127 | );
128 | }
129 |
130 | return $response;
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/tests/VIPSoft/TestCase.php:
--------------------------------------------------------------------------------
1 |
17 | */
18 | class TestCase extends BaseTestCase
19 | {
20 | /**
21 | * @var array
22 | */
23 | static public $proxiedFunctions;
24 |
25 | /**
26 | * {@inheritdoc}
27 | */
28 | protected function setUp()
29 | {
30 | parent::setUp();
31 |
32 | if ( ! class_exists('\\VIPSoft\\Test\\FunctionProxy')) {
33 | eval(<<getCaller();
69 |
70 | if ( ! $caller || ! isset($caller[0]) || ($pos = strrpos($caller[0], '\\')) === false) {
71 | throw new \Exception('Unable to mock functions in the root namespace');
72 | }
73 |
74 | $namespace = str_replace(array('\\Test\\', '\\Tests\\'), '\\', substr($caller[0], 0, $pos));
75 | }
76 |
77 | if ( ! function_exists('\\' . $namespace . '\\' . $functionName)) {
78 | eval(<<getMockFunction('extension_loaded', function () {
24 | return false;
25 | });
26 |
27 | try {
28 | new XCache();
29 |
30 | $this->fail();
31 | } catch (\Exception $e) {
32 | $this->assertTrue($e instanceof \SebastianBergmann\CodeCoverage\RuntimeException);
33 | $this->assertEquals('This driver requires XCache', $e->getMessage());
34 | }
35 | }
36 |
37 | public function testConstructXCacheCoverageNotEnabled()
38 | {
39 | $function = $this->createMock('VIPSoft\Test\FunctionProxy');
40 | $function->expects($this->once())
41 | ->method('invokeFunction')
42 | ->will($this->returnValue(true));
43 |
44 | $this->getMockFunction('extension_loaded', $function);
45 |
46 | $this->getMockFunction('phpversion', function () {
47 | return '3.1.0';
48 | });
49 |
50 | $this->getMockFunction('ini_get', function () {
51 | return false;
52 | });
53 |
54 | try {
55 | new XCache();
56 |
57 | $this->fail();
58 | } catch (\Exception $e) {
59 | $this->assertTrue($e instanceof \SebastianBergmann\CodeCoverage\Exception);
60 | $this->assertEquals('xcache.coverager=On has to be set in php.ini', $e->getMessage());
61 | }
62 | }
63 |
64 | public function testConstructXCache()
65 | {
66 | $function = $this->createMock('VIPSoft\Test\FunctionProxy');
67 | $function->expects($this->once())
68 | ->method('invokeFunction')
69 | ->will($this->returnValue(true));
70 |
71 | $this->getMockFunction('extension_loaded', $function);
72 |
73 | $this->getMockFunction('phpversion', function () {
74 | return '3.1.0';
75 | });
76 |
77 | $this->getMockFunction('ini_get', function () {
78 | return true;
79 | });
80 |
81 | new XCache();
82 | }
83 |
84 | public function testStartXCache()
85 | {
86 | $function = $this->createMock('VIPSoft\Test\FunctionProxy');
87 | $function->expects($this->once())
88 | ->method('invokeFunction')
89 | ->will($this->returnValue(true));
90 |
91 | $this->getMockFunction('extension_loaded', $function);
92 |
93 | $this->getMockFunction('phpversion', function () {
94 | return '3.1.0';
95 | });
96 |
97 | $this->getMockFunction('ini_get', function () {
98 | return true;
99 | });
100 |
101 | $function = $this->createMock('VIPSoft\Test\FunctionProxy');
102 | $function->expects($this->once())
103 | ->method('invokeFunction');
104 |
105 | $this->getMockFunction('xcache_coverager_start', $function);
106 |
107 | $driver = new XCache();
108 | $driver->start();
109 | }
110 |
111 | public function testStopXCache()
112 | {
113 | $function = $this->createMock('VIPSoft\Test\FunctionProxy');
114 | $function->expects($this->once())
115 | ->method('invokeFunction')
116 | ->will($this->returnValue(true));
117 |
118 | $this->getMockFunction('extension_loaded', $function);
119 |
120 | $this->getMockFunction('phpversion', function () {
121 | return '3.1.0';
122 | });
123 |
124 | $this->getMockFunction('ini_get', function () {
125 | return true;
126 | });
127 |
128 | $function = $this->createMock('VIPSoft\Test\FunctionProxy');
129 | $function->expects($this->exactly(2))
130 | ->method('invokeFunction');
131 |
132 | $this->getMockFunction('xcache_coverager_get', $function);
133 | $this->getMockFunction('xcache_coverager_stop', $function);
134 |
135 | $driver = new XCache();
136 | $driver->stop();
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/tests/Driver/RemoteXdebugTest.php:
--------------------------------------------------------------------------------
1 | config = array(
32 | 'base_uri' => 'http://localhost',
33 | 'auth' => array(
34 | 'user' => 'user name',
35 | 'password' => 'password',
36 | ),
37 | 'create' => array(
38 | 'method' => 'POST',
39 | 'path' => '/',
40 | ),
41 | 'read' => array(
42 | 'method' => 'GET',
43 | 'path' => '/',
44 | ),
45 | 'delete' => array(
46 | 'method' => 'DELETE',
47 | 'path' => '/',
48 | ),
49 | );
50 |
51 | $this->response = $this->getMockBuilder('GuzzleHttp\Psr7\Response')
52 | ->disableOriginalConstructor()
53 | ->getMock();
54 |
55 | $request = $this->getMockBuilder('GuzzleHttp\Psr7\Request')
56 | ->disableOriginalConstructor()
57 | ->getMock();
58 |
59 | $response = $this->getMockBuilder('GuzzleHttp\Psr7\Response')
60 | ->disableOriginalConstructor()
61 | ->getMock();
62 |
63 | $response->expects($this->any())
64 | ->method('getStatusCode')
65 | ->will($this->returnValue('302'));
66 |
67 | $this->client = $this->createMock('GuzzleHttp\Client');
68 | $this->client->expects($this->any())
69 | ->method('request')
70 | ->will($this->returnValue($response));
71 | $this->client->expects($this->any())
72 | ->method('request')
73 | ->will($this->returnValue($response));
74 | $this->client->expects($this->any())
75 | ->method('request')
76 | ->will($this->returnValue($response));
77 | $this->client->expects($this->any())
78 | ->method('request')
79 | ->will($this->returnValue($response));
80 | }
81 |
82 | public function testInvalidMethodException()
83 | {
84 | try {
85 | $this->config['create']['method'] = 'TRACE';
86 |
87 | $driver = new RemoteXdebug($this->config, $this->client);
88 | $driver->start();
89 |
90 | $this->fail();
91 | } catch (\Exception $e) {
92 | $this->assertTrue(strpos($e->getMessage(), 'method must be GET, POST, PUT, or DELETE') !== false);
93 | }
94 | }
95 |
96 | public function testStart()
97 | {
98 | $driver = new RemoteXdebug($this->config, $this->client);
99 |
100 | try {
101 | $driver->start();
102 | } catch (\Exception $e) {
103 | $this->assertTrue(strpos($e->getMessage(), 'remote driver start failed: ') === 0);
104 | }
105 |
106 | }
107 |
108 | public function testStartException()
109 | {
110 | try {
111 | $driver = new RemoteXdebug($this->config, $this->client);
112 | $driver->start();
113 |
114 | $this->fail();
115 | } catch (\Exception $e) {
116 | $this->assertTrue(strpos($e->getMessage(), 'remote driver start failed: ') === 0);
117 | }
118 | }
119 |
120 | public function testStop()
121 | {
122 | $driver = new RemoteXdebug($this->config, $this->client);
123 |
124 | try {
125 | $coverage = $driver->stop();
126 | } catch (\Exception $e) {
127 | $this->assertTrue(strpos($e->getMessage(), 'remote driver fetch failed: ') === 0);
128 | }
129 | }
130 |
131 | public function testStopException()
132 | {
133 | try {
134 | $driver = new RemoteXdebug($this->config, $this->client);
135 |
136 | $coverage = $driver->stop();
137 |
138 | $this->fail();
139 | } catch (\Exception $e) {
140 | $this->assertTrue(strpos($e->getMessage(), 'remote driver fetch failed: ') === 0);
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/tests/Listener/EventListenerTest.php:
--------------------------------------------------------------------------------
1 | coverage = $this->createMock('SebastianBergmann\CodeCoverage\CodeCoverage');
38 |
39 | $this->service = $this->getMockBuilder('LeanPHP\Behat\CodeCoverage\Service\ReportService')
40 | ->disableOriginalConstructor()
41 | ->getMock();
42 | }
43 |
44 | public function testGetSubscribedEvents()
45 | {
46 | $listener = new EventListener($this->coverage, $this->service);
47 | $events = $listener->getSubscribedEvents();
48 |
49 | $this->assertTrue(is_array($events));
50 | $this->assertCount(6, $events);
51 | }
52 |
53 | public function testBeforeExercise()
54 | {
55 | $this->coverage->expects($this->once())
56 | ->method('clear');
57 |
58 | $event = $this->getMockBuilder('Behat\Testwork\EventDispatcher\Event\ExerciseCompleted')
59 | ->disableOriginalConstructor()
60 | ->getMock();
61 |
62 | $listener = new EventListener($this->coverage, $this->service);
63 | $listener->beforeExercise($event);
64 | }
65 |
66 | public function testAfterExercise()
67 | {
68 | $this->service->expects($this->once())
69 | ->method('generateReport');
70 |
71 | $event = $this->getMockBuilder('Behat\Testwork\EventDispatcher\Event\ExerciseCompleted')
72 | ->disableOriginalConstructor()
73 | ->getMock();
74 |
75 | $listener = new EventListener($this->coverage, $this->service);
76 | $listener->afterExercise($event);
77 | }
78 |
79 | public function testBeforeScenario()
80 | {
81 | $this->coverage->expects($this->once())
82 | ->method('start')
83 | ->with('MyFile.feature:1');
84 |
85 | $node = new ScenarioNode('scenarioNode', array(), array(), 'Scenario', 1);
86 |
87 | $feature = new FeatureNode('featureNode', 'A Feature', array(), null, array(), 'Feature', 'en', 'MyFile.feature', 0);
88 |
89 | $event = $this->getMockBuilder('Behat\Behat\EventDispatcher\Event\ScenarioTested')
90 | ->disableOriginalConstructor()
91 | ->getMock();
92 |
93 | $event->expects($this->once())
94 | ->method('getScenario')
95 | ->will($this->returnValue($node));
96 |
97 | $event->expects($this->once())
98 | ->method('getFeature')
99 | ->will($this->returnValue($feature));
100 |
101 | $listener = new EventListener($this->coverage, $this->service);
102 | $listener->beforeScenario($event);
103 | }
104 |
105 | public function testBeforeExample()
106 | {
107 | $this->coverage->expects($this->once())
108 | ->method('start')
109 | ->with('MyFile.feature:2');
110 |
111 | $node = new OutlineNode('outlineNode', array(), array(), new ExampleTableNode(array(), 'Example'), 'Outline', 2);
112 |
113 | $feature = new FeatureNode('featureNode', 'A Feature', array(), null, array(), 'Feature', 'en', 'MyFile.feature', 0);
114 |
115 | $event = $this->getMockBuilder('Behat\Behat\EventDispatcher\Event\ScenarioTested')
116 | ->disableOriginalConstructor()
117 | ->getMock();
118 |
119 | $event->expects($this->once())
120 | ->method('getScenario')
121 | ->will($this->returnValue($node));
122 |
123 | $event->expects($this->once())
124 | ->method('getFeature')
125 | ->will($this->returnValue($feature));
126 |
127 | $listener = new EventListener($this->coverage, $this->service);
128 | $listener->beforeScenario($event);
129 | }
130 |
131 | public function testAfterScenario()
132 | {
133 | $this->coverage->expects($this->once())
134 | ->method('stop');
135 |
136 | $event = $this->getMockBuilder('Behat\Behat\EventDispatcher\Event\ScenarioTested')
137 | ->disableOriginalConstructor()
138 | ->getMock();
139 |
140 | $listener = new EventListener($this->coverage, $this->service);
141 | $listener->afterScenario($event);
142 | }
143 | }*/
144 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # CHANGELOG
2 |
3 | All notable changes to [leanphp/behat-code-coverage][0] package will be
4 | documented in this file.
5 |
6 | The format is based on [Keep a Changelog](http://keepachangelog.com/)
7 | and this project adheres to [Semantic Versioning](http://semver.org/).
8 |
9 | ## [3.4.1] - 2018-05-09
10 |
11 | - **BUG**: Fix a bug regarding deprecated CodeCoverage function in v6 (#35)
12 |
13 | ## [3.4.0] - 2018-05-04
14 |
15 | - Require PHP 7.1 and php-code-coverage ^6.0.
16 | - Fixes for Drivers to support php-code-coverage ^6.0.
17 | - Updated require-dev to use phpunit v7.0
18 |
19 | ## [3.3.1] - 2018-05-04
20 |
21 | - Fix compatibility with `phpunit/php-code-coverage:^6.0`, only leaving support
22 | to `5.0,<6.0` as we cannot support both.
23 |
24 | ## [3.3.0] - 2018-04-13
25 |
26 | - Add `--no-coverage` parameter option to skip code coverage generation.
27 | - Update `phpunit/php-code-coverage` requirement from `^5.0` to `^5.0||^6.0`
28 |
29 | ## [3.2.1] - 2018-03-21
30 |
31 | - Fixed a bug where a suffix when whitelisting files would default to `src`.
32 | This would make reports not generate in case no `suffix` was defined in
33 | configuration.
34 | - Fixed Text report printing (issue #12)
35 | - `phpunit/php-code-coverage` dependency version requirement has been updated
36 | from `~4.0|~5.0` to `^5.0` as we do not support version `4.0` anymore.
37 | - Updated README to list all configuration options
38 | - Updated `behat.yml.dist` so that it can be used as a proper example
39 | - `remote` driver is no longer activated by default
40 | - Version constraints in composer.json have been updated from `~` to `^`.
41 |
42 |
43 | ## [3.2.0] - 2017-10-17 - Guzzle 6.0 support release
44 |
45 | - Updated `guzzlehttp/guzzle` requirement from `~4.0||~5.0` to `~6.0`. We are
46 | considering dropping `guzzlehttp` as a requirement altogether and have it as
47 | `suggested` packages instead, as it is only required when using remote xdebug.
48 | We are looking for feedback regarding this on
49 | https://github.com/leanphp/behat-code-coverage/issues/15
50 |
51 | ## [3.1.1] - 2018-03-21
52 |
53 | - Fix for default `suffix` when whitelisting directories being defined as `src`.
54 | See #28 for information.
55 |
56 | ## [3.1.0] - 2017-10-17 - Legacy maintenance release
57 |
58 | - Update PHP requirement to `>=5.6` (from `>=5.3.10`)
59 | - Update `guzzlehttp/guzzle` from `~3.0` to `~4.0||~5.0`.
60 | - Update `phpunit/php-code-coverage` from `~2.2` to `~4.0||~5.0`.
61 | - Removed blacklist functionality from configuration files (use `whiltelisted`
62 | directories with `include`/`exclude` instead).
63 | - Add/implement missing tests for Xml and Crap4j reporters
64 | - Mark `phpdbg` or `xdebug` specific tests so they are skipped automatically
65 | (using phpunit's @requires).
66 |
67 | ## [3.0.0] - 2017-04-08 (backported `3.0.x-dev` + patches)
68 |
69 | - Fixed compatibility with Symfony `2.x` and `3.x` #2
70 | - Fixed abandoned guzzle dependency #6
71 | - Enabled Windows based CI testing (appveyor) to make sure extension is
72 | compatible with Windows OS #5
73 | - Merged commits from `3.0.x-dev` (`master` branch) of
74 | `vipsoft/code-coverage-extension` (adds support for Behat `~3.0`)
75 | - Update Travis CI to test against all supported versions of PHP (`5.3` to
76 | `7.1`).
77 | - Enable windows based CI tests (appveyor).
78 | - Added `symfony/expression-language` as a dependency for users using older
79 | versions of PHP and symonfy `2.x` / `3.x`.
80 |
81 | ## [2.5.5] - 2017-04-04 (backported v2.5.0.5, original release on 2014-02-10)
82 |
83 | **Note!** This version is a direct backport of `2.5.0.5` of
84 | [vipsoft/code-coverage-extension][1] package with updated namespaces to work
85 | as [leanphp/behat-code-coverage][0]. It additionally includes code from
86 | [vipsoft/code-coverage-common][2] package, so in case the package would
87 | disappear, this extension would still work.
88 |
89 | - PHP `>=5.3.10`
90 | - Behat `~2.4`
91 | - Symfony components `~2.2,<2.4`
92 | - PHPUnit `~4.0` (updated from `3.7.*` in order to make tests pass)
93 | - Removed `vipsoft/code-coverage-common` dependency (code is now included in
94 | the package, will be refactored in the future)
95 | - Updated `vfsStream` from `1.2.*` to `1.3.*` to fix failing/skipped test
96 | - Updated versions of dependencies and code is tested to run with Behat `2.5`.
97 |
98 | [3.4.x-dev]: https://github.com/leanphp/behat-code-coverage/compare/v3.4.1...master
99 | [3.4.1]: https://github.com/leanphp/behat-code-coverage/releases/tag/v3.4.1
100 | [3.4.0]: https://github.com/leanphp/behat-code-coverage/releases/tag/v3.4.0
101 | [3.3.1]: https://github.com/leanphp/behat-code-coverage/releases/tag/v3.3.1
102 | [3.3.0]: https://github.com/leanphp/behat-code-coverage/releases/tag/v3.3.0
103 | [3.2.1]: https://github.com/leanphp/behat-code-coverage/releases/tag/v3.2.0
104 | [3.2.0]: https://github.com/leanphp/behat-code-coverage/releases/tag/v3.2.0
105 | [3.1.1]: https://github.com/leanphp/behat-code-coverage/releases/tag/v3.1.1
106 | [3.1.0]: https://github.com/leanphp/behat-code-coverage/releases/tag/v3.1.0
107 | [3.0.0]: https://github.com/leanphp/behat-code-coverage/releases/tag/v3.0.0
108 | [2.5.5]: https://github.com/leanphp/behat-code-coverage/releases/tag/v2.5.5
109 |
110 | [0]: https://github.com/leanphp/behat-code-coverage
111 | [1]: https://github.com/vipsoft/code-coverage-extension
112 | [2]: https://github.com/vipsoft/code-coverage-common
113 |
--------------------------------------------------------------------------------
/tests/Compiler/FilterPassTest.php:
--------------------------------------------------------------------------------
1 | createMock('Symfony\Component\DependencyInjection\ContainerBuilder');
24 | $container->expects($this->exactly(2))
25 | ->method('hasDefinition')
26 | ->will($this->returnValue(false));
27 |
28 | $pass = new FilterPass();
29 | $pass->process($container);
30 | }
31 |
32 | public function testProcessCodeCoverage()
33 | {
34 | $coverage = $this->createMock('Symfony\Component\DependencyInjection\Definition');
35 | $coverage->expects($this->exactly(3))
36 | ->method('addMethodCall');
37 |
38 | $container = $this->createMock('Symfony\Component\DependencyInjection\ContainerBuilder');
39 | $container->expects($this->exactly(2))
40 | ->method('hasDefinition')
41 | ->will($this->onConsecutiveCalls(true, false));
42 |
43 | $container->expects($this->once())
44 | ->method('getDefinition')
45 | ->with('behat.code_coverage.php_code_coverage')
46 | ->will($this->returnValue($coverage));
47 |
48 | $container->expects($this->once())
49 | ->method('getParameter')
50 | ->with('behat.code_coverage.config.filter')
51 | ->will($this->returnValue(array(
52 | 'whitelist' => array(
53 | 'addUncoveredFilesFromWhitelist' => false,
54 | 'processUncoveredFilesFromWhitelist' => true
55 | ),
56 | 'forceCoversAnnotation' => false,
57 | 'mapTestClassNameToCoveredClassName' => true
58 | )));
59 |
60 | $pass = new FilterPass();
61 | $pass->process($container);
62 | }
63 |
64 | public function testProcessCodeCoverageFilter()
65 | {
66 | $filter = $this->createMock('Symfony\Component\DependencyInjection\Definition');
67 | $filter->expects($this->exactly(4))
68 | ->method('addMethodCall');
69 |
70 | $container = $this->createMock('Symfony\Component\DependencyInjection\ContainerBuilder');
71 | $container->expects($this->exactly(2))
72 | ->method('hasDefinition')
73 | ->will($this->onConsecutiveCalls(false, true));
74 |
75 | $container->expects($this->once())
76 | ->method('getDefinition')
77 | ->with('behat.code_coverage.php_code_coverage_filter')
78 | ->will($this->returnValue($filter));
79 |
80 | $container->expects($this->once())
81 | ->method('getParameter')
82 | ->with('behat.code_coverage.config.filter')
83 | ->will($this->returnValue(array(
84 | 'whitelist' => array(
85 | 'addUncoveredFilesFromWhitelist' => false,
86 | 'processUncoveredFilesFromWhitelist' => true,
87 | 'include' => array(
88 | 'directories' => array(
89 | 'directory1' => array(
90 | 'prefix' => 'Secure',
91 | 'suffix' => '.php',
92 | )
93 | ),
94 | 'files' => array(
95 | 'file1'
96 | ),
97 | ),
98 | 'exclude' => array(
99 | 'directories' => array(
100 | 'directory2' => array(
101 | 'prefix' => 'Insecure',
102 | 'suffix' => '.inc',
103 | )
104 | ),
105 | 'files' => array(
106 | 'file2'
107 | ),
108 | ),
109 | ),
110 | 'blacklist' => array(
111 | 'include' => array(
112 | 'directories' => array(
113 | 'directory3' => array(
114 | 'prefix' => 'Public',
115 | 'suffix' => '.php',
116 | )
117 | ),
118 | 'files' => array(
119 | 'file3'
120 | ),
121 | ),
122 | 'exclude' => array(
123 | 'directories' => array(
124 | 'directory4' => array(
125 | 'prefix' => 'Private',
126 | 'suffix' => '.inc',
127 | )
128 | ),
129 | 'files' => array(
130 | 'file4'
131 | ),
132 | ),
133 | ),
134 | )));
135 |
136 | $pass = new FilterPass();
137 | $pass->process($container);
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/Resources/config/services.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | LeanPHP\Behat\CodeCoverage\Controller\Cli\CodeCoverageController
8 | LeanPHP\Behat\CodeCoverage\Driver\Proxy
9 | LeanPHP\Behat\CodeCoverage\Driver\RemoteXdebug
10 | LeanPHP\Behat\CodeCoverage\Listener\EventListener
11 | LeanPHP\Behat\CodeCoverage\Service\ReportService
12 | LeanPHP\Behat\CodeCoverage\Common\Report\Factory
13 | false
14 |
15 |
16 | %mink.base_url%
17 | %behat.code_coverage.config.auth%
18 | %behat.code_coverage.config.create%
19 | %behat.code_coverage.config.read%
20 | %behat.code_coverage.config.delete%
21 | %behat.code_coverage.config.drivers%
22 | %behat.code_coverage.config.filter%
23 | %behat.code_coverage.config.report%
24 |
25 |
26 | LeanPHP\Behat\CodeCoverage\Common\Driver\HHVM
27 | LeanPHP\Behat\CodeCoverage\Common\Driver\XCache
28 | SebastianBergmann\CodeCoverage\Driver\Xdebug
29 | LeanPHP\Behat\CodeCoverage\Common\Driver\Factory
30 |
31 |
32 |
33 |
34 |
36 |
37 |
38 |
39 |
40 |
43 |
44 |
45 |
48 |
49 |
50 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
76 |
77 |
78 |
79 |
80 | %behat.code_coverage.config%
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | %behat.code_coverage.skip%
89 |
90 |
91 |
92 |
93 |
94 |
95 | %behat.code_coverage.config%
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/src/Resources/config/services-2.3.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | LeanPHP\Behat\CodeCoverage\Controller\Cli\CodeCoverageController
8 | LeanPHP\Behat\CodeCoverage\Driver\Proxy
9 | LeanPHP\Behat\CodeCoverage\Driver\RemoteXdebug
10 | LeanPHP\Behat\CodeCoverage\Listener\EventListener
11 | LeanPHP\Behat\CodeCoverage\Service\ReportService
12 | LeanPHP\Behat\CodeCoverage\Common\Report\Factory
13 | false
14 |
15 |
16 | %mink.base_url%
17 | %behat.code_coverage.config.auth%
18 | %behat.code_coverage.config.create%
19 | %behat.code_coverage.config.read%
20 | %behat.code_coverage.config.delete%
21 | %behat.code_coverage.config.drivers%
22 | %behat.code_coverage.config.filter%
23 | %behat.code_coverage.config.report%
24 |
25 |
26 | LeanPHP\Behat\CodeCoverage\Common\Driver\HHVM
27 | LeanPHP\Behat\CodeCoverage\Common\Driver\XCache
28 | SebastianBergmann\CodeCoverage\Driver\Xdebug
29 | LeanPHP\Behat\CodeCoverage\Common\Driver\Factory
30 |
31 |
32 |
33 |
34 |
36 |
37 |
38 |
39 |
40 |
43 |
44 |
45 |
48 |
49 |
50 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
76 |
77 |
78 |
79 |
80 | %behat.code_coverage.config%
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | %behat.code_coverage.skip%
89 |
90 |
91 |
92 |
93 |
94 |
95 | %behat.code_coverage.config%
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | behat-code-coverage
2 | ===================
3 | [](#License)
4 | [](https://packagist.org/packages/leanphp/behat-code-coverage)
5 | [](https://packagist.org/packages/leanphp/behat-code-coverage)
6 | [](https://travis-ci.org/leanphp/behat-code-coverage)
7 | [](https://ci.appveyor.com/project/leanphp/behat-code-coverage)
8 | [](https://packagist.org/packages/leanphp/behat-code-coverage)
9 |
10 | [behat-code-coverage][0] is a [Behat][3] extension that generates Code
11 | Coverage reports for [Behat][3] tests.
12 |
13 | Generating Code Coverage reports allows you to to analyze which parts of your
14 | codebase are tested and how well. However, Code Coverage alone should NOT be
15 | used as a single metric defining how good your tests are.
16 |
17 | **Note!** This is a maintained fork of [vipsoft/code-coverage-extension][1],
18 | including codebase for [vipsoft/code-coverage-common][2] package with
19 | compatible version numbers for stable releases.
20 |
21 | ## Requirements
22 |
23 | - PHP 5.6+ / 7.0+
24 | - [Behat v3][3]
25 | - [Xdebug][5] or [phpdbg][6] extension enabled
26 |
27 | ## Change Log
28 |
29 | Please see [CHANGELOG.md](CHANGELOG.md) for information on recent changes.
30 |
31 | ## Install
32 |
33 | Install this package as a development dependency in your project:
34 |
35 | $ composer require --dev leanphp/behat-code-coverage
36 |
37 | Enable extension by editing `behat.yml` of your project:
38 |
39 | ``` yaml
40 | default:
41 | extensions:
42 | LeanPHP\Behat\CodeCoverage\Extension:
43 | drivers:
44 | - local
45 | filter:
46 | whitelist:
47 | include:
48 | directories:
49 | 'src': ~
50 | report:
51 | format: html
52 | options:
53 | target: build/behat-coverage
54 | ```
55 |
56 | This will sufficient to enable Code Coverage generation in `html` format in
57 | `build/behat-coverage` directory. This extension supports various
58 | [Configuration options](#configuration-options). For a fully annotated example
59 | configuration file check [Configuration section](#configuration).
60 |
61 | ## Usage
62 |
63 | If you execute `bin/behat` command, you will see code coverage generated in
64 | `target` (i.e. `build/behat-coverage`) directory (in `html` format):
65 |
66 | $ bin/behat
67 |
68 | ### Running with phpdbg
69 |
70 | This extension now supports [phpdbg][6], which results in faster execution when
71 | using more recent versions of PHP. Run `phpspec` via [phpdbg][6]:
72 |
73 | $ phpdbg -qrr bin/behat run
74 |
75 | ## Configuration
76 |
77 | You can see fully annotated `behat.yml` example file below, which can be used
78 | as a starting point to further customize the defaults of the extension. The
79 | configuration file below has all of the [Configuration Options](#Configuration
80 | Options).
81 |
82 | ```yaml
83 | # behat.yml
84 | # ...
85 | default:
86 | extensions:
87 | LeanPHP\Behat\CodeCoverage\Extension:
88 | # http auth (optional)
89 | auth: ~
90 | # select which driver to use when gatherig coverage data
91 | drivers:
92 | - local # local Xdebug driver
93 | # filter options
94 | filter:
95 | forceCoversAnnotation: false
96 | mapTestClassNameToCoveredClassName: false
97 | whitelist:
98 | addUncoveredFilesFromWhitelist: true
99 | processUncoveredFilesFromWhitelist: false
100 | include:
101 | directories:
102 | 'src': ~
103 | 'tests':
104 | suffix: '.php'
105 | # files:
106 | # - script1.php
107 | # - script2.php
108 | # exclude:
109 | # directories:
110 | # 'vendor': ~
111 | # 'path/to/dir':
112 | # 'suffix': '.php'
113 | # 'prefix': 'Test'
114 | # files:
115 | # - tests/bootstrap.php
116 | # report configuration
117 | report:
118 | # report format (html, clover, php, text)
119 | format: html
120 | # report options
121 | options:
122 | target: build/behat-coverage/html
123 | ```
124 |
125 | ### Configuration Options
126 |
127 | * `auth` - HTTP authentication options (optional).
128 | - `create` (`method` / `path`) - override options for create method:
129 | - `method` - specify a method (default: `POST`)
130 | - `path` - specify path (default: `/`)
131 | - `read` (`method` / `path`) - override options (method and path) for read
132 | method.
133 | - `method` - specify a method (default: `GET`)
134 | - `path` - specify path (default: `/`)
135 | - `delete` (`method` / `path`) - override options (method and path) for delete
136 | method.
137 | - `method` - specify a method (default: `DELETE`)
138 | - `path` - specify path (default: `/`)
139 | - `drivers` - a list of drivers for gathering code coverage data:
140 | - `local` - local Xdebug driver (default).
141 | - `remote` - remote Xdebug driver (disabled by default).
142 | - `filter` - various filter options:
143 | - `forceCoversAnnotation` - (default: `false`)
144 | - `mapTestClassNameToCoveredClassName` - (default: `false`)
145 | - `whiltelist` - whitelist specific options:
146 | - `addUncoveredFilesFromWhiltelist` - (default: `true`)
147 | - `processUncoveredFilesFromWhitelist` - (default: `false`)
148 | - `include` - a list of files or directories to include in whitelist:
149 | - `directories` - key containing whitelisted directories to include.
150 | - `suffix` - suffix for files to be included (default: `'.php'`)
151 | - `prefix` - prefix of files to be included (default: `''`)
152 | (optional)
153 | - `files` - a list containing whitelisted files to include.
154 | - `exclude` - a list of files or directories to exclude from whitelist:
155 | - `directories` - key containing whitelisted directories to exclude.
156 | - `suffix` - suffix for files to be included (default: `'.php'`)
157 | - `prefix` - prefix of files to be included (default: `''`)
158 | (optional)
159 | - `files` - key containing whitelisted files to exclude.
160 | - `report` - reporter options:
161 | - `format` - specify report format (`html`, `clover`, `php`, `text`)
162 | - `options` - format options:
163 | - `target` - target/output directory
164 |
165 | ## Authors
166 |
167 | Copyright (c) 2017 ek9 (https://ek9.co).
168 |
169 | Copyright (c) 2013-2016 Anthon Pang, Konstantin Kudryashov
170 | [everzet](http://github.com/everzet) and [various
171 | contributors](https://github.com/leanphp/behat-code-coverage/graphs/contributors)
172 | for portions of code from [vipsoft/code-coverage-extension][1] and
173 | [vipsoft/code-coverage-common][2] projects.
174 |
175 | ## License
176 |
177 | Licensed under [BSD-2-Clause License](LICENSE).
178 |
179 | [0]: https://github.com/leanphp/behat-code-coverage
180 | [1]: https://github.com/vipsoft/code-coverage-extension
181 | [2]: https://github.com/vipsoft/code-coverage-common
182 | [3]: http://behat.org/en/v2.5/
183 | [4]: http://mink.behat.org
184 | [5]: https://xdebug.org/
185 | [6]: http://phpdbg.com/
186 |
187 | [travis-image]: https://travis-ci.org/leanphp/behat-code-coverage.svg
188 | [travis-url]: https://travis-ci.org/leanphp/behat-code-coverage
189 |
190 |
--------------------------------------------------------------------------------
/src/Extension.php:
--------------------------------------------------------------------------------
1 |
24 | */
25 | class Extension implements ExtensionInterface
26 | {
27 | /**
28 | * @var string
29 | */
30 | private $configFolder;
31 |
32 | /**
33 | * Constructor
34 | *
35 | * @param string $configFolder
36 | */
37 | public function __construct($configFolder = null)
38 | {
39 | $this->configFolder = $configFolder ?: __DIR__.'/Resources/config';
40 | }
41 |
42 | /**
43 | * {@inheritdoc}
44 | */
45 | public function initialize(ExtensionManager $extensionManager)
46 | {
47 | }
48 |
49 | /**
50 | * {@inheritdoc}
51 | */
52 | public function load(ContainerBuilder $container, array $config)
53 | {
54 | $loader = new XmlFileLoader($container, new FileLocator($this->configFolder));
55 |
56 | $servicesFile = 'services.xml';
57 | if (true === method_exists('Symfony\Component\DependencyInjection\Definition', 'setFactoryClass')) {
58 | $servicesFile = 'services-2.3.xml';
59 | }
60 | $loader->load($servicesFile);
61 |
62 | if (! isset($config['auth']['user']) || ! isset($config['auth']['password'])) {
63 | $config['auth'] = null;
64 | }
65 |
66 | if (! count($config['drivers'])) {
67 | $config['drivers'] = array('local');
68 | }
69 |
70 | if (! count($config['report']['options'])) {
71 | $config['report']['options'] = array(
72 | 'target' => '/tmp',
73 | );
74 | }
75 |
76 | if (! $container->hasParameter('mink.base_url')) {
77 | $container->setParameter('mink.base_url', null);
78 | }
79 |
80 | $container->setParameter('behat.code_coverage.config.auth', $config['auth']);
81 | $container->setParameter('behat.code_coverage.config.create', $config['create']);
82 | $container->setParameter('behat.code_coverage.config.read', $config['read']);
83 | $container->setParameter('behat.code_coverage.config.delete', $config['delete']);
84 | $container->setParameter('behat.code_coverage.config.drivers', $config['drivers']);
85 | $container->setParameter('behat.code_coverage.config.filter', $config['filter']);
86 | $container->setParameter('behat.code_coverage.config.report', $config['report']);
87 | }
88 |
89 | /**
90 | * {@inheritdoc}
91 | */
92 | public function configure(ArrayNodeDefinition $builder)
93 | {
94 | $builder
95 | ->addDefaultsIfNotSet()
96 | ->children()
97 | ->arrayNode('auth')
98 | ->children()
99 | ->scalarNode('user')->end()
100 | ->scalarNode('password')->end()
101 | ->end()
102 | ->end()
103 | ->arrayNode('create')
104 | ->addDefaultsIfNotSet()
105 | ->children()
106 | ->scalarNode('method')->defaultValue('POST')->end()
107 | ->scalarNode('path')->defaultValue('/')->end()
108 | ->end()
109 | ->end()
110 | ->arrayNode('read')
111 | ->addDefaultsIfNotSet()
112 | ->children()
113 | ->scalarNode('method')->defaultValue('GET')->end()
114 | ->scalarNode('path')->defaultValue('/')->end()
115 | ->end()
116 | ->end()
117 | ->arrayNode('delete')
118 | ->addDefaultsIfNotSet()
119 | ->children()
120 | ->scalarNode('method')->defaultValue('DELETE')->end()
121 | ->scalarNode('path')->defaultValue('/')->end()
122 | ->end()
123 | ->end()
124 | ->arrayNode('drivers')
125 | ->prototype('scalar')->end()
126 | ->end()
127 | ->arrayNode('filter')
128 | ->addDefaultsIfNotSet()
129 | ->children()
130 | ->scalarNode('forceCoversAnnotation')
131 | ->defaultFalse()
132 | ->end()
133 | ->scalarNode('mapTestClassNameToCoveredClassName')
134 | ->defaultFalse()
135 | ->end()
136 | ->arrayNode('whitelist')
137 | ->addDefaultsIfNotSet()
138 | ->children()
139 | ->scalarNode('addUncoveredFilesFromWhitelist')
140 | ->defaultTrue()
141 | ->end()
142 | ->scalarNode('processUncoveredFilesFromWhitelist')
143 | ->defaultFalse()
144 | ->end()
145 | ->arrayNode('include')
146 | ->addDefaultsIfNotSet()
147 | ->children()
148 | ->arrayNode('directories')
149 | ->useAttributeAsKey('name')
150 | ->prototype('array')
151 | ->children()
152 | ->scalarNode('prefix')->defaultValue('')->end()
153 | ->scalarNode('suffix')->defaultValue('.php')->end()
154 | ->end()
155 | ->end()
156 | ->end()
157 | ->arrayNode('files')
158 | ->prototype('scalar')->end()
159 | ->end()
160 | ->end()
161 | ->end()
162 | ->arrayNode('exclude')
163 | ->addDefaultsIfNotSet()
164 | ->children()
165 | ->arrayNode('directories')
166 | ->useAttributeAsKey('name')
167 | ->prototype('array')
168 | ->children()
169 | ->scalarNode('prefix')->defaultValue('')->end()
170 | ->scalarNode('suffix')->defaultValue('.php')->end()
171 | ->end()
172 | ->end()
173 | ->end()
174 | ->arrayNode('files')
175 | ->prototype('scalar')->end()
176 | ->end()
177 | ->end()
178 | ->end()
179 | ->end()
180 | ->end()
181 | ->end()
182 | ->end()
183 | ->arrayNode('report')
184 | ->children()
185 | ->scalarNode('format')->defaultValue('html')->end()
186 | ->arrayNode('options')
187 | ->useAttributeAsKey('name')
188 | ->prototype('scalar')->end()
189 | ->end()
190 | ->end()
191 | ->end()
192 | ->end()
193 | ->end();
194 | }
195 |
196 | /**
197 | * {@inheritdoc}
198 | */
199 | public function getConfigKey()
200 | {
201 | return 'code_coverage';
202 | }
203 |
204 | /**
205 | * {@inheritdoc}
206 | */
207 | public function process(ContainerBuilder $container)
208 | {
209 | $input = $container->get('cli.input');
210 | if ($input->hasParameterOption('--no-coverage')) {
211 | $container->getParameterBag()->set('behat.code_coverage.skip', true);
212 | }
213 |
214 | $passes = $this->getCompilerPasses();
215 |
216 | foreach ($passes as $pass) {
217 | $pass->process($container);
218 | }
219 | }
220 |
221 | /**
222 | * return an array of compiler passes
223 | *
224 | * @return array
225 | */
226 | private function getCompilerPasses()
227 | {
228 | return array(
229 | new Compiler\DriverPass(),
230 | new Compiler\FactoryPass(),
231 | new Compiler\FilterPass(),
232 | );
233 | }
234 | }
235 |
--------------------------------------------------------------------------------
/tests/ExtensionTest.php:
--------------------------------------------------------------------------------
1 |
39 |
42 |
43 |
44 | LeanPHP\Behat\CodeCoverage\Service\ReportService
45 |
46 |
47 |
48 |
49 |
50 |
51 | END_OF_CONFIG
52 | );
53 |
54 | $container = new ContainerBuilder;
55 |
56 | $extension = new Extension($configDir);
57 | $extension->load($container, $config);
58 |
59 | foreach ($expected as $key => $value) {
60 | $this->assertEquals($value, $container->getParameter($key));
61 | }
62 | }
63 |
64 | /**
65 | * @return array
66 | */
67 | public function loadProvider()
68 | {
69 | return array(
70 | array(
71 | array(
72 | 'behat.code_coverage.config.auth' => array(
73 | 'user' => 'test_user',
74 | 'password' => 'test_password',
75 | ),
76 | 'behat.code_coverage.config.create' => array(
77 | 'method' => 'CREATE',
78 | 'path' => 'create_path',
79 | ),
80 | 'behat.code_coverage.config.read' => array(
81 | 'method' => 'READ',
82 | 'path' => 'read_path',
83 | ),
84 | 'behat.code_coverage.config.delete' => array(
85 | 'method' => 'DELETE',
86 | 'path' => 'delete_path',
87 | ),
88 | 'behat.code_coverage.config.drivers' => array('remote'),
89 | 'behat.code_coverage.config.filter' => array(
90 | 'whitelist' => array(
91 | 'addUncoveredFilesFromWhitelist' => false,
92 | 'processUncoveredFilesFromWhitelist' => true,
93 | 'include' => array(
94 | 'directories' => array(
95 | 'directory1' => array(
96 | 'prefix' => 'Secure',
97 | 'suffix' => '.php',
98 | )
99 | ),
100 | 'files' => array(
101 | 'file1'
102 | ),
103 | ),
104 | 'exclude' => array(
105 | 'directories' => array(
106 | 'directory2' => array(
107 | 'prefix' => 'Insecure',
108 | 'suffix' => '.inc',
109 | )
110 | ),
111 | 'files' => array(
112 | 'file2'
113 | ),
114 | ),
115 | ),
116 | 'blacklist' => array(
117 | 'include' => array(
118 | 'directories' => array(
119 | 'directory3' => array(
120 | 'prefix' => 'Public',
121 | 'suffix' => '.php',
122 | )
123 | ),
124 | 'files' => array(
125 | 'file3'
126 | ),
127 | ),
128 | 'exclude' => array(
129 | 'directories' => array(
130 | 'directory4' => array(
131 | 'prefix' => 'Private',
132 | 'suffix' => '.inc',
133 | )
134 | ),
135 | 'files' => array(
136 | 'file4'
137 | ),
138 | ),
139 | ),
140 | 'forceCoversAnnotation' => true,
141 | 'mapTestClassNameToCoveredClassName' => true
142 | ),
143 | 'behat.code_coverage.config.report' => array(
144 | 'format' => 'fmt',
145 | 'options' => array(
146 | 'target' => '/tmp'
147 | )
148 | )
149 | ),
150 | array(
151 | 'auth' => array(
152 | 'user' => 'test_user',
153 | 'password' => 'test_password',
154 | ),
155 | 'create' => array(
156 | 'method' => 'CREATE',
157 | 'path' => 'create_path',
158 | ),
159 | 'read' => array(
160 | 'method' => 'READ',
161 | 'path' => 'read_path',
162 | ),
163 | 'delete' => array(
164 | 'method' => 'DELETE',
165 | 'path' => 'delete_path',
166 | ),
167 | 'drivers' => array('remote'),
168 | 'filter' => array(
169 | 'whitelist' => array(
170 | 'addUncoveredFilesFromWhitelist' => false,
171 | 'processUncoveredFilesFromWhitelist' => true,
172 | 'include' => array(
173 | 'directories' => array(
174 | 'directory1' => array(
175 | 'prefix' => 'Secure',
176 | 'suffix' => '.php',
177 | )
178 | ),
179 | 'files' => array(
180 | 'file1'
181 | ),
182 | ),
183 | 'exclude' => array(
184 | 'directories' => array(
185 | 'directory2' => array(
186 | 'prefix' => 'Insecure',
187 | 'suffix' => '.inc',
188 | )
189 | ),
190 | 'files' => array(
191 | 'file2'
192 | ),
193 | ),
194 | ),
195 | 'blacklist' => array(
196 | 'include' => array(
197 | 'directories' => array(
198 | 'directory3' => array(
199 | 'prefix' => 'Public',
200 | 'suffix' => '.php',
201 | )
202 | ),
203 | 'files' => array(
204 | 'file3'
205 | ),
206 | ),
207 | 'exclude' => array(
208 | 'directories' => array(
209 | 'directory4' => array(
210 | 'prefix' => 'Private',
211 | 'suffix' => '.inc',
212 | )
213 | ),
214 | 'files' => array(
215 | 'file4'
216 | ),
217 | ),
218 | ),
219 | 'forceCoversAnnotation' => true,
220 | 'mapTestClassNameToCoveredClassName' => true
221 | ),
222 | 'report' => array(
223 | 'format' => 'fmt',
224 | 'options' => array(
225 | 'target' => '/tmp'
226 | )
227 | )
228 | ),
229 | ),
230 | array(
231 | array(
232 | 'behat.code_coverage.config.auth' => null,
233 | 'behat.code_coverage.config.create' => array(
234 | 'method' => 'POST',
235 | 'path' => '/',
236 | ),
237 | 'behat.code_coverage.config.read' => array(
238 | 'method' => 'GET',
239 | 'path' => '/',
240 | ),
241 | 'behat.code_coverage.config.delete' => array(
242 | 'method' => 'DELETE',
243 | 'path' => '/',
244 | ),
245 | 'behat.code_coverage.config.drivers' => array('local'),
246 | 'behat.code_coverage.config.filter' => array(
247 | 'whitelist' => array(
248 | 'addUncoveredFilesFromWhitelist' => true,
249 | 'processUncoveredFilesFromWhitelist' => false,
250 | 'include' => array(
251 | 'directories' => array(),
252 | 'files' => array(),
253 | ),
254 | 'exclude' => array(
255 | 'directories' => array(),
256 | 'files' => array(),
257 | ),
258 | ),
259 | 'blacklist' => array(
260 | 'include' => array(
261 | 'directories' => array(),
262 | 'files' => array(),
263 | ),
264 | 'exclude' => array(
265 | 'directories' => array(),
266 | 'files' => array(),
267 | ),
268 | ),
269 | 'forceCoversAnnotation' => false,
270 | 'mapTestClassNameToCoveredClassName' => false
271 | )
272 | ),
273 | array(
274 | 'create' => array(
275 | 'method' => 'POST',
276 | 'path' => '/',
277 | ),
278 | 'read' => array(
279 | 'method' => 'GET',
280 | 'path' => '/',
281 | ),
282 | 'delete' => array(
283 | 'method' => 'DELETE',
284 | 'path' => '/',
285 | ),
286 | 'drivers' => array(),
287 | 'filter' => array(
288 | 'whitelist' => array(
289 | 'addUncoveredFilesFromWhitelist' => true,
290 | 'processUncoveredFilesFromWhitelist' => false,
291 | 'include' => array(
292 | 'directories' => array(),
293 | 'files' => array(),
294 | ),
295 | 'exclude' => array(
296 | 'directories' => array(),
297 | 'files' => array(),
298 | ),
299 | ),
300 | 'blacklist' => array(
301 | 'include' => array(
302 | 'directories' => array(),
303 | 'files' => array(),
304 | ),
305 | 'exclude' => array(
306 | 'directories' => array(),
307 | 'files' => array(),
308 | ),
309 | ),
310 | 'forceCoversAnnotation' => false,
311 | 'mapTestClassNameToCoveredClassName' => false
312 | ),
313 | 'report' => array(
314 | 'format' => 'html',
315 | 'options' => array(),
316 | )
317 | ),
318 | ),
319 | );
320 | }
321 |
322 | public function testConfigure()
323 | {
324 | $builder = new ArrayNodeDefinition('test');
325 |
326 | $extension = new Extension();
327 | $extension->configure($builder);
328 |
329 | $children = $this->getPropertyOnObject($builder, 'children');
330 |
331 | $this->assertCount(7, $children);
332 | $this->assertTrue(isset($children['auth']));
333 | $this->assertTrue(isset($children['create']));
334 | $this->assertTrue(isset($children['read']));
335 | $this->assertTrue(isset($children['delete']));
336 | $this->assertTrue(isset($children['drivers']));
337 | $this->assertTrue(isset($children['filter']));
338 | $this->assertTrue(isset($children['report']));
339 |
340 | $auth = $this->getPropertyOnObject($children['auth'], 'children');
341 |
342 | $this->assertCount(2, $auth);
343 | $this->assertTrue(isset($auth['user']));
344 | $this->assertTrue(isset($auth['password']));
345 |
346 | $create = $this->getPropertyOnObject($children['create'], 'children');
347 |
348 | $this->assertCount(2, $create);
349 | $this->assertTrue(isset($create['method']));
350 | $this->assertTrue(isset($create['path']));
351 |
352 | $read = $this->getPropertyOnObject($children['read'], 'children');
353 |
354 | $this->assertCount(2, $read);
355 | $this->assertTrue(isset($read['method']));
356 | $this->assertTrue(isset($read['path']));
357 |
358 | $delete = $this->getPropertyOnObject($children['delete'], 'children');
359 |
360 | $this->assertCount(2, $delete);
361 | $this->assertTrue(isset($delete['method']));
362 | $this->assertTrue(isset($delete['path']));
363 |
364 | $report = $this->getPropertyOnObject($children['report'], 'children');
365 |
366 | $this->assertCount(2, $report);
367 | $this->assertTrue(isset($report['format']));
368 | $this->assertTrue(isset($report['options']));
369 | }
370 |
371 | public function testProcess()
372 | {
373 | $container = $this->createMock('Symfony\Component\DependencyInjection\ContainerBuilder');
374 | $input = $this->createMock('Symfony\Component\Console\Input\ArgvInput');
375 |
376 | $input->expects($this->exactly(1))
377 | ->method('hasParameterOption');
378 |
379 | $container->expects($this->exactly(4))
380 | ->method('hasDefinition');
381 | $container->expects($this->exactly(1))
382 | ->method('get')->willReturn($input);
383 |
384 | $extension = new Extension();
385 |
386 | $compilerPasses = $extension->process($container);
387 | }
388 |
389 | /**
390 | * Gets the given property of an object
391 | *
392 | * @param mixed $object Object
393 | * @param string $name Property name
394 | *
395 | * @return mixed
396 | */
397 | private function getPropertyOnObject($object, $name)
398 | {
399 | $property = new \ReflectionProperty($object, $name);
400 | $property->setAccessible(true);
401 |
402 | return $property->getValue($object);
403 | }
404 | }
405 |
--------------------------------------------------------------------------------