├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── composer.json ├── phpspec.yml ├── spec └── Akeneo │ └── Runner │ └── Maintainer │ └── SkipExampleMaintainerSpec.php └── src └── Akeneo ├── Runner └── Maintainer │ └── SkipExampleMaintainer.php └── SkipExampleExtension.php /.gitignore: -------------------------------------------------------------------------------- 1 | bin/* 2 | vendor/* 3 | composer.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: [7.1, 7.2, 7.3] 4 | 5 | before_script: 6 | - composer install --prefer-dist 7 | 8 | script: 9 | - bin/phpspec run 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changes in PhpSpec Skip Example Extension 2 | 3 | ## 4.0.x (2018-11-13) 4 | 5 | - now depends on phpSpec ^5.0 6 | 7 | ## 3.0.x (2017-07-10) 8 | 9 | - now depends on phpSpec ^4.0 10 | 11 | ## 2.0.x (2016-07-20) 12 | 13 | - now depends on phpSpec ^3.0 14 | 15 | ## 1.2.0 (2015-09-13) 16 | 17 | - now depends on phpSpec ~2.1 18 | 19 | ## 1.1.0 (2015-02-02) 20 | 21 | - now depends on phpSpec 2.0.* 22 | 23 | ## 1.0.1 (2014-09-18) 24 | 25 | - now depends on phpSpec 2.0.1-RC1 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Akeneo 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PhpSpec Skip Example Extension 2 | 3 | This PhpSpec extension allows to skip example through user-friendly annotations. 4 | [![Build Status](https://travis-ci.org/akeneo/PhpSpecSkipExampleExtension.png?branch=master)](https://travis-ci.org/akeneo/PhpSpecSkipExampleExtension) 5 | 6 | ## Installation 7 | 8 | Once you have installed PhpSpec (following the documentation on [the official website](http://www.phpspec.net)), add the extension requirement to your `composer.json`: 9 | 10 | Using phpspec 4.x, 11 | 12 | ```json 13 | { 14 | "require": { 15 | "akeneo/phpspec-skip-example-extension": "^3.0" 16 | } 17 | } 18 | ``` 19 | 20 | Using phpspec 5.x, 21 | 22 | ```json 23 | { 24 | "require": { 25 | "akeneo/phpspec-skip-example-extension": "^4.0" 26 | } 27 | } 28 | ``` 29 | 30 | And run composer update: 31 | 32 | ```bash 33 | $ php composer.phar update akeneo/phpspec-skip-example-extension 34 | ``` 35 | 36 | ## Configuration 37 | 38 | You can now activate the extension by creating a `phpspec.yml` file at the root of your project: 39 | 40 | ``` yaml 41 | extensions: 42 | Akeneo\SkipExampleExtension: ~ 43 | ``` 44 | 45 | ## Usage 46 | 47 | ### @require 48 | 49 | Skips all the spec example if the class or interface is not available 50 | 51 | ```php 52 | /** 53 | * @require Vendor\Builder\ToolInterface 54 | */ 55 | class BridgeBuilderSpec extends ObjectBehavior 56 | { 57 | // Will be skipped if the Vendor\Builder\ToolInterface interface does not exist 58 | function it_builds_a_brige() 59 | { 60 | } 61 | 62 | // Will be skipped if the Vendor\Builder\ToolInterface interface does not exist 63 | function it_builds_the_road() 64 | { 65 | } 66 | 67 | //... 68 | } 69 | ``` 70 | 71 | ## Contributions 72 | 73 | Feel free to contribute to this extension if you find some interesting ways to improve it! 74 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "akeneo/phpspec-skip-example-extension", 3 | "description": "Skip your PhpSpec examples through annotations", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Gildas Quéméner", 8 | "email": "gildas@akeneo.com" 9 | }, 10 | { 11 | "name": "Nicolas Dupont", 12 | "email": "nicolas@akeneo.com" 13 | }, 14 | { 15 | "name": "Kamil Kokot", 16 | "email": "kamil@kokot.me" 17 | } 18 | ], 19 | "require": { 20 | "phpspec/phpspec": "^5.0 || ^6.0 || ^7.0" 21 | }, 22 | "autoload": { 23 | "psr-4": { 24 | "Akeneo\\": "src/Akeneo/" 25 | } 26 | }, 27 | "config": { 28 | "bin-dir": "bin" 29 | }, 30 | "minimum-stability": "stable" 31 | } 32 | -------------------------------------------------------------------------------- /phpspec.yml: -------------------------------------------------------------------------------- 1 | formatter.name: pretty 2 | extensions: 3 | Akeneo\SkipExampleExtension: ~ 4 | -------------------------------------------------------------------------------- /spec/Akeneo/Runner/Maintainer/SkipExampleMaintainerSpec.php: -------------------------------------------------------------------------------- 1 | shouldImplement(Maintainer::class); 25 | } 26 | 27 | function its_priority_is_75(): void 28 | { 29 | $this->getPriority()->shouldBe(75); 30 | } 31 | 32 | function it_supports_specification_that_has_require_doc_comment( 33 | ExampleNode $example, 34 | SpecificationNode $specification, 35 | \ReflectionClass $refClass 36 | ): void { 37 | $example->getSpecification()->willReturn($specification); 38 | $specification->getClassReflection()->willReturn($refClass); 39 | $refClass->getDocComment()->willReturn("/**\n * @require Foo\\Bar\n */"); 40 | 41 | $this->supports($example)->shouldBe(true); 42 | } 43 | 44 | function it_does_not_support_specification_that_does_not_have_doc_comment( 45 | ExampleNode $example, 46 | SpecificationNode $specification, 47 | \ReflectionClass $refClass 48 | ): void { 49 | $example->getSpecification()->willReturn($specification); 50 | $specification->getClassReflection()->willReturn($refClass); 51 | $refClass->getDocComment()->willReturn(false); 52 | 53 | $this->supports($example)->shouldBe(false); 54 | } 55 | 56 | function its_prepare_method_throws_skipping_exception_when_specification_requires_a_non_existing_interface( 57 | ExampleNode $example, 58 | SpecificationNode $specification, 59 | \ReflectionClass $refClass, 60 | Specification $context, 61 | MatcherManager $matchers, 62 | CollaboratorManager $collaborators 63 | ): void { 64 | $example->getSpecification()->willReturn($specification); 65 | $specification->getClassReflection()->willReturn($refClass); 66 | $refClass->getDocComment()->willReturn("/**\n * @require Foo\\Bar\n */"); 67 | 68 | $exception = new SkippingException('"Foo\\Bar" is not available'); 69 | $this->shouldThrow($exception)->duringPrepare($example, $context, $matchers, $collaborators); 70 | } 71 | 72 | function its_prepare_method_does_not_throw_exception_when_specification_requires_an_existing_class( 73 | ExampleNode $example, 74 | SpecificationNode $specification, 75 | \ReflectionClass $refClass, 76 | Specification $context, 77 | MatcherManager $matchers, 78 | CollaboratorManager $collaborators 79 | ): void { 80 | $example->getSpecification()->willReturn($specification); 81 | $specification->getClassReflection()->willReturn($refClass); 82 | $refClass->getDocComment()->willReturn("/**\n * @require Akeneo\Runner\Maintainer\SkipExampleMaintainer\n */"); 83 | 84 | $this->shouldNotThrow(SkippingException::class)->duringPrepare($example, $context, $matchers, $collaborators); 85 | } 86 | 87 | function its_prepare_method_does_not_throw_exception_when_specification_requires_an_existing_interface( 88 | ExampleNode $example, 89 | SpecificationNode $specification, 90 | \ReflectionClass $refClass, 91 | Specification $context, 92 | MatcherManager $matchers, 93 | CollaboratorManager $collaborators 94 | ): void { 95 | $example->getSpecification()->willReturn($specification); 96 | $specification->getClassReflection()->willReturn($refClass); 97 | $refClass->getDocComment()->willReturn("/**\n * @require PhpSpec\Runner\Maintainer\Maintainer\n */"); 98 | 99 | $this->shouldNotThrow(SkippingException::class)->duringPrepare($example, $context, $matchers, $collaborators); 100 | } 101 | 102 | function its_prepare_method_ignores_other_annotation( 103 | ExampleNode $example, 104 | SpecificationNode $specification, 105 | \ReflectionClass $refClass, 106 | Specification $context, 107 | MatcherManager $matchers, 108 | CollaboratorManager $collaborators 109 | ): void { 110 | $example->getSpecification()->willReturn($specification); 111 | $specification->getClassReflection()->willReturn($refClass); 112 | $refClass->getDocComment()->willReturn("/**\n * @author foo@example.com \n */"); 113 | 114 | $this->shouldNotThrow(SkippingException::class)->duringPrepare($example, $context, $matchers, $collaborators); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/Akeneo/Runner/Maintainer/SkipExampleMaintainer.php: -------------------------------------------------------------------------------- 1 | getRequirements($this->getDocComment($example))) > 0; 22 | } 23 | 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public function prepare( 28 | ExampleNode $example, 29 | Specification $context, 30 | MatcherManager $matchers, 31 | CollaboratorManager $collaborators 32 | ): void { 33 | foreach ($this->getRequirements($this->getDocComment($example)) as $requirement) { 34 | if (!class_exists($requirement) && !interface_exists($requirement)) { 35 | throw new SkippingException( 36 | sprintf('"%s" is not available', $requirement) 37 | ); 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function teardown( 46 | ExampleNode $example, 47 | Specification $context, 48 | MatcherManager $matchers, 49 | CollaboratorManager $collaborators 50 | ): void { 51 | 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | public function getPriority(): int 58 | { 59 | return 75; 60 | } 61 | 62 | /** 63 | * Get required interfaces 64 | * 65 | * @param string $docComment 66 | * 67 | * @return array 68 | */ 69 | private function getRequirements(string $docComment): array 70 | { 71 | return array_map( 72 | function($tag) { 73 | preg_match('#@require ([^ ]*)#', $tag, $match); 74 | 75 | return $match[1]; 76 | }, 77 | array_filter( 78 | array_map( 79 | 'trim', 80 | explode( 81 | "\n", 82 | str_replace( 83 | "\r\n", 84 | "\n", 85 | $docComment 86 | ) 87 | ) 88 | ), 89 | function($docline) { 90 | return 0 === strpos($docline, '* @require'); 91 | } 92 | ) 93 | ); 94 | } 95 | 96 | /** 97 | * Get spec doc comment 98 | * 99 | * @param ExampleNode $example 100 | * 101 | * @return string 102 | */ 103 | private function getDocComment(ExampleNode $example): string 104 | { 105 | return $example->getSpecification()->getClassReflection()->getDocComment() ?: ''; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Akeneo/SkipExampleExtension.php: -------------------------------------------------------------------------------- 1 | define('runner.maintainers.skip_example', function (IndexedServiceContainer $c) { 27 | return new Runner\Maintainer\SkipExampleMaintainer(); 28 | }, ['runner.maintainers']); 29 | } 30 | } 31 | --------------------------------------------------------------------------------