From 245f1d72be68c345f6ef417beb1c1fba9e77962b Mon Sep 17 00:00:00 2001 From: alvlapo Date: Sun, 27 Jan 2019 20:15:39 +0300 Subject: [PATCH] Added require annotation propery to the spec example --- README.md | 22 ++- .../Maintainer/SkipExampleMaintainerSpec.php | 132 ++++++++++++++++-- .../Maintainer/SkipExampleMaintainer.php | 29 +++- 3 files changed, 167 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index e3a3aa7..cf4d0d6 100644 --- a/README.md +++ b/README.md @@ -51,16 +51,28 @@ Skips all the spec example if the class or interface is not available ```php /** * @require Vendor\Builder\ToolInterface + * + * All examples will be skipped if the ToolInterface does not exist */ -class BridgeBuilderSpec extends ObjectBehavior +class LondonBridgeBuilderSpec extends ObjectBehavior { - // Will be skipped if the Vendor\Builder\ToolInterface interface does not exist - function it_builds_a_brige() + /** + * @require Vendor\Manufacturer\StoneFactory + * @require Vendor\Manufacturer\BrickFactory + * + * Will be skipped if the ToolInterface OR StoneFactory OR BrickFacroty does not exist + */ + function it_builds_a_stone_brige() { } - // Will be skipped if the Vendor\Builder\ToolInterface interface does not exist - function it_builds_the_road() + /** + * @require Vendor\Manufacturer\WoodFactory + * @require Vendor\Manufacturer\ClayFactory + * + * Will be skipped if the ToolInterface OR WoodFactory OR ClayFactory does not exist + */ + function it_builds_a_wooden_bridge() { } diff --git a/spec/Akeneo/Runner/Maintainer/SkipExampleMaintainerSpec.php b/spec/Akeneo/Runner/Maintainer/SkipExampleMaintainerSpec.php index 7ed6fa1..5756e08 100644 --- a/spec/Akeneo/Runner/Maintainer/SkipExampleMaintainerSpec.php +++ b/spec/Akeneo/Runner/Maintainer/SkipExampleMaintainerSpec.php @@ -19,6 +19,10 @@ */ final class SkipExampleMaintainerSpec extends ObjectBehavior { + const MISSING_REQUIRE = "/**\n * @require Foo\\Bar\n */"; + const EXISTING_CLASS = "/**\n * @require Akeneo\Runner\Maintainer\SkipExampleMaintainer\n */"; + const EXISTING_INTERFACE = "/**\n * @require PhpSpec\Runner\Maintainer\Maintainer\n */"; + function it_is_a_maintainer(): void { $this->shouldImplement(Maintainer::class); @@ -29,26 +33,51 @@ function its_priority_is_75(): void $this->getPriority()->shouldBe(75); } - function it_supports_specification_that_has_require_doc_comment( + function it_supports_specification_that_has_require_class_doc_comment( ExampleNode $example, SpecificationNode $specification, - \ReflectionClass $refClass + \ReflectionClass $refClass, + \ReflectionFunction $refMethod ): void { $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); $specification->getClassReflection()->willReturn($refClass); - $refClass->getDocComment()->willReturn("/**\n * @require Foo\\Bar\n */"); + + $refClass->getDocComment()->willReturn(self::MISSING_REQUIRE); + $refMethod->getDocComment()->willReturn(false); $this->supports($example)->shouldBe(true); } - function it_does_not_support_specification_that_does_not_have_doc_comment( + function it_supports_example_node_that_has_require_method_doc_comment( ExampleNode $example, SpecificationNode $specification, - \ReflectionClass $refClass + \ReflectionClass $refClass, + \ReflectionFunction $refMethod ): void { $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); $specification->getClassReflection()->willReturn($refClass); + $refClass->getDocComment()->willReturn(false); + $refMethod->getDocComment()->willReturn(self::MISSING_REQUIRE); + + $this->supports($example)->shouldBe(true); + } + + function it_does_not_support_specification_that_does_not_have_any_doc_comment( + ExampleNode $example, + SpecificationNode $specification, + \ReflectionClass $refClass, + \ReflectionFunction $refMethod + ): void { + $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); + + $specification->getClassReflection()->willReturn($refClass); + + $refClass->getDocComment()->willReturn(false); + $refMethod->getDocComment()->willReturn(false); $this->supports($example)->shouldBe(false); } @@ -57,13 +86,16 @@ function its_prepare_method_throws_skipping_exception_when_specification_require ExampleNode $example, SpecificationNode $specification, \ReflectionClass $refClass, + \ReflectionFunction $refMethod, Specification $context, MatcherManager $matchers, CollaboratorManager $collaborators ): void { $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); $specification->getClassReflection()->willReturn($refClass); - $refClass->getDocComment()->willReturn("/**\n * @require Foo\\Bar\n */"); + $refClass->getDocComment()->willReturn(self::MISSING_REQUIRE); + $refMethod->getDocComment()->willReturn(self::EXISTING_INTERFACE); $exception = new SkippingException('"Foo\\Bar" is not available'); $this->shouldThrow($exception)->duringPrepare($example, $context, $matchers, $collaborators); @@ -73,13 +105,36 @@ function its_prepare_method_does_not_throw_exception_when_specification_requires ExampleNode $example, SpecificationNode $specification, \ReflectionClass $refClass, + \ReflectionFunction $refMethod, Specification $context, MatcherManager $matchers, CollaboratorManager $collaborators ): void { $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); $specification->getClassReflection()->willReturn($refClass); - $refClass->getDocComment()->willReturn("/**\n * @require Akeneo\Runner\Maintainer\SkipExampleMaintainer\n */"); + + $refClass->getDocComment()->willReturn(self::EXISTING_CLASS); + $refMethod->getDocComment()->willReturn(false); + + $this->shouldNotThrow(SkippingException::class)->duringPrepare($example, $context, $matchers, $collaborators); + } + + function its_prepare_method_does_not_throw_exception_when_example_node_requires_an_existing_class( + ExampleNode $example, + SpecificationNode $specification, + \ReflectionClass $refClass, + \ReflectionFunction $refMethod, + Specification $context, + MatcherManager $matchers, + CollaboratorManager $collaborators + ): void { + $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); + $specification->getClassReflection()->willReturn($refClass); + + $refClass->getDocComment()->willReturn(false); + $refMethod->getDocComment()->willReturn(self::EXISTING_CLASS); $this->shouldNotThrow(SkippingException::class)->duringPrepare($example, $context, $matchers, $collaborators); } @@ -88,28 +143,89 @@ function its_prepare_method_does_not_throw_exception_when_specification_requires ExampleNode $example, SpecificationNode $specification, \ReflectionClass $refClass, + \ReflectionFunction $refMethod, Specification $context, MatcherManager $matchers, CollaboratorManager $collaborators ): void { $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); $specification->getClassReflection()->willReturn($refClass); - $refClass->getDocComment()->willReturn("/**\n * @require PhpSpec\Runner\Maintainer\Maintainer\n */"); + $refClass->getDocComment()->willReturn(self::EXISTING_INTERFACE); + $refMethod->getDocComment()->willReturn(false); $this->shouldNotThrow(SkippingException::class)->duringPrepare($example, $context, $matchers, $collaborators); } + function its_prepare_method_does_not_throw_exception_when_example_node_requires_an_existing_interface( + ExampleNode $example, + SpecificationNode $specification, + \ReflectionClass $refClass, + \ReflectionFunction $refMethod, + Specification $context, + MatcherManager $matchers, + CollaboratorManager $collaborators + ): void { + $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); + $specification->getClassReflection()->willReturn($refClass); + + $refClass->getDocComment()->willReturn(false); + $refMethod->getDocComment()->willReturn(self::EXISTING_INTERFACE); + + $this->shouldNotThrow(SkippingException::class)->duringPrepare($example, $context, $matchers, $collaborators); + } + + function its_prepare_method_throw_exception_when_specification_requires_an_existing_class_but_example_node_requires_an_missing_class( + ExampleNode $example, + SpecificationNode $specification, + \ReflectionClass $refClass, + \ReflectionFunction $refMethod, + Specification $context, + MatcherManager $matchers, + CollaboratorManager $collaborators + ): void { + $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); + $specification->getClassReflection()->willReturn($refClass); + $refClass->getDocComment()->willReturn(self::EXISTING_CLASS); + $refMethod->getDocComment()->willReturn(self::MISSING_REQUIRE); + + $this->shouldThrow(SkippingException::class)->duringPrepare($example, $context, $matchers, $collaborators); + } + + function its_prepare_method_throw_exception_when_specification_requires_an_missing_class_but_example_node_requires_an_existing_class( + ExampleNode $example, + SpecificationNode $specification, + \ReflectionClass $refClass, + \ReflectionFunction $refMethod, + Specification $context, + MatcherManager $matchers, + CollaboratorManager $collaborators + ): void { + $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); + $specification->getClassReflection()->willReturn($refClass); + $refClass->getDocComment()->willReturn(self::MISSING_REQUIRE); + $refMethod->getDocComment()->willReturn(self::EXISTING_CLASS); + + $this->shouldThrow(SkippingException::class)->duringPrepare($example, $context, $matchers, $collaborators); + } + function its_prepare_method_ignores_other_annotation( ExampleNode $example, SpecificationNode $specification, \ReflectionClass $refClass, + \ReflectionFunction $refMethod, Specification $context, MatcherManager $matchers, CollaboratorManager $collaborators ): void { $example->getSpecification()->willReturn($specification); + $example->getFunctionReflection()->willReturn($refMethod); $specification->getClassReflection()->willReturn($refClass); $refClass->getDocComment()->willReturn("/**\n * @author foo@example.com \n */"); + $refMethod->getDocComment()->willReturn("/**\n * @author foo@example.com \n */"); $this->shouldNotThrow(SkippingException::class)->duringPrepare($example, $context, $matchers, $collaborators); } diff --git a/src/Akeneo/Runner/Maintainer/SkipExampleMaintainer.php b/src/Akeneo/Runner/Maintainer/SkipExampleMaintainer.php index 7f18234..9b76b49 100644 --- a/src/Akeneo/Runner/Maintainer/SkipExampleMaintainer.php +++ b/src/Akeneo/Runner/Maintainer/SkipExampleMaintainer.php @@ -18,7 +18,10 @@ final class SkipExampleMaintainer implements Maintainer */ public function supports(ExampleNode $example): bool { - return count($this->getRequirements($this->getDocComment($example))) > 0; + $specDocComments = $this->getSpecDocComment($example); + $exampleDocCommnts = $this->getExampleDocComment($example); + + return count($this->getRequirements($specDocComments . $exampleDocCommnts)) > 0; } /** @@ -30,7 +33,15 @@ public function prepare( MatcherManager $matchers, CollaboratorManager $collaborators ): void { - foreach ($this->getRequirements($this->getDocComment($example)) as $requirement) { + + $specRequirements = $this->getRequirements($this->getSpecDocComment($example)); + $exampleRequirements = $this->getRequirements($this->getExampleDocComment($example)); + + // Push example node requirement to the end of check list, + // if any spec class requirements are missing, all example node will not be executed as well. + $requirements = \array_merge($specRequirements, $exampleRequirements); + + foreach ($requirements as $requirement) { if (!class_exists($requirement) && !interface_exists($requirement)) { throw new SkippingException( sprintf('"%s" is not available', $requirement) @@ -100,8 +111,20 @@ function($docline) { * * @return string */ - private function getDocComment(ExampleNode $example): string + private function getSpecDocComment(ExampleNode $example): string { return $example->getSpecification()->getClassReflection()->getDocComment() ?: ''; } + + /** + * Get example node doc comment + * + * @param ExampleNode $example + * + * @return string + */ + private function getExampleDocComment(ExampleNode $example): string + { + return $example->getFunctionReflection()->getDocComment() ?: ''; + } }