├── .appveyor.yml ├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── autoload.php ├── behat.yml.dist ├── build.php ├── composer.json ├── features ├── bootstrap │ └── FeatureContext.php └── test.feature ├── init.php ├── phpcs.xml ├── phpunit.xml.dist ├── src ├── Common │ ├── Driver │ │ ├── Factory.php │ │ ├── HHVM.php │ │ ├── Stub.php │ │ └── XCache.php │ ├── Model │ │ └── Aggregate.php │ ├── Report │ │ ├── Clover.php │ │ ├── Crap4j.php │ │ ├── Factory.php │ │ ├── Html.php │ │ ├── Php.php │ │ ├── Text.php │ │ └── Xml.php │ └── ReportInterface.php ├── Compiler │ ├── DriverPass.php │ ├── FactoryPass.php │ └── FilterPass.php ├── Controller │ └── Cli │ │ └── CodeCoverageController.php ├── Driver │ ├── Proxy.php │ └── RemoteXdebug.php ├── Extension.php ├── Listener │ └── EventListener.php ├── Resources │ └── config │ │ ├── services-2.3.xml │ │ └── services.xml └── Service │ └── ReportService.php └── tests ├── Common ├── Driver │ ├── FactoryTest.php │ ├── HHVMTest.php │ ├── StubTest.php │ └── XCacheTest.php ├── Model │ └── AggregateTest.php └── Report │ ├── CloverTest.php │ ├── Crap4jTest.php │ ├── FactoryTest.php │ ├── HtmlTest.php │ ├── PhpTest.php │ ├── TextTest.php │ └── XmlTest.php ├── Compiler ├── DriverPassTest.php ├── FactoryPassTest.php └── FilterPassTest.php ├── Driver ├── ProxyTest.php └── RemoteXdebugTest.php ├── ExtensionTest.php ├── Listener └── EventListenerTest.php ├── Service └── ReportServiceTest.php └── VIPSoft └── TestCase.php /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | nbproject/ 3 | vendor/ 4 | build/ 5 | composer.phar 6 | **/*.dbf 7 | /composer.lock 8 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 ek9 (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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | behat-code-coverage 2 | =================== 3 | [![License](https://img.shields.io/packagist/l/leanphp/behat-code-coverage.svg?style=flat-square)](#License) 4 | [![Latest Stable Version](https://img.shields.io/packagist/v/leanphp/behat-code-coverage.svg?style=flat-square)](https://packagist.org/packages/leanphp/behat-code-coverage) 5 | [![Total Downloads](https://img.shields.io/packagist/dt/leanphp/behat-code-coverage.svg?style=flat-square)](https://packagist.org/packages/leanphp/behat-code-coverage) 6 | [![Travis](https://img.shields.io/travis/leanphp/behat-code-coverage.svg?style=flat-square)](https://travis-ci.org/leanphp/behat-code-coverage) 7 | [![AppVeyor](https://img.shields.io/appveyor/ci/leanphp/behat-code-coverage/master.svg?style=flat-square)](https://ci.appveyor.com/project/leanphp/behat-code-coverage) 8 | [![Pre Release](https://img.shields.io/packagist/vpre/leanphp/behat-code-coverage.svg?style=flat-square)](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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /build.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 | chdir(__DIR__); 13 | 14 | $filename = 'code_coverage_extension.phar'; 15 | 16 | if (file_exists($filename)) { 17 | unlink($filename); 18 | } 19 | 20 | $phar = new \Phar($filename, 0, 'extension.phar'); 21 | $phar->setSignatureAlgorithm(\Phar::SHA1); 22 | $phar->startBuffering(); 23 | 24 | foreach (findFiles('src') as $path) { 25 | $phar->addFromString($path, file_get_contents(__DIR__.'/'.$path)); 26 | } 27 | 28 | $phar->addFromString('init.php', file_get_contents(__DIR__.'/init.php')); 29 | 30 | $phar->setStub(<< 37 | * 38 | * This source file is subject to the MIT license that is bundled 39 | * with this source code in the file LICENSE. 40 | */ 41 | 42 | Phar::mapPhar('extension.phar'); 43 | 44 | return require 'phar://extension.phar/init.php'; 45 | 46 | __HALT_COMPILER(); 47 | STUB 48 | ); 49 | $phar->stopBuffering(); 50 | 51 | /** 52 | * Find files 53 | * 54 | * @param string $dir Directory 55 | * 56 | * @return array 57 | */ 58 | function findFiles($dir) 59 | { 60 | $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), 61 | RecursiveIteratorIterator::CHILD_FIRST); 62 | 63 | $files = array(); 64 | foreach ($iterator as $path) { 65 | if ($path->isFile()) { 66 | $files[] = $path->getPath().DIRECTORY_SEPARATOR.$path->getFilename(); 67 | } 68 | } 69 | 70 | return $files; 71 | } 72 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /features/bootstrap/FeatureContext.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 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/Common/Driver/XCacheTest.php: -------------------------------------------------------------------------------- 1 | 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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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, '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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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(<<