Allows passing of regex type (#832)

without this change if one does $(regex("[0-9]")) we have no knowledge of whether the result should be text or a number. What we do ATM is we always generate a String
with this change once can pass the type of regular expression and we will generate the concrete value of that given type

fixes gh-768
This commit is contained in:
Marcin Grzejszczak
2018-12-28 16:29:32 +01:00
committed by GitHub
parent 58bf533462
commit 56fbc11f62
40 changed files with 989 additions and 263 deletions

View File

@@ -21,7 +21,6 @@ import groovy.transform.Canonical
import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
/**
* Matching strategy of dynamic parts of the body.
*
@@ -58,15 +57,18 @@ class BodyMatchers {
return new MatchingTypeValue(MatchingType.TIMESTAMP, this.regexPatterns.isoDateTime())
}
MatchingTypeValue byRegex(String regex) {
assert regex
return new MatchingTypeValue(MatchingType.REGEX, regex)
RegexMatchingTypeValue byRegex(String regex) {
return byRegex(Pattern.compile(regex))
}
// Backward compatibility with RegexPatterns
MatchingTypeValue byRegex(Pattern regex) {
RegexMatchingTypeValue byRegex(RegexProperty regex) {
assert regex
return new MatchingTypeValue(MatchingType.REGEX, regex)
return new RegexMatchingTypeValue(MatchingType.REGEX, regex)
}
RegexMatchingTypeValue byRegex(Pattern regex) {
assert regex
return new RegexMatchingTypeValue(MatchingType.REGEX, new RegexProperty(regex))
}
MatchingTypeValue byEquality() {
@@ -130,6 +132,61 @@ class JsonPathBodyMatcher implements BodyMatcher {
}
}
/**
* Matching type with corresponding values
*/
@ToString(includePackage = false)
@EqualsAndHashCode
class RegexMatchingTypeValue extends MatchingTypeValue {
RegexMatchingTypeValue(MatchingType type, Object value, Integer minTypeOccurrence, Integer maxTypeOccurrence) {
super(type, value, minTypeOccurrence, maxTypeOccurrence)
}
RegexMatchingTypeValue(MatchingType type, Object value) {
super(type, value)
}
RegexMatchingTypeValue asInteger() {
return typed(Integer)
}
private RegexMatchingTypeValue typed(Class clazz) {
assert this.value instanceof RegexProperty
RegexProperty regexProperty = (RegexProperty) this.value
return new RegexMatchingTypeValue(
this.type, new RegexProperty(regexProperty.clientValue,
regexProperty.serverValue, clazz),
this.minTypeOccurrence, this.maxTypeOccurrence
)
}
RegexMatchingTypeValue asDouble() {
return typed(Double)
}
RegexMatchingTypeValue asFloat() {
return typed(Float)
}
RegexMatchingTypeValue asLong() {
return typed(Long)
}
RegexMatchingTypeValue asShort() {
return typed(Short)
}
RegexMatchingTypeValue asString() {
return typed(String)
}
RegexMatchingTypeValue asBooleanType() {
return typed(Boolean)
}
}
/**
* Matching type with corresponding values
*/

View File

@@ -114,19 +114,27 @@ class Common {
return value(server, client)
}
Pattern regex(String regex) {
return Pattern.compile(regex)
RegexProperty regex(String regex) {
return regexProperty(Pattern.compile(regex))
}
RegexProperty regex(RegexProperty regex) {
return regex
}
// Backward compatibility with RegexPatterns
Pattern regex(Pattern regex) {
return regex
RegexProperty regex(Pattern regex) {
return regexProperty(regex)
}
OptionalProperty optional(Object object) {
return new OptionalProperty(object)
}
RegexProperty regexProperty(Object object) {
return new RegexProperty(object)
}
ExecutionProperty execute(String commandToExecute) {
return new ExecutionProperty(commandToExecute)
}

View File

@@ -16,16 +16,13 @@
package org.springframework.cloud.contract.spec.internal
import groovy.util.logging.Commons
import groovy.util.logging.Slf4j
import java.util.regex.Pattern
import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import groovy.transform.TypeChecked
import repackaged.nl.flotsam.xeger.Xeger
import groovy.util.logging.Commons
/**
* Represents an input for messaging. The input can be a message or some
* action inside the application.
@@ -89,17 +86,31 @@ class Input extends Common {
}
DslProperty value(ClientDslProperty client) {
Object clientValue = client.clientValue
if (client.clientValue instanceof Pattern) {
clientValue = new Xeger(((Pattern)client.clientValue).pattern()).generate()
Object dynamicValue = client.clientValue
Object concreteValue = client.serverValue
if (dynamicValue instanceof RegexProperty) {
return dynamicValue.dynamicClientConcreteProducer()
}
return new DslProperty(client.clientValue, clientValue)
return new DslProperty(dynamicValue, concreteValue)
}
DslProperty value(RegexProperty prop) {
return value(client(prop))
}
DslProperty $(RegexProperty prop) {
return value(client(prop))
}
DslProperty $(ClientDslProperty client) {
return value(client)
}
@Override
RegexProperty regexProperty(Object object) {
return new RegexProperty(object).dynamicClientConcreteProducer()
}
@EqualsAndHashCode(includeFields = true, callSuper = true)
@ToString(includeSuper = true)
static class BodyType extends DslProperty {

View File

@@ -19,7 +19,6 @@ package org.springframework.cloud.contract.spec.internal
import java.util.regex.Pattern
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import groovy.transform.ToString
/**
@@ -41,7 +40,12 @@ class OptionalProperty implements Serializable {
* in an optional function
*/
String optionalPattern() {
return "($value)?"
return "(${value()})?"
}
String value() {
return this.value instanceof RegexProperty ?
((RegexProperty) this.value).pattern.pattern() : this.value
}
protected Pattern optionalPatternValue() {

View File

@@ -16,17 +16,13 @@
package org.springframework.cloud.contract.spec.internal
import java.util.regex.Pattern
import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import groovy.transform.TypeChecked
import groovy.util.logging.Commons
import groovy.util.logging.Slf4j
import org.apache.commons.lang3.StringEscapeUtils
import repackaged.nl.flotsam.xeger.Xeger
import java.util.regex.Pattern
/**
* Represents an output for messaging. Used for verifying
* the body and headers that are sent.
@@ -83,26 +79,57 @@ class OutputMessage extends Common {
this.assertThat = new ExecutionProperty(assertThat)
}
/**
* @deprecated - use the server dsl property
*/
@Deprecated
DslProperty value(ClientDslProperty clientDslProperty) {
Object clientValue = clientDslProperty.clientValue
// for the output messages ran via stub runner,
// entries have to have fixed values
if (clientDslProperty.clientValue instanceof Pattern) {
clientValue = StringEscapeUtils.escapeJava(new Xeger(((Pattern)clientDslProperty.clientValue).pattern()).generate())
}
return new DslProperty(clientValue, clientDslProperty.clientValue)
return value(new ServerDslProperty(clientDslProperty.serverValue, clientDslProperty.clientValue))
}
DslProperty value(ServerDslProperty serverDslProperty) {
Object concreteValue = serverDslProperty.clientValue
Object dynamicValue = serverDslProperty.serverValue
// for the output messages ran via stub runner,
// entries have to have fixed values
if (dynamicValue instanceof RegexProperty) {
return dynamicValue
.concreteClientEscapedDynamicProducer()
}
return new DslProperty(concreteValue, dynamicValue)
}
/**
* @deprecated - use the server dsl property
*/
@Deprecated
DslProperty $(ClientDslProperty client) {
return value(client)
}
DslProperty $(ServerDslProperty property) {
return value(property)
}
DslProperty $(Pattern pattern) {
return value(client(pattern))
return value(new RegexProperty(pattern))
}
DslProperty $(RegexProperty pattern) {
return value(pattern)
}
DslProperty value(RegexProperty pattern) {
return value(producer(pattern))
}
DslProperty $(OptionalProperty property) {
return value(client(property.optionalPatternValue()))
return value(producer(property.optionalPatternValue()))
}
@Override
RegexProperty regexProperty(Object object) {
return new RegexProperty(object).concreteClientDynamicProducer()
}
/**

View File

@@ -60,80 +60,80 @@ class RegexPatterns {
return Pattern.compile(values.collect({"^$it\$"}).join("|"))
}
Pattern onlyAlphaUnicode() {
return ONLY_ALPHA_UNICODE
RegexProperty onlyAlphaUnicode() {
return new RegexProperty(ONLY_ALPHA_UNICODE).asString()
}
Pattern alphaNumeric() {
return ALPHA_NUMERIC
RegexProperty alphaNumeric() {
return new RegexProperty(ALPHA_NUMERIC).asString()
}
Pattern number() {
return NUMBER
RegexProperty number() {
return new RegexProperty(NUMBER).asDouble()
}
Pattern positiveInt() {
return POSITIVE_INT
RegexProperty positiveInt() {
return new RegexProperty(POSITIVE_INT).asInteger()
}
Pattern anyBoolean() {
return TRUE_OR_FALSE
RegexProperty anyBoolean() {
return new RegexProperty(TRUE_OR_FALSE).asBooleanType()
}
Pattern anInteger() {
return INTEGER
RegexProperty anInteger() {
return new RegexProperty(INTEGER).asInteger()
}
Pattern aDouble() {
return DOUBLE
RegexProperty aDouble() {
return new RegexProperty(DOUBLE).asDouble()
}
Pattern ipAddress() {
return IP_ADDRESS
RegexProperty ipAddress() {
return new RegexProperty(IP_ADDRESS).asString()
}
Pattern hostname() {
return HOSTNAME_PATTERN
RegexProperty hostname() {
return new RegexProperty(HOSTNAME_PATTERN).asString()
}
Pattern email() {
return EMAIL
RegexProperty email() {
return new RegexProperty(EMAIL).asString()
}
Pattern url() {
return URL
RegexProperty url() {
return new RegexProperty(URL).asString()
}
Pattern httpsUrl() {
return HTTPS_URL
RegexProperty httpsUrl() {
return new RegexProperty(HTTPS_URL).asString()
}
Pattern uuid(){
return UUID
RegexProperty uuid(){
return new RegexProperty(UUID).asString()
}
Pattern isoDate() {
return ANY_DATE
RegexProperty isoDate() {
return new RegexProperty(ANY_DATE).asString()
}
Pattern isoDateTime() {
return ANY_DATE_TIME
RegexProperty isoDateTime() {
return new RegexProperty(ANY_DATE_TIME).asString()
}
Pattern isoTime() {
return ANY_TIME
RegexProperty isoTime() {
return new RegexProperty(ANY_TIME).asString()
}
Pattern iso8601WithOffset() {
return ISO8601_WITH_OFFSET
RegexProperty iso8601WithOffset() {
return new RegexProperty(ISO8601_WITH_OFFSET).asString()
}
Pattern nonEmpty() {
return NON_EMPTY
RegexProperty nonEmpty() {
return new RegexProperty(NON_EMPTY).asString()
}
Pattern nonBlank() {
return NON_BLANK
RegexProperty nonBlank() {
return new RegexProperty(NON_BLANK).asString()
}
// end::regexps[]
@@ -150,7 +150,7 @@ class RegexPatterns {
if (contentType == null) {
return '.*'
}
if (contentType instanceof Pattern) {
if (contentType instanceof RegexProperty) {
return contentType.pattern()
}
return contentType.toString()
@@ -163,7 +163,7 @@ class RegexPatterns {
class UrlHelper {
/**
* Example: "http". Also called 'protocol'.
* Scheme component is optional, even though the RFC doesn't make it optional. Since this regex is validating a
* Scheme component is optional, even though the RFC doesn't make it optional. Since ((RegexProperty) this regex is validating a
* submitted callback url, which determines where the browser will navigate to after a successful authentication,
* the browser will use http or https for the scheme by default.
* Not borrowed from dperini in order to allow any scheme type.

View File

@@ -0,0 +1,172 @@
/*
* Copyright 2013-2018 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
*
* http://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 java.util.regex.Matcher
import java.util.regex.Pattern
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import groovy.transform.TypeChecked
import org.apache.commons.text.StringEscapeUtils
import repackaged.nl.flotsam.xeger.Xeger
/**
* Represents a regular expression property
*
* @since 2.1.0
*/
@TypeChecked
@EqualsAndHashCode
@ToString(includePackage = false, includeNames = true)
class RegexProperty extends DslProperty {
final Pattern pattern
private final Class clazz
RegexProperty(Object value) {
this(value, value, null)
}
RegexProperty(Object client, Object server) {
this(client, server, null)
}
RegexProperty(Object client, Object server, Class clazz) {
super(client, server)
boolean clientDynamic = client instanceof Pattern ||
client instanceof RegexProperty
boolean serverDynamic = server instanceof Pattern ||
server instanceof RegexProperty
if (!clientDynamic && !serverDynamic) {
throw new IllegalStateException("Neither client not server side is dynamic")
}
Object dynamicValue = clientDynamic ? client : server
if (dynamicValue instanceof Pattern) {
this.pattern = dynamicValue
this.clazz = clazz ?: String
} else if (dynamicValue instanceof RegexProperty) {
RegexProperty regexProperty = ((RegexProperty) dynamicValue)
this.pattern = regexProperty.pattern
this.clazz = clazz ?: regexProperty.clazz
} else {
this.clazz = clazz
}
}
Matcher matcher(CharSequence input) {
return this.pattern.matcher(input)
}
String pattern() {
return this.pattern.pattern()
}
Class clazz() {
return this.class
}
RegexProperty asInteger() {
return new RegexProperty(this.clientValue, this.serverValue, Integer)
}
RegexProperty asDouble() {
return new RegexProperty(this.clientValue, this.serverValue, Double)
}
RegexProperty asFloat() {
return new RegexProperty(this.clientValue, this.serverValue, Float)
}
RegexProperty asLong() {
return new RegexProperty(this.clientValue, this.serverValue, Long)
}
RegexProperty asShort() {
return new RegexProperty(this.clientValue, this.serverValue, Short)
}
RegexProperty asString() {
return new RegexProperty(this.clientValue, this.serverValue, String)
}
RegexProperty asBooleanType() {
return new RegexProperty(this.clientValue, this.serverValue, Boolean)
}
Object generate() {
String generatedValue = new Xeger(this.pattern.pattern()).generate()
switch (this.clazz) {
case Integer: return Integer.parseInt(generatedValue)
case Double: return Double.parseDouble(generatedValue)
case Float: return Float.parseFloat(generatedValue)
case Long: return Long.parseLong(generatedValue)
case Short: return Short.parseShort(generatedValue)
case Boolean: return Boolean.parseBoolean(generatedValue)
default: return generatedValue
}
}
Object generateAndEscapeJavaStringIfNeeded() {
Object generated = generate()
if (isNumber()) {
return generated
}
return StringEscapeUtils.escapeJava(generated as String)
}
private boolean isNumber() {
return Number.isAssignableFrom(this.clazz)
}
RegexProperty dynamicClientConcreteProducer() {
return new RegexProperty(this.pattern, generate(), this.clazz)
}
RegexProperty concreteClientDynamicProducer() {
return new RegexProperty(generate(), this.pattern, this.clazz)
}
RegexProperty concreteClientEscapedDynamicProducer() {
return new RegexProperty(generateAndEscapeJavaStringIfNeeded(), this.pattern, this.clazz)
}
RegexProperty dynamicClientEscapedConcreteProducer() {
return new RegexProperty(this.pattern, generateAndEscapeJavaStringIfNeeded(), this.clazz)
}
boolean equals(o) {
if (this.is(o)) return true
if (getClass() != o.class) return false
if (!super.equals(o)) return false
RegexProperty that = (RegexProperty) o
if (this.clazz != that.clazz) return false
if (this.pattern != that.pattern) return false
return true
}
int hashCode() {
int result = super.hashCode()
result = 31 * result + (this.pattern != null ? pattern.hashCode() : 0)
result = 31 * result + (this.clazz != null ? clazz.hashCode() : 0)
return result
}
@Override
String toString() {
return this.pattern()
}
}

View File

@@ -23,8 +23,6 @@ import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import groovy.transform.TypeChecked
import groovy.util.logging.Commons
import org.apache.commons.lang3.StringEscapeUtils
import repackaged.nl.flotsam.xeger.Xeger
import org.springframework.cloud.contract.spec.util.RegexpUtils
/**
@@ -208,13 +206,22 @@ class Request extends Common {
}
DslProperty value(ClientDslProperty client) {
Object clientValue = client.clientValue
if (client.clientValue instanceof Pattern && client.isSingleValue()) {
clientValue = StringEscapeUtils.escapeJava(new Xeger(((Pattern)client.clientValue).pattern()).generate())
} else if (client.clientValue instanceof Pattern && !client.isSingleValue()) {
clientValue = client.serverValue
Object concreteValue = client.serverValue
Object dynamicValue = client.clientValue
if (dynamicValue instanceof RegexProperty && client.isSingleValue()) {
return dynamicValue.dynamicClientEscapedConcreteProducer()
} else if (concreteValue instanceof RegexProperty && !client.isSingleValue()) {
concreteValue = dynamicValue
}
return new DslProperty(client.clientValue, clientValue)
return new DslProperty(dynamicValue, concreteValue)
}
DslProperty $(RegexProperty property) {
return value(property)
}
DslProperty value(RegexProperty property) {
return value(client(property))
}
DslProperty $(ClientDslProperty client) {
@@ -222,13 +229,18 @@ class Request extends Common {
}
DslProperty value(Pattern client) {
return value(new ClientDslProperty(client))
return value(new RegexProperty(client))
}
DslProperty $(Pattern client) {
return value(client)
}
@Override
RegexProperty regexProperty(Object object) {
return new RegexProperty(object).dynamicClientConcreteProducer()
}
/**
* @deprecated Deprecated in favor of bodyMatchers to support other future bodyMatchers too
*/
@@ -246,7 +258,7 @@ class Request extends Common {
@Override
DslProperty value(ClientDslProperty client, ServerDslProperty server) {
if (server.clientValue instanceof Pattern) {
if (server.clientValue instanceof RegexProperty) {
throw new IllegalStateException("You can't have a regular expression for the request on the server side")
}
return super.value(client, server)
@@ -254,7 +266,7 @@ class Request extends Common {
@Override
DslProperty value(ServerDslProperty server, ClientDslProperty client) {
if (server.clientValue instanceof Pattern) {
if (server.clientValue instanceof RegexProperty) {
throw new IllegalStateException("You can't have a regular expression for the request on the server side")
}
return super.value(server, client)

View File

@@ -23,7 +23,6 @@ import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import groovy.transform.TypeChecked
import groovy.util.logging.Commons
import repackaged.nl.flotsam.xeger.Xeger
import org.springframework.cloud.contract.spec.util.RegexpUtils
/**
@@ -109,13 +108,12 @@ class Response extends Common {
}
DslProperty value(ServerDslProperty server) {
Object value = server.clientValue
if (server.clientValue instanceof Pattern && server.isSingleValue()) {
value = new Xeger(((Pattern)server.clientValue).pattern()).generate()
} else if (server.clientValue instanceof Pattern && !server.isSingleValue()) {
value = server.serverValue
Object dynamicValue = server.serverValue
Object concreteValue = server.clientValue
if (dynamicValue instanceof RegexProperty && server.isSingleValue()) {
return ((RegexProperty) dynamicValue).concreteClientDynamicProducer()
}
return new DslProperty(value, server.serverValue)
return new DslProperty(concreteValue, dynamicValue)
}
DslProperty $(ServerDslProperty server) {
@@ -123,13 +121,26 @@ class Response extends Common {
}
DslProperty value(Pattern server) {
return value(new RegexProperty(server))
}
DslProperty value(RegexProperty server) {
return value(new ServerDslProperty(server))
}
DslProperty $(Pattern server) {
DslProperty $(RegexProperty server) {
return value(server)
}
DslProperty $(Pattern server) {
return value(new RegexProperty(server))
}
@Override
RegexProperty regexProperty(Object object) {
return new RegexProperty(object).concreteClientDynamicProducer()
}
/**
* @deprecated Deprecated in favor of bodyMatchers to support other future bodyMatchers too
*/
@@ -151,7 +162,7 @@ class Response extends Common {
@Override
DslProperty value(ClientDslProperty client, ServerDslProperty server) {
if (client.clientValue instanceof Pattern) {
if (client.clientValue instanceof RegexProperty) {
throw new IllegalStateException("You can't have a regular expression for the response on the client side")
}
return super.value(client, server)
@@ -159,7 +170,7 @@ class Response extends Common {
@Override
DslProperty value(ServerDslProperty server, ClientDslProperty client) {
if (client.clientValue instanceof Pattern) {
if (client.clientValue instanceof RegexProperty) {
throw new IllegalStateException("You can't have a regular expression for the response on the client side")
}
return super.value(server, client)

View File

@@ -16,16 +16,12 @@
package org.springframework.cloud.contract.spec.internal
import java.util.regex.Pattern
import groovy.transform.CompileStatic
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import org.codehaus.groovy.runtime.GStringImpl
import repackaged.nl.flotsam.xeger.Xeger
import static org.springframework.cloud.contract.spec.util.ValidateUtils.validateServerValueIsAvailable
/**
* Represents a URL that may contain query parameters
*
@@ -50,13 +46,13 @@ class Url extends DslProperty {
private static Object testUrl(Object url) {
if (url instanceof GString) {
boolean anyPattern = url.values.any { it instanceof Pattern }
boolean anyPattern = url.values.any { it instanceof RegexProperty }
if (!anyPattern) {
return url
}
String newUrl = new GStringImpl(
url.values.collect { it instanceof Pattern ?
new Xeger(it.pattern()).generate() : it
url.values.collect { it instanceof RegexProperty ?
it.generate() : it
} as String[],
Arrays.copyOf(url.strings, url.strings.length) as String[]
).toString()

View File

@@ -14,7 +14,84 @@ class InputSpec extends Specification {
input.with {
property = $(consumer(regex("[0-9]{5}")))
}
def value = Integer.valueOf(property.serverValue as String)
def generatedValue = property.serverValue
generatedValue instanceof String
def value = Integer.valueOf(generatedValue as String)
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Double'() {
given:
Input input = new Input()
DslProperty property
when:
input.with {
property = $(consumer(regex("[0-9]{5}").asDouble()))
}
def value = property.serverValue
value instanceof Double
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Short'() {
given:
Input input = new Input()
DslProperty property
when:
input.with {
property = $(consumer(regex("[0-9]{1}").asShort()))
}
def value = property.serverValue
value instanceof Short
then:
value >= 0
value <= 9
}
def 'should set property when using the $() convenience method for Long'() {
given:
Input input = new Input()
DslProperty property
when:
input.with {
property = $(consumer(regex("[0-9]{5}").asLong()))
}
def value = property.serverValue
value instanceof Long
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Integer'() {
given:
Input input = new Input()
DslProperty property
when:
input.with {
property = $(consumer(regex("[0-9]{5}").asInteger()))
}
def value = property.serverValue
value instanceof Integer
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Float'() {
given:
Input input = new Input()
DslProperty property
when:
input.with {
property = $(consumer(regex("[0-9]{5}").asFloat()))
}
def value = property.serverValue
value instanceof Float
then:
value >= 0
value <= 99_999

View File

@@ -8,13 +8,90 @@ class OutputMessageSpec extends Specification {
def 'should set property when using the $() convenience method'() {
given:
Input input = new Input()
OutputMessage contract = new OutputMessage()
DslProperty property
when:
input.with {
property = $(consumer(regex("[0-9]{5}")))
contract.with {
property = $(producer(regex("[0-9]{5}")))
}
def value = Integer.valueOf(property.serverValue as String)
def generatedValue = property.clientValue
generatedValue instanceof String
def value = Integer.valueOf(generatedValue as String)
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Double'() {
given:
OutputMessage contract = new OutputMessage()
DslProperty property
when:
contract.with {
property = $(producer(regex("[0-9]{5}").asDouble()))
}
def value = property.clientValue
value instanceof Double
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Short'() {
given:
OutputMessage contract = new OutputMessage()
DslProperty property
when:
contract.with {
property = $(producer(regex("[0-9]{1}").asShort()))
}
def value = property.clientValue
value instanceof Short
then:
value >= 0
value <= 9
}
def 'should set property when using the $() convenience method for Long'() {
given:
OutputMessage contract = new OutputMessage()
DslProperty property
when:
contract.with {
property = $(producer(regex("[0-9]{5}").asLong()))
}
def value = property.clientValue
value instanceof Long
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Integer'() {
given:
OutputMessage contract = new OutputMessage()
DslProperty property
when:
contract.with {
property = $(producer(regex("[0-9]{5}").asInteger()))
}
def value = property.clientValue
value instanceof Integer
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Float'() {
given:
OutputMessage contract = new OutputMessage()
DslProperty property
when:
contract.with {
property = $(producer(regex("[0-9]{5}").asFloat()))
}
def value = property.clientValue
value instanceof Float
then:
value >= 0
value <= 99_999

View File

@@ -8,30 +8,106 @@ class RequestSpec extends Specification {
def 'should throw exception when on request side a value contains regex for server'() {
given:
Request request = new Request()
Request contract = new Request()
when:
request.with {
contract.with {
value(consumer("foo"), producer(regex("foo")))
}
then:
thrown(IllegalStateException)
when:
request.with {
contract.with {
value(producer(regex("foo")), consumer("foo"))
}
then:
thrown(IllegalStateException)
}
def 'should generate a value if only regex is passed for client'() {
def 'should set property when using the $() convenience method'() {
given:
Request request = new Request()
Request contract = new Request()
DslProperty property
when:
request.with {
property = value(consumer(regex("[0-9]{5}")))
contract.with {
property = $(consumer(regex("[0-9]{5}")))
}
def value = Integer.valueOf(property.serverValue as String)
def generatedValue = property.serverValue
generatedValue instanceof String
def value = Integer.valueOf(generatedValue as String)
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Double'() {
given:
Request contract = new Request()
DslProperty property
when:
contract.with {
property = $(consumer(regex("[0-9]{5}").asDouble()))
}
def value = property.serverValue
value instanceof Double
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Short'() {
given:
Request contract = new Request()
DslProperty property
when:
contract.with {
property = $(consumer(regex("[0-9]{1}").asShort()))
}
def value = property.serverValue
value instanceof Short
then:
value >= 0
value <= 9
}
def 'should set property when using the $() convenience method for Long'() {
given:
Request contract = new Request()
DslProperty property
when:
contract.with {
property = $(consumer(regex("[0-9]{5}").asLong()))
}
def value = property.serverValue
value instanceof Long
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Integer'() {
given:
Request contract = new Request()
DslProperty property
when:
contract.with {
property = $(consumer(regex("[0-9]{5}").asInteger()))
}
def value = property.serverValue
value instanceof Integer
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Float'() {
given:
Request contract = new Request()
DslProperty property
when:
contract.with {
property = $(consumer(regex("[0-9]{5}").asFloat()))
}
def value = property.serverValue
value instanceof Float
then:
value >= 0
value <= 99_999

View File

@@ -1,9 +1,6 @@
package org.springframework.cloud.contract.spec.internal
import spock.lang.Specification
import java.util.regex.Pattern
import spock.lang.Specification
/**
* @author Marcin Grzejszczak
*/
@@ -26,18 +23,95 @@ class ResponseSpec extends Specification {
thrown(IllegalStateException)
}
def 'should generate a value if only regex is passed for server'() {
def 'should set property when using the $() convenience method'() {
given:
Response request = new Response()
Response contract = new Response()
DslProperty property
when:
request.with {
property = value(producer(regex("[0-9]{5}")))
contract.with {
property = $(producer(regex("[0-9]{5}")))
}
def value = Integer.valueOf(property.clientValue as String)
def generatedValue = property.clientValue
generatedValue instanceof String
def value = Integer.valueOf(generatedValue as String)
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Double'() {
given:
Response contract = new Response()
DslProperty property
when:
contract.with {
property = $(producer(regex("[0-9]{5}").asDouble()))
}
def value = property.clientValue
value instanceof Double
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Short'() {
given:
Response contract = new Response()
DslProperty property
when:
contract.with {
property = $(producer(regex("[0-9]{1}").asShort()))
}
def value = property.clientValue
value instanceof Short
then:
value >= 0
value <= 9
}
def 'should set property when using the $() convenience method for Long'() {
given:
Response contract = new Response()
DslProperty property
when:
contract.with {
property = $(producer(regex("[0-9]{5}").asLong()))
}
def value = property.clientValue
value instanceof Long
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Integer'() {
given:
Response contract = new Response()
DslProperty property
when:
contract.with {
property = $(producer(regex("[0-9]{5}").asInteger()))
}
def value = property.clientValue
value instanceof Integer
then:
value >= 0
value <= 99_999
}
def 'should set property when using the $() convenience method for Float'() {
given:
Response contract = new Response()
DslProperty property
when:
contract.with {
property = $(producer(regex("[0-9]{5}").asFloat()))
}
def value = property.clientValue
value instanceof Float
then:
value >= 0
value <= 99_999
(property.serverValue as Pattern).pattern() == '[0-9]{5}'
}
}