Skip to content

Commit d237796

Browse files
committed
[Kotlin Java8] Support closures
The implementation of t he `ConstantPoolTypeIntrospector` did not fully support closures. Using a closure without scoped variables would result in a null pointer exception. E.g: ```java Given("^A statement with a body expression$") { assertTrue(true) } ``` This is resolved check if the member reference method equals the magic constant "INSTANCE" and return no type arguments. Related issues: - #1123 - #1126 This fixes #1123
1 parent 004e192 commit d237796

File tree

6 files changed

+199
-4
lines changed

6 files changed

+199
-4
lines changed

java8/src/main/java/cucumber/runtime/java8/ConstantPoolTypeIntrospector.java

+9
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ public Type[] getGenericTypes(Class<? extends StepdefBody> clazz, Class<? extend
3535
final String[] member = getMemberReference(constantPool);
3636
final int parameterCount = interfac3.getTypeParameters().length;
3737

38+
// Kotlin lambda expression without arguments or closure variables
39+
if (member[REFERENCE_METHOD].equals("INSTANCE")) {
40+
return handleKotlinInstance();
41+
}
42+
3843
final jdk.internal.org.objectweb.asm.Type[] argumentTypes = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(member[REFERENCE_ARGUMENT_TYPES]);
3944

4045
// If we are one parameter short, this is a
@@ -75,6 +80,10 @@ private static Type[] handleLambda(jdk.internal.org.objectweb.asm.Type[] argumen
7580
return typeArguments;
7681
}
7782

83+
private static Type[] handleKotlinInstance() {
84+
return new Type[0];
85+
}
86+
7887
private static String[] getMemberReference(ConstantPool constantPool) {
7988
int size = constantPool.getSize();
8089

kotlin-java8/pom.xml

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>io.cucumber</groupId>
8+
<artifactId>cucumber-jvm</artifactId>
9+
<relativePath>../pom.xml</relativePath>
10+
<version>2.0.0-SNAPSHOT</version>
11+
</parent>
12+
13+
<artifactId>cucumber-kotlin-java8</artifactId>
14+
<packaging>jar</packaging>
15+
<name>Cucumber-JVM: Kotlin Java8</name>
16+
17+
<properties>
18+
<kotlin.version>1.1.2-2</kotlin.version>
19+
</properties>
20+
21+
<dependencies>
22+
<dependency>
23+
<groupId>io.cucumber</groupId>
24+
<artifactId>cucumber-java8</artifactId>
25+
</dependency>
26+
<dependency>
27+
<groupId>io.cucumber</groupId>
28+
<artifactId>cucumber-junit</artifactId>
29+
<scope>test</scope>
30+
</dependency>
31+
<dependency>
32+
<groupId>junit</groupId>
33+
<artifactId>junit</artifactId>
34+
<scope>test</scope>
35+
</dependency>
36+
<dependency>
37+
<groupId>net.sourceforge.cobertura</groupId>
38+
<artifactId>cobertura</artifactId>
39+
<scope>test</scope>
40+
</dependency>
41+
42+
<dependency>
43+
<groupId>org.jetbrains.kotlin</groupId>
44+
<artifactId>kotlin-stdlib</artifactId>
45+
<version>${kotlin.version}</version>
46+
<scope>test</scope>
47+
</dependency>
48+
</dependencies>
49+
50+
<build>
51+
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
52+
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
53+
<plugins>
54+
<plugin>
55+
<artifactId>kotlin-maven-plugin</artifactId>
56+
<groupId>org.jetbrains.kotlin</groupId>
57+
<version>${kotlin.version}</version>
58+
59+
<executions>
60+
<execution>
61+
<id>compile</id>
62+
<goals>
63+
<goal>compile</goal>
64+
</goals>
65+
</execution>
66+
67+
<execution>
68+
<id>test-compile</id>
69+
<goals>
70+
<goal>test-compile</goal>
71+
</goals>
72+
</execution>
73+
</executions>
74+
</plugin>
75+
</plugins>
76+
</build>
77+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package cucumber.runtime.kotlin.test;
2+
3+
import cucumber.api.DataTable
4+
import cucumber.api.Scenario
5+
import cucumber.api.java8.En
6+
import org.junit.Assert.*
7+
8+
var lastInstance : LambdaStepdefs? = null
9+
10+
class LambdaStepdefs : En {
11+
12+
init {
13+
Before { scenario: Scenario ->
14+
assertNotSame(this, lastInstance)
15+
lastInstance = this
16+
}
17+
18+
Given("^this data table:$") { peopleTable: DataTable ->
19+
val people = peopleTable.asList(Person::class.java)
20+
assertEquals("Aslak", people[0].first)
21+
assertEquals("Hellesøy", people[0].last)
22+
}
23+
24+
val alreadyHadThisManyCukes = 1
25+
Given("^I have (\\d+) cukes in my belly$") { n: Long ->
26+
assertEquals(1, alreadyHadThisManyCukes)
27+
assertEquals(42L, n)
28+
}
29+
30+
val localState = "hello"
31+
Then("^I really have (\\d+) cukes in my belly") { i: Int ->
32+
assertEquals(42, i)
33+
assertEquals("hello", localState)
34+
}
35+
36+
Given("^A statement with a body expression$") { assertTrue(true) }
37+
38+
Given("^A statement with a simple match$", { -> assertTrue(true) })
39+
40+
val localInt = 1
41+
Given("^A statement with a scoped argument$", { assertEquals(2, localInt + 1) })
42+
43+
Given("^I will give you (\\d+) and ([\\d\\.]+) and (\\w+) and (\\d+)$") { a: Int, b: Float, c: String, d: Int ->
44+
assertEquals(1, a)
45+
assertEquals(2.2f, b)
46+
assertEquals("three", c)
47+
assertEquals(4, d)
48+
}
49+
}
50+
51+
class Person {
52+
internal var first: String? = null
53+
internal var last: String? = null
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package cucumber.runtime.kotlin.test
2+
3+
import cucumber.api.junit.Cucumber
4+
import org.junit.runner.RunWith
5+
6+
@RunWith(Cucumber::class)
7+
class RunCukesTest {
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Feature: Kotlin
2+
3+
Scenario: use the API with Java8 style
4+
Given I have 42 cukes in my belly
5+
Then I really have 42 cukes in my belly
6+
7+
Scenario: another scenario which should have isolated state
8+
Given I have 42 cukes in my belly
9+
And something that isn't defined
10+
11+
Scenario: Parameterless lambdas
12+
Given A statement with a simple match
13+
Given A statement with a scoped argument
14+
15+
Scenario: I can use body expressions
16+
Given A statement with a body expression
17+
18+
Scenario: Multi-param lambdas
19+
Given I will give you 1 and 2.2 and three and 4
20+
21+
Scenario: use a table
22+
Given this data table:
23+
| first | last |
24+
| Aslak | Hellesøy |
25+
| Donald | Duck |

pom.xml

+25-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
24
<modelVersion>4.0.0</modelVersion>
35
<groupId>io.cucumber</groupId>
46
<artifactId>cucumber-jvm</artifactId>
@@ -579,9 +581,25 @@
579581
<activation>
580582
<jdk>1.8</jdk>
581583
</activation>
584+
582585
<modules>
583586
<module>java8</module>
587+
<module>kotlin-java8</module>
584588
</modules>
589+
<dependencyManagement>
590+
<dependencies>
591+
<dependency>
592+
<groupId>io.cucumber</groupId>
593+
<artifactId>cucumber-java8</artifactId>
594+
<version>${project.version}</version>
595+
</dependency>
596+
<dependency>
597+
<groupId>io.cucumber</groupId>
598+
<artifactId>cucumber-kotlin-java8</artifactId>
599+
<version>${project.version}</version>
600+
</dependency>
601+
</dependencies>
602+
</dependencyManagement>
585603
</profile>
586604

587605
<profile>
@@ -754,7 +772,8 @@
754772
<configuration>
755773
<aggregate>true</aggregate>
756774
<use>false</use>
757-
<excludePackageNames>cucumber.runtime,cucumber.runtime.*</excludePackageNames>
775+
<excludePackageNames>cucumber.runtime,cucumber.runtime.*
776+
</excludePackageNames>
758777
<links>
759778
<link>http://docs.oracle.com/javase/7/docs/api/</link>
760779
<link>http://junit.sourceforge.net/javadoc/</link>
@@ -922,12 +941,14 @@
922941
<version>[${minimum.maven.version},)</version>
923942
</requireMavenVersion>
924943
<requirePluginVersions>
925-
<message>Best Practice is to always define plugin versions!</message>
944+
<message>Best Practice is to always define plugin versions!
945+
</message>
926946
<banLatest>true</banLatest>
927947
<banRelease>true</banRelease>
928948
<banSnapshots>true</banSnapshots>
929949
<phases>clean,deploy,site</phases>
930-
<unCheckedPluginList>org.codehaus.mojo:cobertura-maven-plugin</unCheckedPluginList>
950+
<unCheckedPluginList>org.codehaus.mojo:cobertura-maven-plugin
951+
</unCheckedPluginList>
931952
</requirePluginVersions>
932953
<bannedDependencies>
933954
<excludes>

0 commit comments

Comments
 (0)