diff --git a/cucumber-tck b/cucumber-tck index 0f42d85e17..1288b20f46 160000 --- a/cucumber-tck +++ b/cucumber-tck @@ -1 +1 @@ -Subproject commit 0f42d85e17c1bbfa6da76960fc40985db69e49bd +Subproject commit 1288b20f464881e6428854cee6145e774b65248e diff --git a/jython/src/main/java/cucumber/runtime/jython/JythonBackend.java b/jython/src/main/java/cucumber/runtime/jython/JythonBackend.java index 19b2cc8e1f..ed90a98a48 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.PyException; @@ -78,7 +75,22 @@ 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) throws Throwable { + PyObject[] pyArgs = new PyObject[args.length + 1]; pyArgs[0] = pyWorld; for (int i = 0; i < args.length; i++) { 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..64ac9cc49a --- /dev/null +++ b/jython/src/main/java/cucumber/runtime/jython/JythonHookDefinition.java @@ -0,0 +1,42 @@ +package cucumber.runtime.jython; + +import cucumber.runtime.HookDefinition; +import cucumber.runtime.ScenarioResult; +import gherkin.TagExpression; +import gherkin.formatter.model.Tag; +import org.python.core.*; +import java.util.Collection; +import java.util.List; + +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 String getLocation(boolean detail) { + return null; + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/jython/src/main/java/cucumber/runtime/jython/JythonStepDefinition.java b/jython/src/main/java/cucumber/runtime/jython/JythonStepDefinition.java index a2f11c8394..c31f733558 100644 --- a/jython/src/main/java/cucumber/runtime/jython/JythonStepDefinition.java +++ b/jython/src/main/java/cucumber/runtime/jython/JythonStepDefinition.java @@ -64,4 +64,4 @@ public boolean isDefinedAt(StackTraceElement stackTraceElement) { public String getPattern() { return stepdef.invoke("pattern").toString(); } -} +} \ No newline at end of file diff --git a/jython/src/main/resources/cucumber/runtime/jython/dsl.py b/jython/src/main/resources/cucumber/runtime/jython/dsl.py index 2e466d4e1d..5d35a24ed8 100644 --- a/jython/src/main/resources/cucumber/runtime/jython/dsl.py +++ b/jython/src/main/resources/cucumber/runtime/jython/dsl.py @@ -40,3 +40,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)) 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))) + +