diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/DelegatingJsonVerifiable.java b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/DelegatingJsonVerifiable.java index aff8c210d0..92af31d149 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/DelegatingJsonVerifiable.java +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/DelegatingJsonVerifiable.java @@ -16,13 +16,13 @@ package org.springframework.cloud.contract.verifier.util; +import static org.apache.commons.lang3.StringEscapeUtils.escapeJava; + import java.util.LinkedList; import java.util.regex.Pattern; import com.toomuchcoding.jsonassert.JsonVerifiable; -import static org.apache.commons.lang3.StringEscapeUtils.escapeJava; - /** * Implementation of the {@link MethodBufferingJsonVerifiable} that contains a list * of String method commands that need to be executed to assert JSONs. @@ -191,14 +191,24 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable { public MethodBufferingJsonVerifiable matches(String value) { DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.matches(value), this.methodsBuffer); if (this.delegate.isAssertingAValueInArray()) { - readyToCheck.appendMethodWithQuotedValue("matches", escapeJava(value)); + readyToCheck.appendMethodWithQuotedValue("matches", escapedHackedJavaText(value)); readyToCheck.methodsBuffer.offer(".value()"); } else { - readyToCheck.appendMethodWithQuotedValue("matches", escapeJava(value)); + readyToCheck.appendMethodWithQuotedValue("matches", escapedHackedJavaText(value)); } return readyToCheck; } + /** + * We need to escape the pattern in order for the produced text to be compilable. + * The problem is that sometimes we get quotes that already escaped. If we escape them + * we get code that doesn't compile. That's why we're doing this hack to unescape + * an double escaped text. Related to https://github.com/spring-cloud/spring-cloud-contract/issues/169 + */ + private String escapedHackedJavaText(String value) { + return escapeJava(value).replace("\\\"", "\""); + } + @Override public MethodBufferingJsonVerifiable isEqualTo(Boolean value) { DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(this.delegate.isEqualTo(value), this.methodsBuffer); diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy index 3373c6a535..f381c63cd1 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy @@ -2005,26 +2005,24 @@ World.'''""" "MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' } - @Issue('#173') - @Unroll - def "should resolve Optional object when used in query parameters"() { + @Issue('#169') + def "should escape quotes properly using [#methodBuilderName]"() { given: - Contract contractDsl = Contract.make { + Contract contractDsl = Contract.make { request { - method 'GET' - urlPath('/blacklist') { - queryParameters { - parameter 'isActive': value(consumer(optional(regex('(true|false)')))) - parameter 'limit': value(consumer(optional(regex('([0-9]{1,10})')))) - parameter 'offset': value(consumer(optional(regex('([0-9]{1,10})')))) - } - } - headers { - header 'Content-Type': 'application/json' - } + method 'POST' + url '/foo' + body( + xyz: 'abc' + ) + headers { header('Content-Type', 'application/json;charset=UTF-8') } } response { - status(200) + status 200 + body( + bar: $(producer(regex('some value \u0022with quote\u0022|bar'))) + ) + headers { header('Content-Type': 'application/json;charset=UTF-8') } } } MethodBodyBuilder builder = methodBuilder(contractDsl) @@ -2033,10 +2031,13 @@ World.'''""" builder.appendTo(blockBuilder) def test = blockBuilder.toString() then: - !test.contains('org.springframework.cloud.contract.spec.internal.OptionalProperty') - test.contains('(([0-9]{1,10}))?') +// test.contains('assertThatJson(parsedJson).field("bar").matches("some value \\"with quote\\"|bar")') +// and: + SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: - methodBuilder << [{ Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties)}, - { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties)}] + //order is inverted cause Intellij didn't parse this properly + methodBuilderName | methodBuilder | expectedAssertion + "MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"''' + "MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' } }