Skip to content

Commit

Permalink
Fix tagged hooks for scenario outlines. Closes cucumber#209, closes c…
Browse files Browse the repository at this point in the history
  • Loading branch information
aslakhellesoy committed Feb 19, 2012
1 parent 91e6032 commit 45d06e2
Show file tree
Hide file tree
Showing 27 changed files with 115 additions and 63 deletions.
Expand Up @@ -5,6 +5,7 @@
import cucumber.runtime.ScenarioResult;
import cucumber.runtime.Utils;
import gherkin.TagExpression;
import gherkin.formatter.model.Tag;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -42,7 +43,7 @@ public void execute(ScenarioResult scenarioResult) throws Throwable {
}

@Override
public boolean matches(Collection<String> tags) {
public boolean matches(Collection<Tag> tags) {
return tagExpression.eval(tags);
}

Expand Down
Expand Up @@ -14,7 +14,7 @@
public class FormatterFactory {

private final ClassLoader classLoader;

private static final Map<String, String> BUILTIN_FORMATTERS = new HashMap<String, String>() {{
put("progress", ProgressFormatter.class.getName());
put("html", HTMLFormatter.class.getName());
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/cucumber/runtime/FeatureBuilder.java
Expand Up @@ -103,7 +103,7 @@ public void parse(Resource resource, List<Object> filters) {

String checksum = checksum(gherkin);
String path = pathsByChecksum.get(checksum);
if(path != null) {
if (path != null) {
throw new CucumberException(String.format("Found the same source in %s and %s", path, resource.getPath()));
}
pathsByChecksum.put(checksum, resource.getPath());
Expand Down
1 change: 0 additions & 1 deletion core/src/main/java/cucumber/runtime/Glue.java
Expand Up @@ -6,7 +6,6 @@
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Locale;


//TODO: now that this is just basically a java bean storing values
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/cucumber/runtime/HookDefinition.java
@@ -1,11 +1,13 @@
package cucumber.runtime;

import gherkin.formatter.model.Tag;

import java.util.Collection;

public interface HookDefinition {
void execute(ScenarioResult scenarioResult) throws Throwable;

boolean matches(Collection<String> tags);
boolean matches(Collection<Tag> tags);

int getOrder();
}
11 changes: 6 additions & 5 deletions core/src/main/java/cucumber/runtime/Runtime.java
Expand Up @@ -14,6 +14,7 @@
import gherkin.formatter.model.Match;
import gherkin.formatter.model.Result;
import gherkin.formatter.model.Step;
import gherkin.formatter.model.Tag;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -148,21 +149,21 @@ public Glue getGlue() {
return glue;
}

public void runBeforeHooks(Reporter reporter, Set<String> tags) {
public void runBeforeHooks(Reporter reporter, Set<Tag> tags) {
runHooks(glue.getBeforeHooks(), reporter, tags);
}

public void runAfterHooks(Reporter reporter, Set<String> tags) {
public void runAfterHooks(Reporter reporter, Set<Tag> tags) {
runHooks(glue.getAfterHooks(), reporter, tags);
}

private void runHooks(List<HookDefinition> hooks, Reporter reporter, Set<String> tags) {
private void runHooks(List<HookDefinition> hooks, Reporter reporter, Set<Tag> tags) {
for (HookDefinition hook : hooks) {
runHookIfTagsMatch(hook, reporter, tags);
}
}

private void runHookIfTagsMatch(HookDefinition hook, Reporter reporter, Set<String> tags) {
private void runHookIfTagsMatch(HookDefinition hook, Reporter reporter, Set<Tag> tags) {
if (hook.matches(tags)) {
long start = System.nanoTime();
try {
Expand Down Expand Up @@ -200,7 +201,7 @@ public void runUnreportedStep(String uri, I18n i18n, String stepKeyword, String
}

public void runStep(String uri, Step step, Reporter reporter, I18n i18n) {
StepDefinitionMatch match = null;
StepDefinitionMatch match;

try {
match = glue.stepDefinitionMatch(uri, step, i18n);
Expand Down
@@ -1,12 +1,10 @@
package cucumber.runtime;

import cucumber.table.DataTable;
import gherkin.I18n;
import gherkin.formatter.model.DataTableRow;
import gherkin.formatter.model.DocString;

import java.util.List;
import java.util.Locale;

public interface UnreportedStepExecutor {
//TODO: Maybe this should go into the cucumber step execution model and it should return the result of that execution!
Expand Down
13 changes: 12 additions & 1 deletion core/src/main/java/cucumber/runtime/model/CucumberExamples.java
Expand Up @@ -3,9 +3,12 @@
import gherkin.formatter.Formatter;
import gherkin.formatter.model.Examples;
import gherkin.formatter.model.ExamplesTableRow;
import gherkin.formatter.model.Tag;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class CucumberExamples {
private final CucumberScenarioOutline cucumberScenarioOutline;
Expand All @@ -20,12 +23,20 @@ public List<CucumberScenario> createExampleScenarios() {
List<CucumberScenario> exampleScenarios = new ArrayList<CucumberScenario>();

List<ExamplesTableRow> rows = examples.getRows();
List<Tag> tags = new ArrayList<Tag>(tagsAndInheritedTags());
for (int i = 1; i < rows.size(); i++) {
exampleScenarios.add(cucumberScenarioOutline.createExampleScenario(rows.get(0), rows.get(i), examples.getTags()));
exampleScenarios.add(cucumberScenarioOutline.createExampleScenario(rows.get(0), rows.get(i), tags));
}
return exampleScenarios;
}

private Set<Tag> tagsAndInheritedTags() {
Set<Tag> tags = new HashSet<Tag>();
tags.addAll(cucumberScenarioOutline.tagsAndInheritedTags());
tags.addAll(examples.getTags());
return tags;
}

public Examples getExamples() {
return examples;
}
Expand Down
Expand Up @@ -33,7 +33,7 @@ public static List<CucumberFeature> load(ResourceLoader resourceLoader, List<Str
builder.parse(resource, filters);
}
}
if(cucumberFeatures.isEmpty()) {
if (cucumberFeatures.isEmpty()) {
throw new CucumberException(String.format("No features found at %s", featurePaths));
}
return cucumberFeatures;
Expand Down
Expand Up @@ -25,13 +25,13 @@ public CucumberScenario(CucumberFeature cucumberFeature, CucumberBackground cucu
@Override
public void run(Formatter formatter, Reporter reporter, Runtime runtime) {
runtime.buildBackendWorlds();
runtime.runBeforeHooks(reporter, tags());
runtime.runBeforeHooks(reporter, tagsAndInheritedTags());

runBackground(formatter, reporter, runtime);
format(formatter);
runSteps(reporter, runtime);

runtime.runAfterHooks(reporter, tags());
runtime.runAfterHooks(reporter, tagsAndInheritedTags());
runtime.disposeBackendWorlds();
}

Expand Down
Expand Up @@ -47,8 +47,8 @@ public void run(Formatter formatter, Reporter reporter, Runtime runtime) {
}
}

CucumberScenario createExampleScenario(ExamplesTableRow header, ExamplesTableRow example, List<Tag> tags) {
Scenario exampleScenario = new Scenario(example.getComments(), tags, tagStatement.getKeyword(), tagStatement.getName(), "", example.getLine(), example.getId());
CucumberScenario createExampleScenario(ExamplesTableRow header, ExamplesTableRow example, List<Tag> examplesTags) {
Scenario exampleScenario = new Scenario(example.getComments(), examplesTags, tagStatement.getKeyword(), tagStatement.getName(), "", example.getLine(), example.getId());
CucumberScenario cucumberScenario = new CucumberScenario(cucumberFeature, cucumberBackground, exampleScenario, example);
for (Step step : getSteps()) {
cucumberScenario.step(createExampleStep(step, header, example));
Expand Down
Expand Up @@ -28,14 +28,10 @@ public CucumberTagStatement(CucumberFeature cucumberFeature, TagStatement tagSta
this.visualName = "| " + join(example.getCells(), " | ") + " |";
}

protected Set<String> tags() {
Set<String> tags = new HashSet<String>();
for (Tag tag : cucumberFeature.getFeature().getTags()) {
tags.add(tag.getName());
}
for (Tag tag : tagStatement.getTags()) {
tags.add(tag.getName());
}
protected Set<Tag> tagsAndInheritedTags() {
Set<Tag> tags = new HashSet<Tag>();
tags.addAll(cucumberFeature.getFeature().getTags());
tags.addAll(tagStatement.getTags());
return tags;
}

Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/cucumber/runtime/model/StepContainer.java
Expand Up @@ -11,12 +11,12 @@

public class StepContainer {
private final List<Step> steps = new ArrayList<Step>();
private final BasicStatement statement;
protected final CucumberFeature cucumberFeature;
private final BasicStatement statement;

public StepContainer(CucumberFeature cucumberFeature, BasicStatement statement) {
this.statement = statement;
this.cucumberFeature = cucumberFeature;
this.statement = statement;
}

public List<Step> getSteps() {
Expand Down
9 changes: 5 additions & 4 deletions core/src/test/java/cucumber/runtime/HookOrderTest.java
Expand Up @@ -2,6 +2,7 @@

import cucumber.io.ResourceLoader;
import gherkin.formatter.Reporter;
import gherkin.formatter.model.Tag;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InOrder;
Expand Down Expand Up @@ -37,7 +38,7 @@ public void before_hooks_execute_in_order() throws Throwable {
glue.addBeforeHook(hook);
}

runtime.runBeforeHooks(mock(Reporter.class), new HashSet<String>());
runtime.runBeforeHooks(mock(Reporter.class), new HashSet<Tag>());

InOrder inOrder = inOrder(hooks.toArray());
inOrder.verify(hooks.get(2)).execute(Matchers.<ScenarioResult>any());
Expand All @@ -52,7 +53,7 @@ public void after_hooks_execute_in_reverse_order() throws Throwable {
glue.addAfterHook(hook);
}

runtime.runAfterHooks(mock(Reporter.class), new HashSet<String>());
runtime.runAfterHooks(mock(Reporter.class), new HashSet<Tag>());

InOrder inOrder = inOrder(hooks.toArray());
inOrder.verify(hooks.get(1)).execute(Matchers.<ScenarioResult>any());
Expand All @@ -71,7 +72,7 @@ public void hooks_order_across_many_backends() throws Throwable {
glue.addBeforeHook(hook);
}

runtime.runBeforeHooks(mock(Reporter.class), new HashSet<String>());
runtime.runBeforeHooks(mock(Reporter.class), new HashSet<Tag>());

List<HookDefinition> allHooks = new ArrayList<HookDefinition>();
allHooks.addAll(backend1Hooks);
Expand All @@ -91,7 +92,7 @@ private List<HookDefinition> mockHooks(int... ordering) {
for (int order : ordering) {
HookDefinition hook = mock(HookDefinition.class, "Mock number " + order);
when(hook.getOrder()).thenReturn(order);
when(hook.matches(anyListOf(String.class))).thenReturn(true);
when(hook.matches(anyListOf(Tag.class))).thenReturn(true);
hooks.add(hook);
}
return hooks;
Expand Down
2 changes: 1 addition & 1 deletion core/src/test/java/cucumber/runtime/HookTest.java
Expand Up @@ -35,7 +35,7 @@ public class HookTest {
public void after_hooks_execute_before_objects_are_disposed() throws Throwable {
Backend backend = mock(Backend.class);
HookDefinition hook = mock(HookDefinition.class);
when(hook.matches(anyListOf(String.class))).thenReturn(true);
when(hook.matches(anyListOf(Tag.class))).thenReturn(true);
Scenario gherkinScenario = mock(Scenario.class);

CucumberFeature feature = mock(CucumberFeature.class);
Expand Down
Expand Up @@ -3,35 +3,46 @@
import gherkin.formatter.model.Comment;
import gherkin.formatter.model.Examples;
import gherkin.formatter.model.ExamplesTableRow;
import gherkin.formatter.model.Feature;
import gherkin.formatter.model.ScenarioOutline;
import gherkin.formatter.model.Step;
import gherkin.formatter.model.Tag;
import org.junit.Test;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.junit.Assert.assertEquals;

public class CucumberExamplesTest {
private static final List<Comment> COMMENTS = emptyList();
private static final List<Tag> TAGS = emptyList();
private static final List<Tag> FEATURE_TAGS = asList(new Tag("@feature", 1));
private static final List<Tag> SO_TAGS = asList(new Tag("@scenario_outline", 1));
private static final List<Tag> E_TAGS = asList(new Tag("@example", 1));

@Test
public void should_create_example_scenarios() {
ScenarioOutline so = new ScenarioOutline(COMMENTS, TAGS, "Scenario Outline", "", "", 1, "");
CucumberScenarioOutline cso = new CucumberScenarioOutline(null, null, so);
cso.step(new Step(COMMENTS, "Given ", "I have 5 <what> in my <where>", 2, null, null));
Examples examples = new Examples(COMMENTS, TAGS, "Examples", "", "", 3, "", asList(
new ExamplesTableRow(COMMENTS, asList("what", "where"), 4, ""),
new ExamplesTableRow(COMMENTS, asList("cukes", "belly"), 5, ""),
new ExamplesTableRow(COMMENTS, asList("apples", "basket"), 6, "")
CucumberFeature cucumberFeature = new CucumberFeature(new Feature(COMMENTS, FEATURE_TAGS, "Feature", "", "", 2, "fid"), "f.feature");
ScenarioOutline so = new ScenarioOutline(COMMENTS, SO_TAGS, "Scenario Outline", "", "", 4, "");
CucumberScenarioOutline cso = new CucumberScenarioOutline(cucumberFeature, null, so);
cso.step(new Step(COMMENTS, "Given ", "I have 5 <what> in my <where>", 5, null, null));
Examples examples = new Examples(COMMENTS, E_TAGS, "Examples", "", "", 6, "", asList(
new ExamplesTableRow(COMMENTS, asList("what", "where"), 7, ""),
new ExamplesTableRow(COMMENTS, asList("cukes", "belly"), 8, ""),
new ExamplesTableRow(COMMENTS, asList("apples", "basket"), 9, "")
));

CucumberExamples cucumberExamples = new CucumberExamples(cso, examples);
List<CucumberScenario> exampleScenarios = cucumberExamples.createExampleScenarios();
assertEquals(2, exampleScenarios.size());
Set<Tag> expectedTags = new HashSet<Tag>();
expectedTags.addAll(FEATURE_TAGS);
expectedTags.addAll(SO_TAGS);
expectedTags.addAll(E_TAGS);
assertEquals(expectedTags, exampleScenarios.get(0).tagsAndInheritedTags());

CucumberScenario cucumberScenario = exampleScenarios.get(0);
Step step = cucumberScenario.getSteps().get(0);
Expand Down
Expand Up @@ -3,6 +3,7 @@
import cucumber.runtime.HookDefinition;
import cucumber.runtime.ScenarioResult;
import gherkin.TagExpression;
import gherkin.formatter.model.Tag;
import groovy.lang.Closure;

import java.util.Collection;
Expand All @@ -24,7 +25,7 @@ public void execute(ScenarioResult scenarioResult) throws Throwable {
}

@Override
public boolean matches(Collection<String> tags) {
public boolean matches(Collection<Tag> tags) {
return tagExpression.eval(tags);
}

Expand Down
Expand Up @@ -4,6 +4,7 @@
import cucumber.runtime.HookDefinition;
import cucumber.runtime.ScenarioResult;
import gherkin.TagExpression;
import gherkin.formatter.model.Tag;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -53,7 +54,7 @@ public void execute(ScenarioResult scenarioResult) throws Throwable {
}

@Override
public boolean matches(Collection<String> tags) {
public boolean matches(Collection<Tag> tags) {
return tagExpression.eval(tags);
}

Expand Down
5 changes: 3 additions & 2 deletions java/src/test/java/cucumber/runtime/java/JavaHookTest.java
Expand Up @@ -8,6 +8,7 @@
import cucumber.runtime.RuntimeGlue;
import cucumber.runtime.UndefinedStepsTracker;
import cucumber.runtime.converters.LocalizedXStreams;
import gherkin.formatter.model.Tag;
import org.junit.Test;

import java.lang.reflect.Method;
Expand Down Expand Up @@ -80,15 +81,15 @@ public void matches_matching_tags() {
backend.buildWorld();
backend.addHook(BEFORE.getAnnotation(Before.class), HasHooks.class, BEFORE);
HookDefinition before = glue.getBeforeHooks().get(0);
assertTrue(before.matches(asList("@bar", "@zap")));
assertTrue(before.matches(asList(new Tag("@bar", 0), new Tag("@zap", 0))));
}

@Test
public void does_not_match_non_matching_tags() {
backend.buildWorld();
backend.addHook(BEFORE.getAnnotation(Before.class), HasHooks.class, BEFORE);
HookDefinition before = glue.getBeforeHooks().get(0);
assertFalse(before.matches(asList("@bar")));
assertFalse(before.matches(asList(new Tag("@bar", 0))));
}

public static class HasHooks {
Expand Down

0 comments on commit 45d06e2

Please sign in to comment.