├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── src ├── main │ └── kotlin │ │ └── com │ │ └── marcinziolo │ │ └── kotlin │ │ └── wiremock │ │ ├── ReturnsStep.kt │ │ ├── Wrapper.kt │ │ ├── BuildingStep.kt │ │ ├── Delay.kt │ │ ├── Constraint.kt │ │ ├── dslAdapters.kt │ │ ├── ResponseSpecification.kt │ │ ├── ContainsStep.kt │ │ ├── WireMockInstance.kt │ │ ├── VerifySpecification.kt │ │ ├── RequestSpecification.kt │ │ └── api.kt └── test │ └── kotlin │ └── com │ └── marcinziolo │ └── kotlin │ └── wiremock │ ├── utils.kt │ ├── AbstractTest.kt │ ├── Junit5RegisterExtensionTest.kt │ ├── PriorityTest.kt │ ├── AndTest.kt │ ├── Junit5ExtensionTest.kt │ ├── RequestUrlTest.kt │ ├── AndExtensionTest.kt │ ├── ResponseDelayTest.kt │ ├── ResponseTest.kt │ ├── otherPackage │ └── WithBuilderTest.kt │ ├── ScenarioTest.kt │ ├── RequestCookiesTest.kt │ ├── RequestHeadersTest.kt │ ├── RequestOtherMethodsTest.kt │ ├── RequestQueryParamsTest.kt │ ├── RequestOtherMethodsExtensionTest.kt │ ├── ExampleExtensionTest.kt │ ├── ExampleTest.kt │ ├── RequestPostTest.kt │ └── VerifyTest.kt ├── .gitattributes ├── settings.gradle.kts ├── .github └── workflows │ └── workflow.yaml ├── kotlin-wiremock-examples ├── src │ └── test │ │ └── kotlin │ │ └── com │ │ └── marcinziolo │ │ └── kotlin │ │ └── wiremock │ │ └── JUnit4ExampleTest.kt └── pom.xml ├── gradlew.bat ├── gradlew ├── README.md ├── LICENSE.txt └── detekt.yml /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wiremock/kotlin-wiremock/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Gradle project-specific cache directory 2 | .gradle 3 | 4 | # Ignore Gradle build output directory 5 | build 6 | target 7 | .idea 8 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/ReturnsStep.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | data class ReturnsStep(val buildingStep: BuildingStep) 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/utils.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import java.net.ServerSocket 4 | 5 | fun findRandomOpenPort(): Int { 6 | ServerSocket(0).use { socket -> return socket.localPort } 7 | } 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/Wrapper.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import kotlin.reflect.KClass 4 | 5 | @Suppress("UseDataClass") 6 | class Wrapper(var value: T) 7 | 8 | @Suppress("UNUSED_PARAMETER","UNCHECKED_CAST") 9 | fun Any.wrap(claz: KClass) = Wrapper(this as T) 10 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/6.2/userguide/multi_project_builds.html 8 | */ 9 | 10 | rootProject.name = "kotlin-wiremock" -------------------------------------------------------------------------------- /.github/workflows/workflow.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | - name: Set up JDK 11 12 | uses: actions/setup-java@v2 13 | with: 14 | java-version: '11' 15 | distribution: 'adopt' 16 | - name: Validate Gradle wrapper 17 | uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b 18 | - name: Build with Gradle 19 | run: ./gradlew build 20 | - name: codecov 21 | uses: codecov/codecov-action@v2 -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/BuildingStep.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder 4 | import com.github.tomakehurst.wiremock.client.WireMock 5 | import java.util.UUID 6 | 7 | data class BuildingStep( 8 | val id: UUID? = null, 9 | val wireMockInstance: WireMockInstance, 10 | val method: Method, 11 | val specifyRequestList: List, 12 | val specifyResponseList: List = emptyList(), 13 | val responseDefinitionBuilder: ResponseDefinitionBuilder = WireMock.aResponse() 14 | ) 15 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/Delay.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | sealed class Delay 4 | 5 | data class FixedDelay(val delay: Int) : Delay() 6 | data class NormalDistributionDelay(val median: Int, val sigma: Double) : Delay() 7 | 8 | infix fun Wrapper.fixedMs(delay: Int) { 9 | this.value = FixedDelay(delay) 10 | } 11 | 12 | @Suppress("UNCHECKED_CAST") 13 | infix fun Wrapper.medianMs(median: Int): MedianStep { 14 | val normalDistribution = 15 | NormalDistributionDelay(median, 0.0) 16 | this.value = normalDistribution 17 | return MedianStep(this as Wrapper) 18 | } 19 | 20 | data class MedianStep(val delay: Wrapper) 21 | 22 | infix fun MedianStep.sigma(sigma: Double) { 23 | this.delay.value = this.delay.value.copy(sigma = sigma) 24 | } 25 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/AbstractTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.WireMockServer 4 | import com.github.tomakehurst.wiremock.common.ConsoleNotifier 5 | import com.github.tomakehurst.wiremock.core.WireMockConfiguration.options 6 | import org.junit.jupiter.api.AfterEach 7 | import org.junit.jupiter.api.BeforeEach 8 | 9 | @Suppress("UnnecessaryAbstractClass") 10 | abstract class AbstractTest { 11 | private val port = findRandomOpenPort() 12 | val wiremock: WireMockServer = WireMockServer(options().port(port).notifier(ConsoleNotifier(true))) 13 | val url 14 | get() = "http://localhost:$port" 15 | 16 | @BeforeEach 17 | fun setUp() { 18 | wiremock.start() 19 | } 20 | 21 | @AfterEach 22 | fun afterEach() { 23 | wiremock.resetAll() 24 | wiremock.stop() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/Constraint.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | sealed class Constraint 4 | sealed class StringConstraint: Constraint() 5 | data class EqualTo(val value: String) : StringConstraint() 6 | data class Like(val value: String) : StringConstraint() 7 | data class NotLike(val value: String) : StringConstraint() 8 | object Whatever : StringConstraint() 9 | data class StronglyEqualTo(val value: T): Constraint() 10 | data class EqualToJson(val value: String): Constraint() 11 | 12 | infix fun Wrapper.equalTo(value: String) { 13 | this.value = EqualTo(value) 14 | } 15 | 16 | infix fun Wrapper.like(value: String) { 17 | this.value = Like(value) 18 | } 19 | 20 | infix fun Wrapper.notLike(value: String) { 21 | this.value = NotLike(value) 22 | } 23 | 24 | infix fun Wrapper.contains(value: String) { 25 | this.value = Like(".*$value.*") 26 | } 27 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/Junit5RegisterExtensionTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig 4 | import com.github.tomakehurst.wiremock.junit5.WireMockExtension 5 | import io.restassured.module.kotlin.extensions.Then 6 | import io.restassured.module.kotlin.extensions.When 7 | import org.junit.jupiter.api.Test 8 | import org.junit.jupiter.api.extension.RegisterExtension 9 | 10 | class Junit5RegisterExtensionTest { 11 | 12 | @JvmField 13 | @RegisterExtension 14 | var wm = WireMockExtension.newInstance() 15 | .options(wireMockConfig().dynamicPort()) 16 | .build() 17 | 18 | @Test 19 | fun testGet() { 20 | wm.get { 21 | url equalTo "/hello" 22 | } returns { 23 | statusCode = 200 24 | } 25 | 26 | When { 27 | get("${wm.baseUrl()}/hello") 28 | } Then { 29 | statusCode(200) 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/PriorityTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import io.restassured.module.kotlin.extensions.Given 4 | import io.restassured.module.kotlin.extensions.Then 5 | import io.restassured.module.kotlin.extensions.When 6 | import org.junit.jupiter.api.Test 7 | 8 | internal class PriorityTest : AbstractTest() { 9 | 10 | @Test 11 | fun `prioritized response is returned`() { 12 | wiremock.post { 13 | url equalTo "/test" 14 | priority = 2 15 | } returnsJson { 16 | statusCode = 403 17 | } 18 | 19 | wiremock.post { 20 | url equalTo "/test" 21 | headers contains "Authorization" 22 | priority = 1 23 | } returnsJson { 24 | statusCode = 200 25 | } 26 | 27 | Given { 28 | header("Authorization", "Bearer token") 29 | } When { 30 | post("$url/test") 31 | } Then { 32 | statusCode(200) 33 | } 34 | 35 | When { 36 | post("$url/test") 37 | } Then { 38 | statusCode(403) 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/dslAdapters.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.client.WireMock 4 | 5 | internal fun Map.toStringValuePatterns() = this.entries.map { 6 | val jsonRegex: String = when (val constraint = it.value) { 7 | is EqualTo -> "\$[?(@.${it.key} === '${constraint.value}')]" 8 | is StronglyEqualTo<*> -> "\$[?(@.${it.key} === ${constraint.value})]" 9 | is Like -> "\$[?(@.${it.key} =~ /${constraint.value}/i)]" 10 | is NotLike -> "\$[?(!(@.${it.key} =~ /${constraint.value}/i))]" 11 | is Whatever -> "\$.${it.key}" 12 | is EqualToJson -> constraint.value 13 | } 14 | if (it.value !is EqualToJson) { 15 | WireMock.matchingJsonPath(jsonRegex) 16 | } else { 17 | WireMock.equalToJson(jsonRegex) 18 | } 19 | } 20 | 21 | internal fun getStringValuePattern(stringConstraint: StringConstraint) = 22 | when (stringConstraint) { 23 | is EqualTo -> WireMock.equalTo(stringConstraint.value) 24 | is Like -> WireMock.matching(stringConstraint.value) 25 | is NotLike -> WireMock.notMatching(stringConstraint.value) 26 | is Whatever -> WireMock.matching(".*") 27 | } 28 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/AndTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import io.restassured.module.kotlin.extensions.Given 4 | import io.restassured.module.kotlin.extensions.Then 5 | import io.restassured.module.kotlin.extensions.When 6 | import org.hamcrest.Matchers.equalTo 7 | import org.junit.jupiter.api.Test 8 | 9 | class AndTest : AbstractTest() { 10 | @Test 11 | fun `request and`() { 12 | wiremock.get { 13 | url equalTo "/hello" 14 | } and { 15 | headers contains "User-Agent" equalTo "curl" 16 | } returns { 17 | statusCode = 200 18 | } 19 | 20 | Given { 21 | header("User-Agent", "curl") 22 | } When { 23 | get("$url/hello") 24 | } Then { 25 | statusCode(200) 26 | } 27 | } 28 | 29 | @Test 30 | fun `response and`() { 31 | wiremock.get { 32 | url equalTo "/hello" 33 | } returns { 34 | header = "Content-Type" to "application/json" 35 | body = """ 36 | {"pet": "dog"} 37 | """ 38 | } and { 39 | statusCode = 200 40 | } 41 | 42 | When { 43 | get("$url/hello") 44 | } Then { 45 | statusCode(200) 46 | body("pet", equalTo("dog")) 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /kotlin-wiremock-examples/src/test/kotlin/com/marcinziolo/kotlin/wiremock/JUnit4ExampleTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.junit.WireMockRule 4 | import io.restassured.module.kotlin.extensions.Then 5 | import io.restassured.module.kotlin.extensions.When 6 | import org.hamcrest.Matchers.equalTo 7 | import org.junit.Rule 8 | import org.junit.Test 9 | import java.net.ServerSocket 10 | 11 | class JUnit4ExampleTest { 12 | 13 | val port = findRandomPort() 14 | 15 | val url = "http://localhost:$port" 16 | 17 | @Rule 18 | @JvmField 19 | var wiremock: WireMockRule = WireMockRule(port) 20 | 21 | @Test 22 | fun `url matching`() { 23 | wiremock.get { 24 | url like "/users/.*" 25 | } returns { 26 | header = "Content-Type" to "application/json" 27 | statusCode = 200 28 | body = """ 29 | { 30 | "id": 1, 31 | "name": "Bob" 32 | } 33 | """ 34 | } 35 | assertBobSuccess() 36 | } 37 | 38 | private fun assertBobSuccess() { 39 | When { 40 | get("$url/users/1") 41 | } Then { 42 | statusCode(200) 43 | body("id", equalTo(1)) 44 | body("name", equalTo("Bob")) 45 | } 46 | } 47 | 48 | fun findRandomPort(): Int { 49 | ServerSocket(0).use { socket -> return socket.localPort } 50 | } 51 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/Junit5ExtensionTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.client.WireMock 4 | import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo 5 | import com.github.tomakehurst.wiremock.junit5.WireMockTest 6 | import io.restassured.module.kotlin.extensions.Then 7 | import io.restassured.module.kotlin.extensions.When 8 | import org.junit.jupiter.api.BeforeEach 9 | import org.junit.jupiter.api.Test 10 | 11 | @WireMockTest 12 | class Junit5ExtensionTest { 13 | 14 | lateinit var wm: WireMock 15 | lateinit var baseUrl: String 16 | 17 | @BeforeEach 18 | fun setup(wireMockRuntimeInfo: WireMockRuntimeInfo){ 19 | wm = wireMockRuntimeInfo.wireMock 20 | baseUrl = wireMockRuntimeInfo.httpBaseUrl 21 | } 22 | 23 | @Test 24 | fun testGet() { 25 | wm.get { 26 | url equalTo "/hello" 27 | } returns { 28 | statusCode = 200 29 | } 30 | 31 | When { 32 | get("$baseUrl/hello") 33 | } Then { 34 | statusCode(200) 35 | } 36 | 37 | wm.verify { 38 | url equalTo "/hello" 39 | } 40 | } 41 | 42 | @Test 43 | fun testPost() { 44 | wm.post { 45 | url equalTo "/hello" 46 | } returns { 47 | statusCode = 200 48 | } 49 | 50 | When { 51 | post("$baseUrl/hello") 52 | } Then { 53 | statusCode(200) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/RequestUrlTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import io.restassured.module.kotlin.extensions.Then 4 | import io.restassured.module.kotlin.extensions.When 5 | import org.junit.jupiter.api.Test 6 | 7 | class RequestUrlTest : AbstractTest() { 8 | @Test 9 | fun `url equalTo`() { 10 | wiremock.get { 11 | url equalTo "/hello" 12 | } returns { 13 | statusCode = 200 14 | } 15 | 16 | When { 17 | get("$url/hello") 18 | } Then { 19 | statusCode(200) 20 | } 21 | } 22 | 23 | @Test 24 | fun `url notLike`() { 25 | wiremock.get { 26 | url notLike "/hello2" 27 | } returns { 28 | statusCode = 200 29 | } 30 | 31 | When { 32 | get("$url/hello") 33 | } Then { 34 | statusCode(200) 35 | } 36 | } 37 | 38 | @Test 39 | fun `url like`() { 40 | wiremock.get { 41 | url like "/hel.*" 42 | } returns { 43 | statusCode = 200 44 | } 45 | 46 | When { 47 | get("$url/hello") 48 | } Then { 49 | statusCode(200) 50 | } 51 | } 52 | 53 | @Test 54 | fun `url contains`() { 55 | wiremock.get { 56 | url contains "hel" 57 | } returns { 58 | statusCode = 200 59 | } 60 | 61 | When { 62 | get("$url/hello") 63 | } Then { 64 | statusCode(200) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/AndExtensionTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo 4 | import com.github.tomakehurst.wiremock.junit5.WireMockTest 5 | import io.restassured.module.kotlin.extensions.Given 6 | import io.restassured.module.kotlin.extensions.Then 7 | import io.restassured.module.kotlin.extensions.When 8 | import org.hamcrest.Matchers.equalTo 9 | import org.junit.jupiter.api.Test 10 | 11 | @WireMockTest 12 | class AndExtensionTest { 13 | @Test 14 | fun `request and`(wmRuntimeInfo: WireMockRuntimeInfo) { 15 | mockGet { 16 | url equalTo "/hello" 17 | } and { 18 | headers contains "User-Agent" equalTo "curl" 19 | } returns { 20 | statusCode = 200 21 | } 22 | 23 | Given { 24 | header("User-Agent", "curl") 25 | } When { 26 | get("${wmRuntimeInfo.httpBaseUrl}/hello") 27 | } Then { 28 | statusCode(200) 29 | } 30 | 31 | verifyCalls { 32 | url equalTo "/hello" 33 | } 34 | } 35 | 36 | @Test 37 | fun `response and`(wmRuntimeInfo: WireMockRuntimeInfo) { 38 | mockGet { 39 | url equalTo "/hello" 40 | } returns { 41 | header = "Content-Type" to "application/json" 42 | body = """ 43 | {"pet": "dog"} 44 | """ 45 | } and { 46 | statusCode = 200 47 | } 48 | 49 | When { 50 | get("${wmRuntimeInfo.httpBaseUrl}/hello") 51 | } Then { 52 | statusCode(200) 53 | body("pet", equalTo("dog")) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/ResponseDelayTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.WireMockServer 4 | import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder 5 | import io.mockk.mockk 6 | import io.mockk.verify 7 | import io.restassured.module.kotlin.extensions.Then 8 | import io.restassured.module.kotlin.extensions.When 9 | import org.hamcrest.Matchers.equalTo 10 | import org.hamcrest.Matchers.greaterThanOrEqualTo 11 | import org.junit.jupiter.api.Test 12 | 13 | class ResponseDelayTest : AbstractTest() { 14 | @Test 15 | fun `delayed fixed response`() { 16 | wiremock.get { 17 | url equalTo "/hello" 18 | } returnsJson { 19 | body = """ 20 | {"pet": "dog"} 21 | """ 22 | delay fixedMs 100 23 | } 24 | repeat(4) { 25 | When { 26 | get("$url/hello") 27 | } Then { 28 | statusCode(200) 29 | body("pet", equalTo("dog")) 30 | time(greaterThanOrEqualTo(100L)) 31 | } 32 | } 33 | } 34 | 35 | @Test 36 | fun `unit delayed median response`() { 37 | //given 38 | val wireMockServer = mockk(relaxed = true) 39 | val responseDefinitionBuilder = mockk(relaxed = true) 40 | 41 | //when 42 | wireMockServer.get { 43 | url equalTo "/hello" 44 | }.copy(responseDefinitionBuilder = responseDefinitionBuilder) returns { 45 | delay medianMs 100 sigma 0.1 46 | } 47 | 48 | //then 49 | verify { responseDefinitionBuilder.withLogNormalRandomDelay(100.0, 0.1) } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/ResponseTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import io.restassured.module.kotlin.extensions.Then 4 | import io.restassured.module.kotlin.extensions.When 5 | import org.hamcrest.Matchers.equalTo 6 | import org.junit.jupiter.api.Assertions.assertEquals 7 | import org.junit.jupiter.api.Test 8 | 9 | class ResponseTest : AbstractTest() { 10 | @Test 11 | fun `response with two headers`() { 12 | wiremock.get { 13 | url equalTo "/hello" 14 | } returns { 15 | statusCode = 200 16 | header = "TraceId" to "abcd123" 17 | header = "ExecutionTime" to "10" 18 | } 19 | 20 | When { 21 | get("$url/hello") 22 | } Then { 23 | statusCode(200) 24 | header("TraceId", "abcd123") 25 | header("ExecutionTime", "10") 26 | } 27 | } 28 | 29 | @Test 30 | fun `response with multi-value headers`() { 31 | wiremock.get { 32 | url equalTo "/hello" 33 | } returns { 34 | statusCode = 200 35 | header = "TraceId" to "abcd123" 36 | header = "TraceId" to "efgh456" 37 | } 38 | 39 | When { 40 | get("$url/hello") 41 | } Then { 42 | statusCode(200) 43 | extract().headers().getValues("TraceId").also { values -> 44 | assertEquals(listOf("abcd123", "efgh456"), values) 45 | } 46 | } 47 | } 48 | 49 | @Test 50 | fun `returns json`() { 51 | wiremock.get { 52 | url equalTo "/hello" 53 | } returnsJson { 54 | body = """ 55 | {"pet": "dog"} 56 | """ 57 | } 58 | 59 | When { 60 | get("$url/hello") 61 | } Then { 62 | statusCode(200) 63 | body("pet", equalTo("dog")) 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/ResponseSpecification.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder 4 | 5 | class ResponseSpecification { 6 | var whenState: String? = null 7 | var toState: String? = null 8 | var clearState = false 9 | var body = "" 10 | var statusCode = 200 11 | @SuppressWarnings("VariableNaming") 12 | var __headers: MutableMap> = mutableMapOf() 13 | var header: Pair = "" to "" 14 | set(value) { 15 | __headers.getOrPut(value.first) { mutableListOf() } += value.second 16 | field = value 17 | } 18 | var delay = FixedDelay(0) 19 | .wrap(Delay::class) 20 | 21 | private val builders: MutableList Unit> = mutableListOf() 22 | 23 | fun withBuilder(block: ResponseDefinitionBuilder.() -> Unit) { 24 | builders.add(block) 25 | } 26 | 27 | @SuppressWarnings("SpreadOperator") 28 | fun decorateResponseDefinitionBuilder( 29 | responseDefinitionBuilder: ResponseDefinitionBuilder 30 | ): ResponseDefinitionBuilder { 31 | 32 | responseDefinitionBuilder 33 | .withStatus(statusCode) 34 | .withBody(body.trimIndent()) 35 | 36 | when (val delay = delay.value) { 37 | is FixedDelay -> responseDefinitionBuilder.withFixedDelay(delay.delay) 38 | is NormalDistributionDelay -> 39 | responseDefinitionBuilder.withLogNormalRandomDelay(delay.median.toDouble(), delay.sigma) 40 | } 41 | __headers.forEach { (key, values) -> responseDefinitionBuilder.withHeader(key, *values.toTypedArray()) } 42 | 43 | this.builders.forEach { b -> responseDefinitionBuilder.b() } 44 | 45 | return responseDefinitionBuilder 46 | } 47 | 48 | 49 | companion object { 50 | internal fun create(specifyResponseList: List): ResponseSpecification { 51 | val responseSpecification = ResponseSpecification() 52 | specifyResponseList.forEach { it(responseSpecification) } 53 | return responseSpecification 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/ContainsStep.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import java.util.UUID 4 | 5 | sealed class ContainsStep(open val key: String, open val map: MutableMap) 6 | 7 | data class ConstraintContainsStep( 8 | override val key: String, 9 | override val map: MutableMap 10 | ) : ContainsStep(key, map) 11 | 12 | data class StringContainsStep( 13 | override val key: String, 14 | override val map: MutableMap 15 | ) : ContainsStep(key, map) 16 | 17 | infix fun MutableMap.contains(key: String): StringContainsStep { 18 | this[key] = Whatever 19 | return StringContainsStep(key, this) 20 | } 21 | 22 | infix fun MutableMap.equalTo(json: String): ConstraintContainsStep { 23 | val key = UUID.randomUUID().toString() 24 | this[key] = EqualToJson(json) 25 | return ConstraintContainsStep(key, this) 26 | } 27 | 28 | infix fun MutableMap.contains(key: String): ConstraintContainsStep { 29 | this[key] = Whatever 30 | return ConstraintContainsStep(key, this) 31 | } 32 | 33 | @Suppress("UNCHECKED_CAST") 34 | infix fun ContainsStep.equalTo(value: String) { 35 | this.map[this.key] = EqualTo(value) as T 36 | } 37 | 38 | infix fun ContainsStep.equalTo(value: Int) { 39 | this.map[this.key] = StronglyEqualTo(value) 40 | } 41 | 42 | infix fun ContainsStep.equalTo(value: Long) { 43 | this.map[this.key] = StronglyEqualTo(value) 44 | } 45 | 46 | infix fun ContainsStep.equalTo(value: Boolean) { 47 | this.map[this.key] = StronglyEqualTo(value) 48 | } 49 | 50 | infix fun ContainsStep.equalTo(value: Double) { 51 | this.map[this.key] = StronglyEqualTo(value) 52 | } 53 | 54 | @Suppress("UNCHECKED_CAST") 55 | infix fun ContainsStep.like(value: String) { 56 | this.map[this.key] = Like(value) as T 57 | } 58 | 59 | @Suppress("UNCHECKED_CAST") 60 | infix fun ContainsStep.contains(value: String) { 61 | this.map[this.key] = Like(".*$value.*") as T 62 | } 63 | 64 | @Suppress("UNCHECKED_CAST") 65 | infix fun ContainsStep.notLike(value: String) { 66 | this.map[this.key] = NotLike(value) as T 67 | } 68 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/otherPackage/WithBuilderTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock.otherPackage 2 | 3 | import com.github.tomakehurst.wiremock.client.WireMock.matching 4 | import com.marcinziolo.kotlin.wiremock.* 5 | import io.restassured.module.kotlin.extensions.Given 6 | import io.restassured.module.kotlin.extensions.Then 7 | import io.restassured.module.kotlin.extensions.When 8 | import org.hamcrest.Matchers.equalTo 9 | import org.junit.jupiter.api.Assertions.assertEquals 10 | import org.junit.jupiter.api.Test 11 | 12 | class WithBuilderTest : AbstractTest() { 13 | @Test 14 | fun `response with two headers`() { 15 | wiremock.get { 16 | url equalTo "/hello" 17 | withBuilder { 18 | withHeader("SessionId", matching("1234")) 19 | } 20 | } returns { 21 | statusCode = 200 22 | header = "TraceId" to "abcd123" 23 | header = "ExecutionTime" to "10" 24 | } 25 | 26 | Given { 27 | headers("SessionId", "1234") 28 | } When { 29 | get("$url/hello") 30 | 31 | 32 | } Then { 33 | statusCode(200) 34 | header("TraceId", "abcd123") 35 | header("ExecutionTime", "10") 36 | } 37 | } 38 | 39 | @Test 40 | fun `response with multi-value headers`() { 41 | wiremock.get { 42 | url equalTo "/hello" 43 | } returns { 44 | statusCode = 200 45 | header = "TraceId" to "abcd123" 46 | header = "TraceId" to "efgh456" 47 | } 48 | 49 | When { 50 | get("$url/hello") 51 | } Then { 52 | statusCode(200) 53 | extract().headers().getValues("TraceId").also { values -> 54 | assertEquals(listOf("abcd123", "efgh456"), values) 55 | } 56 | } 57 | } 58 | 59 | fun ResponseSpecification.json(status: Int = 200) { 60 | withBuilder { 61 | withStatus(status) 62 | withHeader("Content-Type", "application/json") 63 | } 64 | } 65 | 66 | @Test 67 | fun `returns json`() { 68 | wiremock.get { 69 | url equalTo "/hello" 70 | } returns { 71 | json() 72 | body = """ 73 | {"pet": "dog"} 74 | """ 75 | } 76 | 77 | When { 78 | get("$url/hello") 79 | } Then { 80 | statusCode(200) 81 | body("pet", equalTo("dog")) 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/ScenarioTest.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.marcinziolo.kotlin.wiremock 3 | 4 | import io.restassured.module.kotlin.extensions.Then 5 | import io.restassured.module.kotlin.extensions.When 6 | import org.junit.jupiter.api.Test 7 | 8 | internal class ScenarioTest : AbstractTest() { 9 | 10 | @Test 11 | fun `wiremock works in stateful stae`() { 12 | wiremock.post { 13 | url equalTo "/test" 14 | toState = "400" 15 | } returnsJson { 16 | statusCode = 200 17 | } 18 | 19 | wiremock.post { 20 | url equalTo "/test" 21 | whenState = "400" 22 | toState = "500" 23 | 24 | } returnsJson { 25 | statusCode = 400 26 | } 27 | 28 | wiremock.post { 29 | url equalTo "/test" 30 | whenState = "500" 31 | clearState = true 32 | 33 | } returnsJson { 34 | statusCode = 500 35 | } 36 | 37 | When { 38 | post("$url/test") 39 | } Then { 40 | statusCode(200) 41 | } 42 | 43 | When { 44 | post("$url/test") 45 | } Then { 46 | statusCode(400) 47 | } 48 | 49 | When { 50 | post("$url/test") 51 | } Then { 52 | statusCode(500) 53 | } 54 | 55 | When { 56 | post("$url/test") 57 | } Then { 58 | statusCode(200) 59 | } 60 | 61 | When { 62 | post("$url/test") 63 | } Then { 64 | statusCode(400) 65 | } 66 | } 67 | 68 | @Test 69 | fun `wiremock stays in given sate`() { 70 | wiremock.post { 71 | url equalTo "/test" 72 | toState = "400" 73 | } returnsJson { 74 | statusCode = 200 75 | } 76 | 77 | wiremock.post { 78 | url equalTo "/test" 79 | whenState = "400" 80 | } returnsJson { 81 | statusCode = 400 82 | } 83 | 84 | 85 | When { 86 | post("$url/test") 87 | } Then { 88 | statusCode(200) 89 | } 90 | 91 | When { 92 | post("$url/test") 93 | } Then { 94 | statusCode(400) 95 | } 96 | 97 | When { 98 | post("$url/test") 99 | } Then { 100 | statusCode(400) 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/RequestCookiesTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import io.restassured.module.kotlin.extensions.Given 4 | import io.restassured.module.kotlin.extensions.Then 5 | import io.restassured.module.kotlin.extensions.When 6 | import org.junit.jupiter.api.Test 7 | 8 | class RequestCookiesTest : AbstractTest() { 9 | @Test 10 | fun `cookies contains negative`() { 11 | wiremock.get { 12 | url equalTo "/hello" 13 | cookies contains "any" 14 | } returns { 15 | statusCode = 200 16 | } 17 | 18 | When { 19 | get("$url/hello") 20 | } Then { 21 | statusCode(404) 22 | } 23 | } 24 | 25 | @Test 26 | fun `cookies contains positive`() { 27 | wiremock.get { 28 | url equalTo "/hello" 29 | cookies contains "User-Agent" 30 | } returns { 31 | statusCode = 200 32 | } 33 | 34 | Given { 35 | cookie("User-Agent", "whatever") 36 | } When { 37 | get("$url/hello") 38 | } Then { 39 | statusCode(200) 40 | } 41 | } 42 | 43 | @Test 44 | fun `cookies contains equalTo negative`() { 45 | wiremock.get { 46 | url equalTo "/hello" 47 | cookies contains "User-Agent" equalTo "curl" 48 | } returns { 49 | statusCode = 200 50 | } 51 | 52 | Given { 53 | cookie("User-Agent", "whatever") 54 | } When { 55 | get("$url/hello") 56 | } Then { 57 | statusCode(404) 58 | } 59 | } 60 | 61 | @Test 62 | fun `cookies contains equalTo positive`() { 63 | wiremock.get { 64 | url equalTo "/hello" 65 | cookies contains "User-Agent" equalTo "curl" 66 | } returns { 67 | statusCode = 200 68 | } 69 | 70 | Given { 71 | cookie("User-Agent", "curl") 72 | } When { 73 | get("$url/hello") 74 | } Then { 75 | statusCode(200) 76 | } 77 | } 78 | 79 | @Test 80 | fun `cookies contains like positive`() { 81 | wiremock.get { 82 | url equalTo "/hello" 83 | cookies contains "User-Agent" like "cu.*" 84 | } returns { 85 | statusCode = 200 86 | } 87 | 88 | Given { 89 | cookie("User-Agent", "curl") 90 | } When { 91 | get("$url/hello") 92 | } Then { 93 | statusCode(200) 94 | } 95 | } 96 | 97 | @Test 98 | fun `cookies contains like negative`() { 99 | wiremock.get { 100 | url equalTo "/hello" 101 | cookies contains "User-Agent" like "cur.." 102 | } returns { 103 | statusCode = 200 104 | } 105 | 106 | Given { 107 | cookie("User-Agent", "curl") 108 | } When { 109 | get("$url/hello") 110 | } Then { 111 | statusCode(404) 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/RequestHeadersTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import io.restassured.module.kotlin.extensions.Given 4 | import io.restassured.module.kotlin.extensions.Then 5 | import io.restassured.module.kotlin.extensions.When 6 | import org.junit.jupiter.api.Test 7 | 8 | class RequestHeadersTest : AbstractTest() { 9 | @Test 10 | fun `headers contains negative`() { 11 | wiremock.get { 12 | url equalTo "/hello" 13 | headers contains "any" 14 | } returns { 15 | statusCode = 200 16 | } 17 | 18 | When { 19 | get("$url/hello") 20 | } Then { 21 | statusCode(404) 22 | } 23 | } 24 | 25 | @Test 26 | fun `headers contains positive`() { 27 | wiremock.get { 28 | url equalTo "/hello" 29 | headers contains "User-Agent" 30 | } returns { 31 | statusCode = 200 32 | } 33 | 34 | Given { 35 | header("User-Agent", "whatever") 36 | } When { 37 | get("$url/hello") 38 | } Then { 39 | statusCode(200) 40 | } 41 | } 42 | 43 | @Test 44 | fun `headers contains equalTo negative`() { 45 | wiremock.get { 46 | url equalTo "/hello" 47 | headers contains "User-Agent" equalTo "curl" 48 | } returns { 49 | statusCode = 200 50 | } 51 | 52 | Given { 53 | header("User-Agent", "whatever") 54 | } When { 55 | get("$url/hello") 56 | } Then { 57 | statusCode(404) 58 | } 59 | } 60 | 61 | @Test 62 | fun `headers contains equalTo positive`() { 63 | wiremock.get { 64 | url equalTo "/hello" 65 | headers contains "User-Agent" equalTo "curl" 66 | } returns { 67 | statusCode = 200 68 | } 69 | 70 | Given { 71 | header("User-Agent", "curl") 72 | } When { 73 | get("$url/hello") 74 | } Then { 75 | statusCode(200) 76 | } 77 | } 78 | 79 | @Test 80 | fun `headers contains like positive`() { 81 | wiremock.get { 82 | url equalTo "/hello" 83 | headers contains "User-Agent" like "cu.*" 84 | } returns { 85 | statusCode = 200 86 | } 87 | 88 | Given { 89 | header("User-Agent", "curl") 90 | } When { 91 | get("$url/hello") 92 | } Then { 93 | statusCode(200) 94 | } 95 | } 96 | 97 | @Test 98 | fun `headers contains like negative`() { 99 | wiremock.get { 100 | url equalTo "/hello" 101 | headers contains "User-Agent" like "cur.." 102 | } returns { 103 | statusCode = 200 104 | } 105 | 106 | Given { 107 | header("User-Agent", "curl") 108 | } When { 109 | get("$url/hello") 110 | } Then { 111 | statusCode(404) 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/WireMockInstance.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.WireMockServer 4 | import com.github.tomakehurst.wiremock.client.CountMatchingStrategy 5 | import com.github.tomakehurst.wiremock.client.MappingBuilder 6 | import com.github.tomakehurst.wiremock.client.WireMock 7 | import com.github.tomakehurst.wiremock.junit.DslWrapper 8 | import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder 9 | import com.github.tomakehurst.wiremock.stubbing.StubMapping 10 | import java.util.UUID 11 | 12 | interface WireMockInstance { 13 | fun stubFor(mappingBuilder: MappingBuilder): StubMapping 14 | fun removeStubMapping(stubMapping: StubMapping) 15 | fun getSingleStubMapping(uuid: UUID): StubMapping 16 | fun verify(countMatchingStrategy: CountMatchingStrategy, requestPatternBuilder: RequestPatternBuilder) 17 | } 18 | 19 | object WiremockDefaultInstance : WireMockInstance { 20 | override fun stubFor(mappingBuilder: MappingBuilder) = WireMock.stubFor(mappingBuilder) 21 | override fun removeStubMapping(stubMapping: StubMapping) = WireMock.removeStub(stubMapping) 22 | override fun getSingleStubMapping(uuid: UUID) = WireMock.getSingleStubMapping(uuid) 23 | override fun verify(countMatchingStrategy: CountMatchingStrategy, requestPatternBuilder: RequestPatternBuilder) = 24 | WireMock.verify(countMatchingStrategy, requestPatternBuilder) 25 | } 26 | 27 | class WiremockServerInstance(private val wireMockServer: WireMockServer) : WireMockInstance { 28 | override fun stubFor(mappingBuilder: MappingBuilder) = wireMockServer.stubFor(mappingBuilder) 29 | override fun removeStubMapping(stubMapping: StubMapping) = wireMockServer.removeStub(stubMapping) 30 | override fun getSingleStubMapping(uuid: UUID) = wireMockServer.getSingleStubMapping(uuid) 31 | override fun verify(countMatchingStrategy: CountMatchingStrategy, requestPatternBuilder: RequestPatternBuilder) = 32 | wireMockServer.verify(countMatchingStrategy, requestPatternBuilder) 33 | } 34 | 35 | class WiremockClientInstance(private val wireMock: WireMock) : WireMockInstance { 36 | override fun stubFor(mappingBuilder: MappingBuilder) = wireMock.register(mappingBuilder) 37 | override fun removeStubMapping(stubMapping: StubMapping) = wireMock.removeStubMapping(stubMapping) 38 | override fun getSingleStubMapping(uuid: UUID) = wireMock.getStubMapping(uuid).item 39 | override fun verify(countMatchingStrategy: CountMatchingStrategy, requestPatternBuilder: RequestPatternBuilder) = 40 | wireMock.verifyThat(countMatchingStrategy, requestPatternBuilder) 41 | } 42 | 43 | class WiremockDslWrapperInstance(private val dslWrapper: DslWrapper) : WireMockInstance { 44 | override fun stubFor(mappingBuilder: MappingBuilder) = dslWrapper.stubFor(mappingBuilder) 45 | override fun removeStubMapping(stubMapping: StubMapping) = dslWrapper.removeStub(stubMapping) 46 | override fun getSingleStubMapping(uuid: UUID) = dslWrapper.getSingleStubMapping(uuid) 47 | override fun verify(countMatchingStrategy: CountMatchingStrategy, requestPatternBuilder: RequestPatternBuilder) = 48 | dslWrapper.verify(countMatchingStrategy, requestPatternBuilder) 49 | } 50 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/VerifySpecification.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.client.CountMatchingStrategy 4 | import com.github.tomakehurst.wiremock.client.WireMock 5 | import com.github.tomakehurst.wiremock.client.WireMock.exactly 6 | import com.github.tomakehurst.wiremock.client.WireMock.lessThanOrExactly 7 | import com.github.tomakehurst.wiremock.client.WireMock.moreThanOrExactly 8 | import com.github.tomakehurst.wiremock.http.RequestMethod 9 | import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder 10 | import com.github.tomakehurst.wiremock.matching.UrlPathPattern 11 | import com.github.tomakehurst.wiremock.matching.UrlPattern 12 | 13 | class VerifySpecification { 14 | var method = RequestMethod.ANY 15 | val urlPath = Whatever.wrap(StringConstraint::class) 16 | val url = Whatever.wrap(StringConstraint::class) 17 | val headers: MutableMap = mutableMapOf() 18 | val body: MutableMap = mutableMapOf() 19 | val cookies: MutableMap = mutableMapOf() 20 | val queryParams: MutableMap = mutableMapOf() 21 | var exactly: Int? = null 22 | var atLeast: Int? = null 23 | var atMost: Int? = null 24 | private val builders: MutableList Unit> = mutableListOf() 25 | 26 | fun withBuilder(block: RequestPatternBuilder.() -> Unit) { 27 | builders.add(block) 28 | } 29 | 30 | internal fun toCountMatchingStrategyList(): List { 31 | val countMatchingStrategyList = listOfNotNull( 32 | if (exactly != null) exactly(exactly!!) else null, 33 | if (atLeast != null) moreThanOrExactly(atLeast!!) else null, 34 | if (atMost != null) lessThanOrExactly(atMost!!) else null 35 | ) 36 | return countMatchingStrategyList.ifEmpty { listOf(moreThanOrExactly(1)) } 37 | } 38 | 39 | internal fun toRequestPatternBuilder(): RequestPatternBuilder { 40 | val requestPatternBuilder = RequestPatternBuilder(method, urlBuilder()) 41 | headers.forEach { requestPatternBuilder.withHeader(it.key, getStringValuePattern(it.value)) } 42 | cookies.forEach { requestPatternBuilder.withCookie(it.key, getStringValuePattern(it.value)) } 43 | queryParams.forEach { requestPatternBuilder.withQueryParam(it.key, getStringValuePattern(it.value)) } 44 | body.toStringValuePatterns().forEach { requestPatternBuilder.withRequestBody(it) } 45 | builders.forEach { requestPatternBuilder.it() } 46 | return requestPatternBuilder 47 | } 48 | 49 | private fun urlBuilder(): UrlPattern = when (val url = url.value) { 50 | is EqualTo -> WireMock.urlEqualTo(url.value) 51 | is Like -> WireMock.urlMatching(url.value) 52 | is NotLike -> UrlPattern(WireMock.notMatching(url.value), true) 53 | is Whatever -> urlPathBuilder() 54 | } 55 | 56 | private fun urlPathBuilder(): UrlPattern = 57 | when (val urlPath = urlPath.value) { 58 | is EqualTo -> WireMock.urlPathEqualTo(urlPath.value) 59 | is Like -> WireMock.urlPathMatching(urlPath.value) 60 | is NotLike -> UrlPathPattern(WireMock.notMatching(urlPath.value), true) 61 | is Whatever -> WireMock.urlPathMatching(".*") 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/RequestOtherMethodsTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import io.restassured.http.Method 4 | import io.restassured.module.kotlin.extensions.Given 5 | import io.restassured.module.kotlin.extensions.Then 6 | import io.restassured.module.kotlin.extensions.When 7 | import org.junit.jupiter.api.Test 8 | 9 | class RequestOtherMethodsTest : AbstractTest() { 10 | @Test 11 | fun `put method`() { 12 | wiremock.put { 13 | url equalTo "/hello" 14 | body contains "pet" equalTo "dog" 15 | } returnsJson { } 16 | 17 | Given { 18 | body(//language=JSON 19 | """ 20 | {"pet":"dog"} 21 | """ 22 | ) 23 | } When { 24 | put("$url/hello") 25 | } Then { 26 | statusCode(200) 27 | } 28 | } 29 | 30 | @Test 31 | fun `patch method`() { 32 | wiremock.patch { 33 | url equalTo "/hello" 34 | body contains "pet" equalTo "dog" 35 | } returnsJson { } 36 | 37 | Given { 38 | body(//language=JSON 39 | """ 40 | {"pet":"dog"} 41 | """ 42 | ) 43 | } When { 44 | patch("$url/hello") 45 | } Then { 46 | statusCode(200) 47 | } 48 | } 49 | 50 | @Test 51 | fun `options method`() { 52 | wiremock.options { 53 | url equalTo "/hello" 54 | body contains "pet" equalTo "dog" 55 | } returnsJson { } 56 | 57 | Given { 58 | body(//language=JSON 59 | """ 60 | {"pet":"dog"} 61 | """ 62 | ) 63 | } When { 64 | options("$url/hello") 65 | } Then { 66 | statusCode(200) 67 | } 68 | } 69 | 70 | @Test 71 | fun `head method`() { 72 | wiremock.head { 73 | url equalTo "/hello" 74 | body contains "pet" equalTo "dog" 75 | } returnsJson { } 76 | 77 | Given { 78 | body(//language=JSON 79 | """ 80 | {"pet":"dog"} 81 | """ 82 | ) 83 | } When { 84 | head("$url/hello") 85 | } Then { 86 | statusCode(200) 87 | } 88 | } 89 | 90 | @Test 91 | fun `delete method`() { 92 | wiremock.delete { 93 | url equalTo "/hello" 94 | body contains "pet" equalTo "dog" 95 | } returnsJson { } 96 | 97 | Given { 98 | body(//language=JSON 99 | """ 100 | {"pet":"dog"} 101 | """ 102 | ) 103 | } When { 104 | delete("$url/hello") 105 | } Then { 106 | statusCode(200) 107 | } 108 | } 109 | 110 | @Test 111 | fun `trace method`() { 112 | wiremock.trace { 113 | url equalTo "/hello" 114 | body contains "pet" equalTo "dog" 115 | } returnsJson { } 116 | 117 | Given { 118 | body(//language=JSON 119 | """ 120 | {"pet":"dog"} 121 | """ 122 | ) 123 | } When { 124 | request(Method.TRACE, "$url/hello") 125 | } Then { 126 | statusCode(200) 127 | } 128 | } 129 | 130 | @Test 131 | fun `delete and patch negative`() { 132 | wiremock.delete { 133 | url equalTo "/hello" 134 | body contains "pet" equalTo "dog" 135 | } returnsJson { } 136 | 137 | Given { 138 | body(//language=JSON 139 | """ 140 | {"pet":"dog"} 141 | """ 142 | ) 143 | } When { 144 | patch("$url/hello") 145 | } Then { 146 | statusCode(404) 147 | } 148 | } 149 | 150 | @Test 151 | fun `any method`() { 152 | wiremock.any { 153 | url equalTo "/hello" 154 | body contains "pet" equalTo "dog" 155 | } returnsJson { } 156 | 157 | Given { 158 | body(//language=JSON 159 | """ 160 | {"pet":"dog"} 161 | """ 162 | ) 163 | } When { 164 | patch("$url/hello") 165 | } Then { 166 | statusCode(200) 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/RequestQueryParamsTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import io.restassured.module.kotlin.extensions.Given 4 | import io.restassured.module.kotlin.extensions.Then 5 | import io.restassured.module.kotlin.extensions.When 6 | import org.junit.jupiter.api.Test 7 | 8 | class RequestQueryParamsTest : AbstractTest() { 9 | @Test 10 | fun `queryParams contains negative`() { 11 | wiremock.get { 12 | urlPath equalTo "/hello" 13 | queryParams contains "any" 14 | } returns { 15 | statusCode = 200 16 | } 17 | 18 | When { 19 | get("$url/hello") 20 | } Then { 21 | statusCode(404) 22 | } 23 | } 24 | 25 | @Test 26 | fun `queryParams contains negative2`() { 27 | wiremock.get { 28 | urlPath equalTo "/hello2" 29 | queryParams contains "filter" 30 | } returns { 31 | statusCode = 200 32 | } 33 | When { 34 | get("$url/hello?filter=true") 35 | } Then { 36 | statusCode(404) 37 | } 38 | } 39 | 40 | @Test 41 | fun `queryParams precedence`() { 42 | wiremock.get { 43 | urlPath equalTo "/hello" 44 | url equalTo "/hello" 45 | queryParams contains "filter" 46 | } returns { 47 | statusCode = 200 48 | } 49 | When { 50 | get("$url/hello?filter=true") 51 | } Then { 52 | statusCode(404) 53 | } 54 | } 55 | 56 | @Test 57 | fun `queryParams contains equalTo negative`() { 58 | wiremock.get { 59 | urlPath equalTo "/hello" 60 | queryParams contains "filter" equalTo "true" 61 | } returns { 62 | statusCode = 200 63 | } 64 | 65 | When { 66 | get("$url/hello?filter=false") 67 | } Then { 68 | statusCode(404) 69 | } 70 | } 71 | 72 | @Test 73 | fun `queryParams contains equalTo positive`() { 74 | wiremock.get { 75 | urlPath equalTo "/hello" 76 | queryParams contains "filter" equalTo "true" 77 | } returns { 78 | statusCode = 200 79 | } 80 | 81 | When { 82 | get("$url/hello?filter=true") 83 | } Then { 84 | statusCode(200) 85 | } 86 | } 87 | 88 | @Test 89 | fun `queryParams contains like positive`() { 90 | wiremock.get { 91 | urlPath equalTo "/hello" 92 | queryParams contains "filter" like "[rute]*" 93 | } returns { 94 | statusCode = 200 95 | } 96 | 97 | Given { 98 | queryParam("filter", "true") 99 | } When { 100 | get("$url/hello") 101 | } Then { 102 | statusCode(200) 103 | } 104 | } 105 | 106 | @Test 107 | fun `queryParams contains like negative`() { 108 | wiremock.get { 109 | urlPath equalTo "/hello" 110 | queryParams contains "filter" like "[tru]*" 111 | } returns { 112 | statusCode = 200 113 | } 114 | 115 | Given { 116 | queryParam("filter", "true") 117 | } When { 118 | get("$url/hello") 119 | } Then { 120 | statusCode(404) 121 | } 122 | } 123 | 124 | 125 | @Test 126 | fun `urlPathLike`() { 127 | wiremock.get { 128 | urlPath like "/hell.*" 129 | } returns { 130 | statusCode = 200 131 | } 132 | 133 | When { 134 | get("$url/hello") 135 | } Then { 136 | statusCode(200) 137 | } 138 | } 139 | 140 | @Test 141 | fun `urlPathLike negative`() { 142 | wiremock.get { 143 | urlPath notLike "/hel.{1}" 144 | } returns { 145 | statusCode = 200 146 | } 147 | 148 | When { 149 | get("$url/hello") 150 | } Then { 151 | statusCode(200) 152 | } 153 | } 154 | 155 | @Test 156 | fun `onlyQueryParams`() { 157 | wiremock.post { 158 | queryParams contains "filter" 159 | } returns { 160 | statusCode = 200 161 | } 162 | 163 | When { 164 | post("$url/whatever?filter=true") 165 | } Then { 166 | statusCode(200) 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/RequestSpecification.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.client.MappingBuilder 4 | import com.github.tomakehurst.wiremock.client.WireMock.notMatching 5 | import com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo 6 | import com.github.tomakehurst.wiremock.client.WireMock.urlMatching 7 | import com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo 8 | import com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching 9 | import com.github.tomakehurst.wiremock.matching.UrlPathPattern 10 | import com.github.tomakehurst.wiremock.matching.UrlPattern 11 | import com.github.tomakehurst.wiremock.stubbing.Scenario 12 | 13 | class RequestSpecification { 14 | var whenState: String? = null 15 | var toState: String? = null 16 | var clearState: Boolean = false 17 | var priority = 1 18 | val urlPath = Whatever.wrap(StringConstraint::class) 19 | val url = Whatever.wrap(StringConstraint::class) 20 | val headers: MutableMap = mutableMapOf() 21 | val body: MutableMap = mutableMapOf() 22 | val cookies: MutableMap = mutableMapOf() 23 | val queryParams: MutableMap = mutableMapOf() 24 | private val builders: MutableList Unit> = mutableListOf() 25 | 26 | fun withBuilder(block: MappingBuilder.() -> Unit) { 27 | builders.add(block) 28 | } 29 | 30 | @SuppressWarnings("ComplexMethod") 31 | internal fun toMappingBuilder(method: Method): MappingBuilder = 32 | urlBuilder(method) 33 | .also { headersBuilder(it) } 34 | .also { bodyBuilder(it) } 35 | .also { cookieBuilder(it) } 36 | .also { queryParamsBuilder(it) } 37 | .also { it.atPriority(priority) } 38 | .also { scenarioBuilder(it) } 39 | .also { this.builders.forEach { b -> it.b() } } 40 | 41 | 42 | private fun scenarioBuilder(it: MappingBuilder) { 43 | val newState = toState ?: if (clearState) Scenario.STARTED else whenState 44 | if (newState != null || toState != null || clearState) { 45 | it.inScenario("default") 46 | .whenScenarioStateIs(whenState ?: Scenario.STARTED) 47 | .willSetStateTo(newState) 48 | } 49 | } 50 | 51 | private fun urlBuilder(method: Method): MappingBuilder = when (val url = url.value) { 52 | is EqualTo -> method(urlEqualTo(url.value)) 53 | is Like -> method(urlMatching(url.value)) 54 | is NotLike -> method(UrlPattern(notMatching(url.value), true)) 55 | is Whatever -> urlPathBuilder(method) 56 | } 57 | 58 | private fun urlPathBuilder(method: Method): MappingBuilder = 59 | when (val urlPath = urlPath.value) { 60 | is EqualTo -> method(urlPathEqualTo(urlPath.value)) 61 | is Like -> method(urlPathMatching(urlPath.value)) 62 | is NotLike -> method(UrlPathPattern(notMatching(urlPath.value), true)) 63 | is Whatever -> method(urlPathMatching(".*")) 64 | } 65 | 66 | private fun headersBuilder(mappingBuilder: MappingBuilder) { 67 | headers.forEach { 68 | mappingBuilder.withHeader( 69 | it.key, 70 | getStringValuePattern(it.value) 71 | ) 72 | } 73 | } 74 | 75 | private fun queryParamsBuilder(mappingBuilder: MappingBuilder) { 76 | queryParams.forEach { 77 | mappingBuilder.withQueryParam( 78 | it.key, 79 | getStringValuePattern(it.value) 80 | ) 81 | } 82 | } 83 | 84 | private fun bodyBuilder(mappingBuilder: MappingBuilder) { 85 | body.toStringValuePatterns() 86 | .forEach { mappingBuilder.withRequestBody(it) } 87 | } 88 | 89 | private fun cookieBuilder(mappingBuilder: MappingBuilder) { 90 | cookies.forEach { 91 | mappingBuilder.withCookie( 92 | it.key, 93 | getStringValuePattern(it.value) 94 | ) 95 | } 96 | } 97 | 98 | 99 | companion object { 100 | internal fun create(specifyRequestList: List): RequestSpecification { 101 | val requestSpecification = RequestSpecification() 102 | specifyRequestList.forEach { it(requestSpecification) } 103 | return requestSpecification 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/RequestOtherMethodsExtensionTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo 4 | import com.github.tomakehurst.wiremock.junit5.WireMockTest 5 | import io.restassured.http.Method 6 | import io.restassured.module.kotlin.extensions.Given 7 | import io.restassured.module.kotlin.extensions.Then 8 | import io.restassured.module.kotlin.extensions.When 9 | import org.junit.jupiter.api.BeforeEach 10 | import org.junit.jupiter.api.Test 11 | 12 | @WireMockTest 13 | class RequestOtherMethodsExtensionTest { 14 | 15 | lateinit var url: String 16 | 17 | @BeforeEach 18 | fun urlSetup(wmRuntimeInfo: WireMockRuntimeInfo) { 19 | url = wmRuntimeInfo.httpBaseUrl 20 | } 21 | 22 | @Test 23 | fun `put method`() { 24 | mockPut { 25 | url equalTo "/hello" 26 | body contains "pet" equalTo "dog" 27 | } returnsJson { } 28 | 29 | Given { 30 | body(//language=JSON 31 | """ 32 | {"pet":"dog"} 33 | """ 34 | ) 35 | } When { 36 | put("$url/hello") 37 | } Then { 38 | statusCode(200) 39 | } 40 | } 41 | 42 | @Test 43 | fun `patch method`() { 44 | mockPatch { 45 | url equalTo "/hello" 46 | body contains "pet" equalTo "dog" 47 | } returnsJson { } 48 | 49 | Given { 50 | body(//language=JSON 51 | """ 52 | {"pet":"dog"} 53 | """ 54 | ) 55 | } When { 56 | patch("$url/hello") 57 | } Then { 58 | statusCode(200) 59 | } 60 | } 61 | 62 | @Test 63 | fun `options method`() { 64 | mockOptions { 65 | url equalTo "/hello" 66 | body contains "pet" equalTo "dog" 67 | } returnsJson { } 68 | 69 | Given { 70 | body(//language=JSON 71 | """ 72 | {"pet":"dog"} 73 | """ 74 | ) 75 | } When { 76 | options("$url/hello") 77 | } Then { 78 | statusCode(200) 79 | } 80 | } 81 | 82 | @Test 83 | fun `head method`() { 84 | mockHead { 85 | url equalTo "/hello" 86 | body contains "pet" equalTo "dog" 87 | } returnsJson { } 88 | 89 | Given { 90 | body(//language=JSON 91 | """ 92 | {"pet":"dog"} 93 | """ 94 | ) 95 | } When { 96 | head("$url/hello") 97 | } Then { 98 | statusCode(200) 99 | } 100 | } 101 | 102 | @Test 103 | fun `delete method`() { 104 | mockDelete { 105 | url equalTo "/hello" 106 | body contains "pet" equalTo "dog" 107 | } returnsJson { } 108 | 109 | Given { 110 | body(//language=JSON 111 | """ 112 | {"pet":"dog"} 113 | """ 114 | ) 115 | } When { 116 | delete("$url/hello") 117 | } Then { 118 | statusCode(200) 119 | } 120 | } 121 | 122 | @Test 123 | fun `trace method`() { 124 | mockTrace { 125 | url equalTo "/hello" 126 | body contains "pet" equalTo "dog" 127 | } returnsJson { } 128 | 129 | Given { 130 | body(//language=JSON 131 | """ 132 | {"pet":"dog"} 133 | """ 134 | ) 135 | } When { 136 | request(Method.TRACE, "$url/hello") 137 | } Then { 138 | statusCode(200) 139 | } 140 | } 141 | 142 | @Test 143 | fun `delete and patch negative`() { 144 | mockDelete { 145 | url equalTo "/hello" 146 | body contains "pet" equalTo "dog" 147 | } returnsJson { } 148 | 149 | Given { 150 | body(//language=JSON 151 | """ 152 | {"pet":"dog"} 153 | """ 154 | ) 155 | } When { 156 | patch("$url/hello") 157 | } Then { 158 | statusCode(404) 159 | } 160 | } 161 | 162 | @Test 163 | fun `any method`() { 164 | mockAny { 165 | url equalTo "/hello" 166 | body contains "pet" equalTo "dog" 167 | } returnsJson { } 168 | 169 | Given { 170 | body(//language=JSON 171 | """ 172 | {"pet":"dog"} 173 | """ 174 | ) 175 | } When { 176 | patch("$url/hello") 177 | } Then { 178 | statusCode(200) 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /kotlin-wiremock-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | com.marcinziolo 8 | kotlin-wiremock-examples 9 | 1.0-SNAPSHOT 10 | 11 | kotlin-wiremock-examples 12 | 13 | http://www.example.com 14 | 15 | 16 | UTF-8 17 | 1.7 18 | 1.7 19 | 1.6.0 20 | 4.3.0 21 | 22 | 23 | 24 | 25 | org.jetbrains.kotlin 26 | kotlin-stdlib 27 | ${kotlin.version} 28 | 29 | 30 | 31 | com.marcinziolo 32 | kotlin-wiremock 33 | 1.0.0 34 | 35 | 36 | 37 | io.rest-assured 38 | rest-assured 39 | ${rest-assured.version} 40 | 41 | 42 | 43 | io.rest-assured 44 | json-path 45 | ${rest-assured.version} 46 | 47 | 48 | 49 | io.rest-assured 50 | kotlin-extensions 51 | ${rest-assured.version} 52 | 53 | 54 | 55 | junit 56 | junit 57 | 4.13.1 58 | test 59 | 60 | 61 | 62 | 63 | ${project.basedir}/src/main/java 64 | ${project.basedir}/src/test/kotlin 65 | 66 | 67 | org.apache.maven.plugins 68 | maven-surefire-plugin 69 | 2.22.1 70 | 71 | 72 | 73 | kotlin-maven-plugin 74 | org.jetbrains.kotlin 75 | ${kotlin.version} 76 | 77 | 78 | 79 | compile 80 | 81 | compile 82 | 83 | 84 | 85 | 86 | test-compile 87 | 88 | test-compile 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | maven-clean-plugin 101 | 3.1.0 102 | 103 | 104 | 105 | maven-resources-plugin 106 | 3.0.2 107 | 108 | 109 | maven-compiler-plugin 110 | 3.8.0 111 | 112 | 113 | maven-surefire-plugin 114 | 2.22.1 115 | 116 | 117 | maven-jar-plugin 118 | 3.0.2 119 | 120 | 121 | maven-install-plugin 122 | 2.5.2 123 | 124 | 125 | maven-deploy-plugin 126 | 2.8.2 127 | 128 | 129 | 130 | maven-site-plugin 131 | 3.7.1 132 | 133 | 134 | maven-project-info-reports-plugin 135 | 3.0.0 136 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/ExampleExtensionTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo 4 | import com.github.tomakehurst.wiremock.junit5.WireMockTest 5 | import io.restassured.module.kotlin.extensions.Given 6 | import io.restassured.module.kotlin.extensions.Then 7 | import io.restassured.module.kotlin.extensions.When 8 | import org.hamcrest.Matchers.equalTo 9 | import org.junit.jupiter.api.BeforeEach 10 | import org.junit.jupiter.api.Test 11 | 12 | @WireMockTest 13 | class ExampleExtensionTest { 14 | 15 | lateinit var url: String 16 | 17 | @BeforeEach 18 | fun urlSetup(wmRuntimeInfo: WireMockRuntimeInfo) { 19 | url = wmRuntimeInfo.httpBaseUrl 20 | } 21 | 22 | @Test 23 | fun `url equalTo`() { 24 | mockGet { 25 | url equalTo "/users/1" 26 | } returns { 27 | header = "Content-Type" to "application/json" 28 | statusCode = 200 29 | body = """ 30 | { 31 | "id": 1, 32 | "name": "Bob" 33 | } 34 | """ 35 | } 36 | 37 | When { 38 | get("$url/users/1") 39 | } Then { 40 | statusCode(200) 41 | body("id", equalTo(1)) 42 | body("name", equalTo("Bob")) 43 | } 44 | } 45 | 46 | @Test 47 | fun `returns json`() { 48 | mockGet { 49 | url like "/users/.*" 50 | } returnsJson { 51 | body = """ 52 | { 53 | "id": 1, 54 | "name": "Bob" 55 | } 56 | """ 57 | } 58 | 59 | When { 60 | get("$url/users/1") 61 | } Then { 62 | statusCode(200) 63 | body("id", equalTo(1)) 64 | body("name", equalTo("Bob")) 65 | } 66 | } 67 | 68 | val bobResponse: SpecifyResponse = { 69 | body = """ 70 | { 71 | "id": 1, 72 | "name": "Bob" 73 | } 74 | """ 75 | } 76 | 77 | val aliceResponse: SpecifyResponse = { 78 | body = """ 79 | { 80 | "id": 2, 81 | "name": "Alice" 82 | } 83 | """ 84 | } 85 | @Test 86 | 87 | fun `body checking`() { 88 | mockPost { 89 | url equalTo "/users" 90 | body contains "id" equalTo 1 91 | body contains "isAdmin" equalTo true 92 | body contains "points" equalTo 3.0 93 | } returnsJson bobResponse 94 | 95 | Given { 96 | body(//language=JSON 97 | """ 98 | { 99 | "id": 1, 100 | "isAdmin": true, 101 | "points": 3.0 102 | } 103 | """ 104 | ) 105 | } When { 106 | post("$url/users") 107 | } Then { 108 | statusCode(200) 109 | body("id", equalTo(1)) 110 | body("name", equalTo("Bob")) 111 | } 112 | } 113 | 114 | @Test 115 | fun `and`() { 116 | mockPost { 117 | url equalTo "/users" 118 | } and { 119 | body contains "id" equalTo 1 120 | } and { 121 | body contains "isAdmin" equalTo true 122 | } returns { 123 | header = "Content-Type" to "application/json" 124 | } and bobResponse and { 125 | statusCode = 201 126 | } 127 | 128 | Given { 129 | body(//language=JSON 130 | """ 131 | { 132 | "id": 1, 133 | "isAdmin": true 134 | } 135 | """ 136 | ) 137 | } When { 138 | post("$url/users") 139 | } Then { 140 | statusCode(201) 141 | body("id", equalTo(1)) 142 | body("name", equalTo("Bob")) 143 | } 144 | } 145 | 146 | @Test 147 | fun `delay`() { 148 | mockPost { 149 | url equalTo "/users" 150 | } returnsJson { 151 | delay fixedMs 100 152 | delay medianMs 100 sigma 0.1 153 | } and bobResponse 154 | 155 | Given { 156 | body(//language=JSON 157 | """ 158 | { 159 | "id": 1, 160 | "isAdmin": true 161 | } 162 | """ 163 | ) 164 | } When { 165 | post("$url/users") 166 | } Then { 167 | statusCode(200) 168 | body("id", equalTo(1)) 169 | body("name", equalTo("Bob")) 170 | } 171 | } 172 | 173 | @Test 174 | fun `scenarios`() { 175 | mockPost { 176 | url equalTo "/users" 177 | } returnsJson bobResponse and { 178 | toState = "Alice" 179 | } 180 | 181 | mockPost { 182 | url equalTo "/users" 183 | whenState = "Alice" 184 | } returnsJson aliceResponse and { 185 | clearState = true 186 | } 187 | 188 | When { 189 | post("$url/users") 190 | } Then { 191 | body("name", equalTo("Bob")) 192 | } 193 | 194 | When { 195 | post("$url/users") 196 | } Then { 197 | body("name", equalTo("Alice")) 198 | } 199 | 200 | When { 201 | post("$url/users") 202 | } Then { 203 | body("name", equalTo("Bob")) 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/ExampleTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import io.restassured.module.kotlin.extensions.Given 4 | import io.restassured.module.kotlin.extensions.Then 5 | import io.restassured.module.kotlin.extensions.When 6 | import org.hamcrest.Matchers.equalTo 7 | import org.junit.jupiter.api.Test 8 | 9 | class ExampleTest : AbstractTest() { 10 | @Test 11 | fun `url equalTo`() { 12 | wiremock.get { 13 | url equalTo "/users/1" 14 | } returns { 15 | header = "Content-Type" to "application/json" 16 | statusCode = 200 17 | body = """ 18 | { 19 | "id": 1, 20 | "name": "Bob" 21 | } 22 | """ 23 | } 24 | 25 | When { 26 | get("$url/users/1") 27 | } Then { 28 | statusCode(200) 29 | body("id", equalTo(1)) 30 | body("name", equalTo("Bob")) 31 | } 32 | 33 | wiremock.verify { 34 | url equalTo "/users/1" 35 | exactly = 1 36 | } 37 | } 38 | 39 | @Test 40 | fun `returns json`() { 41 | wiremock.get { 42 | url like "/users/.*" 43 | } returnsJson { 44 | body = """ 45 | { 46 | "id": 1, 47 | "name": "Bob" 48 | } 49 | """ 50 | } 51 | 52 | When { 53 | get("$url/users/1") 54 | } Then { 55 | statusCode(200) 56 | body("id", equalTo(1)) 57 | body("name", equalTo("Bob")) 58 | } 59 | } 60 | 61 | val bobResponse: SpecifyResponse = { 62 | body = """ 63 | { 64 | "id": 1, 65 | "name": "Bob" 66 | } 67 | """ 68 | } 69 | 70 | val aliceResponse: SpecifyResponse = { 71 | body = """ 72 | { 73 | "id": 2, 74 | "name": "Alice" 75 | } 76 | """ 77 | } 78 | @Test 79 | 80 | fun `body checking`() { 81 | wiremock.post { 82 | url equalTo "/users" 83 | body contains "id" equalTo 1L 84 | body contains "isAdmin" equalTo true 85 | body contains "points" equalTo 3.0 86 | } returnsJson bobResponse 87 | 88 | Given { 89 | body(//language=JSON 90 | """ 91 | { 92 | "id": 1, 93 | "isAdmin": true, 94 | "points": 3.0 95 | } 96 | """ 97 | ) 98 | } When { 99 | post("$url/users") 100 | } Then { 101 | statusCode(200) 102 | body("id", equalTo(1)) 103 | body("name", equalTo("Bob")) 104 | } 105 | } 106 | 107 | @Test 108 | fun `queryParams`() { 109 | wiremock.get { 110 | urlPath equalTo "/hello" 111 | queryParams contains "filter" 112 | } returns { 113 | statusCode = 200 114 | } 115 | When { 116 | get("$url/hello?filter=true") 117 | } Then { 118 | statusCode(200) 119 | } 120 | } 121 | 122 | @Test 123 | fun `and`() { 124 | wiremock.post { 125 | url equalTo "/users" 126 | } and { 127 | body contains "id" equalTo 1 128 | } and { 129 | body contains "isAdmin" equalTo true 130 | } returns { 131 | header = "Content-Type" to "application/json" 132 | } and bobResponse and { 133 | statusCode = 201 134 | } 135 | 136 | Given { 137 | body(//language=JSON 138 | """ 139 | { 140 | "id": 1, 141 | "isAdmin": true 142 | } 143 | """ 144 | ) 145 | } When { 146 | post("$url/users") 147 | } Then { 148 | statusCode(201) 149 | body("id", equalTo(1)) 150 | body("name", equalTo("Bob")) 151 | } 152 | } 153 | 154 | @Test 155 | fun `delay`() { 156 | wiremock.post { 157 | url equalTo "/users" 158 | } returnsJson { 159 | delay fixedMs 100 160 | delay medianMs 100 sigma 0.1 161 | } and bobResponse 162 | 163 | Given { 164 | body(//language=JSON 165 | """ 166 | { 167 | "id": 1, 168 | "isAdmin": true 169 | } 170 | """ 171 | ) 172 | } When { 173 | post("$url/users") 174 | } Then { 175 | statusCode(200) 176 | body("id", equalTo(1)) 177 | body("name", equalTo("Bob")) 178 | } 179 | } 180 | 181 | @Test 182 | fun `scenarios`() { 183 | wiremock.post { 184 | url equalTo "/users" 185 | } returnsJson bobResponse and { 186 | toState = "Alice" 187 | } 188 | 189 | wiremock.post { 190 | url equalTo "/users" 191 | whenState = "Alice" 192 | } returnsJson aliceResponse and { 193 | clearState = true 194 | } 195 | 196 | When { 197 | post("$url/users") 198 | } Then { 199 | body("name", equalTo("Bob")) 200 | } 201 | 202 | When { 203 | post("$url/users") 204 | } Then { 205 | body("name", equalTo("Alice")) 206 | } 207 | 208 | When { 209 | post("$url/users") 210 | } Then { 211 | body("name", equalTo("Bob")) 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/RequestPostTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import io.restassured.module.kotlin.extensions.Given 4 | import io.restassured.module.kotlin.extensions.Then 5 | import io.restassured.module.kotlin.extensions.When 6 | import org.junit.jupiter.api.Test 7 | 8 | class RequestPostTest : AbstractTest() { 9 | @Test 10 | fun `post body negative`() { 11 | wiremock.post { 12 | url equalTo "/hello" 13 | body contains "pet" equalTo "dog" 14 | } returnsJson { } 15 | 16 | When { 17 | post("$url/hello") 18 | } Then { 19 | statusCode(404) 20 | } 21 | } 22 | 23 | @Test 24 | fun `post body positive`() { 25 | wiremock.post { 26 | url equalTo "/hello" 27 | body contains "pet" equalTo "dog" 28 | } returnsJson { } 29 | 30 | Given { 31 | body(//language=JSON 32 | """ 33 | {"pet":"dog"} 34 | """ 35 | ) 36 | } When { 37 | post("$url/hello") 38 | } Then { 39 | statusCode(200) 40 | } 41 | } 42 | 43 | @Test 44 | fun `post body like positive`() { 45 | wiremock.post { 46 | url equalTo "/hello" 47 | body contains "pet" like "d.*" 48 | } returnsJson { } 49 | 50 | Given { 51 | body(//language=JSON 52 | """ 53 | {"pet":"doggy"} 54 | """ 55 | ) 56 | } When { 57 | post("$url/hello") 58 | } Then { 59 | statusCode(200) 60 | } 61 | } 62 | 63 | @Test 64 | fun `post body nested like positive`() { 65 | wiremock.post { 66 | url equalTo "/hello" 67 | body contains "pet.type" like "d.*" 68 | } returnsJson { } 69 | 70 | Given { 71 | body(//language=JSON 72 | """ 73 | {"pet":{"type":"doggy"}} 74 | """ 75 | ) 76 | } When { 77 | post("$url/hello") 78 | } Then { 79 | statusCode(200) 80 | } 81 | } 82 | 83 | @Test 84 | fun `post body contains`() { 85 | wiremock.post { 86 | url equalTo "/hello" 87 | body contains "pet.type" contains "ggy" 88 | } returnsJson { } 89 | 90 | Given { 91 | body(//language=JSON 92 | """ 93 | {"pet":{"type":"doggy"}} 94 | """ 95 | ) 96 | } When { 97 | post("$url/hello") 98 | } Then { 99 | statusCode(200) 100 | } 101 | } 102 | 103 | @Test 104 | fun `post body like negative`() { 105 | wiremock.post { 106 | url equalTo "/hello" 107 | body contains "pet" like "dog.+" 108 | } returnsJson { } 109 | 110 | Given { 111 | body(//language=JSON 112 | """ 113 | {"pet":"dog"} 114 | """ 115 | ) 116 | } When { 117 | post("$url/hello") 118 | } Then { 119 | statusCode(404) 120 | } 121 | } 122 | 123 | @Test 124 | fun `post body not like`() { 125 | wiremock.post { 126 | url equalTo "/hello" 127 | body contains "pet" notLike "dog.+" 128 | } returnsJson { } 129 | 130 | Given { 131 | body(//language=JSON 132 | """ 133 | {"pet":"dog"} 134 | """ 135 | ) 136 | } When { 137 | post("$url/hello") 138 | } Then { 139 | statusCode(200) 140 | } 141 | } 142 | 143 | @Test 144 | fun `post body contains just key`() { 145 | wiremock.post { 146 | url equalTo "/hello" 147 | body contains "pet" 148 | } returnsJson { } 149 | 150 | Given { 151 | body(//language=JSON 152 | """ 153 | {"pet":"dog"} 154 | """ 155 | ) 156 | } When { 157 | post("$url/hello") 158 | } Then { 159 | statusCode(200) 160 | } 161 | } 162 | 163 | @Test 164 | fun `body equal to`() { 165 | wiremock.post { 166 | url equalTo "/hello" 167 | body equalTo """ 168 | {"pet":"dog"} 169 | """ 170 | } returnsJson { } 171 | 172 | Given { 173 | body(//language=JSON 174 | """ 175 | {"pet":"dog"} 176 | """ 177 | ) 178 | } When { 179 | post("$url/hello") 180 | } Then { 181 | statusCode(200) 182 | } 183 | } 184 | 185 | @Test 186 | fun `body equal to negative`() { 187 | wiremock.post { 188 | url equalTo "/hello" 189 | body equalTo """ 190 | {"pet":"cat"} 191 | """ 192 | } returnsJson { } 193 | 194 | Given { 195 | body(//language=JSON 196 | """] 197 | {"pet":"dog"} 198 | """ 199 | ) 200 | } When { 201 | post("$url/hello") 202 | } Then { 203 | statusCode(404) 204 | } 205 | } 206 | 207 | @Test 208 | fun `body equal to negative mix`() { 209 | wiremock.post { 210 | url equalTo "/hello" 211 | body equalTo """ 212 | {"pet":"dog"} 213 | """ 214 | body contains "pet" equalTo "cat" 215 | } returnsJson { } 216 | 217 | Given { 218 | body(//language=JSON 219 | """ 220 | {"pet":"dog"} 221 | """ 222 | ) 223 | } When { 224 | post("$url/hello") 225 | } Then { 226 | statusCode(404) 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src/test/kotlin/com/marcinziolo/kotlin/wiremock/VerifyTest.kt: -------------------------------------------------------------------------------- 1 | package com.marcinziolo.kotlin.wiremock 2 | 3 | import com.github.tomakehurst.wiremock.client.VerificationException 4 | import com.github.tomakehurst.wiremock.core.WireMockConfiguration 5 | import com.github.tomakehurst.wiremock.http.RequestMethod 6 | import com.github.tomakehurst.wiremock.junit5.WireMockExtension 7 | import io.restassured.module.kotlin.extensions.Given 8 | import io.restassured.module.kotlin.extensions.Then 9 | import io.restassured.module.kotlin.extensions.When 10 | import org.junit.jupiter.api.Test 11 | import org.junit.jupiter.api.assertThrows 12 | import org.junit.jupiter.api.extension.RegisterExtension 13 | 14 | class VerifyTest { 15 | 16 | @JvmField 17 | @RegisterExtension 18 | var wm = WireMockExtension.newInstance() 19 | .options(WireMockConfiguration.wireMockConfig().dynamicPort()) 20 | .build() 21 | 22 | @Test 23 | fun `verify exactly`() { 24 | stubWiremock() 25 | performCall() 26 | 27 | wm.verify { 28 | url equalTo "/users/1" 29 | exactly = 1 30 | } 31 | 32 | assertThrows { 33 | wm.verify { 34 | url equalTo "/users/1" 35 | exactly = 2 36 | } 37 | } 38 | } 39 | 40 | @Test 41 | fun `verify atMost`() { 42 | stubWiremock() 43 | performCall() 44 | performCall() 45 | 46 | wm.verify { 47 | url equalTo "/users/1" 48 | atMost = 2 49 | } 50 | 51 | assertThrows { 52 | wm.verify { 53 | url equalTo "/users/1" 54 | atMost = 1 55 | } 56 | } 57 | } 58 | 59 | @Test 60 | fun `verify atLeast`() { 61 | stubWiremock() 62 | performCall() 63 | performCall() 64 | 65 | wm.verify { 66 | url equalTo "/users/1" 67 | atLeast = 2 68 | } 69 | 70 | assertThrows { 71 | wm.verify { 72 | url equalTo "/users/1" 73 | atLeast = 3 74 | } 75 | } 76 | } 77 | 78 | @Test 79 | fun `verify atLeast atMost`() { 80 | stubWiremock() 81 | performCall() 82 | performCall() 83 | 84 | wm.verify { 85 | url equalTo "/users/1" 86 | atLeast = 1 87 | atMost = 3 88 | } 89 | 90 | assertThrows { 91 | wm.verify { 92 | url equalTo "/users/1" 93 | atLeast = 3 94 | atMost = 4 95 | } 96 | } 97 | } 98 | 99 | @Test 100 | fun `verify withBuilders`() { 101 | stubWiremock() 102 | performCall() 103 | performCall() 104 | 105 | wm.verify { 106 | withBuilder { withUrl("/users/1") } 107 | } 108 | } 109 | 110 | @Test 111 | fun `verify method`() { 112 | stubWiremock() 113 | performCall() 114 | performCall() 115 | 116 | wm.verify { 117 | url equalTo "/users/1" 118 | method = RequestMethod.GET 119 | } 120 | 121 | assertThrows { 122 | wm.verify { 123 | url equalTo "/users/1" 124 | method = RequestMethod.POST 125 | } 126 | } 127 | } 128 | 129 | @Test 130 | fun `verify urlLike`() { 131 | stubWiremock() 132 | performCall() 133 | performCall() 134 | 135 | wm.verify { 136 | url like "/users/.*" 137 | } 138 | } 139 | 140 | @Test 141 | fun `verify urlNotLike`() { 142 | stubWiremock() 143 | performCall() 144 | performCall() 145 | 146 | wm.verify { 147 | url notLike "/aaa" 148 | } 149 | } 150 | 151 | @Test 152 | fun `verify urlPath`() { 153 | stubWiremock() 154 | performCall(queryParams = "?filter=true") 155 | 156 | wm.verify { 157 | urlPath equalTo "/users/1" 158 | } 159 | } 160 | 161 | @Test 162 | fun `verify urlPathLike`() { 163 | stubWiremock() 164 | performCall(queryParams = "?filter=true") 165 | 166 | wm.verify { 167 | urlPath like "/users/[0-9]{0,1}" 168 | } 169 | } 170 | 171 | @Test 172 | fun `verify urlPathNotLike`() { 173 | stubWiremock() 174 | performCall(queryParams = "?filter=true") 175 | 176 | wm.verify { 177 | urlPath notLike "/users/[2-9]{0,1}" 178 | } 179 | } 180 | 181 | @Test 182 | fun `verify post requests`() { 183 | wm.post { 184 | url equalTo "/users/1?filter=true" 185 | } returnsJson { body = """{}""" } 186 | Given { 187 | header("User-Agent", "curl") 188 | queryParam("filter", true) 189 | cookie("cookieKey", "cookieValue") 190 | body(//language=JSON 191 | """ 192 | {"pet":"dog"} 193 | """ 194 | ) 195 | } When { 196 | post("${wm.baseUrl()}/users/1") 197 | } Then { 198 | statusCode(200) 199 | } 200 | 201 | wm.verify { 202 | headers contains "User-Agent" equalTo "curl" 203 | queryParams contains "filter" equalTo "true" 204 | cookies contains "cookieKey" equalTo "cookieValue" 205 | body contains "pet" equalTo "dog" 206 | } 207 | 208 | 209 | assertThrows { 210 | wm.verify { 211 | headers contains "User-Agent" equalTo "curl2" 212 | } 213 | } 214 | 215 | assertThrows { 216 | wm.verify { 217 | queryParams contains "filter" equalTo "false" 218 | } 219 | } 220 | 221 | assertThrows { 222 | wm.verify { 223 | cookies contains "cookieKey" notLike "cookieValue" 224 | } 225 | } 226 | 227 | assertThrows { 228 | wm.verify { 229 | body contains "pet" equalTo "cat" 230 | } 231 | } 232 | } 233 | 234 | private fun performCall(queryParams: String = "") { 235 | When { 236 | get("${wm.baseUrl()}/users/1" + queryParams) 237 | } 238 | } 239 | 240 | private fun stubWiremock() { 241 | wm.get { 242 | url equalTo "/users/1" 243 | } returns { 244 | header = "Content-Type" to "application/json" 245 | statusCode = 200 246 | body = """ 247 | { 248 | "id": 1, 249 | "name": "Bob" 250 | } 251 | """ 252 | } 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kotlin DSL for WireMock 2 | 3 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.marcinziolo/kotlin-wiremock/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.marcinziolo/kotlin-wiremock) 4 | ![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/wiremock/kotlin-wiremock/workflow.yaml) 5 | [![codecov](https://codecov.io/gh/marcinziolo/kotlin-wiremock/branch/master/graph/badge.svg)](https://codecov.io/gh/marcinziolo/kotlin-wiremock) 6 | 7 | This is library provides handy kotlin dsl for [WireMock](http://wiremock.org/) stubbing. 8 | Read more about WireMock and Kotlin [here](https://wiremock.org/docs/solutions/kotlin/). 9 | 10 | ### Getting started 11 | 12 | Gradle 13 | ```kotlin 14 | testImplementation("com.marcinziolo:kotlin-wiremock:version") 15 | ``` 16 | 17 | Maven 18 | 19 | ```xml 20 | 21 | com.marcinziolo 22 | kotlin-wiremock 23 | :version 24 | test 25 | 26 | ``` 27 | ### Features 28 | 29 | * Request Matching 30 | * Http methods (post/get/put/delete/patch/options/head/trace/any) 31 | ```kotlin 32 | wiremock.post { 33 | url equalTo "/users/1" 34 | } returnsJson { 35 | body = """ 36 | { 37 | "id": 1, 38 | "name": "Bob" 39 | } 40 | """ 41 | } 42 | ``` 43 | * JSON body - with strong type checking of json value 44 | ```kotlin 45 | wiremock.post { 46 | body contains "id" equalTo 1 47 | body contains "name" like "Alice" 48 | body contains "isAdmin" equalTo true 49 | body contains "points" equalTo 3.0 50 | body contains "lastName" // just checking if key exists 51 | } 52 | ``` 53 | * Headers 54 | ```kotlin 55 | wiremock.post { 56 | headers contains "User-Agent" like "Firefox.*" 57 | } 58 | ``` 59 | * Query parameters 60 | ```kotlin 61 | wiremock.post { 62 | urlPath equalTo "/users/1" 63 | queryParams contains "page" like "1.*" 64 | } 65 | ``` 66 | * Priority 67 | ```kotlin 68 | wiremock.post { 69 | url equalTo "/test" 70 | priority = 2 71 | } returnsJson { 72 | statusCode = 403 73 | } 74 | 75 | wiremock.post { 76 | url equalTo "/test" 77 | headers contains "Authorization" 78 | priority = 1 79 | } returnsJson { 80 | statusCode = 200 81 | } 82 | ``` 83 | * Cookies 84 | * Response specification 85 | * Returns 86 | ```kotlin 87 | wiremock.get { 88 | url equalTo "/users/1" 89 | } returns { 90 | statusCode = 200 91 | header = "Content-Type" to "application/json" 92 | body = """ 93 | { 94 | "id": 1, 95 | "name": "Bob" 96 | } 97 | """ 98 | } 99 | ``` 100 | * Or easier `returnsJson` 101 | ```kotlin 102 | wiremock.get { 103 | url equalTo "/users/1" 104 | } returnsJson { 105 | body = """ 106 | { 107 | "id": 1, 108 | "name": "Bob" 109 | } 110 | """ 111 | } 112 | ``` 113 | * Delays 114 | ```kotlin 115 | wiremock.post { 116 | url equalTo "/users" 117 | } returnsJson { 118 | delay fixedMs 100 119 | //or gaussian distribution 120 | delay medianMs 100 sigma 0.1 121 | } 122 | ``` 123 | * Chaining 124 | ```kotlin 125 | val bobResponse: SpecifyResponse = { 126 | body = """ 127 | { 128 | "id": 1, 129 | "name": "Bob" 130 | } 131 | """ 132 | } 133 | 134 | wiremock.post { 135 | url equalTo "/users" 136 | } and { 137 | body contains "id" equalTo 1 138 | } and { 139 | body contains "isAdmin" equalTo true 140 | } returns { 141 | header = "Content-Type" to "application/json" 142 | } and bobResponse and { 143 | statusCode = 201 144 | } 145 | ``` 146 | * Scenarios - stateful behaviour 147 | ```kotlin 148 | wiremock.post { 149 | url equalTo "/users" 150 | } returnsJson bobResponse and { 151 | toState = "Alice" 152 | } 153 | 154 | wiremock.post { 155 | url equalTo "/users" 156 | whenState = "Alice" 157 | } returnsJson aliceResponse and { 158 | clearState = true 159 | } 160 | ``` 161 | * Verification api 162 | ```kotlin 163 | wm.verify { 164 | headers contains "User-Agent" equalTo "curl" 165 | queryParams contains "filter" equalTo "true" 166 | cookies contains "cookieKey" equalTo "cookieValue" 167 | body contains "pet" equalTo "dog" 168 | } 169 | 170 | //exactly 171 | wm.verify { 172 | urlPath equalTo "/users/1" 173 | exactly = 1 174 | } moreThan 2 //lessThan lessThanOrEqual moreThanOrEqual 175 | 176 | //atLeast atMost 177 | wm.verify { 178 | urlPath equalTo "/users/1" 179 | atLeast = 1 180 | atMost = 3 181 | } 182 | ``` 183 | 184 | * WiremMckTest Junit5 extension 185 | ```kotlin 186 | class Junit5RegisterExtensionTest { 187 | 188 | @JvmField 189 | @RegisterExtension 190 | var wm = WireMockExtension.newInstance() 191 | .options(wireMockConfig().dynamicPort()) 192 | .build() 193 | 194 | @Test 195 | fun testGet() { 196 | wm.get { 197 | url equalTo "/hello" 198 | } returns { 199 | statusCode = 200 200 | } 201 | 202 | When { 203 | get("${wm.baseUrl()}/hello") 204 | } Then { 205 | statusCode(200) 206 | } 207 | } 208 | } 209 | ``` 210 | #### More examples 211 | 212 | * [Examples.kt](src/test/kotlin/com/marcinziolo/kotlin/wiremock/ExampleTest.kt) 213 | * [JUnit4 example](kotlin-wiremock-examples/src/test/kotlin/com/marcinziolo/kotlin/wiremock/JUnit4ExampleTest.kt) 214 | * [Junit5 base class](src/test/kotlin/com/marcinziolo/kotlin/wiremock/AbstractTest.kt) 215 | * [Verification test cases](src/test/kotlin/com/marcinziolo/kotlin/wiremock/Verify.kt) 216 | * [WithBuilderTests](src/test/kotlin/com/marcinziolo/kotlin/wiremock/otherPackage/WithBuilderTest.kt) - extension point for using original wiremock api and its extensions(like webhooks) 217 | 218 | ### Compatibility 219 | 220 | The Library is compatible with WireMock - 2.8.0 and higher 221 | 222 | ### Release notes 223 | 224 | | Version | Notes | 225 | |:-------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 226 | | 2.0.2 | Supports WireMock 3.0.0 and Jetty 11 | 227 | | 2.0.0 | Breaking change for verification DSL - changed api for specifying counting | 228 | | 1.1.0 | Introduced DSL for [verfication API](https://wiremock.org/docs/verifying/) | 229 | | 1.0.5 | In version 1.0.4 `url` argument (eg.`url equalTo "/hello"`) was treated as a path and matches only a path of url, which was wrong and misleading, in version 1.0.5 it was fixed and new keyword `urlPath` was introduced for matching a path of url (eg.`urlPath equalTo "/hello"`). Note: `url` has precedence in case both are specified | 230 | -------------------------------------------------------------------------------- /src/main/kotlin/com/marcinziolo/kotlin/wiremock/api.kt: -------------------------------------------------------------------------------- 1 | @file:SuppressWarnings("TooManyFunctions") 2 | package com.marcinziolo.kotlin.wiremock 3 | 4 | import com.github.tomakehurst.wiremock.WireMockServer 5 | import com.github.tomakehurst.wiremock.client.MappingBuilder 6 | import com.github.tomakehurst.wiremock.client.WireMock 7 | import com.github.tomakehurst.wiremock.junit.DslWrapper 8 | import com.github.tomakehurst.wiremock.matching.UrlPattern 9 | import java.util.UUID 10 | 11 | typealias SpecifyRequest = RequestSpecification.() -> Unit 12 | typealias SpecifyResponse = ResponseSpecification.() -> Unit 13 | typealias Method = (UrlPattern) -> MappingBuilder 14 | 15 | fun WireMock.get(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::get) 16 | fun WireMock.post(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::post) 17 | fun WireMock.put(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::put) 18 | fun WireMock.patch(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::patch) 19 | fun WireMock.delete(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::delete) 20 | fun WireMock.head(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::head) 21 | fun WireMock.options(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::options) 22 | fun WireMock.trace(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::trace) 23 | fun WireMock.any(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::any) 24 | fun WireMock.verify(block: VerifySpecification.() -> Unit) = verify(WiremockClientInstance(this), block) 25 | 26 | fun DslWrapper.get(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::get) 27 | fun DslWrapper.post(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::post) 28 | fun DslWrapper.put(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::put) 29 | fun DslWrapper.patch(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::patch) 30 | fun DslWrapper.delete(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::delete) 31 | fun DslWrapper.head(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::head) 32 | fun DslWrapper.options(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::options) 33 | fun DslWrapper.trace(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::trace) 34 | fun DslWrapper.any(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::any) 35 | fun DslWrapper.verify(block: VerifySpecification.() -> Unit) = verify(WiremockDslWrapperInstance(this), block) 36 | 37 | fun WireMockServer.get(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::get) 38 | fun WireMockServer.post(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::post) 39 | fun WireMockServer.put(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::put) 40 | fun WireMockServer.patch(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::patch) 41 | fun WireMockServer.delete(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::delete) 42 | fun WireMockServer.head(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::head) 43 | fun WireMockServer.options(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::options) 44 | fun WireMockServer.trace(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::trace) 45 | fun WireMockServer.any(specifyRequest: SpecifyRequest) = requestServerBuilderStep(specifyRequest, WireMock::any) 46 | fun WireMockServer.verify(block: VerifySpecification.() -> Unit) = verify(WiremockServerInstance(this), block) 47 | 48 | fun mockGet(specifyRequest: SpecifyRequest) = requestDefaultBuilderStep(specifyRequest, WireMock::get) 49 | fun mockPost(specifyRequest: SpecifyRequest) = requestDefaultBuilderStep(specifyRequest, WireMock::post) 50 | fun mockPut(specifyRequest: SpecifyRequest) = requestDefaultBuilderStep(specifyRequest, WireMock::put) 51 | fun mockPatch(specifyRequest: SpecifyRequest) = requestDefaultBuilderStep(specifyRequest, WireMock::patch) 52 | fun mockDelete(specifyRequest: SpecifyRequest) = requestDefaultBuilderStep(specifyRequest, WireMock::delete) 53 | fun mockHead(specifyRequest: SpecifyRequest) = requestDefaultBuilderStep(specifyRequest, WireMock::head) 54 | fun mockOptions(specifyRequest: SpecifyRequest) = requestDefaultBuilderStep(specifyRequest, WireMock::options) 55 | fun mockTrace(specifyRequest: SpecifyRequest) = requestDefaultBuilderStep(specifyRequest, WireMock::trace) 56 | fun mockAny(specifyRequest: SpecifyRequest) = requestDefaultBuilderStep(specifyRequest, WireMock::any) 57 | fun verifyCalls(block: VerifySpecification.() -> Unit) = verify(WiremockDefaultInstance, block) 58 | 59 | 60 | private fun verify(wiremockInstance: WireMockInstance, block: VerifySpecification.() -> Unit) { 61 | val verifySpecification = VerifySpecification() 62 | verifySpecification.block() 63 | val countingStrategies = verifySpecification.toCountMatchingStrategyList() 64 | val requestPatternBuilder = verifySpecification.toRequestPatternBuilder() 65 | countingStrategies.forEach { wiremockInstance.verify(it, requestPatternBuilder) } 66 | } 67 | 68 | private fun WireMock.requestServerBuilderStep( 69 | specifyRequest: SpecifyRequest, 70 | method: Method 71 | ) = BuildingStep( 72 | wireMockInstance = WiremockClientInstance(this), 73 | method = method, 74 | specifyRequestList = listOf(specifyRequest) 75 | ) 76 | 77 | private fun DslWrapper.requestServerBuilderStep( 78 | specifyRequest: SpecifyRequest, 79 | method: Method 80 | ) = BuildingStep( 81 | wireMockInstance = WiremockDslWrapperInstance(this), 82 | method = method, 83 | specifyRequestList = listOf(specifyRequest) 84 | ) 85 | 86 | fun WireMockServer.requestServerBuilderStep( 87 | specifyRequest: SpecifyRequest, 88 | method: Method 89 | ) = BuildingStep( 90 | wireMockInstance = WiremockServerInstance(this), 91 | method = method, 92 | specifyRequestList = listOf(specifyRequest) 93 | ) 94 | 95 | private fun requestDefaultBuilderStep( 96 | specifyRequest: SpecifyRequest, 97 | method: Method 98 | ) = BuildingStep( 99 | wireMockInstance = WiremockDefaultInstance, 100 | method = method, 101 | specifyRequestList = listOf(specifyRequest) 102 | ) 103 | 104 | infix fun BuildingStep.and(specifyRequest: SpecifyRequest) = 105 | copy(specifyRequestList = specifyRequestList + specifyRequest) 106 | 107 | infix fun BuildingStep.returnsJson(specifyResponse: SpecifyResponse) = 108 | this returns { 109 | statusCode = 200 110 | header = "Content-Type" to "application/json" 111 | } and specifyResponse 112 | 113 | infix fun BuildingStep.returns(specifyResponse: SpecifyResponse) = 114 | copy(specifyResponseList = specifyResponseList + specifyResponse) 115 | .let { 116 | val returnsStep = ReturnsStep(it) 117 | returnsStep.copy( 118 | buildingStep = returnsStep.buildingStep 119 | .assignId() 120 | .compute() 121 | ) 122 | } 123 | 124 | infix fun ReturnsStep.and(specifyResponse: SpecifyResponse) = 125 | copy(buildingStep = buildingStep.copy(specifyResponseList = buildingStep.specifyResponseList + specifyResponse)) 126 | .let { 127 | it.copy( 128 | buildingStep = it.buildingStep 129 | .assignId() 130 | .compute() 131 | ) 132 | } 133 | 134 | private fun BuildingStep.assignId(): BuildingStep { 135 | if (id != null) { 136 | wireMockInstance.removeStubMapping(wireMockInstance.getSingleStubMapping(id)) 137 | } 138 | return this.copy(id = UUID.randomUUID()) 139 | } 140 | 141 | private fun BuildingStep.compute(): BuildingStep { 142 | val requestSpecification = RequestSpecification 143 | .create(specifyRequestList) 144 | val responseSpecification = ResponseSpecification 145 | .create(specifyResponseList) 146 | 147 | requestSpecification copyScenariosAttributesFrom responseSpecification 148 | 149 | wireMockInstance.stubFor( 150 | requestSpecification 151 | .toMappingBuilder(method) 152 | .withId(id) 153 | .willReturn( 154 | responseSpecification 155 | .decorateResponseDefinitionBuilder(responseDefinitionBuilder) 156 | ) 157 | ) 158 | return this 159 | } 160 | 161 | private infix fun RequestSpecification.copyScenariosAttributesFrom( 162 | responseSpecification: ResponseSpecification 163 | ) { 164 | whenState = whenState ?: responseSpecification.whenState 165 | toState = toState ?: responseSpecification.toState 166 | clearState = clearState || responseSpecification.clearState 167 | } 168 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /detekt.yml: -------------------------------------------------------------------------------- 1 | build: 2 | maxIssues: 0 3 | 4 | processors: 5 | active: true 6 | exclude: 7 | - 'DetektProgressListener' 8 | - 'FunctionCountProcessor' 9 | - 'PropertyCountProcessor' 10 | - 'ClassCountProcessor' 11 | - 'PackageCountProcessor' 12 | - 'KtFileCountProcessor' 13 | 14 | console-reports: 15 | active: true 16 | 17 | comments: 18 | active: false 19 | 20 | complexity: 21 | active: true 22 | ComplexCondition: 23 | active: true 24 | threshold: 4 25 | ComplexInterface: 26 | active: true 27 | threshold: 10 28 | includeStaticDeclarations: false 29 | ComplexMethod: 30 | active: true 31 | threshold: 10 32 | ignoreSingleWhenExpression: false 33 | ignoreSimpleWhenEntries: false 34 | LabeledExpression: 35 | active: true 36 | ignoredLabels: "" 37 | LargeClass: 38 | active: true 39 | threshold: 600 40 | LongMethod: 41 | active: true 42 | threshold: 60 43 | LongParameterList: 44 | active: true 45 | threshold: 6 46 | ignoreDefaultParameters: false 47 | MethodOverloading: 48 | active: false 49 | threshold: 6 50 | NestedBlockDepth: 51 | active: true 52 | threshold: 4 53 | StringLiteralDuplication: 54 | active: false 55 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 56 | threshold: 3 57 | ignoreAnnotation: true 58 | excludeStringsWithLessThan5Characters: true 59 | ignoreStringsRegex: '$^' 60 | TooManyFunctions: 61 | active: true 62 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 63 | thresholdInFiles: 30 64 | thresholdInClasses: 30 65 | thresholdInInterfaces: 30 66 | thresholdInObjects: 30 67 | thresholdInEnums: 30 68 | ignoreDeprecated: false 69 | ignorePrivate: false 70 | ignoreOverridden: false 71 | 72 | empty-blocks: 73 | active: true 74 | EmptyCatchBlock: 75 | active: true 76 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)" 77 | EmptyClassBlock: 78 | active: true 79 | EmptyDefaultConstructor: 80 | active: true 81 | EmptyDoWhileBlock: 82 | active: true 83 | EmptyElseBlock: 84 | active: true 85 | EmptyFinallyBlock: 86 | active: true 87 | EmptyForBlock: 88 | active: true 89 | EmptyFunctionBlock: 90 | active: true 91 | ignoreOverriddenFunctions: false 92 | EmptyIfBlock: 93 | active: true 94 | EmptyInitBlock: 95 | active: true 96 | EmptyKtFile: 97 | active: true 98 | EmptySecondaryConstructor: 99 | active: true 100 | EmptyWhenBlock: 101 | active: true 102 | EmptyWhileBlock: 103 | active: true 104 | 105 | exceptions: 106 | active: true 107 | ExceptionRaisedInUnexpectedLocation: 108 | active: true 109 | methodNames: 'toString,hashCode,equals,finalize' 110 | InstanceOfCheckForException: 111 | active: true 112 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 113 | NotImplementedDeclaration: 114 | active: true 115 | PrintStackTrace: 116 | active: true 117 | RethrowCaughtException: 118 | active: true 119 | ReturnFromFinally: 120 | active: true 121 | ignoreLabeled: false 122 | SwallowedException: 123 | active: true 124 | ignoredExceptionTypes: 'InterruptedException,NumberFormatException,ParseException,MalformedURLException' 125 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)" 126 | ThrowingExceptionFromFinally: 127 | active: true 128 | ThrowingExceptionInMain: 129 | active: true 130 | ThrowingExceptionsWithoutMessageOrCause: 131 | active: true 132 | exceptions: 'IllegalArgumentException,IllegalStateException,IOException' 133 | ThrowingNewInstanceOfSameException: 134 | active: true 135 | TooGenericExceptionCaught: 136 | active: true 137 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 138 | exceptionNames: 139 | - ArrayIndexOutOfBoundsException 140 | - Error 141 | - Exception 142 | - IllegalMonitorStateException 143 | - NullPointerException 144 | - IndexOutOfBoundsException 145 | - RuntimeException 146 | - Throwable 147 | allowedExceptionNameRegex: "^(_|(ignore|expected).*)" 148 | TooGenericExceptionThrown: 149 | active: true 150 | exceptionNames: 151 | - Error 152 | - Exception 153 | - Throwable 154 | - RuntimeException 155 | 156 | formatting: 157 | active: true 158 | android: false 159 | autoCorrect: true 160 | AnnotationOnSeparateLine: 161 | active: false 162 | autoCorrect: true 163 | ChainWrapping: 164 | active: true 165 | autoCorrect: true 166 | CommentSpacing: 167 | active: true 168 | autoCorrect: true 169 | Filename: 170 | active: true 171 | FinalNewline: 172 | active: true 173 | autoCorrect: true 174 | ImportOrdering: 175 | active: false 176 | autoCorrect: true 177 | Indentation: 178 | active: false 179 | autoCorrect: true 180 | indentSize: 4 181 | continuationIndentSize: 4 182 | MaximumLineLength: 183 | active: true 184 | maxLineLength: 120 185 | ModifierOrdering: 186 | active: true 187 | autoCorrect: true 188 | MultiLineIfElse: 189 | active: true 190 | autoCorrect: true 191 | NoBlankLineBeforeRbrace: 192 | active: true 193 | autoCorrect: true 194 | NoConsecutiveBlankLines: 195 | active: true 196 | autoCorrect: true 197 | NoEmptyClassBody: 198 | active: true 199 | autoCorrect: true 200 | NoLineBreakAfterElse: 201 | active: true 202 | autoCorrect: true 203 | NoLineBreakBeforeAssignment: 204 | active: true 205 | autoCorrect: true 206 | NoMultipleSpaces: 207 | active: true 208 | autoCorrect: true 209 | NoSemicolons: 210 | active: true 211 | autoCorrect: true 212 | NoTrailingSpaces: 213 | active: true 214 | autoCorrect: true 215 | NoUnitReturn: 216 | active: true 217 | autoCorrect: true 218 | NoUnusedImports: 219 | active: true 220 | autoCorrect: true 221 | NoWildcardImports: 222 | active: false 223 | PackageName: 224 | active: true 225 | autoCorrect: true 226 | ParameterListWrapping: 227 | active: true 228 | autoCorrect: true 229 | indentSize: 4 230 | SpacingAroundColon: 231 | active: true 232 | autoCorrect: true 233 | SpacingAroundComma: 234 | active: true 235 | autoCorrect: true 236 | SpacingAroundCurly: 237 | active: true 238 | autoCorrect: true 239 | SpacingAroundDot: 240 | active: true 241 | autoCorrect: true 242 | SpacingAroundKeyword: 243 | active: true 244 | autoCorrect: true 245 | SpacingAroundOperators: 246 | active: true 247 | autoCorrect: true 248 | SpacingAroundParens: 249 | active: true 250 | autoCorrect: true 251 | SpacingAroundRangeOperator: 252 | active: true 253 | autoCorrect: true 254 | StringTemplate: 255 | active: true 256 | autoCorrect: true 257 | 258 | naming: 259 | active: true 260 | ClassNaming: 261 | active: true 262 | classPattern: '[A-Z$][a-zA-Z0-9$]*' 263 | ConstructorParameterNaming: 264 | active: true 265 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 266 | parameterPattern: '[a-z][A-Za-z0-9]*' 267 | privateParameterPattern: '[a-z][A-Za-z0-9]*' 268 | excludeClassPattern: '$^' 269 | EnumNaming: 270 | active: true 271 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 272 | enumEntryPattern: '^[A-Z][_a-zA-Z0-9]*' 273 | ForbiddenClassName: 274 | active: true 275 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 276 | forbiddenName: 'Manager' 277 | FunctionMaxLength: 278 | active: true 279 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 280 | maximumFunctionNameLength: 64 281 | FunctionMinLength: 282 | active: false 283 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 284 | minimumFunctionNameLength: 3 285 | FunctionNaming: 286 | active: true 287 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 288 | functionPattern: '^([a-z$][a-zA-Z$0-9]*)|(`.*`)$' 289 | excludeClassPattern: '$^' 290 | ignoreOverridden: true 291 | FunctionParameterNaming: 292 | active: true 293 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 294 | parameterPattern: '[a-z][A-Za-z0-9]*' 295 | excludeClassPattern: '$^' 296 | ignoreOverriddenFunctions: true 297 | InvalidPackageDeclaration: 298 | active: false 299 | rootPackage: '' 300 | MatchingDeclarationName: 301 | active: true 302 | excludes: "**/*[Dd]sl.kt" 303 | MemberNameEqualsClassName: 304 | active: true 305 | ignoreOverriddenFunction: true 306 | ObjectPropertyNaming: 307 | active: true 308 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 309 | constantPattern: '[A-Za-z][_A-Za-z0-9]*' 310 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*' 311 | privatePropertyPattern: '(_)?[A-Za-z][_A-Za-z0-9]*' 312 | PackageNaming: 313 | active: true 314 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 315 | packagePattern: '^[a-z]+(\.[a-z][A-Za-z0-9]*)*$' 316 | TopLevelPropertyNaming: 317 | active: true 318 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 319 | constantPattern: '[A-Z][_A-Z0-9]*' 320 | propertyPattern: '[A-Za-z][_A-Za-z0-9]*' 321 | privatePropertyPattern: '_?[A-Za-z][_A-Za-z0-9]*' 322 | VariableMaxLength: 323 | active: true 324 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 325 | maximumVariableNameLength: 64 326 | VariableMinLength: 327 | active: false 328 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 329 | minimumVariableNameLength: 1 330 | VariableNaming: 331 | active: true 332 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 333 | variablePattern: '[a-z][A-Za-z0-9]*' 334 | privateVariablePattern: '(_)?[a-z][A-Za-z0-9]*' 335 | excludeClassPattern: '$^' 336 | ignoreOverridden: true 337 | 338 | performance: 339 | active: true 340 | ArrayPrimitive: 341 | active: true 342 | ForEachOnRange: 343 | active: true 344 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 345 | SpreadOperator: 346 | active: true 347 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 348 | UnnecessaryTemporaryInstantiation: 349 | active: true 350 | 351 | potential-bugs: 352 | active: true 353 | Deprecation: 354 | active: true 355 | DuplicateCaseInWhenExpression: 356 | active: true 357 | EqualsAlwaysReturnsTrueOrFalse: 358 | active: true 359 | EqualsWithHashCodeExist: 360 | active: true 361 | ExplicitGarbageCollectionCall: 362 | active: true 363 | HasPlatformType: 364 | active: true 365 | InvalidRange: 366 | active: true 367 | IteratorHasNextCallsNextMethod: 368 | active: true 369 | IteratorNotThrowingNoSuchElementException: 370 | active: true 371 | LateinitUsage: 372 | active: false 373 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt" 374 | excludeAnnotatedProperties: "" 375 | ignoreOnClassesPattern: "" 376 | MissingWhenCase: 377 | active: true 378 | RedundantElseInWhen: 379 | active: true 380 | UnconditionalJumpStatementInLoop: 381 | active: true 382 | UnreachableCode: 383 | active: true 384 | UnsafeCallOnNullableType: 385 | active: true 386 | UnsafeCast: 387 | active: true 388 | UselessPostfixExpression: 389 | active: true 390 | WrongEqualsTypeParameter: 391 | active: true 392 | 393 | style: 394 | active: true 395 | CollapsibleIfStatements: 396 | active: true 397 | DataClassContainsFunctions: 398 | active: false 399 | conversionFunctionPrefix: 'to' 400 | DataClassShouldBeImmutable: 401 | active: true 402 | EqualsNullCall: 403 | active: true 404 | EqualsOnSignatureLine: 405 | active: true 406 | ExplicitItLambdaParameter: 407 | active: true 408 | ExpressionBodySyntax: 409 | active: true 410 | includeLineWrapping: false 411 | ForbiddenComment: 412 | active: true 413 | values: 'TODO:,FIXME:,STOPSHIP:' 414 | allowedPatterns: "" 415 | ForbiddenImport: 416 | active: true 417 | imports: '' 418 | forbiddenPatterns: "" 419 | ForbiddenVoid: 420 | active: true 421 | ignoreOverridden: false 422 | ignoreUsageInGenerics: false 423 | FunctionOnlyReturningConstant: 424 | active: true 425 | ignoreOverridableFunction: true 426 | excludedFunctions: 'describeContents' 427 | excludeAnnotatedFunction: "dagger.Provides" 428 | LibraryCodeMustSpecifyReturnType: 429 | active: false 430 | LoopWithTooManyJumpStatements: 431 | active: false 432 | maxJumpCount: 1 433 | MagicNumber: 434 | active: false 435 | excludes: "**/test/**,**/androidTest/**,**/*.Test.kt,**/*.Spec.kt,**/*.Spek.kt,**/*Stubs.kt" 436 | ignoreNumbers: '-1,0,1,2' 437 | ignoreHashCodeFunction: true 438 | ignorePropertyDeclaration: false 439 | ignoreConstantDeclaration: true 440 | ignoreCompanionObjectPropertyDeclaration: true 441 | ignoreAnnotation: false 442 | ignoreNamedArgument: true 443 | ignoreEnums: false 444 | ignoreRanges: false 445 | MandatoryBracesIfStatements: 446 | active: true 447 | MaxLineLength: 448 | active: true 449 | maxLineLength: 120 450 | excludePackageStatements: true 451 | excludeImportStatements: true 452 | excludeCommentStatements: false 453 | MayBeConst: 454 | active: true 455 | ModifierOrder: 456 | active: true 457 | NestedClassesVisibility: 458 | active: true 459 | NewLineAtEndOfFile: 460 | active: true 461 | NoTabs: 462 | active: true 463 | OptionalAbstractKeyword: 464 | active: true 465 | OptionalUnit: 466 | active: true 467 | OptionalWhenBraces: 468 | active: true 469 | PreferToOverPairSyntax: 470 | active: true 471 | ProtectedMemberInFinalClass: 472 | active: true 473 | RedundantExplicitType: 474 | active: true 475 | RedundantVisibilityModifierRule: 476 | active: true 477 | ReturnCount: 478 | active: true 479 | max: 2 480 | excludedFunctions: "equals" 481 | excludeLabeled: false 482 | excludeReturnFromLambda: true 483 | excludeGuardClauses: false 484 | SafeCast: 485 | active: true 486 | SerialVersionUIDInSerializableClass: 487 | active: true 488 | SpacingBetweenPackageAndImports: 489 | active: true 490 | ThrowsCount: 491 | active: true 492 | max: 2 493 | TrailingWhitespace: 494 | active: true 495 | UnderscoresInNumericLiterals: 496 | active: true 497 | acceptableDecimalLength: 5 498 | UnnecessaryAbstractClass: 499 | active: true 500 | excludeAnnotatedClasses: "dagger.Module" 501 | UnnecessaryApply: 502 | active: true 503 | UnnecessaryInheritance: 504 | active: true 505 | UnnecessaryLet: 506 | active: true 507 | UnnecessaryParentheses: 508 | active: true 509 | UntilInsteadOfRangeTo: 510 | active: true 511 | UnusedImports: 512 | active: true 513 | UnusedPrivateClass: 514 | active: true 515 | UnusedPrivateMember: 516 | active: true 517 | allowedNames: "(_|ignored|expected|serialVersionUID)" 518 | UseArrayLiteralsInAnnotations: 519 | active: true 520 | UseCheckOrError: 521 | active: true 522 | UseDataClass: 523 | active: true 524 | excludeAnnotatedClasses: "" 525 | allowVars: false 526 | UseIfInsteadOfWhen: 527 | active: false 528 | UseRequire: 529 | active: true 530 | UselessCallOnNotNull: 531 | active: true 532 | UtilityClassWithPublicConstructor: 533 | active: true 534 | VarCouldBeVal: 535 | active: true 536 | WildcardImport: 537 | active: false 538 | --------------------------------------------------------------------------------