@@ -1311,7 +1311,7 @@ Example of a `pom.xml` inside the `server` folder.
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud-contract.version>1.0.3.BUILD-SNAPSHOT</spring-cloud-contract.version>
|
||||
<spring-cloud-contract.version>1.1.0.BUILD-SNAPSHOT</spring-cloud-contract.version>
|
||||
<spring-cloud-dependencies.version>Camden.BUILD-SNAPSHOT</spring-cloud-dependencies.version>
|
||||
</properties>
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ import groovy.transform.EqualsAndHashCode
|
||||
import groovy.transform.ToString
|
||||
import groovy.transform.TypeChecked
|
||||
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* Represents a set of headers of a request / response or a message
|
||||
*
|
||||
@@ -68,6 +70,10 @@ class Headers {
|
||||
return new DslProperty(value)
|
||||
}
|
||||
|
||||
protected NotToEscapePattern notEscaped(Pattern pattern) {
|
||||
return new NotToEscapePattern(pattern)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the headers into their stub side representations and returns as
|
||||
* a map of String key => Object value.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.springframework.cloud.contract.spec.internal
|
||||
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
/**
|
||||
* Special case of Patterns that we don't want to escape
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.0.3
|
||||
*/
|
||||
class NotToEscapePattern extends DslProperty<Pattern> {
|
||||
|
||||
NotToEscapePattern(Pattern clientValue, Pattern serverValue) {
|
||||
super(clientValue, serverValue)
|
||||
}
|
||||
|
||||
NotToEscapePattern(Pattern singleValue) {
|
||||
super(singleValue)
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,7 @@ class Response extends Common {
|
||||
|
||||
@Override
|
||||
DslProperty matching(String value) {
|
||||
return $(p(Pattern.compile("${RegexpUtils.escapeSpecialRegexWithSingleEscape(value)}.*")),
|
||||
return $(p(notEscaped(Pattern.compile("${RegexpUtils.escapeSpecialRegexWithSingleEscape(value)}.*"))),
|
||||
c(value))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +169,10 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder
|
||||
|
||||
private String buildEscapedMatchesMethod(Pattern headerValue) {
|
||||
String escapedHeader = convertUnicodeEscapesIfRequired("$headerValue")
|
||||
return createMatchesMethod(escapedHeader)
|
||||
}
|
||||
|
||||
protected String createMatchesMethod(String escapedHeader) {
|
||||
return "matches(\"$escapedHeader\")"
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import groovy.transform.TypeChecked
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.spec.internal.Header
|
||||
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
|
||||
import org.springframework.cloud.contract.spec.internal.NotToEscapePattern
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
|
||||
import java.util.regex.Pattern
|
||||
@@ -62,6 +63,13 @@ class MockMvcJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder {
|
||||
return null
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Object value) {
|
||||
if (value instanceof NotToEscapePattern) {
|
||||
blockBuilder.addLine("assertThat(response.header(\"$property\")).${createMatchesMethod(value.serverValue.pattern())};")
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processHeaderElement(BlockBuilder blockBuilder, String property, String value) {
|
||||
blockBuilder.addLine("assertThat(response.header(\"$property\")).${createHeaderComparison(value)}")
|
||||
|
||||
@@ -21,6 +21,7 @@ import groovy.transform.TypeChecked
|
||||
import org.springframework.cloud.contract.spec.Contract
|
||||
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
|
||||
import org.springframework.cloud.contract.spec.internal.Header
|
||||
import org.springframework.cloud.contract.spec.internal.NotToEscapePattern
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
|
||||
import java.util.regex.Pattern
|
||||
@@ -55,6 +56,12 @@ class MockMvcSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequestP
|
||||
return 'response.body.asString()'
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processHeaderElement(BlockBuilder blockBuilder, String property, Object value) {
|
||||
if (value instanceof NotToEscapePattern) {
|
||||
blockBuilder.addLine("response.header('$property') ${patternComparison(value.serverValue)}")
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void processHeaderElement(BlockBuilder blockBuilder, String property, ExecutionProperty exec) {
|
||||
blockBuilder.addLine("${exec.insertValue("response.header(\'$property\')")}")
|
||||
|
||||
@@ -147,7 +147,7 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing
|
||||
return patternComparison(headerValue)
|
||||
}
|
||||
|
||||
private String patternComparison(Pattern pattern) {
|
||||
protected String patternComparison(Pattern pattern) {
|
||||
return "==~ java.util.regex.Pattern.compile('$pattern')"
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.springframework.cloud.contract.verifier.dsl.WireMockStubVerifier
|
||||
import spock.lang.Issue
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Specification
|
||||
import spock.lang.Unroll
|
||||
import spock.util.environment.RestoreSystemProperties
|
||||
|
||||
import java.util.regex.Pattern
|
||||
@@ -1537,7 +1538,7 @@ World.'''"""
|
||||
responseElement: $(producer(regex('[0-9]{7}')))
|
||||
])
|
||||
headers {
|
||||
contentType("application/vnd.fraud.v1.json")
|
||||
contentType("application/vnd.fraud.v1+json")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1557,8 +1558,8 @@ World.'''"""
|
||||
strippedTest.matches(""".*header\\("header", "application\\/vnd\\.fraud\\.v1\\+json;.*"\\).*""")
|
||||
strippedTest.matches(""".*body\\('''\\{"requestElement":"[0-9]{5}"\\}'''\\).*""")
|
||||
strippedTest.matches(""".*put\\("/foo/[0-9]{5}"\\).*""")
|
||||
strippedTest.contains("""response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application/vnd\\.fraud\\.v1\\.json.*')""")
|
||||
"application/vnd.fraud.v1+json;charset=UTF-8".matches('application/vnd.fraud.v1.json.*')
|
||||
strippedTest.contains("""response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application/vnd\\.fraud\\.v1\\+json.*')""")
|
||||
"application/vnd.fraud.v1+json;charset=UTF-8".matches('application/vnd\\.fraud\\.v1\\+json.*')
|
||||
strippedTest.contains("""assertThatJson(parsedJson).field("responseElement").matches("[0-9]{7}")""")
|
||||
}
|
||||
|
||||
@@ -1749,4 +1750,35 @@ World.'''"""
|
||||
test.contains('assertThatJson(parsedJson).field("uuid").matches("[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}")')
|
||||
!test.contains('cursor')
|
||||
}
|
||||
|
||||
@Issue('#162')
|
||||
@Unroll
|
||||
def "should escape regex properly for content type"() {
|
||||
given:
|
||||
Contract contractDsl = Contract.make {
|
||||
request {
|
||||
method GET()
|
||||
url 'get'
|
||||
headers {
|
||||
contentType("application/vnd.fraud.v1+json")
|
||||
}
|
||||
}
|
||||
response {
|
||||
status 200
|
||||
headers {
|
||||
contentType("application/vnd.fraud.v1+json")
|
||||
}
|
||||
}
|
||||
}
|
||||
MethodBodyBuilder builder = methodBuilder(contractDsl)
|
||||
BlockBuilder blockBuilder = new BlockBuilder(" ")
|
||||
when:
|
||||
builder.appendTo(blockBuilder)
|
||||
def test = blockBuilder.toString()
|
||||
then:
|
||||
test.contains('application/vnd\\.fraud\\.v1\\+json.*')
|
||||
where:
|
||||
methodBuilder << [{ Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties)},
|
||||
{ Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties)}]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user