Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 71b7087

Browse files
committed
Merge branch 'Luxor-master'
2 parents 37cdab1 + 9b80957 commit 71b7087

File tree

11 files changed

+300
-28
lines changed

11 files changed

+300
-28
lines changed

History.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [1.1.9-SNAPSHOT (Git master)](https://github.com/cucumber/cucumber-jvm/compare/v1.1.8...master) (Not released)
2+
3+
* [Groovy] Support more then one `World {}` definition ([#716](https://github.com/cucumber/cucumber-jvm/pull/716) Anton)
4+
15
## [1.1.8](https://github.com/cucumber/cucumber-jvm/compare/v1.1.7...v1.1.8) (2014-06-26)
26

37
* [JUnit] Let JUnitReporter fire event(s) on the step notifier for every step ([#656](https://github.com/cucumber/cucumber-jvm/pull/656) Björn Rasmusson)

android/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.1.7" package="cucumber.api.android">
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.1.8" package="cucumber.api.android">
33
</manifest>

groovy/src/main/java/cucumber/runtime/groovy/GroovyBackend.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package cucumber.runtime.groovy;
22

33
import cucumber.runtime.Backend;
4+
import cucumber.runtime.ClassFinder;
45
import cucumber.runtime.CucumberException;
56
import cucumber.runtime.Glue;
67
import cucumber.runtime.UnreportedStepExecutor;
7-
import cucumber.runtime.ClassFinder;
88
import cucumber.runtime.io.Resource;
99
import cucumber.runtime.io.ResourceLoader;
1010
import cucumber.runtime.io.ResourceLoaderClassFinder;
@@ -22,7 +22,9 @@
2222

2323
import java.io.IOException;
2424
import java.io.InputStreamReader;
25+
import java.util.Collection;
2526
import java.util.HashSet;
27+
import java.util.LinkedList;
2628
import java.util.List;
2729
import java.util.Set;
2830
import java.util.regex.Pattern;
@@ -37,8 +39,8 @@ public class GroovyBackend implements Backend {
3739
private final GroovyShell shell;
3840
private final ClassFinder classFinder;
3941

40-
private Closure worldClosure;
41-
private Object world;
42+
private Collection<Closure> worldClosures = new LinkedList<Closure>();
43+
private GroovyWorld world;
4244
private Glue glue;
4345

4446
public static GroovyBackend getInstance(){
@@ -102,7 +104,10 @@ public void setUnreportedStepExecutor(UnreportedStepExecutor executor) {
102104

103105
@Override
104106
public void buildWorld() {
105-
world = worldClosure == null ? new Object() : worldClosure.call();
107+
world = new GroovyWorld();
108+
for (Closure closure : worldClosures) {
109+
world.registerWorld(closure.call());
110+
}
106111
}
107112

108113
private Script parse(Resource resource) {
@@ -132,8 +137,7 @@ public void addStepDefinition(Pattern regexp, long timeoutMillis, Closure body)
132137
}
133138

134139
public void registerWorld(Closure closure) {
135-
if (worldClosure != null) throw new CucumberException("World is already set");
136-
worldClosure = closure;
140+
worldClosures.add(closure);
137141
}
138142

139143
public void addBeforeHook(TagExpression tagExpression, long timeoutMillis, Closure body) {
@@ -145,6 +149,7 @@ public void addAfterHook(TagExpression tagExpression, long timeoutMillis, Closur
145149
}
146150

147151
public void invoke(Closure body, Object[] args) throws Throwable {
152+
body.setResolveStrategy(Closure.DELEGATE_FIRST);
148153
body.setDelegate(world);
149154
try {
150155
body.call(args);
@@ -153,6 +158,10 @@ public void invoke(Closure body, Object[] args) throws Throwable {
153158
}
154159
}
155160

161+
GroovyWorld getGroovyWorld() {
162+
return world;
163+
}
164+
156165
private static StackTraceElement currentLocation() {
157166
Throwable t = new Throwable();
158167
StackTraceElement[] stackTraceElements = t.getStackTrace();
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package cucumber.runtime.groovy;
2+
3+
import groovy.lang.GroovyObject;
4+
import groovy.lang.GroovyObjectSupport;
5+
import groovy.lang.MissingMethodException;
6+
import groovy.lang.MissingPropertyException;
7+
import groovy.lang.Tuple;
8+
import org.codehaus.groovy.runtime.MetaClassHelper;
9+
10+
import java.util.LinkedList;
11+
import java.util.List;
12+
13+
class GroovyWorld extends GroovyObjectSupport {
14+
private final List<GroovyObject> worlds;
15+
16+
public GroovyWorld() {
17+
super();
18+
worlds = new LinkedList<GroovyObject>();
19+
}
20+
21+
public void registerWorld(Object world) {
22+
if (world instanceof GroovyObject) {
23+
worlds.add((GroovyObject) world);
24+
} else {
25+
throw new RuntimeException("Only GroovyObject supported");
26+
}
27+
}
28+
29+
public Object getProperty(String property) {
30+
return findWorldWithProperty(property).getProperty(property);
31+
}
32+
33+
public void setProperty(String property, Object newValue) {
34+
findWorldWithProperty(property).setProperty(property, newValue);
35+
}
36+
37+
public Object invokeMethod(String name, Object args) {
38+
return findWorldWithMethod(name, args).invokeMethod(name, args);
39+
}
40+
41+
int worldsCount() {
42+
return worlds.size();
43+
}
44+
45+
private GroovyObject findWorldWithProperty(String property) {
46+
if (worlds.isEmpty()) {
47+
throw new MissingPropertyException(property, GroovyWorld.class);
48+
}
49+
50+
if (worlds.size() == 1) {
51+
return worlds.get(0);
52+
}
53+
54+
GroovyObject worldWithProperty = null;
55+
56+
for (GroovyObject world : worlds) {
57+
if (world.getMetaClass().hasProperty(this, property) != null) {
58+
if (worldWithProperty == null) {
59+
worldWithProperty = world;
60+
} else {
61+
throw new RuntimeException("Multiple property call: " + property);
62+
}
63+
}
64+
}
65+
66+
if (worldWithProperty == null) {
67+
throw new MissingPropertyException(property, GroovyWorld.class);
68+
}
69+
70+
return worldWithProperty;
71+
}
72+
73+
private GroovyObject findWorldWithMethod(String methodName, Object arguments) {
74+
Object[] args = unwrapMethodArguments(arguments);
75+
76+
if (worlds.isEmpty()) {
77+
throw new MissingMethodException(methodName, this.getClass(), args);
78+
}
79+
if (worlds.size() == 1) {
80+
return worlds.get(0);
81+
}
82+
83+
GroovyObject worldWithMethod = null;
84+
for (GroovyObject world : worlds) {
85+
if (world.getMetaClass().getMetaMethod(methodName, args) != null) {
86+
if (worldWithMethod == null) {
87+
worldWithMethod = world;
88+
} else {
89+
throw new RuntimeException("Multiple method call: " + methodName);
90+
}
91+
}
92+
}
93+
if (worldWithMethod == null) {
94+
throw new MissingMethodException(methodName, this.getClass(), args);
95+
}
96+
return worldWithMethod;
97+
}
98+
99+
private Object[] unwrapMethodArguments(Object arguments) {
100+
if (arguments == null) {
101+
return MetaClassHelper.EMPTY_ARRAY;
102+
}
103+
if (arguments instanceof Tuple) {
104+
Tuple tuple = (Tuple) arguments;
105+
return tuple.toArray();
106+
}
107+
if (arguments instanceof Object[]) {
108+
return (Object[]) arguments;
109+
} else {
110+
return new Object[]{arguments};
111+
}
112+
}
113+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package cucumber.runtime.groovy
2+
3+
class AnotherCustomWorld {
4+
def aProperty
5+
def methodArgs
6+
7+
def aMethod() {
8+
methodArgs = "no args"
9+
}
10+
11+
def aMethod(List<Integer> args) {
12+
methodArgs = args
13+
}
14+
15+
def getPropertyValue() {
16+
aProperty
17+
}
18+
19+
20+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package cucumber.runtime.groovy
2+
3+
class WorldWithPropertyAndMethod {
4+
def aProperty
5+
void aMethod(List<Integer> args) {}
6+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package cucumber.runtime.groovy
2+
3+
this.metaClass.mixin(cucumber.api.groovy.EN)
4+
this.metaClass.mixin(cucumber.api.groovy.Hooks)
5+
6+
def topLevelValueWrite = 100
7+
def topLevelValueRead = "TOP"
8+
9+
10+
World {
11+
new AnotherCustomWorld()
12+
}
13+
14+
When(~/^set world property "(\w+)"$/) { p ->
15+
aProperty = p
16+
topLevelValueWrite = p
17+
}
18+
19+
Then(~/^properties visibility is ok$/) { ->
20+
assert topLevelValueWrite && topLevelValueWrite != 100
21+
assert topLevelValueRead == "TOP"
22+
}
23+
24+
Then(~/^world property is "(\w+)"$/) { p ->
25+
assert aProperty == p
26+
assert propertyValue == p
27+
assert topLevelValueWrite == p
28+
}
29+
30+
When(~/^world method call$/) { ->
31+
aMethod()
32+
}
33+
34+
When(~/^world method call:$/) { table ->
35+
aMethod(table.asList(Integer))
36+
}
37+
38+
Then(~/^world method call is:$/) { table ->
39+
methodArgs == table.asList(Integer)
40+
}
41+
42+
43+
Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
package cucumber.runtime.groovy;
22

3-
import cucumber.runtime.CucumberException;
43
import cucumber.runtime.io.ResourceLoader;
5-
import groovy.lang.Closure;
4+
import org.codehaus.groovy.runtime.MethodClosure;
65
import org.junit.Before;
76
import org.junit.Test;
87
import org.junit.runner.RunWith;
98
import org.mockito.Mock;
109
import org.mockito.runners.MockitoJUnitRunner;
1110

12-
import static org.mockito.Mockito.verify;
13-
11+
import static junit.framework.Assert.assertEquals;
12+
import static junit.framework.Assert.assertNull;
1413

1514
@RunWith(MockitoJUnitRunner.class)
1615
public class GroovyBackendTest {
1716
@Mock
1817
ResourceLoader resourceLoader;
19-
@Mock
20-
Closure closure;
2118

2219
GroovyBackend backend;
2320

@@ -27,21 +24,35 @@ public void setUp() throws Exception {
2724
}
2825

2926
@Test
30-
public void builds_world_by_calling_closure() {
31-
backend.registerWorld(closure);
27+
public void should_build_world_by_calling_the_closure() {
28+
backend.registerWorld(new MethodClosure(this, "worldClosureCall"));
29+
backend.buildWorld();
30+
31+
GroovyWorld groovyWorld = backend.getGroovyWorld();
32+
assertEquals(1, groovyWorld.worldsCount());
33+
}
34+
35+
@Test
36+
public void should_build_world_object_even_if_closure_world_was_not_added() {
37+
assertNull(backend.getGroovyWorld());
38+
3239
backend.buildWorld();
3340

34-
verify(closure).call();
41+
assertEquals(0, backend.getGroovyWorld().worldsCount());
3542
}
3643

3744
@Test
38-
public void builds_default_wold_if_wold_closer_does_not_set() {
45+
public void should_clean_up_worlds_after_dispose() {
46+
backend.registerWorld(new MethodClosure(this, "worldClosureCall"));
3947
backend.buildWorld();
48+
49+
backend.disposeWorld();
50+
51+
assertNull(backend.getGroovyWorld());
4052
}
4153

42-
@Test(expected = CucumberException.class)
43-
public void raises_exception_for_two_wolds() {
44-
backend.registerWorld(closure);
45-
backend.registerWorld(closure);
54+
@SuppressWarnings("UnusedDeclaration")
55+
private AnotherCustomWorld worldClosureCall() {
56+
return new AnotherCustomWorld();
4657
}
4758
}

0 commit comments

Comments
 (0)