From a7bbc3113d14240da332f552666bea27dde6e0d8 Mon Sep 17 00:00:00 2001 From: Rodrigue Villetard Date: Wed, 26 Jul 2017 18:08:48 +0200 Subject: [PATCH 1/4] wip: behat tests are dirty passing, keep going --- .../Annotation/StepInjectorArgument.php | 28 ++++ .../Argument/ArgumentOrganiser.php | 42 +++--- argumentsExt/Argument/StepArgumentHolder.php | 22 ++++ .../Call/Handler/RuntimeCallHandler.php | 6 +- .../Resolver/ArgumentsResolver.php | 40 +++--- .../StepArgumentInjectorExtension.php | 123 ++++++++++++++++++ composer.json | 1 + src/.php_cs.cache | 1 + src/Annotation/ScenarioStateArgument.php | 4 +- .../Initializer/ScenarioStateInitializer.php | 13 +- src/ScenarioStateInterface.php | 2 + .../ScenarioStateExtension.php | 65 +-------- testapp/behat.yml | 1 + .../Annotation/ScenarioStateArgumentTest.php | 56 ++++++++ .../ScenarioStateArgumentOrganiserTest.php | 6 +- .../Resolver/ArgumentsResolverTest.php | 0 16 files changed, 304 insertions(+), 106 deletions(-) create mode 100644 argumentsExt/Annotation/StepInjectorArgument.php rename src/Argument/ScenarioStateArgumentOrganiser.php => argumentsExt/Argument/ArgumentOrganiser.php (51%) create mode 100644 argumentsExt/Argument/StepArgumentHolder.php rename {src => argumentsExt}/Call/Handler/RuntimeCallHandler.php (91%) rename {src => argumentsExt}/Resolver/ArgumentsResolver.php (61%) create mode 100644 argumentsExt/ServiceContainer/StepArgumentInjectorExtension.php create mode 100644 src/.php_cs.cache create mode 100644 testsSAI/Annotation/ScenarioStateArgumentTest.php rename {tests => testsSAI}/Argument/ScenarioStateArgumentOrganiserTest.php (95%) rename {tests => testsSAI}/Resolver/ArgumentsResolverTest.php (100%) diff --git a/argumentsExt/Annotation/StepInjectorArgument.php b/argumentsExt/Annotation/StepInjectorArgument.php new file mode 100644 index 0000000..9186499 --- /dev/null +++ b/argumentsExt/Annotation/StepInjectorArgument.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gorghoa\StepArgumentInjectorBehatExtension\Annotation; + +/** + * @author Rodrigue Villetard + */ +interface StepInjectorArgument +{ + /** + * @return string + */ + public function getName(); + + /** + * @return string + */ + public function getArgument(); +} diff --git a/src/Argument/ScenarioStateArgumentOrganiser.php b/argumentsExt/Argument/ArgumentOrganiser.php similarity index 51% rename from src/Argument/ScenarioStateArgumentOrganiser.php rename to argumentsExt/Argument/ArgumentOrganiser.php index 172652a..f55c681 100644 --- a/src/Argument/ScenarioStateArgumentOrganiser.php +++ b/argumentsExt/Argument/ArgumentOrganiser.php @@ -1,7 +1,7 @@ * @@ -9,39 +9,40 @@ * file that was distributed with this source code. */ -namespace Gorghoa\ScenarioStateBehatExtension\Argument; +namespace Gorghoa\StepArgumentInjectorBehatExtension\Argument; -use Behat\Testwork\Argument\ArgumentOrganiser; +use Behat\Testwork\Argument\ArgumentOrganiser as BehatArgumentOrganiser; use Doctrine\Common\Annotations\Reader; -use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; -use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; +use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepArgumentInjectorArgument; +use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepInjectorArgument; +// use Gorghoa\StepArgumentInjectorBehatExtension\Context\Initializer\StepArgumentInjectorInitializer; use ReflectionFunctionAbstract; /** * @author Rodrigue Villetard * @author Vincent Chalamon */ -final class ScenarioStateArgumentOrganiser implements ArgumentOrganiser +final class ArgumentOrganiser implements BehatArgumentOrganiser { /** - * @var ArgumentOrganiser + * @var BehatArgumentOrganiser */ private $baseOrganiser; /** - * @var ScenarioStateInitializer + * @var StepArgumentInjectorInitializer */ - private $store; + private $hookers; /** * @var Reader */ private $reader; - public function __construct(ArgumentOrganiser $organiser, ScenarioStateInitializer $store, Reader $reader) + public function __construct(BehatArgumentOrganiser $organiser, array $hookers, Reader $reader) { $this->baseOrganiser = $organiser; - $this->store = $store; + $this->hookers = $hookers; $this->reader = $reader; } @@ -59,16 +60,21 @@ public function organiseArguments(ReflectionFunctionAbstract $function, array $m return $this->baseOrganiser->organiseArguments($function, $match); } - /** @var ScenarioStateArgument[] $annotations */ + /** @var StepArgumentInjectorArgument[] $annotations */ $annotations = $this->reader->getMethodAnnotations($function); - $store = $this->store->getStore(); + foreach ($annotations as $annotation) { - if ($annotation instanceof ScenarioStateArgument && - in_array($annotation->getArgument(), $paramsKeys) && - $store->hasStateFragment($annotation->getName()) + if ($annotation instanceof StepInjectorArgument && + in_array($annotation->getArgument(), $paramsKeys) ) { - $match[$annotation->getArgument()] = $store->getStateFragment($annotation->getName()); - $match[strval(++$i)] = $store->getStateFragment($annotation->getName()); + foreach ($this->hookers as $hooker) { + if ($hooker->hasStepArgumentFor($annotation->getName())) { + $match[$annotation->getArgument()] + = $match[strval(++$i)] + = $hooker->getStepArgumentFor($annotation->getName()) + ; + } + } } } diff --git a/argumentsExt/Argument/StepArgumentHolder.php b/argumentsExt/Argument/StepArgumentHolder.php new file mode 100644 index 0000000..24844ca --- /dev/null +++ b/argumentsExt/Argument/StepArgumentHolder.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gorghoa\StepArgumentInjectorBehatExtension\Argument; + +/** + * @author Rodrigue Villetard + */ +interface StepArgumentHolder +{ + public function hasStepArgumentFor($key); + + public function getStepArgumentFor($key); +} diff --git a/src/Call/Handler/RuntimeCallHandler.php b/argumentsExt/Call/Handler/RuntimeCallHandler.php similarity index 91% rename from src/Call/Handler/RuntimeCallHandler.php rename to argumentsExt/Call/Handler/RuntimeCallHandler.php index 9a8cb75..a60b3cf 100644 --- a/src/Call/Handler/RuntimeCallHandler.php +++ b/argumentsExt/Call/Handler/RuntimeCallHandler.php @@ -1,7 +1,7 @@ * @@ -9,14 +9,14 @@ * file that was distributed with this source code. */ -namespace Gorghoa\ScenarioStateBehatExtension\Call\Handler; +namespace Gorghoa\StepArgumentInjectorBehatExtension\Call\Handler; use Behat\Behat\Transformation\Call\TransformationCall; use Behat\Testwork\Call\Call; use Behat\Testwork\Call\Handler\CallHandler; use Behat\Testwork\Environment\Call\EnvironmentCall; use Behat\Testwork\Hook\Call\HookCall; -use Gorghoa\ScenarioStateBehatExtension\Resolver\ArgumentsResolver; +use Gorghoa\StepArgumentInjectorBehatExtension\Resolver\ArgumentsResolver; /** * @author Vincent Chalamon diff --git a/src/Resolver/ArgumentsResolver.php b/argumentsExt/Resolver/ArgumentsResolver.php similarity index 61% rename from src/Resolver/ArgumentsResolver.php rename to argumentsExt/Resolver/ArgumentsResolver.php index d25e4bd..96bcd82 100644 --- a/src/Resolver/ArgumentsResolver.php +++ b/argumentsExt/Resolver/ArgumentsResolver.php @@ -1,7 +1,7 @@ * @@ -9,11 +9,10 @@ * file that was distributed with this source code. */ -namespace Gorghoa\ScenarioStateBehatExtension\Resolver; +namespace Gorghoa\StepArgumentInjectorBehatExtension\Resolver; use Doctrine\Common\Annotations\Reader; -use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; -use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; +use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepInjectorArgument; /** * @author Vincent Chalamon @@ -21,22 +20,21 @@ class ArgumentsResolver { /** - * @var ScenarioStateInitializer + * @var Reader */ - private $store; + private $reader; /** - * @var Reader + * @var array */ - private $reader; + private $hookers; /** - * @param ScenarioStateInitializer $store - * @param Reader $reader + * @param Reader $reader */ - public function __construct(ScenarioStateInitializer $store, Reader $reader) + public function __construct(array $hookers, Reader $reader) { - $this->store = $store; + $this->hookers = $hookers; $this->reader = $reader; } @@ -48,25 +46,27 @@ public function __construct(ScenarioStateInitializer $store, Reader $reader) */ public function resolve(\ReflectionMethod $function, array $arguments) { - // No `@ScenarioStateArgument` annotation found - if (null === $this->reader->getMethodAnnotation($function, ScenarioStateArgument::class)) { + // No `@StepArgumentInjectorArgument` annotation found + if (null === $this->reader->getMethodAnnotation($function, StepInjectorArgument::class)) { return $arguments; } $paramsKeys = array_map(function (\ReflectionParameter $element) { return $element->getName(); }, $function->getParameters()); - $store = $this->store->getStore(); // Prepare arguments from annotations - /** @var ScenarioStateArgument[] $annotations */ + /** @var StepArgumentInjectorArgument[] $annotations */ $annotations = $this->reader->getMethodAnnotations($function); foreach ($annotations as $annotation) { - if ($annotation instanceof ScenarioStateArgument && - in_array($annotation->getArgument(), $paramsKeys) && - $store->hasStateFragment($annotation->getName()) + if ($annotation instanceof StepInjectorArgument && + in_array($annotation->getArgument(), $paramsKeys) ) { - $arguments[$annotation->getArgument()] = $store->getStateFragment($annotation->getName()); + foreach ($this->hookers as $hooker) { + if ($hooker->hasStepArgumentFor($annotation->getName())) { + $arguments[$annotation->getArgument()] = $hooker->getStepArgumentFor($annotation->getName()); + } + } } } diff --git a/argumentsExt/ServiceContainer/StepArgumentInjectorExtension.php b/argumentsExt/ServiceContainer/StepArgumentInjectorExtension.php new file mode 100644 index 0000000..ff65b4e --- /dev/null +++ b/argumentsExt/ServiceContainer/StepArgumentInjectorExtension.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gorghoa\StepArgumentInjectorBehatExtension\ServiceContainer; + +use Behat\Testwork\Argument\ServiceContainer\ArgumentExtension; +use Behat\Testwork\Call\ServiceContainer\CallExtension; +use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface; +use Behat\Testwork\ServiceContainer\ExtensionManager; +use Doctrine\Common\Annotations\AnnotationReader; +use Gorghoa\StepArgumentInjectorBehatExtension\Argument\ArgumentOrganiser; +use Gorghoa\StepArgumentInjectorBehatExtension\Call\Handler\RuntimeCallHandler; +use Gorghoa\StepArgumentInjectorBehatExtension\Resolver\ArgumentsResolver; +use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Behat store for Behat contexts. + * + * @author Rodrigue Villetard + * @author Vincent Chalamon + */ +class StepArgumentInjectorExtension implements ExtensionInterface +{ + const STEP_ARGUMENT_INJECTOR_ARGUMENT_ORGANISER_ID = 'argument.step_argument_injector.organiser'; + const STEP_ARGUMENT_INJECTOR_DISPATCHER_ID = 'hook.step_argument_injector.dispatcher'; + const STEP_ARGUMENT_INJECTOR_TESTER_ID = 'tester.step_argument_injector.wrapper'; + const STEP_ARGUMENT_INJECTOR_CALL_HANDLER_ID = 'call.step_argument_injector.call_handler'; + const STEP_ARGUMENT_INJECTOR_ARGUMENTS_RESOLVER_ID = 'step_argument_injector.arguments_resolver'; + const STEP_ARGUMENT_INJECTOR_STORE_ID = 'behatstore.context_initializer.store_aware'; + const STEP_ARGUMENT_INJECTOR_DOCTRINE_READER_ID = 'doctrine.reader.annotation'; + const STEP_ARGUMENT_INJECTOR_HOOK_TAG_ID = 'step_argument_injector.hook_tag_id'; + + /** + * {@inheritdoc} + */ + public function getConfigKey() + { + return 'stepargumentinjector'; + } + + /** + * {@inheritdoc} + */ + public function initialize(ExtensionManager $extensionManager) + { + } + + /** + * {@inheritdoc} + */ + public function configure(ArrayNodeDefinition $builder) + { + } + + /** + * {@inheritdoc} + */ + public function load(ContainerBuilder $container, array $config) + { + // Declare Doctrine annotation reader as service + $container->register(self::STEP_ARGUMENT_INJECTOR_DOCTRINE_READER_ID, AnnotationReader::class) + // Ignore Behat annotations in reader + ->addMethodCall('addGlobalIgnoredName', ['Given']) + ->addMethodCall('addGlobalIgnoredName', ['When']) + ->addMethodCall('addGlobalIgnoredName', ['Then']) + ->addMethodCall('addGlobalIgnoredName', ['Transform']) + ->addMethodCall('addGlobalIgnoredName', ['BeforeStep']) + ->addMethodCall('addGlobalIgnoredName', ['BeforeScenario']) + ->addMethodCall('addGlobalIgnoredName', ['BeforeFeature']) + ->addMethodCall('addGlobalIgnoredName', ['BeforeSuite']) + ->addMethodCall('addGlobalIgnoredName', ['AfterStep']) + ->addMethodCall('addGlobalIgnoredName', ['AfterScenario']) + ->addMethodCall('addGlobalIgnoredName', ['AfterFeature']) + ->addMethodCall('addGlobalIgnoredName', ['AfterSuite']); + + $taggedServices = array_map(function ($serviceId) { + return new Reference($serviceId); + }, array_keys($container->findTaggedServiceIds(self::STEP_ARGUMENT_INJECTOR_HOOK_TAG_ID))); + + // Arguments resolver: resolve StepArgumentInjector arguments from annotation + $container->register(self::STEP_ARGUMENT_INJECTOR_ARGUMENTS_RESOLVER_ID, ArgumentsResolver::class) + ->setArguments([ + $taggedServices, + new Reference(self::STEP_ARGUMENT_INJECTOR_DOCTRINE_READER_ID), + ]); + + // Argument organiser + $container->register(self::STEP_ARGUMENT_INJECTOR_ARGUMENT_ORGANISER_ID, ArgumentOrganiser::class) + ->setDecoratedService(ArgumentExtension::PREG_MATCH_ARGUMENT_ORGANISER_ID) + ->setPublic(false) + ->setArguments([ + new Reference(sprintf('%s.inner', self::STEP_ARGUMENT_INJECTOR_ARGUMENT_ORGANISER_ID)), + $taggedServices, + new Reference(self::STEP_ARGUMENT_INJECTOR_DOCTRINE_READER_ID), + new Reference(self::STEP_ARGUMENT_INJECTOR_ARGUMENTS_RESOLVER_ID), + ]); + + // Override calls process + $container->register(self::STEP_ARGUMENT_INJECTOR_CALL_HANDLER_ID, RuntimeCallHandler::class) + ->setDecoratedService(CallExtension::CALL_HANDLER_TAG.'.runtime') + ->setArguments([ + new Reference(self::STEP_ARGUMENT_INJECTOR_CALL_HANDLER_ID.'.inner'), + new Reference(self::STEP_ARGUMENT_INJECTOR_ARGUMENTS_RESOLVER_ID), + ]); + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + } +} diff --git a/composer.json b/composer.json index 5e63c3c..cbaa576 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,7 @@ "autoload": { "psr-4": { + "Gorghoa\\StepArgumentInjectorBehatExtension\\": "argumentsExt/", "Gorghoa\\ScenarioStateBehatExtension\\": "src/", "Symfony\\Component\\Process\\": "vendor/symfony/process/" } diff --git a/src/.php_cs.cache b/src/.php_cs.cache new file mode 100644 index 0000000..c98949c --- /dev/null +++ b/src/.php_cs.cache @@ -0,0 +1 @@ +{"php":"7.1.7-1+0~20170711133214.5+stretch~1.gbp5284f4","version":"2.4.0:v2.4.0#63661f3add3609e90e4ab8115113e189ae547bb4","rules":{"binary_operator_spaces":{"align_double_arrow":false,"align_equals":false},"blank_line_after_opening_tag":true,"blank_line_before_statement":{"statements":["return"]},"braces":{"allow_single_line_closure":true},"cast_spaces":true,"class_definition":{"singleLine":true},"concat_space":{"spacing":"none"},"declare_equal_normalize":true,"function_typehint_space":true,"hash_to_slash_comment":true,"include":true,"lowercase_cast":true,"magic_constant_casing":true,"method_argument_space":true,"method_separation":true,"native_function_casing":true,"new_with_braces":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_empty_comment":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_consecutive_blank_lines":{"tokens":["curly_brace_block","extra","parenthesis_brace_block","square_brace_block","throw","use"]},"no_leading_import_slash":true,"no_leading_namespace_whitespace":true,"no_mixed_echo_print":{"use":"echo"},"no_multiline_whitespace_around_double_arrow":true,"no_short_bool_cast":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_around_offset":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_unneeded_control_parentheses":true,"no_unused_imports":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"object_operator_without_whitespace":true,"php_unit_fqcn_annotation":true,"phpdoc_align":true,"phpdoc_annotation_without_dot":true,"phpdoc_indent":true,"phpdoc_inline_tag":true,"phpdoc_no_access":true,"phpdoc_no_alias_tag":true,"phpdoc_no_empty_return":true,"phpdoc_no_package":true,"phpdoc_no_useless_inheritdoc":true,"phpdoc_return_self_reference":true,"phpdoc_scalar":true,"phpdoc_separation":true,"phpdoc_single_line_var_spacing":true,"phpdoc_summary":true,"phpdoc_to_comment":true,"phpdoc_trim":true,"phpdoc_types":true,"phpdoc_var_without_name":true,"pre_increment":true,"protected_to_private":true,"return_type_declaration":true,"self_accessor":true,"short_scalar_cast":true,"single_blank_line_before_namespace":true,"single_class_element_per_statement":true,"single_quote":true,"space_after_semicolon":true,"standardize_not_equals":true,"ternary_operator_spaces":true,"trailing_comma_in_multiline_array":true,"trim_array_spaces":true,"unary_operator_spaces":true,"whitespace_after_comma_in_array":true,"blank_line_after_namespace":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":true,"encoding":true,"full_opening_tag":true},"hashes":{"\/ScenarioStateInterface.php":2824836438,"\/Annotation\/ScenarioStateArgument.php":2979727378,"\/Context\/Initializer\/ScenarioStateInitializer.php":781987277,"\/Context\/ScenarioStateAwareTrait.php":2441401241,"\/Context\/ScenarioStateAwareContext.php":1438795547,"\/ScenarioState.php":3549039778,"\/ServiceContainer\/ScenarioStateExtension.php":1698856486,"\/Exception\/MissingStateException.php":1656618837}} \ No newline at end of file diff --git a/src/Annotation/ScenarioStateArgument.php b/src/Annotation/ScenarioStateArgument.php index b447264..a6f58cc 100644 --- a/src/Annotation/ScenarioStateArgument.php +++ b/src/Annotation/ScenarioStateArgument.php @@ -11,13 +11,15 @@ namespace Gorghoa\ScenarioStateBehatExtension\Annotation; +use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepInjectorArgument; + /** * @author Vincent Chalamon * * @Annotation * @Target("METHOD") */ -class ScenarioStateArgument +class ScenarioStateArgument implements StepInjectorArgument { /** * Argument name in store. diff --git a/src/Context/Initializer/ScenarioStateInitializer.php b/src/Context/Initializer/ScenarioStateInitializer.php index 379a5d8..0996819 100644 --- a/src/Context/Initializer/ScenarioStateInitializer.php +++ b/src/Context/Initializer/ScenarioStateInitializer.php @@ -17,12 +17,13 @@ use Gorghoa\ScenarioStateBehatExtension\Context\ScenarioStateAwareContext; use Gorghoa\ScenarioStateBehatExtension\ScenarioState; use Gorghoa\ScenarioStateBehatExtension\ScenarioStateInterface; +use Gorghoa\StepArgumentInjectorBehatExtension\Argument\StepArgumentHolder; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * @author Rodrigue Villetard */ -class ScenarioStateInitializer implements ContextInitializer, EventSubscriberInterface +class ScenarioStateInitializer implements ContextInitializer, EventSubscriberInterface, StepArgumentHolder { /** * @var ScenarioStateInterface @@ -68,4 +69,14 @@ public function getStore() { return $this->store; } + + public function hasStepArgumentFor($key) + { + return $this->store->hasStateFragment($key); + } + + public function getStepArgumentFor($key) + { + return $this->store->getStateFragment($key); + } } diff --git a/src/ScenarioStateInterface.php b/src/ScenarioStateInterface.php index 780b51d..6c7733f 100644 --- a/src/ScenarioStateInterface.php +++ b/src/ScenarioStateInterface.php @@ -26,7 +26,9 @@ public function provideStateFragment($key, $value); /** * @param string $key + * * @throws MissingStateException + * * @return mixed */ public function getStateFragment($key); diff --git a/src/ServiceContainer/ScenarioStateExtension.php b/src/ServiceContainer/ScenarioStateExtension.php index 7bd85fa..ef15327 100644 --- a/src/ServiceContainer/ScenarioStateExtension.php +++ b/src/ServiceContainer/ScenarioStateExtension.php @@ -12,24 +12,14 @@ namespace Gorghoa\ScenarioStateBehatExtension\ServiceContainer; use Behat\Behat\Context\ServiceContainer\ContextExtension; -use Behat\Behat\Tester\ServiceContainer\TesterExtension; -use Behat\Testwork\Argument\ServiceContainer\ArgumentExtension; -use Behat\Testwork\Call\ServiceContainer\CallExtension; use Behat\Testwork\EventDispatcher\ServiceContainer\EventDispatcherExtension; -use Behat\Testwork\Hook\ServiceContainer\HookExtension; use Behat\Testwork\ServiceContainer\Extension as ExtensionInterface; use Behat\Testwork\ServiceContainer\ExtensionManager; -use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\AnnotationRegistry; -use Gorghoa\ScenarioStateBehatExtension\Argument\ScenarioStateArgumentOrganiser; -use Gorghoa\ScenarioStateBehatExtension\Call\Handler\RuntimeCallHandler; use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; -use Gorghoa\ScenarioStateBehatExtension\Hook\Dispatcher\ScenarioStateHookDispatcher; -use Gorghoa\ScenarioStateBehatExtension\Hook\Tester\ScenarioStateHookableScenarioTester; -use Gorghoa\ScenarioStateBehatExtension\Resolver\ArgumentsResolver; +use Gorghoa\StepArgumentInjectorBehatExtension\ServiceContainer\StepArgumentInjectorExtension; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; /** * Behat store for Behat contexts. @@ -39,13 +29,8 @@ */ class ScenarioStateExtension implements ExtensionInterface { - const SCENARIO_STATE_ARGUMENT_ORGANISER_ID = 'argument.scenario_state.organiser'; - const SCENARIO_STATE_DISPATCHER_ID = 'hook.scenario_state.dispatcher'; - const SCENARIO_STATE_TESTER_ID = 'tester.scenario_state.wrapper'; - const SCENARIO_STATE_CALL_HANDLER_ID = 'call.scenario_state.call_handler'; - const SCENARIO_STATE_ARGUMENTS_RESOLVER_ID = 'scenario_state.arguments_resolver'; const SCENARIO_STATE_STORE_ID = 'behatstore.context_initializer.store_aware'; - const SCENARIO_STATE_DOCTRINE_READER_ID = 'doctrine.reader.annotation'; + const SCENARIO_STATE_ARGUMENT_INJECTOR_STORE_ID = 'behatstore.context_initializer.store_aware'; /** * {@inheritdoc} @@ -78,49 +63,9 @@ public function load(ContainerBuilder $container, array $config) // Load ScenarioState store $container->register(self::SCENARIO_STATE_STORE_ID, ScenarioStateInitializer::class) ->addTag(ContextExtension::INITIALIZER_TAG, ['priority' => 0]) - ->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, ['priority' => 0]); - - // Declare Doctrine annotation reader as service - $container->register(self::SCENARIO_STATE_DOCTRINE_READER_ID, AnnotationReader::class) - // Ignore Behat annotations in reader - ->addMethodCall('addGlobalIgnoredName', ['Given']) - ->addMethodCall('addGlobalIgnoredName', ['When']) - ->addMethodCall('addGlobalIgnoredName', ['Then']) - ->addMethodCall('addGlobalIgnoredName', ['Transform']) - ->addMethodCall('addGlobalIgnoredName', ['BeforeStep']) - ->addMethodCall('addGlobalIgnoredName', ['BeforeScenario']) - ->addMethodCall('addGlobalIgnoredName', ['BeforeFeature']) - ->addMethodCall('addGlobalIgnoredName', ['BeforeSuite']) - ->addMethodCall('addGlobalIgnoredName', ['AfterStep']) - ->addMethodCall('addGlobalIgnoredName', ['AfterScenario']) - ->addMethodCall('addGlobalIgnoredName', ['AfterFeature']) - ->addMethodCall('addGlobalIgnoredName', ['AfterSuite']); - - // Arguments resolver: resolve ScenarioState arguments from annotation - $container->register(self::SCENARIO_STATE_ARGUMENTS_RESOLVER_ID, ArgumentsResolver::class) - ->setArguments([ - new Reference(self::SCENARIO_STATE_STORE_ID), - new Reference(self::SCENARIO_STATE_DOCTRINE_READER_ID), - ]); - - // Argument organiser - $container->register(self::SCENARIO_STATE_ARGUMENT_ORGANISER_ID, ScenarioStateArgumentOrganiser::class) - ->setDecoratedService(ArgumentExtension::PREG_MATCH_ARGUMENT_ORGANISER_ID) - ->setPublic(false) - ->setArguments([ - new Reference(sprintf('%s.inner', self::SCENARIO_STATE_ARGUMENT_ORGANISER_ID)), - new Reference(self::SCENARIO_STATE_STORE_ID), - new Reference(self::SCENARIO_STATE_DOCTRINE_READER_ID), - new Reference(self::SCENARIO_STATE_ARGUMENTS_RESOLVER_ID), - ]); - - // Override calls process - $container->register(self::SCENARIO_STATE_CALL_HANDLER_ID, RuntimeCallHandler::class) - ->setDecoratedService(CallExtension::CALL_HANDLER_TAG.'.runtime') - ->setArguments([ - new Reference(self::SCENARIO_STATE_CALL_HANDLER_ID.'.inner'), - new Reference(self::SCENARIO_STATE_ARGUMENTS_RESOLVER_ID), - ]); + ->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, ['priority' => 0]) + ->addTag(StepArgumentInjectorExtension::STEP_ARGUMENT_INJECTOR_HOOK_TAG_ID, ['priority' => 0]) + ; } /** diff --git a/testapp/behat.yml b/testapp/behat.yml index efdd3fc..9ca9379 100644 --- a/testapp/behat.yml +++ b/testapp/behat.yml @@ -1,3 +1,4 @@ default: extensions: Gorghoa\ScenarioStateBehatExtension\ServiceContainer\ScenarioStateExtension: ~ + Gorghoa\StepArgumentInjectorBehatExtension\ServiceContainer\StepArgumentInjectorExtension: ~ diff --git a/testsSAI/Annotation/ScenarioStateArgumentTest.php b/testsSAI/Annotation/ScenarioStateArgumentTest.php new file mode 100644 index 0000000..8ce684a --- /dev/null +++ b/testsSAI/Annotation/ScenarioStateArgumentTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gorghoa\ScenarioStateBehatExtension\Annotation; + +/** + * @author Vincent Chalamon + */ +class ScenarioStateArgumentTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getArguments + * + * @param array $arguments + * @param string $name + * @param string $argument + */ + public function testWithValue(array $arguments, $name, $argument) + { + $annotation = new ScenarioStateArgument($arguments); + $this->assertEquals($name, $annotation->name); + $this->assertEquals($argument, $annotation->argument); + } + + /** + * @return array + */ + public function getArguments() + { + return [ + [ + ['value' => 'foo'], + 'foo', + 'foo', + ], + [ + ['name' => 'foo'], + 'foo', + 'foo', + ], + [ + ['name' => 'foo', 'argument' => 'bar'], + 'foo', + 'bar', + ], + ]; + } +} diff --git a/tests/Argument/ScenarioStateArgumentOrganiserTest.php b/testsSAI/Argument/ScenarioStateArgumentOrganiserTest.php similarity index 95% rename from tests/Argument/ScenarioStateArgumentOrganiserTest.php rename to testsSAI/Argument/ScenarioStateArgumentOrganiserTest.php index a5a30e9..575a245 100644 --- a/tests/Argument/ScenarioStateArgumentOrganiserTest.php +++ b/testsSAI/Argument/ScenarioStateArgumentOrganiserTest.php @@ -21,10 +21,10 @@ /** * @author Vincent Chalamon */ -class ScenarioStateArgumentOrganiserTest extends \PHPUnit_Framework_TestCase +class ArgumentOrganiserTest extends \PHPUnit_Framework_TestCase { /** - * @var ScenarioStateArgumentOrganiser + * @var ArgumentOrganiser */ private $organiser; @@ -67,7 +67,7 @@ protected function setUp() $this->readerMock = $this->prophesize(Reader::class); $this->annotationMock = $this->prophesize(ScenarioStateArgument::class); - $this->organiser = new ScenarioStateArgumentOrganiser( + $this->organiser = new ArgumentOrganiser( $this->organiserMock->reveal(), $this->initializerMock->reveal(), $this->readerMock->reveal() diff --git a/tests/Resolver/ArgumentsResolverTest.php b/testsSAI/Resolver/ArgumentsResolverTest.php similarity index 100% rename from tests/Resolver/ArgumentsResolverTest.php rename to testsSAI/Resolver/ArgumentsResolverTest.php From ae553093c401b3893aab0da81ed04192bf2a54ec Mon Sep 17 00:00:00 2001 From: Rodrigue Villetard Date: Thu, 27 Jul 2017 11:51:24 +0200 Subject: [PATCH 2/4] Delegate annotation handling to hooked services --- .gitignore | 1 + .../Annotation/StepInjectorArgument.php | 7 ++-- argumentsExt/Argument/ArgumentOrganiser.php | 17 +++++----- argumentsExt/Argument/StepArgumentHolder.php | 20 ++++++++++-- .../Exception/RejectedAnnotationException.php | 19 +++++++++++ argumentsExt/Resolver/ArgumentsResolver.php | 21 ++++++------ .../Initializer/ScenarioStateInitializer.php | 32 ++++++++++++++++--- 7 files changed, 88 insertions(+), 29 deletions(-) create mode 100644 argumentsExt/Exception/RejectedAnnotationException.php diff --git a/.gitignore b/.gitignore index 7579f74..4a45ef5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ vendor composer.lock +.php_cs.cache diff --git a/argumentsExt/Annotation/StepInjectorArgument.php b/argumentsExt/Annotation/StepInjectorArgument.php index 9186499..3e19fbe 100644 --- a/argumentsExt/Annotation/StepInjectorArgument.php +++ b/argumentsExt/Annotation/StepInjectorArgument.php @@ -17,11 +17,8 @@ interface StepInjectorArgument { /** - * @return string - */ - public function getName(); - - /** + * The argument name this annotation is targeting to inject. + * * @return string */ public function getArgument(); diff --git a/argumentsExt/Argument/ArgumentOrganiser.php b/argumentsExt/Argument/ArgumentOrganiser.php index f55c681..9b5f94a 100644 --- a/argumentsExt/Argument/ArgumentOrganiser.php +++ b/argumentsExt/Argument/ArgumentOrganiser.php @@ -13,7 +13,6 @@ use Behat\Testwork\Argument\ArgumentOrganiser as BehatArgumentOrganiser; use Doctrine\Common\Annotations\Reader; -use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepArgumentInjectorArgument; use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepInjectorArgument; // use Gorghoa\StepArgumentInjectorBehatExtension\Context\Initializer\StepArgumentInjectorInitializer; use ReflectionFunctionAbstract; @@ -30,19 +29,19 @@ final class ArgumentOrganiser implements BehatArgumentOrganiser private $baseOrganiser; /** - * @var StepArgumentInjectorInitializer + * @var StepArgumentHolder[] */ - private $hookers; + private $stepArgumentHolders; /** * @var Reader */ private $reader; - public function __construct(BehatArgumentOrganiser $organiser, array $hookers, Reader $reader) + public function __construct(BehatArgumentOrganiser $organiser, array $stepArgumentHolders, Reader $reader) { $this->baseOrganiser = $organiser; - $this->hookers = $hookers; + $this->stepArgumentHolders = $stepArgumentHolders; $this->reader = $reader; } @@ -60,18 +59,18 @@ public function organiseArguments(ReflectionFunctionAbstract $function, array $m return $this->baseOrganiser->organiseArguments($function, $match); } - /** @var StepArgumentInjectorArgument[] $annotations */ $annotations = $this->reader->getMethodAnnotations($function); foreach ($annotations as $annotation) { if ($annotation instanceof StepInjectorArgument && in_array($annotation->getArgument(), $paramsKeys) ) { - foreach ($this->hookers as $hooker) { - if ($hooker->hasStepArgumentFor($annotation->getName())) { + /* @var StepInjectorArgument $annotation */ + foreach ($this->stepArgumentHolders as $hooker) { + if ($hooker->doesHandleStepArgument($annotation)) { $match[$annotation->getArgument()] = $match[strval(++$i)] - = $hooker->getStepArgumentFor($annotation->getName()) + = $hooker->getStepArgumentValueFor($annotation) ; } } diff --git a/argumentsExt/Argument/StepArgumentHolder.php b/argumentsExt/Argument/StepArgumentHolder.php index 24844ca..a683c58 100644 --- a/argumentsExt/Argument/StepArgumentHolder.php +++ b/argumentsExt/Argument/StepArgumentHolder.php @@ -11,12 +11,28 @@ namespace Gorghoa\StepArgumentInjectorBehatExtension\Argument; +use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepInjectorArgument; + /** * @author Rodrigue Villetard */ interface StepArgumentHolder { - public function hasStepArgumentFor($key); + /** + * Check if an annotation is handled by the service. + * + * @param StepInjectorArgument $annotation + * + * @return bool + */ + public function doesHandleStepArgument(StepInjectorArgument $annotation); - public function getStepArgumentFor($key); + /** + * Get value to inject for a step argument. + * + * @param StepInjectorArgument $annotation + * + * @return mixed + */ + public function getStepArgumentValueFor(StepInjectorArgument $annotation); } diff --git a/argumentsExt/Exception/RejectedAnnotationException.php b/argumentsExt/Exception/RejectedAnnotationException.php new file mode 100644 index 0000000..4e926ce --- /dev/null +++ b/argumentsExt/Exception/RejectedAnnotationException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gorghoa\StepArgumentInjectorBehatExtension\Exception; + +/** + * @author Rodrigue Villetard + */ +class RejectedAnnotationException extends \LogicException +{ +} diff --git a/argumentsExt/Resolver/ArgumentsResolver.php b/argumentsExt/Resolver/ArgumentsResolver.php index 96bcd82..94217c3 100644 --- a/argumentsExt/Resolver/ArgumentsResolver.php +++ b/argumentsExt/Resolver/ArgumentsResolver.php @@ -25,16 +25,19 @@ class ArgumentsResolver private $reader; /** - * @var array + * @var StepArgumentHolder[] */ - private $hookers; + private $stepArgumentHolders; /** - * @param Reader $reader + * ArgumentsResolver constructor. + * + * @param StepArgumentHolder[] $stepArgumentHolders + * @param Reader $reader */ - public function __construct(array $hookers, Reader $reader) + public function __construct($stepArgumentHolders, Reader $reader) { - $this->hookers = $hookers; + $this->stepArgumentHolders = $stepArgumentHolders; $this->reader = $reader; } @@ -56,15 +59,15 @@ public function resolve(\ReflectionMethod $function, array $arguments) }, $function->getParameters()); // Prepare arguments from annotations - /** @var StepArgumentInjectorArgument[] $annotations */ $annotations = $this->reader->getMethodAnnotations($function); foreach ($annotations as $annotation) { if ($annotation instanceof StepInjectorArgument && in_array($annotation->getArgument(), $paramsKeys) ) { - foreach ($this->hookers as $hooker) { - if ($hooker->hasStepArgumentFor($annotation->getName())) { - $arguments[$annotation->getArgument()] = $hooker->getStepArgumentFor($annotation->getName()); + /* @var StepArgumentInjectorArgument $annotation */ + foreach ($this->stepArgumentHolders as $hooker) { + if ($hooker->doesHandleStepArgument($annotation)) { + $arguments[$annotation->getArgument()] = $hooker->getStepArgumentValueFor($annotation); } } } diff --git a/src/Context/Initializer/ScenarioStateInitializer.php b/src/Context/Initializer/ScenarioStateInitializer.php index 0996819..5259796 100644 --- a/src/Context/Initializer/ScenarioStateInitializer.php +++ b/src/Context/Initializer/ScenarioStateInitializer.php @@ -14,10 +14,13 @@ use Behat\Behat\Context\Context; use Behat\Behat\Context\Initializer\ContextInitializer; use Behat\Behat\EventDispatcher\Event\ScenarioTested; +use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; use Gorghoa\ScenarioStateBehatExtension\Context\ScenarioStateAwareContext; use Gorghoa\ScenarioStateBehatExtension\ScenarioState; use Gorghoa\ScenarioStateBehatExtension\ScenarioStateInterface; +use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepInjectorArgument; use Gorghoa\StepArgumentInjectorBehatExtension\Argument\StepArgumentHolder; +use Gorghoa\StepArgumentInjectorBehatExtension\Exception\RejectedAnnotationException; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -70,13 +73,34 @@ public function getStore() return $this->store; } - public function hasStepArgumentFor($key) + /** + * Test if this service should handle specific argument injection. + * + * @param StepInjectorArgument $annotation + * + * @return bool + */ + public function doesHandleStepArgument(StepInjectorArgument $annotation) { - return $this->store->hasStateFragment($key); + return $annotation instanceof ScenarioStateArgument && $this->store->hasStateFragment($annotation->getName()); } - public function getStepArgumentFor($key) + /** + * Get an argument value to inject. + * + * @param StepInjectorArgument $annotation + * + * @throws RejectedAnnotationException + * + * @return mixed + */ + public function getStepArgumentValueFor(StepInjectorArgument $annotation) { - return $this->store->getStateFragment($key); + if (!($annotation instanceof ScenarioStateArgument)) { + $class = get_class($annotation); + throw new RejectedAnnotationException("$class not handled by ScenarioStateBehatExtension"); + } + + return $this->store->getStateFragment($annotation->getName()); } } From b83b7758fe4fd27807c397b04435697ca278db46 Mon Sep 17 00:00:00 2001 From: Rodrigue Villetard Date: Thu, 27 Jul 2017 17:50:18 +0200 Subject: [PATCH 3/4] Decouple phpunit tests --- argumentsExt/Argument/ArgumentOrganiser.php | 5 +- argumentsExt/Resolver/ArgumentsResolver.php | 6 +- phpunit.xml.dist | 3 + .../Annotation/ScenarioStateArgumentTest.php | 56 --------- testsSAI/Argument/ArgumentOrganiserTest.php | 115 ++++++++++++++++++ .../ScenarioStateArgumentOrganiserTest.php | 114 ----------------- testsSAI/Resolver/ArgumentsResolverTest.php | 34 +++--- 7 files changed, 143 insertions(+), 190 deletions(-) delete mode 100644 testsSAI/Annotation/ScenarioStateArgumentTest.php create mode 100644 testsSAI/Argument/ArgumentOrganiserTest.php delete mode 100644 testsSAI/Argument/ScenarioStateArgumentOrganiserTest.php diff --git a/argumentsExt/Argument/ArgumentOrganiser.php b/argumentsExt/Argument/ArgumentOrganiser.php index 9b5f94a..34aba7e 100644 --- a/argumentsExt/Argument/ArgumentOrganiser.php +++ b/argumentsExt/Argument/ArgumentOrganiser.php @@ -63,12 +63,13 @@ public function organiseArguments(ReflectionFunctionAbstract $function, array $m foreach ($annotations as $annotation) { if ($annotation instanceof StepInjectorArgument && - in_array($annotation->getArgument(), $paramsKeys) + in_array($argument = $annotation->getArgument(), $paramsKeys) ) { /* @var StepInjectorArgument $annotation */ foreach ($this->stepArgumentHolders as $hooker) { if ($hooker->doesHandleStepArgument($annotation)) { - $match[$annotation->getArgument()] + + $match[$argument] = $match[strval(++$i)] = $hooker->getStepArgumentValueFor($annotation) ; diff --git a/argumentsExt/Resolver/ArgumentsResolver.php b/argumentsExt/Resolver/ArgumentsResolver.php index 94217c3..994f896 100644 --- a/argumentsExt/Resolver/ArgumentsResolver.php +++ b/argumentsExt/Resolver/ArgumentsResolver.php @@ -49,7 +49,7 @@ public function __construct($stepArgumentHolders, Reader $reader) */ public function resolve(\ReflectionMethod $function, array $arguments) { - // No `@StepArgumentInjectorArgument` annotation found + // No `@StepInjectorArgument` annotation found if (null === $this->reader->getMethodAnnotation($function, StepInjectorArgument::class)) { return $arguments; } @@ -62,12 +62,12 @@ public function resolve(\ReflectionMethod $function, array $arguments) $annotations = $this->reader->getMethodAnnotations($function); foreach ($annotations as $annotation) { if ($annotation instanceof StepInjectorArgument && - in_array($annotation->getArgument(), $paramsKeys) + in_array($argument = $annotation->getArgument(), $paramsKeys) ) { /* @var StepArgumentInjectorArgument $annotation */ foreach ($this->stepArgumentHolders as $hooker) { if ($hooker->doesHandleStepArgument($annotation)) { - $arguments[$annotation->getArgument()] = $hooker->getStepArgumentValueFor($annotation); + $arguments[$argument] = $hooker->getStepArgumentValueFor($annotation); } } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a62fc3b..b9de83c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -14,5 +14,8 @@ tests + + testsSAI + diff --git a/testsSAI/Annotation/ScenarioStateArgumentTest.php b/testsSAI/Annotation/ScenarioStateArgumentTest.php deleted file mode 100644 index 8ce684a..0000000 --- a/testsSAI/Annotation/ScenarioStateArgumentTest.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Gorghoa\ScenarioStateBehatExtension\Annotation; - -/** - * @author Vincent Chalamon - */ -class ScenarioStateArgumentTest extends \PHPUnit_Framework_TestCase -{ - /** - * @dataProvider getArguments - * - * @param array $arguments - * @param string $name - * @param string $argument - */ - public function testWithValue(array $arguments, $name, $argument) - { - $annotation = new ScenarioStateArgument($arguments); - $this->assertEquals($name, $annotation->name); - $this->assertEquals($argument, $annotation->argument); - } - - /** - * @return array - */ - public function getArguments() - { - return [ - [ - ['value' => 'foo'], - 'foo', - 'foo', - ], - [ - ['name' => 'foo'], - 'foo', - 'foo', - ], - [ - ['name' => 'foo', 'argument' => 'bar'], - 'foo', - 'bar', - ], - ]; - } -} diff --git a/testsSAI/Argument/ArgumentOrganiserTest.php b/testsSAI/Argument/ArgumentOrganiserTest.php new file mode 100644 index 0000000..fc76a7f --- /dev/null +++ b/testsSAI/Argument/ArgumentOrganiserTest.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gorghoa\StepArgumentInjectorBehatExtension\Argument; + +use Doctrine\Common\Annotations\Reader; +use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepInjectorArgument; +use Prophecy\Prophecy\ObjectProphecy; +use Behat\Testwork\Argument\ArgumentOrganiser as BehatArgumentOrganiser; + +/** + * @author Vincent Chalamon + * @author Rodrigue Villetard + */ +class ArgumentOrganiserTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var ArgumentOrganiser + */ + private $organiser; + + /** + * @var ObjectProphecy|ArgumentOrganiser + */ + private $organiserMock; + + /** + * @var ObjectProphecy + */ + private $initializerMock; + + /** + * @var ObjectProphecy|\ReflectionMethod + */ + private $functionMock; + + /** + * @var ObjectProphecy|Reader + */ + private $readerMock; + + /** + * @var StepArgumentHolder + */ + private $holderMock; + + protected function setUp() + { + $this->organiserMock = $this->prophesize(BehatArgumentOrganiser::class); + $this->functionMock = $this->prophesize(\ReflectionMethod::class); + $this->readerMock = $this->prophesize(Reader::class); + $this->holderMock = $this->prophesize(StepArgumentHolder::class); + + $this->organiser = new ArgumentOrganiser( + $this->organiserMock->reveal(), + [$this->holderMock->reveal()], + $this->readerMock->reveal() + ); + } + + /** + * @return ObjectProphecy + */ + private function annotationMockFactory() + { + return $this->prophesize(StepInjectorArgument::class); + } + + public function testOrganiseArguments() + { + $this->functionMock->getParameters()->willReturn([ + (object) ['name' => 'scenarioBanana'], // argument with injector annotation and **a service hold** value + (object) ['name' => 'gorilla'], // argument with injector annotation but **no service hold** value + (object) ['name' => 'foo'], // argument not handled by this extension + ])->shouldBeCalledTimes(1); + + $annot1 = $this->annotationMockFactory(); + $annot1->getArgument()->willReturn('scenarioBanana')->shouldBeCalledTimes(1); + $annot1->reveal(); + + $annot2 = $this->annotationMockFactory(); + $annot2->getArgument()->willReturn('gorilla')->shouldBeCalledTimes(1); + $annot2->reveal(); + + $this->readerMock->getMethodAnnotations($this->functionMock->reveal())->willReturn([ + $annot1, + $annot2, + ])->shouldBeCalledTimes(1); + + $this->holderMock->doesHandleStepArgument($annot1)->willReturn(true); + $this->holderMock->doesHandleStepArgument($annot2)->willReturn(false); + + $this->holderMock->getStepArgumentValueFor($annot1)->willReturn('yammyBanana')->shouldBeCalledTimes(1); + $this->holderMock->getStepArgumentValueFor($annot2)->shouldNotBeCalled(); + + $this->holderMock->getStepArgumentValueFor($annot2); + + $this->organiserMock->organiseArguments($this->functionMock->reveal(), [ + 0 => 'scenarioBanana', + 1 => 'gorilla', + 'scenarioBanana' => 'yammyBanana', + 2 => 'yammyBanana', + ])->shouldBeCalledTimes(1); + + $this->organiser->organiseArguments($this->functionMock->reveal(), ['scenarioBanana', 'gorilla']); + } +} diff --git a/testsSAI/Argument/ScenarioStateArgumentOrganiserTest.php b/testsSAI/Argument/ScenarioStateArgumentOrganiserTest.php deleted file mode 100644 index 575a245..0000000 --- a/testsSAI/Argument/ScenarioStateArgumentOrganiserTest.php +++ /dev/null @@ -1,114 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Gorghoa\ScenarioStateBehatExtension\Argument; - -use Behat\Testwork\Argument\ArgumentOrganiser; -use Doctrine\Common\Annotations\Reader; -use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; -use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; -use Gorghoa\ScenarioStateBehatExtension\ScenarioStateInterface; -use Prophecy\Prophecy\ObjectProphecy; - -/** - * @author Vincent Chalamon - */ -class ArgumentOrganiserTest extends \PHPUnit_Framework_TestCase -{ - /** - * @var ArgumentOrganiser - */ - private $organiser; - - /** - * @var ObjectProphecy|ArgumentOrganiser - */ - private $organiserMock; - - /** - * @var ObjectProphecy|ScenarioStateInitializer - */ - private $initializerMock; - - /** - * @var ObjectProphecy|ScenarioStateInterface - */ - private $storeMock; - - /** - * @var ObjectProphecy|\ReflectionMethod - */ - private $functionMock; - - /** - * @var ObjectProphecy|Reader - */ - private $readerMock; - - /** - * @var ObjectProphecy|ScenarioStateArgument - */ - private $annotationMock; - - protected function setUp() - { - $this->organiserMock = $this->prophesize(ArgumentOrganiser::class); - $this->initializerMock = $this->prophesize(ScenarioStateInitializer::class); - $this->storeMock = $this->prophesize(ScenarioStateInterface::class); - $this->functionMock = $this->prophesize(\ReflectionMethod::class); - $this->readerMock = $this->prophesize(Reader::class); - $this->annotationMock = $this->prophesize(ScenarioStateArgument::class); - - $this->organiser = new ArgumentOrganiser( - $this->organiserMock->reveal(), - $this->initializerMock->reveal(), - $this->readerMock->reveal() - ); - } - - public function testOrganiseArguments() - { - $this->functionMock->getParameters()->willReturn([ - (object) ['name' => 'scenarioBanana'], - (object) ['name' => 'gorilla'], - (object) ['name' => 'foo'], - ])->shouldBeCalledTimes(1); - - $this->initializerMock->getStore()->willReturn($this->storeMock->reveal())->shouldBeCalledTimes(1); - $this->readerMock->getMethodAnnotations($this->functionMock->reveal())->willReturn([ - $this->annotationMock->reveal(), - $this->annotationMock->reveal(), - ])->shouldBeCalledTimes(1); - $this->annotationMock->getArgument() - ->willReturn('scenarioBanana', 'scenarioBanana', 'gorilla', 'gorilla') - ->shouldBeCalled(); - $this->annotationMock->getName() - ->willReturn('scenarioBanana', 'scenarioBanana', 'scenarioBanana', 'scenarioGorilla', 'scenarioGorilla', 'scenarioGorilla') - ->shouldBeCalled(); - $this->storeMock->hasStateFragment('scenarioBanana')->willReturn(true)->shouldBeCalledTimes(1); - $this->storeMock->hasStateFragment('scenarioGorilla')->willReturn(true)->shouldBeCalledTimes(1); - $this->storeMock->hasStateFragment('foo')->shouldNotBeCalled(); - $this->storeMock->getStateFragment('scenarioBanana')->willReturn('Yummy banana!')->shouldBeCalledTimes(2); - $this->storeMock->getStateFragment('scenarioGorilla')->willReturn('Bonobo')->shouldBeCalledTimes(2); - $this->storeMock->getStateFragment('foo')->shouldNotBeCalled(); - - $this->organiserMock->organiseArguments($this->functionMock->reveal(), [ - 0 => 'scenarioBanana', - 1 => 'gorilla', - 'scenarioBanana' => 'Yummy banana!', - 2 => 'Yummy banana!', - 'gorilla' => 'Bonobo', - 3 => 'Bonobo', - ])->shouldBeCalledTimes(1); - - $this->organiser->organiseArguments($this->functionMock->reveal(), ['scenarioBanana', 'gorilla']); - } -} diff --git a/testsSAI/Resolver/ArgumentsResolverTest.php b/testsSAI/Resolver/ArgumentsResolverTest.php index 3badd3f..82e1443 100644 --- a/testsSAI/Resolver/ArgumentsResolverTest.php +++ b/testsSAI/Resolver/ArgumentsResolverTest.php @@ -1,7 +1,7 @@ * @@ -9,38 +9,42 @@ * file that was distributed with this source code. */ -namespace Gorghoa\ScenarioStateBehatExtension\Resolver; +namespace Gorghoa\StepArgumentInjectorBehatExtension\Resolver; use Doctrine\Common\Annotations\Reader; -use Gorghoa\ScenarioStateBehatExtension\Annotation\ScenarioStateArgument; -use Gorghoa\ScenarioStateBehatExtension\Context\Initializer\ScenarioStateInitializer; -use Gorghoa\ScenarioStateBehatExtension\ScenarioStateInterface; +use Gorghoa\StepArgumentInjectorBehatExtension\Annotation\StepInjectorArgument; +use Gorghoa\StepArgumentInjectorBehatExtension\Argument\StepArgumentHolder; /** * @author Vincent Chalamon + * @author Rodrigue Villetard */ class ArgumentsResolverTest extends \PHPUnit_Framework_TestCase { public function testResolve() { - $initializerMock = $this->prophesize(ScenarioStateInitializer::class); - $storeMock = $this->prophesize(ScenarioStateInterface::class); $readerMock = $this->prophesize(Reader::class); $functionMock = $this->prophesize(\ReflectionMethod::class); $parameterMock = $this->prophesize(\ReflectionParameter::class); - $annotationMock = $this->prophesize(ScenarioStateArgument::class); + $annotationMock = $this->prophesize(StepInjectorArgument::class); $functionMock->getParameters()->willReturn([$parameterMock, $parameterMock])->shouldBeCalledTimes(2); $parameterMock->getName()->willReturn('lorem', 'foo', 'lorem', 'foo')->shouldBeCalledTimes(4); - $initializerMock->getStore()->willReturn($storeMock)->shouldBeCalledTimes(1); - $readerMock->getMethodAnnotation($functionMock, ScenarioStateArgument::class)->willReturn($annotationMock)->shouldBeCalledTimes(1); + + $holderMock1 = $this->prophesize(StepArgumentHolder::class); + $holderMock2 = $this->prophesize(StepArgumentHolder::class); + + $readerMock->getMethodAnnotation($functionMock, StepInjectorArgument::class)->willReturn($annotationMock)->shouldBeCalledTimes(1); $readerMock->getMethodAnnotations($functionMock)->willReturn([$this->prophesize(\stdClass::class), $annotationMock])->shouldBeCalledTimes(1); - $annotationMock->getArgument()->willReturn('lorem')->shouldBeCalledTimes(2); - $annotationMock->getName()->willReturn('ipsum')->shouldBeCalledTimes(2); - $storeMock->hasStateFragment('ipsum')->willReturn(true)->shouldBeCalledTimes(1); - $storeMock->getStateFragment('ipsum')->willReturn('pouet')->shouldBeCalledTimes(1); + $annotationMock->getArgument()->willReturn('lorem')->shouldBeCalledTimes(1); + + $holderMock1->doesHandleStepArgument($annotationMock)->willReturn(true)->shouldBeCalledTimes(1); + $holderMock1->getStepArgumentValueFor($annotationMock)->willReturn(true)->shouldBeCalledTimes(1); + + $holderMock2->doesHandleStepArgument($annotationMock)->willReturn(false)->shouldBeCalledTimes(1); + $holderMock2->getStepArgumentValueFor($annotationMock)->shouldNotBeCalled(); - $resolver = new ArgumentsResolver($initializerMock->reveal(), $readerMock->reveal()); + $resolver = new ArgumentsResolver([$holderMock1->reveal(), $holderMock2->reveal()], $readerMock->reveal()); $resolver->resolve($functionMock->reveal(), ['lorem' => 'pouet', 'foo' => 'bar']); } } From 00ac8975a37c65e31b1a67981d06bdfa15411a5b Mon Sep 17 00:00:00 2001 From: Rodrigue Villetard Date: Thu, 27 Jul 2017 21:47:29 +0200 Subject: [PATCH 4/4] removing .php_cs.cache --- src/.php_cs.cache | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/.php_cs.cache diff --git a/src/.php_cs.cache b/src/.php_cs.cache deleted file mode 100644 index c98949c..0000000 --- a/src/.php_cs.cache +++ /dev/null @@ -1 +0,0 @@ -{"php":"7.1.7-1+0~20170711133214.5+stretch~1.gbp5284f4","version":"2.4.0:v2.4.0#63661f3add3609e90e4ab8115113e189ae547bb4","rules":{"binary_operator_spaces":{"align_double_arrow":false,"align_equals":false},"blank_line_after_opening_tag":true,"blank_line_before_statement":{"statements":["return"]},"braces":{"allow_single_line_closure":true},"cast_spaces":true,"class_definition":{"singleLine":true},"concat_space":{"spacing":"none"},"declare_equal_normalize":true,"function_typehint_space":true,"hash_to_slash_comment":true,"include":true,"lowercase_cast":true,"magic_constant_casing":true,"method_argument_space":true,"method_separation":true,"native_function_casing":true,"new_with_braces":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_empty_comment":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_consecutive_blank_lines":{"tokens":["curly_brace_block","extra","parenthesis_brace_block","square_brace_block","throw","use"]},"no_leading_import_slash":true,"no_leading_namespace_whitespace":true,"no_mixed_echo_print":{"use":"echo"},"no_multiline_whitespace_around_double_arrow":true,"no_short_bool_cast":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_around_offset":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_unneeded_control_parentheses":true,"no_unused_imports":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"object_operator_without_whitespace":true,"php_unit_fqcn_annotation":true,"phpdoc_align":true,"phpdoc_annotation_without_dot":true,"phpdoc_indent":true,"phpdoc_inline_tag":true,"phpdoc_no_access":true,"phpdoc_no_alias_tag":true,"phpdoc_no_empty_return":true,"phpdoc_no_package":true,"phpdoc_no_useless_inheritdoc":true,"phpdoc_return_self_reference":true,"phpdoc_scalar":true,"phpdoc_separation":true,"phpdoc_single_line_var_spacing":true,"phpdoc_summary":true,"phpdoc_to_comment":true,"phpdoc_trim":true,"phpdoc_types":true,"phpdoc_var_without_name":true,"pre_increment":true,"protected_to_private":true,"return_type_declaration":true,"self_accessor":true,"short_scalar_cast":true,"single_blank_line_before_namespace":true,"single_class_element_per_statement":true,"single_quote":true,"space_after_semicolon":true,"standardize_not_equals":true,"ternary_operator_spaces":true,"trailing_comma_in_multiline_array":true,"trim_array_spaces":true,"unary_operator_spaces":true,"whitespace_after_comma_in_array":true,"blank_line_after_namespace":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":true,"encoding":true,"full_opening_tag":true},"hashes":{"\/ScenarioStateInterface.php":2824836438,"\/Annotation\/ScenarioStateArgument.php":2979727378,"\/Context\/Initializer\/ScenarioStateInitializer.php":781987277,"\/Context\/ScenarioStateAwareTrait.php":2441401241,"\/Context\/ScenarioStateAwareContext.php":1438795547,"\/ScenarioState.php":3549039778,"\/ServiceContainer\/ScenarioStateExtension.php":1698856486,"\/Exception\/MissingStateException.php":1656618837}} \ No newline at end of file