From 9612724a7cfede4cc5ab52d1745f9c6430f0f050 Mon Sep 17 00:00:00 2001 From: Stephen Abrams Date: Thu, 19 Jul 2012 21:35:42 -0400 Subject: [PATCH] Add Before and After annotation support for Jython --- .../runtime/jython/JythonBackend.java | 19 +++++++--- .../runtime/jython/JythonHookDefinition.java | 35 +++++++++++++++++++ .../resources/cucumber/runtime/jython/dsl.py | 23 ++++++++++++ .../runtime/jython/annotated_cukes.feature | 9 +++++ .../jython/step_definitions/cuke_steps.py | 18 ++++++++++ 5 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 jython/src/main/java/cucumber/runtime/jython/JythonHookDefinition.java create mode 100644 jython/src/test/resources/cucumber/runtime/jython/annotated_cukes.feature diff --git a/jython/src/main/java/cucumber/runtime/jython/JythonBackend.java b/jython/src/main/java/cucumber/runtime/jython/JythonBackend.java index e78b280ab3..5e72b3c1c9 100644 --- a/jython/src/main/java/cucumber/runtime/jython/JythonBackend.java +++ b/jython/src/main/java/cucumber/runtime/jython/JythonBackend.java @@ -2,10 +2,7 @@ import cucumber.io.Resource; import cucumber.io.ResourceLoader; -import cucumber.runtime.Backend; -import cucumber.runtime.CucumberException; -import cucumber.runtime.Glue; -import cucumber.runtime.UnreportedStepExecutor; +import cucumber.runtime.*; import cucumber.runtime.snippets.SnippetGenerator; import gherkin.formatter.model.Step; import org.python.core.PyInstance; @@ -77,6 +74,20 @@ public void registerStepdef(PyInstance stepdef, int arity) { glue.addStepDefinition(new JythonStepDefinition(this, stepdef, arity)); } + public void addBeforeHook(PyInstance hookDefinition) { + glue.addBeforeHook(new JythonHookDefinition(this, hookDefinition)); + } + + public void addAfterHook(PyInstance hookDefinition) { + glue.addAfterHook(new JythonHookDefinition(this, hookDefinition)); + } + + public void executeHook(PyInstance hookDefinition, Object[] scenarioResults) { + PyObject[] pyArgs = new PyObject[1]; + pyArgs[0] = pyWorld; + hookDefinition.invoke("execute", pyArgs); + } + public void execute(PyInstance stepdef, Object[] args) { PyObject[] pyArgs = new PyObject[args.length + 1]; pyArgs[0] = pyWorld; diff --git a/jython/src/main/java/cucumber/runtime/jython/JythonHookDefinition.java b/jython/src/main/java/cucumber/runtime/jython/JythonHookDefinition.java new file mode 100644 index 0000000000..1b9e1b0ab8 --- /dev/null +++ b/jython/src/main/java/cucumber/runtime/jython/JythonHookDefinition.java @@ -0,0 +1,35 @@ +package cucumber.runtime.jython; + +import cucumber.runtime.HookDefinition; +import cucumber.runtime.ScenarioResult; +import gherkin.TagExpression; +import org.python.core.*; +import java.util.Collection; + +public class JythonHookDefinition implements HookDefinition { + private final PyInstance hookDefinition; + private final TagExpression tagExpression; + private final JythonBackend backend; + + public JythonHookDefinition(JythonBackend backend, PyInstance hookDefinition) { + this.backend = backend; + this.hookDefinition = hookDefinition; + PyTuple tags = (PyTuple)hookDefinition.__dict__.__finditem__("tags"); + this.tagExpression = new TagExpression(tags); + } + + @Override + public void execute(ScenarioResult scenarioResult) throws Throwable { + backend.executeHook(hookDefinition, new Object[]{scenarioResult}); + } + + @Override + public boolean matches(Collection tags) { + return tagExpression.eval(tags); + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/jython/src/main/resources/cucumber/runtime/jython/dsl.py b/jython/src/main/resources/cucumber/runtime/jython/dsl.py index 6238165347..796c5108df 100644 --- a/jython/src/main/resources/cucumber/runtime/jython/dsl.py +++ b/jython/src/main/resources/cucumber/runtime/jython/dsl.py @@ -38,3 +38,26 @@ def pattern(self): class World: """The World""" + +class HookDefinition: + + def __init__(self, tags, func): + self.tags = tags + self.func = func + + def execute(self, *args): + self.func.__call__(*args) + +class Before(): + def __init__(self, *tags): + self.tags = tags + + def __call__(self, func): + backend.addBeforeHook(HookDefinition(self.tags, func)) + +class After(): + def __init__(self, *tags): + self.tags = tags + + def __call__(self, func): + backend.addAfterHook(HookDefinition(self.tags, func)) \ No newline at end of file diff --git a/jython/src/test/resources/cucumber/runtime/jython/annotated_cukes.feature b/jython/src/test/resources/cucumber/runtime/jython/annotated_cukes.feature new file mode 100644 index 0000000000..aed1ef328b --- /dev/null +++ b/jython/src/test/resources/cucumber/runtime/jython/annotated_cukes.feature @@ -0,0 +1,9 @@ +Feature: Cukes + Scenario: default cukes in the belly from a tagless Before annotation + Given I have "5" cukes in my belly + + @must_have_more_cukes + @and_then_some + Scenario: more cukes in the belly from tagged and tagless Before annotations + Given I have "6" cukes in my belly + diff --git a/jython/src/test/resources/cucumber/runtime/jython/step_definitions/cuke_steps.py b/jython/src/test/resources/cucumber/runtime/jython/step_definitions/cuke_steps.py index a891077466..458ff38383 100644 --- a/jython/src/test/resources/cucumber/runtime/jython/step_definitions/cuke_steps.py +++ b/jython/src/test/resources/cucumber/runtime/jython/step_definitions/cuke_steps.py @@ -7,3 +7,21 @@ def something_in_the_belly(self, n, what): def i_am(self, mood): if ("happy" != mood): raise(Exception("Not happy, only %d %s" % (self.n, self.what))) + +@Before() +def default_cukes_in_the_belly(self): + self.n = 5 + self.what = "cukes" + +@Before('@must_have_more_cukes','@and_then_some') +def more_cukes_in_the_belly(self): + self.n = self.n + 1 + self.what = "cukes" + +@Given('^I have "([^"]*)" cukes in my belly$') +def I_have_cukes_in_my_belly(self, arg1): + val = int(arg1) + if (self.n != val): + raise(Exception("Default cukes were %d, not %d" % (self.n, val))) + +