Merge branch '2.2.x'

This commit is contained in:
Marcin Grzejszczak
2021-03-08 17:15:43 +01:00
3 changed files with 80 additions and 4 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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: