Merge branch '2.1.x'

This commit is contained in:
Olga Maciaszek-Sharma
2019-08-19 13:09:34 +02:00
2 changed files with 131 additions and 5 deletions

View File

@@ -16,6 +16,7 @@
package org.springframework.cloud.contract.verifier.util
import java.util.regex.Matcher
import java.util.regex.Pattern
import com.jayway.jsonpath.DocumentContext
@@ -42,6 +43,7 @@ import org.springframework.util.SerializationUtils
*
* @author Marcin Grzejszczak
* @author Tim Ysewyn
* @author Olga Maciaszek-Sharma
*/
@Commons
class JsonToJsonPathsConverter {
@@ -54,7 +56,7 @@ class JsonToJsonPathsConverter {
private static final Boolean SERVER_SIDE = false
private static final Boolean CLIENT_SIDE = true
private static final String ANY_ARRAY_NOTATION_IN_JSONPATH = "[*]"
private static final Pattern ANY_ARRAY_NOTATION_IN_JSONPATH = ~/\[(.*?)\]/
private static final String DESCENDANT_OPERATOR = ".."
private final boolean assertJsonSize
@@ -132,7 +134,7 @@ class JsonToJsonPathsConverter {
}
/**
* Related to #391. The converted body looks different when done via the String notation than
* Related to #391 and #1091. The converted body looks different when done via the String notation than
* it does when done via a map notation. When working with String body and when matchers
* are provided, even when all entries of a map / list got removed, the map / list itself
* remains. That leads to unnecessary creation of checks for empty collection. With this method
@@ -141,9 +143,10 @@ class JsonToJsonPathsConverter {
* defining body...
*/
private static boolean removeTrailingContainers(String matcherPath, DocumentContext context) {
boolean containsArray = matcherPath.contains(ANY_ARRAY_NOTATION_IN_JSONPATH)
String pathWithoutAnyArray = containsArray ? matcherPath.substring(0, matcherPath.
lastIndexOf(ANY_ARRAY_NOTATION_IN_JSONPATH)) : matcherPath
Matcher matcher = ANY_ARRAY_NOTATION_IN_JSONPATH.matcher(matcherPath)
boolean containsArray = matcher.find()
String pathWithoutAnyArray = containsArray ? matcherPath.
substring(0, matcherPath.lastIndexOf(lastMatch(matcher))) : matcherPath
def object = entry(context, pathWithoutAnyArray)
// object got removed and it was the only element
// let's get its parent and see if it contains an empty element
@@ -170,6 +173,15 @@ class JsonToJsonPathsConverter {
return false
}
private static String lastMatch(Matcher matcher) {
List<String> matches = []
while ({
matches << matcher.group()
matcher.find()
}()) continue
return matches[matches.size() - 1]
}
private static boolean isIterable(Object object) {
return object instanceof Iterable || object instanceof Map
}

View File

@@ -623,4 +623,118 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements
}
}
@Issue('#1091')
def 'should work for map with array value where matchers cover all array fields for [#methodBuilderName]'() {
given:
Contract contractDsl = Contract.make {
request {
name "ISSUE 1091"
method 'GET'
url '/test'
headers {
contentType(applicationJson())
}
}
response {
status OK()
body('''
{
"prices": [
{
"country" : "ES",
"originalPrice": "1500"
}
]
}
'''
)
bodyMatchers {
jsonPath('$.prices[0].country', byRegex(nonBlank()))
jsonPath('$.prices[0].originalPrice', byRegex(number()))
}
headers {
contentType(applicationJsonUtf8())
}
}
}
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
and:
builder.appendTo(blockBuilder)
String test = blockBuilder.toString()
when:
SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test)
then:
!test.contains('isEmpty()')
where:
methodBuilderName | methodBuilder
HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) }
MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) }
JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) }
JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) }
WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) }
}
@Issue('#1091')
def 'should work for array containing map with array value where matchers cover all array fields for [#methodBuilderName]'() {
given:
Contract contractDsl = Contract.make {
request {
name "ISSUE 1091"
method 'GET'
url '/test'
headers {
contentType(applicationJson())
}
}
response {
status OK()
body('''
{
"test": [
{
"prices": [
{
"country" : "ES",
"originalPrice": 1500
}
]
}
]
}
'''
)
bodyMatchers {
jsonPath('$.test[0].barcode', byRegex(nonBlank()))
jsonPath('$.test[0].id', byRegex(nonBlank()))
jsonPath('$.test[0].prices[0].country', byRegex(nonBlank()))
jsonPath('$.test[0].prices[0].originalPrice', byRegex(nonBlank()))
jsonPath('$.test[0].prices[?(@.originalPrice==1500)].originalPrice',
byRegex(nonBlank()))
}
headers {
contentType(applicationJsonUtf8())
}
}
}
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
and:
builder.appendTo(blockBuilder)
String test = blockBuilder.toString()
when:
SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test)
then:
!test.contains('isEmpty()')
where:
methodBuilderName | methodBuilder
HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) }
MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) }
JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) }
JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) }
WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) }
}
}