Skip to content

Commit 0d63c1f

Browse files
committed
Workaround for arity mismatch on Groovy. Need an explicitly empty list of closure parameters. Closes #297.
1 parent 01932dc commit 0d63c1f

File tree

10 files changed

+94
-59
lines changed

10 files changed

+94
-59
lines changed

History.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## [Git master](https://github.com/cucumber/cucumber-jvm/compare/v1.0.1...master)
22

3+
* [Groovy] Arity mismatch can be avoided by explicitly declaring an empty list of closure parameters. ([#297](https://github.com/cucumber/cucumber-jvm/issues/297) Aslak Hellesøy)
34
* [Core] Added DataTable.toTable(List<?> other) for creating a new table. Handy for printing a table when diffing isn't helpful. (Aslak Hellesøy)
45

56
## [1.0.2](https://github.com/cucumber/cucumber-jvm/compare/v1.0.1...v1.0.2)

core/src/main/java/cucumber/runtime/StepDefinitionMatch.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ private Object[] transformedArgs(List<ParameterType> parameterTypes, Step step,
6565
if (step.getRows() != null) argumentCount++;
6666
if (parameterTypes != null) {
6767
if (parameterTypes.size() != argumentCount) {
68-
List<Argument> arguments = createArgumentsForErrorMessage(step);
69-
throw new CucumberException("Arity mismatch. Declared parameters: " + parameterTypes + ". Matched arguments: " + arguments);
68+
throw arityMismatch(parameterTypes, step);
7069
}
7170
} else {
7271
// Some backends, like ClojureBackend, don't know the arity and therefore pass in null.
@@ -116,6 +115,21 @@ private Object[] transformedArgs(List<ParameterType> parameterTypes, Step step,
116115
return result;
117116
}
118117

118+
private CucumberException arityMismatch(List<ParameterType> parameterTypes, Step step) {
119+
List<Argument> arguments = createArgumentsForErrorMessage(step);
120+
return new CucumberException(String.format(
121+
"Arity mismatch: Step Definition '%s' with pattern /%s/ is declared with %s parameters%s. However, the gherkin step matched %s arguments%s. \nStep: %s%s",
122+
stepDefinition.getLocation(),
123+
stepDefinition.getPattern(),
124+
parameterTypes.size(),
125+
parameterTypes.isEmpty() ? "" : " " + parameterTypes.toString(),
126+
arguments.size(),
127+
arguments.isEmpty() ? "" : " " + arguments.toString(),
128+
step.getKeyword(),
129+
step.getName()
130+
));
131+
}
132+
119133
private List<Argument> createArgumentsForErrorMessage(Step step) {
120134
List<Argument> arguments = new ArrayList<Argument>(getArguments());
121135
if (step.getDocString() != null) {

core/src/test/java/cucumber/runtime/StepDefinitionMatchTest.java

+13-14
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import cucumber.runtime.converters.LocalizedXStreams;
44
import gherkin.I18n;
55
import gherkin.formatter.Argument;
6-
import gherkin.formatter.Reporter;
76
import gherkin.formatter.model.DocString;
87
import gherkin.formatter.model.Step;
98
import org.junit.Test;
@@ -14,6 +13,7 @@
1413

1514
import static java.util.Arrays.asList;
1615
import static org.junit.Assert.assertEquals;
16+
import static org.junit.Assert.fail;
1717
import static org.mockito.Mockito.mock;
1818
import static org.mockito.Mockito.verify;
1919
import static org.mockito.Mockito.when;
@@ -25,7 +25,6 @@ public class StepDefinitionMatchTest {
2525
@Test
2626
public void converts_numbers() throws Throwable {
2727
StepDefinition stepDefinition = mock(StepDefinition.class);
28-
Reporter reporter = mock(Reporter.class);
2928
List<ParameterType> parameterTypes = asList(new ParameterType(Integer.TYPE, null));
3029
when(stepDefinition.getParameterTypes()).thenReturn(parameterTypes);
3130

@@ -41,7 +40,6 @@ public void converts_numbers() throws Throwable {
4140
@Test
4241
public void can_have_doc_string_as_only_argument() throws Throwable {
4342
StepDefinition stepDefinition = mock(StepDefinition.class);
44-
Reporter reporter = mock(Reporter.class);
4543
List<ParameterType> parameterTypes = asList(new ParameterType(String.class, null));
4644
when(stepDefinition.getParameterTypes()).thenReturn(parameterTypes);
4745

@@ -58,7 +56,6 @@ public void can_have_doc_string_as_only_argument() throws Throwable {
5856
@Test
5957
public void can_have_doc_string_as_last_argument_among_many() throws Throwable {
6058
StepDefinition stepDefinition = mock(StepDefinition.class);
61-
Reporter reporter = mock(Reporter.class);
6259
List<ParameterType> parameterTypes = asList(new ParameterType(Integer.TYPE, null), new ParameterType(String.class, null));
6360
when(stepDefinition.getParameterTypes()).thenReturn(parameterTypes);
6461

@@ -73,15 +70,17 @@ public void can_have_doc_string_as_last_argument_among_many() throws Throwable {
7370
}
7471

7572
@Test
76-
public void retrieve_step_name() {
77-
String theName = "name";
78-
79-
Step step = mock(Step.class);
80-
when(step.getName()).thenReturn(theName);
81-
82-
StepDefinitionMatch stepDefinitionMatch = new StepDefinitionMatch(null, mock(StepDefinition.class), null, step, null);
83-
84-
String stepName = stepDefinitionMatch.getStepName();
85-
assertEquals(theName, stepName);
73+
public void throws_arity_mismatch_exception() throws Throwable {
74+
Step step = new Step(null, "Given ", "I have 4 cukes in my belly", 1, null, null);
75+
76+
StepDefinition stepDefinition = new StubStepDefinition(new Object(), Object.class.getMethod("toString"), "some pattern");
77+
StepDefinitionMatch stepDefinitionMatch = new StepDefinitionMatch(asList(new Argument(7, "3")), stepDefinition, null, step, new LocalizedXStreams(getClass().getClassLoader()));
78+
try {
79+
stepDefinitionMatch.runStep(new I18n("en"));
80+
fail();
81+
} catch(CucumberException expected) {
82+
assertEquals("Arity mismatch: Step Definition 'toString' with pattern /some pattern/ is declared with 0 parameters. However, the gherkin step matched 1 arguments [3]. \n" +
83+
"Step: Given I have 4 cukes in my belly", expected.getMessage());
84+
}
8685
}
8786
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package cucumber.runtime;
2+
3+
import gherkin.I18n;
4+
import gherkin.formatter.Argument;
5+
import gherkin.formatter.model.Step;
6+
7+
import java.lang.reflect.Method;
8+
import java.util.List;
9+
10+
public class StubStepDefinition implements StepDefinition {
11+
private final Object target;
12+
private final Method method;
13+
private final String pattern;
14+
15+
public StubStepDefinition(Object target, Method method, String pattern) {
16+
this.target = target;
17+
this.method = method;
18+
this.pattern = pattern;
19+
}
20+
21+
@Override
22+
public List<Argument> matchedArguments(Step step) {
23+
throw new UnsupportedOperationException();
24+
}
25+
26+
@Override
27+
public String getLocation() {
28+
return method.getName();
29+
}
30+
31+
@Override
32+
public List<ParameterType> getParameterTypes() {
33+
return ParameterType.fromMethod(method);
34+
}
35+
36+
@Override
37+
public void execute(I18n i18n, Object[] args) throws Throwable {
38+
method.invoke(target, args);
39+
}
40+
41+
@Override
42+
public boolean isDefinedAt(StackTraceElement stackTraceElement) {
43+
return false;
44+
}
45+
46+
@Override
47+
public String getPattern() {
48+
return pattern;
49+
}
50+
}

core/src/test/java/cucumber/table/FromDataTableTest.java

+2-41
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
1010
import cucumber.DateFormat;
1111
import cucumber.runtime.CucumberException;
12-
import cucumber.runtime.ParameterType;
1312
import cucumber.runtime.StepDefinition;
1413
import cucumber.runtime.StepDefinitionMatch;
14+
import cucumber.runtime.StubStepDefinition;
1515
import cucumber.runtime.converters.LocalizedXStreams;
1616
import gherkin.I18n;
1717
import gherkin.formatter.Argument;
@@ -171,7 +171,7 @@ public void does_not_transform_to_list_of_non_generic_map() throws Throwable {
171171

172172
private StepDefs runStepDef(Method method, List<DataTableRow> rows) throws Throwable {
173173
StepDefs stepDefs = new StepDefs();
174-
StepDefinition stepDefinition = new DirectStepDef(stepDefs, method);
174+
StepDefinition stepDefinition = new StubStepDefinition(stepDefs, method, "some pattern");
175175

176176
Step stepWithRows = new Step(NO_COMMENTS, "Given ", "something", 10, rows, null);
177177

@@ -276,43 +276,4 @@ public boolean canConvert(Class type) {
276276
}
277277
}
278278

279-
private class DirectStepDef implements StepDefinition {
280-
private final Object target;
281-
private final Method method;
282-
283-
public DirectStepDef(Object target, Method method) {
284-
this.target = target;
285-
this.method = method;
286-
}
287-
288-
@Override
289-
public List<Argument> matchedArguments(Step step) {
290-
throw new UnsupportedOperationException();
291-
}
292-
293-
@Override
294-
public String getLocation() {
295-
return getClass().getName();
296-
}
297-
298-
@Override
299-
public List<ParameterType> getParameterTypes() {
300-
return ParameterType.fromMethod(method);
301-
}
302-
303-
@Override
304-
public void execute(I18n i18n, Object[] args) throws Throwable {
305-
method.invoke(target, args);
306-
}
307-
308-
@Override
309-
public boolean isDefinedAt(StackTraceElement stackTraceElement) {
310-
return false;
311-
}
312-
313-
@Override
314-
public String getPattern() {
315-
throw new UnsupportedOperationException();
316-
}
317-
}
318279
}

groovy/src/test/groovy/cucumber/runtime/groovy/compiled_stepdefs.groovy

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Given(~'^I have (\\d+) apples in my belly') { int apples ->
1313
lastAte('apples')
1414
}
1515

16-
Given(~'^a big basket with cukes') {->
16+
Given(~'^a big basket with cukes') { ->
1717
}
1818

1919
Given(~'^the following table:$') { table ->

groovy/src/test/java/cucumber/runtime/groovy/RunCukesTest.java

+1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
import org.junit.runner.RunWith;
55

66
@RunWith(Cucumber.class)
7+
@Cucumber.Options(tags="@focus")
78
public class RunCukesTest {
89
}

groovy/src/test/resources/cucumber/runtime/groovy/a_feature.feature

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ Feature: Cucumber Runner Rocks
1616
| 13 | cukes | happy |
1717
| 4 | apples | tired |
1818

19-
@focus
2019
Scenario: a table
2120
Given the following table:
2221
| year | name |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@focus
2+
Feature: Issue 297
3+
Scenario: Carbon Coder executes unsuccessfully
4+
Given Carbon Coder is running correctly
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package cucumber.runtime.groovy
2+
this.metaClass.mixin(cucumber.runtime.groovy.EN)
3+
4+
// Step definitions without parameters must explicitly define an empty list of parameters.
5+
Given(~"Carbon Coder is running correctly\$") { ->
6+
}

0 commit comments

Comments
 (0)