Merge branch '2.2.x'
This commit is contained in:
@@ -39,6 +39,7 @@ import org.springframework.cloud.contract.spec.internal.MatchingStrategy
|
||||
import org.springframework.cloud.contract.spec.internal.NamedProperty
|
||||
import org.springframework.cloud.contract.spec.internal.OptionalProperty
|
||||
import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor
|
||||
import org.springframework.util.StringUtils
|
||||
|
||||
import static org.apache.commons.text.StringEscapeUtils.escapeJava
|
||||
import static org.apache.commons.text.StringEscapeUtils.escapeJson
|
||||
@@ -108,7 +109,7 @@ class ContentUtils {
|
||||
* @return JSON structure with replaced client / server side parts
|
||||
*/
|
||||
static Object extractValue(GString bodyAsValue, ContentType contentType, Closure valueProvider) {
|
||||
if (bodyAsValue.isEmpty()) {
|
||||
if (!StringUtils.hasText(bodyAsValue.toString())) {
|
||||
return bodyAsValue
|
||||
}
|
||||
if (contentType == ContentType.TEXT || contentType == ContentType.FORM) {
|
||||
|
||||
@@ -140,7 +140,7 @@ class JsonToJsonPathsConverter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Related to #391 and #1091. The converted body looks different when done via the String notation than
|
||||
* Related to #391 and #1091 and #1414. 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
|
||||
@@ -163,8 +163,16 @@ class JsonToJsonPathsConverter {
|
||||
&& isNotRootArray(matcherPath)) {
|
||||
String pathToDelete = pathToDelete(pathWithoutAnyArray)
|
||||
context.delete(pathToDelete)
|
||||
return pathToDelete.contains(DESCENDANT_OPERATOR) ? false :
|
||||
removeTrailingContainers(pathToDelete, context)
|
||||
if (pathToDelete.contains(DESCENDANT_OPERATOR)) {
|
||||
Object root = context.read('$')
|
||||
if (rootContainsEmptyContainers(root)) {
|
||||
// now root contains only empty elements, we should remove the trailing containers
|
||||
context.delete('$[*]')
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
return removeTrailingContainers(pathToDelete, context)
|
||||
}
|
||||
else {
|
||||
int lastIndexOfDot = matcherPath.lastIndexOf(".")
|
||||
@@ -191,6 +199,10 @@ class JsonToJsonPathsConverter {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean rootContainsEmptyContainers(root) {
|
||||
root instanceof Iterable && root.every { containsOnlyEmptyElements(it) }
|
||||
}
|
||||
|
||||
private static String lastMatch(Matcher matcher) {
|
||||
List<String> matches = []
|
||||
while ({
|
||||
@@ -204,6 +216,10 @@ class JsonToJsonPathsConverter {
|
||||
return object instanceof Iterable || object instanceof Map
|
||||
}
|
||||
|
||||
private static boolean isEmpty(Object object) {
|
||||
return isIterable(object) && object instanceof Iterable ? object.isEmpty() : ((Map) object).isEmpty()
|
||||
}
|
||||
|
||||
private static String pathToDelete(String pathWithoutAnyArray) {
|
||||
// we can't remove root
|
||||
return pathWithoutAnyArray == '$' ? '$[*]' : pathWithoutAnyArray
|
||||
|
||||
@@ -1755,6 +1755,65 @@ response:
|
||||
}
|
||||
}
|
||||
|
||||
@Issue("#1414")
|
||||
def "should work with empty arrays after doing array matching [#methodBuilderName]"() {
|
||||
given:
|
||||
String yaml = '''\
|
||||
name: GET sample
|
||||
description: sample
|
||||
request:
|
||||
method: GET
|
||||
urlPath: /sample
|
||||
response:
|
||||
status: 200
|
||||
body:
|
||||
- foo: "sample1"
|
||||
bar: true
|
||||
- foo: "sample2"
|
||||
bar: false
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
matchers:
|
||||
body:
|
||||
- path: $..foo
|
||||
type: by_regex
|
||||
value: .*
|
||||
- path: $..bar
|
||||
type: by_regex
|
||||
predefined: any_boolean
|
||||
'''
|
||||
File tmpFile = File.createTempFile("foo", ".yml")
|
||||
tmpFile.createNewFile()
|
||||
tmpFile.text = yaml
|
||||
Contract contractDsl = new YamlContractConverter().convertFrom(tmpFile).
|
||||
first()
|
||||
methodBuilder()
|
||||
when:
|
||||
String test = singleTestGenerator(contractDsl)
|
||||
then:
|
||||
SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test)
|
||||
!test.contains('''assertThatJson(parsedJson).array().isEmpty()''')
|
||||
and:
|
||||
stubMappingIsValidWireMockStub(contractDsl)
|
||||
where:
|
||||
methodBuilderName | methodBuilder
|
||||
"spock" | {
|
||||
properties.testFramework = TestFramework.SPOCK
|
||||
}
|
||||
"mockmvc" | {
|
||||
properties.testMode = TestMode.MOCKMVC
|
||||
}
|
||||
"jaxrs-spock" | {
|
||||
properties.testFramework = TestFramework.SPOCK; properties.testMode = TestMode.JAXRSCLIENT
|
||||
}
|
||||
"jaxrs" | {
|
||||
properties.testFramework = TestFramework.JUNIT; properties.testMode = TestMode.JAXRSCLIENT
|
||||
}
|
||||
"testNG" | {
|
||||
properties.testFramework = TestFramework.TESTNG
|
||||
}
|
||||
}
|
||||
|
||||
@Issue("#1262")
|
||||
def "should work with the timeout flag for groovy [#methodBuilderName]"() {
|
||||
given:
|
||||
|
||||
Reference in New Issue
Block a user