diff --git a/specs/spring-cloud-contract-spec-kotlin/pom.xml b/specs/spring-cloud-contract-spec-kotlin/pom.xml index 61ae965805..b14b22f6b8 100644 --- a/specs/spring-cloud-contract-spec-kotlin/pom.xml +++ b/specs/spring-cloud-contract-spec-kotlin/pom.xml @@ -31,6 +31,26 @@ kotlin-stdlib-jdk8 ${kotlin.version} + + org.jetbrains.kotlin + kotlin-compiler + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-scripting-compiler + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-script-runtime + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-script-util + ${kotlin.version} + org.jetbrains.kotlin kotlin-test diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverter.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverter.kt new file mode 100644 index 0000000000..98285809fc --- /dev/null +++ b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverter.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.contract.spec.internal + +import org.springframework.cloud.contract.spec.Contract +import org.springframework.cloud.contract.spec.ContractConverter +import java.io.File +import javax.script.ScriptEngineManager + +/** + * @author Tim Ysewyn + */ +class KotlinContractConverter: ContractConverter> { + + private val ext = "kts" + + constructor() { + // Sets an {@code idea.use.native.fs.for.win} system property to {@code false} + // to disable a native engine discovery for Windows: may be resolved in the future Kotlin versions. + System.setProperty("idea.use.native.fs.for.win", "false") + } + + override fun isAccepted(file: File): Boolean { + return ext == file.extension + } + + override fun convertFrom(file: File): Collection { + val eval = file.reader().use { + // Get a new engine every time we need to process a file. + // Reusing the script engine could leak context and will fail subsequent evals + ScriptEngineManager().getEngineByExtension(ext).eval(it) + } + return when (eval) { + is Contract -> listOf(eval) + is Iterable<*> -> eval.filterIsInstance(Contract::class.java) + is Array<*> -> eval.filterIsInstance(Contract::class.java) + else -> emptyList() + } + } + + override fun convertTo(contract: Collection) = contract.toList() +} \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt index 267d9993b2..bf7de2fea8 100644 --- a/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt +++ b/specs/spring-cloud-contract-spec-kotlin/src/main/kotlin/org/springframework/cloud/contract/spec/internal/RequestDsl.kt @@ -44,20 +44,20 @@ open class RequestDsl : CommonDsl(), RegexCreatingProperty { this.method(method.toString()) } - fun url(url: String): Url { - return Url(url) + fun url(url: String) { + this.url = Url(url) } - fun url(url: DslProperty): Url { - return Url(url) + fun url(url: DslProperty) { + this.url = Url(url) } - fun urlPath(url: String): UrlPath { - return UrlPath(url) + fun urlPath(url: String) { + this.urlPath = UrlPath(url) } - fun urlPath(url: DslProperty): UrlPath { - return UrlPath(url) + fun urlPath(url: DslProperty) { + this.urlPath = UrlPath(url) } fun headers(headers: Headers.() -> Unit) { diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory b/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory new file mode 100644 index 0000000000..f8f5900378 --- /dev/null +++ b/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/services/javax.script.ScriptEngineFactory @@ -0,0 +1 @@ +org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/spring.factories b/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000..331f97675a --- /dev/null +++ b/specs/spring-cloud-contract-spec-kotlin/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.cloud.contract.spec.ContractConverter=\ +org.springframework.cloud.contract.spec.internal.KotlinContractConverter diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverterTest.kt b/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverterTest.kt new file mode 100644 index 0000000000..4d2cd56536 --- /dev/null +++ b/specs/spring-cloud-contract-spec-kotlin/src/test/kotlin/org/springframework/cloud/contract/spec/internal/KotlinContractConverterTest.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.contract.spec.internal + +import org.junit.Test +import java.io.File +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class KotlinContractConverterTest { + + @Test + fun `accept kts files`() { + assertTrue(KotlinContractConverter().isAccepted(file("contracts/singleDefinition.kts"))) + } + + @Test + fun `should convert single contract definition`() { + val converter = KotlinContractConverter() + val contracts = converter.convertFrom(file("contracts/singleDefinition.kts")) + assertEquals(1, contracts.size) + } + + @Test + fun `should convert multiple contract definitions`() { + val converter = KotlinContractConverter() + val contracts = converter.convertFrom(file("contracts/multipleDefinitions.kts")) + assertEquals(2, contracts.size) + } + + private fun file(filename: String) = File(javaClass.classLoader.getResource(filename)!!.toURI()) +} \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipleDefinitions.kts b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipleDefinitions.kts new file mode 100644 index 0000000000..8838386cd8 --- /dev/null +++ b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/multipleDefinitions.kts @@ -0,0 +1,48 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package contracts + +import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract + +arrayOf( + contract { + request { + method("GET") + url("/frauds") + } + response { + status(200) + body("count" to 200) + headers { + contentType("application/vnd.fraud.v1+json") + } + } + }, + contract { + request { + method("GET") + url("/drunks") + } + response { + status(200) + body("count" to 100) + headers { + contentType("application/vnd.fraud.v1+json") + } + } + } +) \ No newline at end of file diff --git a/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/singleDefinition.kts b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/singleDefinition.kts new file mode 100644 index 0000000000..f3047ff2c7 --- /dev/null +++ b/specs/spring-cloud-contract-spec-kotlin/src/test/resources/contracts/singleDefinition.kts @@ -0,0 +1,43 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package contracts + +import org.springframework.cloud.contract.spec.ContractDsl.Companion.contract + +contract { + request { + method("PUT") + url("/fraudcheck") + body("clientId" to value(consumer(regex("[0-9]{10}")), producer("1234567890")), + "loanAmount" to 123.123 + ) + headers { + contentType("application/vnd.fraud.v1+json") + } + + } + response { + status(200) + body( + "fraudCheckStatus" to "OK", + "rejectionReason" to listOf(value(consumer(null), producer("assertThatRejectionReasonIsNull(\$it)"))) + ) + headers { + contentType("application/vnd.fraud.v1+json") + } + } +} \ No newline at end of file