Made DSL less error prone

This commit is contained in:
Tim Ysewyn
2019-08-10 17:51:13 +02:00
parent cb1a836c17
commit 9954efdf28
8 changed files with 44 additions and 360 deletions

View File

@@ -24,14 +24,8 @@ contract {
method = GET
url = url("/frauds/name")
cookies {
cookie {
name = "name"
value = "foo"
}
cookie{
name = "name2"
value = "bar"
}
cookie("name", "foo")
cookie("name2", "bar")
}
}
response {

View File

@@ -1,30 +0,0 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.spec.internal
import kotlin.properties.Delegates
/**
* @author Tim Ysewyn
*/
class BodyMatcherDsl {
var path: String by Delegates.notNull()
var matcher: MatchingTypeValue by Delegates.notNull()
}

View File

@@ -27,31 +27,23 @@ open class BodyMatchersDsl {
private val xPathMatchers = LinkedHashMap<String, MatchingTypeValue>()
/**
* Adds and configures a JSON path matcher.
* Adds a JSON path matcher.
*
* @param configurer The lambda to configure the JSON path matcher.
* @param path The path.
* @param matcher The matcher.
*/
fun jsonPath(configurer: BodyMatcherDsl.() -> Unit) {
try {
val bodyMatcher = BodyMatcherDsl().apply(configurer)
this.jsonPathMatchers[bodyMatcher.path] = bodyMatcher.matcher
} catch (ex: IllegalStateException) {
throw IllegalStateException("Body matcher is missing its path or matcher")
}
fun jsonPath(path: String, matcher: MatchingTypeValue) {
this.jsonPathMatchers[path] = matcher
}
/**
* Adds and configures a xPath matcher.
* Adds an xPath matcher.
*
* @param configurer The lambda to configure the xPath matcher.
* @param path The path.
* @param matcher The matcher.
*/
fun xPath(configurer: BodyMatcherDsl.() -> Unit) {
try {
val bodyMatcher = BodyMatcherDsl().apply(configurer)
this.jsonPathMatchers[bodyMatcher.path] = bodyMatcher.matcher
} catch (ex: IllegalStateException) {
throw IllegalStateException("Body matcher is missing its path or matcher")
}
fun xPath(path: String, matcher: MatchingTypeValue) {
this.xPathMatchers[path] = matcher
}
fun byDate() = MatchingTypeValue(MatchingType.DATE, RegexPatterns.isoDate())

View File

@@ -1,29 +0,0 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.spec.internal
import kotlin.properties.Delegates
/**
* @author Tim Ysewyn
*/
class CookieDsl {
var name: String by Delegates.notNull()
var value: Any by Delegates.notNull()
}

View File

@@ -26,17 +26,13 @@ open class CookiesDsl : CommonDsl() {
open fun matching(value: Any?): Any? = value
/**
* Adds and configures a cookie.
* Adds a cookie.
*
* @param configurer The lambda to configure the cookie.
* @param name The name of the cookie.
* @param value The value of the cookie.
*/
fun cookie(configurer: CookieDsl.() -> Unit) {
try {
val cookie = CookieDsl().apply(configurer)
this.cookies[cookie.name] = cookie.value
} catch (ex: IllegalStateException) {
throw IllegalStateException("Cookie is missing its name or value")
}
fun cookie(name: String, value: Any) {
this.cookies[name] = value
}
internal fun get(): Cookies {

View File

@@ -1,29 +0,0 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.contract.spec.internal
import kotlin.properties.Delegates
/**
* @author Tim Ysewyn
*/
class HeaderDsl {
var name: String by Delegates.notNull()
var value: Any by Delegates.notNull()
}

View File

@@ -438,17 +438,13 @@ open class HeadersDsl: CommonDsl() {
val TEXT_XML = MediaTypes.TEXT_XML
/**
* Adds and configures a configurer.
* Adds a header.
*
* @param configurer The lambda to configure the configurer.
* @param name The name of the header.
* @param value The value of the header.
*/
fun header(configurer: HeaderDsl.() -> Unit) {
try {
val header = HeaderDsl().apply(configurer)
this.headers[header.name] = header.value
} catch (ex: IllegalStateException) {
throw IllegalStateException("Header is missing its name or value")
}
fun header(name: String, value: Any) {
this.headers[name] = value
}
internal fun get(): Headers {

View File

@@ -39,20 +39,14 @@ class ContractTests {
url = url("/foo")
method = PUT
headers {
header {
name = "foo"
value = "bar"
}
header("foo", "bar")
}
body = body("foo" to "bar")
}
response {
status = OK
headers {
header {
name = "foo2"
value = "bar"
}
header("foo2", "bar")
}
body = body("foo2" to "bar")
}
@@ -148,20 +142,14 @@ class ContractTests {
messageFrom = messageFrom("input")
messageBody = messageBody("foo" to "bar")
headers {
header {
name = "foo"
value = "bar"
}
header("foo", "bar")
}
}
outputMessage {
sentTo = sentTo("output")
body = body("foo2" to "bar")
headers {
header {
name = "foo2"
value = "bar"
}
header("foo2", "bar")
}
}
}
@@ -200,20 +188,14 @@ class ContractTests {
messageFrom("input")
messageBody("foo" to anyNonBlankString())
headers {
header {
name = "foo"
value = anyNumber()
}
header("foo", anyNumber())
}
}
outputMessage {
sentTo("output")
body("foo2" to anyNonEmptyString())
headers {
header {
name = "foo2"
value = anyIpAddress()
}
header("foo2", anyIpAddress())
}
}
}
@@ -415,20 +397,18 @@ then:
method = GET
url = url("/path")
headers {
header {
name = "Accept"
header(name = "Accept",
value = value(
consumer(regex("text/.*")),
producer("text/plain")
)
}
header {
name = "X-Custom-Header"
)
header(name = "X-Custom-Header",
value = value(
consumer(regex("^.*2134.*$")),
producer("121345")
)
}
)
}
}
response {
@@ -439,10 +419,7 @@ then:
"created" to "2014-02-02 12:23:43"
)
headers {
header {
name = "Content-Type"
value = "text/plain"
}
header("Content-Type", "text/plain")
}
}
}
@@ -451,20 +428,18 @@ then:
method = GET
url = url("/path")
headers {
header {
name = "Accept"
header(name = "Accept",
value = value(
consumer(regex("text/.*")),
producer("text/plain")
)
}
header {
name = "X-Custom-Header"
)
header(name = "X-Custom-Header",
value = value(
consumer(regex("^.*2134.*$")),
producer("121345")
)
}
)
}
}
response {
@@ -475,10 +450,7 @@ then:
"created" to "2014-02-02 12:23:43"
)
headers {
header {
name = "Content-Type"
value = "text/plain"
}
header("Content-Type", "text/plain")
}
}
}
@@ -533,10 +505,7 @@ then:
url = url("/path")
body = body("id" to mapOf("value" to "132"))
bodyMatchers {
jsonPath {
path = "$.id.value"
matcher = byRegex(anInteger())
}
jsonPath( "$.id.value", byRegex(anInteger()))
}
}
response {
@@ -550,10 +519,7 @@ then:
contentType = APPLICATION_JSON
}
bodyMatchers {
jsonPath {
path = "$.id.value"
matcher = byTimestamp()
}
jsonPath("$.id.value", byTimestamp())
}
}
}
@@ -581,84 +547,6 @@ then:
}
}
@Test
fun `should throw error when body matcher is not configured correctly`() {
assertThrows<IllegalStateException> {
contract {
request {
method = GET
url = url("/cookie")
bodyMatchers {
jsonPath {
matcher = byRegex(anInteger())
}
}
}
response {
status = OK
}
}
}.also {
assertThat(it.message).contains("Body matcher is missing its path or matcher")
}
assertThrows<IllegalStateException> {
contract {
request {
method = GET
url = url("/cookie")
bodyMatchers {
jsonPath {
path = "$.id.value"
}
}
}
response {
status = OK
}
}
}.also {
assertThat(it.message).contains("Body matcher is missing its path or matcher")
}
assertThrows<IllegalStateException> {
contract {
request {
method = GET
url = url("/cookie")
bodyMatchers {
xPath {
matcher = byRegex(anInteger())
}
}
}
response {
status = OK
}
}
}.also {
assertThat(it.message).contains("Body matcher is missing its path or matcher")
}
assertThrows<IllegalStateException> {
contract {
request {
method = GET
url = url("/cookie")
bodyMatchers {
xPath {
path = "$.id.value"
}
}
}
response {
status = OK
}
}
}.also {
assertThat(it.message).contains("Body matcher is missing its path or matcher")
}
}
@Test
fun `should support query parameters for url`() {
val contract = contract {
@@ -752,47 +640,6 @@ then:
}
}
@Test
fun `should throw error when header is not configured correctly`() {
assertThrows<IllegalStateException> {
contract {
request {
method = GET
url = url("/cookie")
headers {
header {
name = "foo"
}
}
}
response {
status = OK
}
}
}.also {
assertThat(it.message).contains("Header is missing its name or value")
}
assertThrows<IllegalStateException> {
contract {
request {
method = GET
url = url("/cookie")
headers {
header {
value = "bar"
}
}
}
response {
status = OK
}
}
}.also {
assertThat(it.message).contains("Header is missing its name or value")
}
}
@Test
fun `should work with cookies`() {
val contract = contract {
@@ -800,27 +647,15 @@ then:
method = GET
url = url("/cookie")
cookies {
cookie {
name = "name"
value = "foo"
}
cookie {
name = "name2"
value = "bar"
}
cookie("name", "foo")
cookie("name2", "bar")
}
}
response {
status = OK
cookies {
cookie {
name = "name"
value = "foo"
}
cookie {
name = "name2"
value = "bar"
}
cookie("name", "foo")
cookie("name2", "bar")
}
}
}
@@ -840,47 +675,6 @@ then:
}
}
@Test
fun `should throw error when cookie is not configured correctly`() {
assertThrows<IllegalStateException> {
contract {
request {
method = GET
url = url("/cookie")
cookies {
cookie {
value = "bar"
}
}
}
response {
status = OK
}
}
}.also {
assertThat(it.message).contains("Cookie is missing its name or value")
}
assertThrows<IllegalStateException> {
contract {
request {
method = GET
url = url("/cookie")
cookies {
cookie {
name = "foo"
}
}
}
response {
status = OK
}
}
}.also {
assertThat(it.message).contains("Cookie is missing its name or value")
}
}
@Test
fun `should support fromRequest`() {
val contract = contract {