Fixed the unnecessary isEmpty generation; fixes gh-727

This commit is contained in:
Marcin Grzejszczak
2019-01-24 17:55:04 +01:00
parent 42329bcacb
commit e8f774f874
2 changed files with 77 additions and 14 deletions

View File

@@ -84,8 +84,11 @@ class JsonToJsonPathsConverter {
if (bodyMatchers?.hasMatchers()) {
bodyMatchers.jsonPathMatchers().each { BodyMatcher matcher ->
try {
context.delete(matcher.path())
removeTrailingContainers(matcher, context)
def entry = entry(context, matcher.path())
if (entry != null) {
context.delete(matcher.path())
removeTrailingContainers(matcher, context)
}
} catch (RuntimeException e) {
if (log.isDebugEnabled()) {
log.debug("Exception occurred while trying to delete path [${matcher.path()}]", e)
@@ -96,6 +99,17 @@ class JsonToJsonPathsConverter {
return jsonCopy
}
private static def entry(DocumentContext context, String path) {
try {
return context.read(path)
} catch (Exception ex) {
if (log.isDebugEnabled()) {
log.debug("Exception occurred while trying to retrieve element via path [${path}]", ex)
}
return null
}
}
/**
* Related to #391. 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
@@ -106,22 +120,26 @@ class JsonToJsonPathsConverter {
* defining body...
*/
private static void removeTrailingContainers(BodyMatcher matcher, DocumentContext context) {
if (matcher.path().contains(ANY_ARRAY_NOTATION_IN_JSONPATH)) {
String pathWithoutAnyArray = matcher.path().substring(0, matcher.path().lastIndexOf(ANY_ARRAY_NOTATION_IN_JSONPATH))
def object = context.read(pathWithoutAnyArray)
if (object instanceof Iterable && containsOnlyEmptyElements(object)) {
String pathToDelete = pathToDelete(pathWithoutAnyArray)
context.delete(pathToDelete)
} else {
String lastParent = matcher.path().substring(0, matcher.path().lastIndexOf("."))
def lastParentObject = context.read(lastParent)
if (lastParentObject instanceof Iterable && containsOnlyEmptyElements(lastParentObject)) {
context.delete(lastParent)
}
String pathWithoutAnyArray = matcher.path().contains(ANY_ARRAY_NOTATION_IN_JSONPATH) ? matcher.path().substring(0, matcher.path().lastIndexOf(ANY_ARRAY_NOTATION_IN_JSONPATH)) : matcher.path()
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
if (isIterable(object) && containsOnlyEmptyElements(object)) {
String pathToDelete = pathToDelete(pathWithoutAnyArray)
context.delete(pathToDelete)
} else {
String lastParent = matcher.path().substring(0, matcher.path().lastIndexOf("."))
def lastParentObject = context.read(lastParent)
if (isIterable(lastParentObject) && containsOnlyEmptyElements(lastParentObject)) {
context.delete(lastParent)
}
}
}
private static boolean isIterable(Object object) {
return object instanceof Iterable || object instanceof Map
}
private static String pathToDelete(String pathWithoutAnyArray) {
// we can't remove root
return pathWithoutAnyArray == '$' ? '$[*]' : pathWithoutAnyArray

View File

@@ -981,4 +981,49 @@ DocumentContext parsedJson = JsonPath.parse(json);
"JaxRsClientJUnitMethodBodyBuilder" | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) }
}
@Issue("#727")
def "should not leave empty arrays [#methodBuilderName]"() {
given:
Contract contractDsl = Contract.make {
request {
method 'GET'
url '/list'
}
response {
status 200
body(
[
content: [
one: "two",
two: "two",
three: [
six: "seven"
]
]
]
)
bodyMatchers {
jsonPath('$.content.three.six', byRegex(".*seven.*"))
jsonPath('$.content.one', byRegex(".*two.*"))
}
}
}
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
then:
String test = blockBuilder.toString()
SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test)
!test.contains('''.isEmpty()''')
and:
stubMappingIsValidWireMockStub(contractDsl)
where:
methodBuilderName | methodBuilder
"MockMvcSpockMethodBuilder" | { Contract dsl -> new MockMvcSpockMethodRequestProcessingBodyBuilder(dsl, properties) }
"MockMvcJUnitMethodBuilder" | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) }
"JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) }
"JaxRsClientJUnitMethodBodyBuilder" | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) }
}
}