From cd515d3523bd5e31009eed03a3b61a89959c34c1 Mon Sep 17 00:00:00 2001 From: "M.P. Korstanje" Date: Sat, 3 Jun 2017 15:59:35 +0200 Subject: [PATCH] [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: - https://github.com/cucumber/cucumber-jvm/issues/1123 - https://github.com/cucumber/cucumber-jvm/issues/1126 This fixes #1123 --- History.md | 1 + .../java8/ConstantPoolTypeIntrospector.java | 9 ++ kotlin-java8/README.md | 6 ++ kotlin-java8/pom.xml | 93 +++++++++++++++++++ .../runtime/kotlin/test/LambdaStepdefs.kt | 55 +++++++++++ .../runtime/kotlin/test/RunCukesTest.kt | 8 ++ .../runtime/kotlin/test/kotlin.feature | 25 +++++ pom.xml | 11 +++ 8 files changed, 208 insertions(+) create mode 100644 kotlin-java8/README.md create mode 100644 kotlin-java8/pom.xml create mode 100644 kotlin-java8/src/test/kotlin/cucumber/runtime/kotlin/test/LambdaStepdefs.kt create mode 100644 kotlin-java8/src/test/kotlin/cucumber/runtime/kotlin/test/RunCukesTest.kt create mode 100644 kotlin-java8/src/test/resources/cucumber/runtime/kotlin/test/kotlin.feature diff --git a/History.md b/History.md index eaf9317504..765e4360b8 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,6 @@ ## [2.0.0-SNAPSHOT](https://github.com/cucumber/cucumber-jvm/compare/v1.2.5...master) (In Git) +* [Java8, Kotlin Java8] Support java 8 method references ([#1140](https://github.com/cucumber/cucumber-jvm/pull/1140) M.P. Korstanje) * [Core] Show explicit error message when field name missed in table header ([#1014](https://github.com/cucumber/cucumber-jvm/pull/1014) Mykola Gurov) * [Examples] Properly quit selenium in webbit examples ([#1146](https://github.com/cucumber/cucumber-jvm/pull/1146) Alberto Scotto) * [JUnit] Use AssumptionFailed to mark scenarios/steps as skipped ([#1142](https://github.com/cucumber/cucumber-jvm/pull/1142) Björn Rasmusson) diff --git a/java8/src/main/java/cucumber/runtime/java8/ConstantPoolTypeIntrospector.java b/java8/src/main/java/cucumber/runtime/java8/ConstantPoolTypeIntrospector.java index 7614a3b691..7f8aafc590 100644 --- a/java8/src/main/java/cucumber/runtime/java8/ConstantPoolTypeIntrospector.java +++ b/java8/src/main/java/cucumber/runtime/java8/ConstantPoolTypeIntrospector.java @@ -35,6 +35,11 @@ public Type[] getGenericTypes(Class clazz, Class + 4.0.0 + + + io.cucumber + cucumber-jvm + ../pom.xml + 2.0.0-SNAPSHOT + + + cucumber-kotlin-java8 + jar + Cucumber-JVM: Kotlin Java8 + + + 1.1.2-2 + + + + + io.cucumber + cucumber-java8 + + + io.cucumber + cucumber-junit + test + + + junit + junit + test + + + net.sourceforge.cobertura + cobertura + test + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + test + + + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/test/kotlin + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${kotlin.version} + + + compile + + compile + + + + test-compile + + test-compile + + + + + + maven-jar-plugin + + true + + + + maven-install-plugin + + true + + + + maven-deploy-plugin + + true + + + + + + diff --git a/kotlin-java8/src/test/kotlin/cucumber/runtime/kotlin/test/LambdaStepdefs.kt b/kotlin-java8/src/test/kotlin/cucumber/runtime/kotlin/test/LambdaStepdefs.kt new file mode 100644 index 0000000000..3949031987 --- /dev/null +++ b/kotlin-java8/src/test/kotlin/cucumber/runtime/kotlin/test/LambdaStepdefs.kt @@ -0,0 +1,55 @@ +package cucumber.runtime.kotlin.test; + +import cucumber.api.DataTable +import cucumber.api.Scenario +import cucumber.api.java8.En +import org.junit.Assert.* + +var lastInstance : LambdaStepdefs? = null + +class LambdaStepdefs : En { + + init { + Before { scenario: Scenario -> + assertNotSame(this, lastInstance) + lastInstance = this + } + + Given("^this data table:$") { peopleTable: DataTable -> + val people = peopleTable.asList(Person::class.java) + assertEquals("Aslak", people[0].first) + assertEquals("Hellesøy", people[0].last) + } + + val alreadyHadThisManyCukes = 1 + Given("^I have (\\d+) cukes in my belly$") { n: Long -> + assertEquals(1, alreadyHadThisManyCukes) + assertEquals(42L, n) + } + + val localState = "hello" + Then("^I really have (\\d+) cukes in my belly") { i: Int -> + assertEquals(42, i) + assertEquals("hello", localState) + } + + Given("^A statement with a body expression$") { assertTrue(true) } + + Given("^A statement with a simple match$", { -> assertTrue(true) }) + + val localInt = 1 + Given("^A statement with a scoped argument$", { assertEquals(2, localInt + 1) }) + + Given("^I will give you (\\d+) and ([\\d\\.]+) and (\\w+) and (\\d+)$") { a: Int, b: Float, c: String, d: Int -> + assertEquals(1, a) + assertEquals(2.2f, b) + assertEquals("three", c) + assertEquals(4, d) + } + } + + class Person { + internal var first: String? = null + internal var last: String? = null + } +} diff --git a/kotlin-java8/src/test/kotlin/cucumber/runtime/kotlin/test/RunCukesTest.kt b/kotlin-java8/src/test/kotlin/cucumber/runtime/kotlin/test/RunCukesTest.kt new file mode 100644 index 0000000000..77e63fff7f --- /dev/null +++ b/kotlin-java8/src/test/kotlin/cucumber/runtime/kotlin/test/RunCukesTest.kt @@ -0,0 +1,8 @@ +package cucumber.runtime.kotlin.test + +import cucumber.api.junit.Cucumber +import org.junit.runner.RunWith + +@RunWith(Cucumber::class) +class RunCukesTest { +} diff --git a/kotlin-java8/src/test/resources/cucumber/runtime/kotlin/test/kotlin.feature b/kotlin-java8/src/test/resources/cucumber/runtime/kotlin/test/kotlin.feature new file mode 100644 index 0000000000..e9b47a62d0 --- /dev/null +++ b/kotlin-java8/src/test/resources/cucumber/runtime/kotlin/test/kotlin.feature @@ -0,0 +1,25 @@ +Feature: Kotlin + + Scenario: use the API with Java8 style + Given I have 42 cukes in my belly + Then I really have 42 cukes in my belly + + Scenario: another scenario which should have isolated state + Given I have 42 cukes in my belly + And something that isn't defined + + Scenario: Parameterless lambdas + Given A statement with a simple match + Given A statement with a scoped argument + + Scenario: I can use body expressions + Given A statement with a body expression + + Scenario: Multi-param lambdas + Given I will give you 1 and 2.2 and three and 4 + + Scenario: use a table + Given this data table: + | first | last | + | Aslak | Hellesøy | + | Donald | Duck | diff --git a/pom.xml b/pom.xml index e8e2859251..078de7b7f3 100644 --- a/pom.xml +++ b/pom.xml @@ -192,6 +192,16 @@ android-examples ${project.version} + + io.cucumber + cucumber-java8 + ${project.version} + + + io.cucumber + cucumber-kotlin-java8 + ${project.version} + @@ -581,6 +591,7 @@ java8 + kotlin-java8