Ensures reversed order of body matchers
without this change if in json paths we have .a[0].b[0] and .a[0].b[1] when the first entry is removed, then there is no longer any .a[0].b[1] since it becomes .a[0].b[0]. with this change we're first deleting enties without removing the trailing containers, then we're reversing the order of jsonpaths so that we delete starting from .a[0].b[1] and only then .a[0].b and finally we're removing the containers fixes gh-1125
This commit is contained in:
@@ -85,20 +85,26 @@ class JsonToJsonPathsConverter {
|
||||
def jsonCopy = cloneBody(json)
|
||||
DocumentContext context = JsonPath.parse(jsonCopy)
|
||||
if (bodyMatchers?.hasMatchers()) {
|
||||
bodyMatchers.matchers().each { BodyMatcher matcher ->
|
||||
List<String> pathsToDelete = []
|
||||
List<String> paths = bodyMatchers.matchers().collect { it.path() }
|
||||
paths.each { String path ->
|
||||
try {
|
||||
def entry = entry(context, matcher.path())
|
||||
def entry = entry(context, path)
|
||||
if (entry != null) {
|
||||
context.delete(matcher.path())
|
||||
removeTrailingContainers(matcher.path(), context)
|
||||
context.delete(path)
|
||||
pathsToDelete.add(path)
|
||||
}
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Exception occurred while trying to delete path [${matcher.path()}]", e)
|
||||
log.debug("Exception occurred while trying to delete path [${path}]", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
pathsToDelete.sort(Collections.reverseOrder())
|
||||
pathsToDelete.each {
|
||||
removeTrailingContainers(it, context)
|
||||
}
|
||||
}
|
||||
return jsonCopy
|
||||
}
|
||||
@@ -137,38 +143,46 @@ class JsonToJsonPathsConverter {
|
||||
* defining body...
|
||||
*/
|
||||
private static boolean removeTrailingContainers(String matcherPath, DocumentContext context) {
|
||||
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
|
||||
if (isIterable(object)
|
||||
&&
|
||||
containsOnlyEmptyElements(object)
|
||||
&& isNotRootArray(matcherPath)) {
|
||||
String pathToDelete = pathToDelete(pathWithoutAnyArray)
|
||||
context.delete(pathToDelete)
|
||||
return pathToDelete.contains(DESCENDANT_OPERATOR) ? false :
|
||||
removeTrailingContainers(pathToDelete, context)
|
||||
}
|
||||
else {
|
||||
int lastIndexOfDot = matcherPath.lastIndexOf(".")
|
||||
if (lastIndexOfDot == -1) {
|
||||
return false
|
||||
}
|
||||
String lastParent = matcherPath.substring(0, lastIndexOfDot)
|
||||
def lastParentObject = context.read(lastParent)
|
||||
if (isIterable(lastParentObject)
|
||||
try {
|
||||
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
|
||||
if (isIterable(object)
|
||||
&&
|
||||
containsOnlyEmptyElements(lastParentObject)
|
||||
&& isNotRoot(lastParent)) {
|
||||
context.delete(lastParent)
|
||||
return removeTrailingContainers(lastParent, context)
|
||||
containsOnlyEmptyElements(object)
|
||||
&& isNotRootArray(matcherPath)) {
|
||||
String pathToDelete = pathToDelete(pathWithoutAnyArray)
|
||||
context.delete(pathToDelete)
|
||||
return pathToDelete.contains(DESCENDANT_OPERATOR) ? false :
|
||||
removeTrailingContainers(pathToDelete, context)
|
||||
}
|
||||
else {
|
||||
int lastIndexOfDot = matcherPath.lastIndexOf(".")
|
||||
if (lastIndexOfDot == -1) {
|
||||
return false
|
||||
}
|
||||
String lastParent = matcherPath.substring(0, lastIndexOfDot)
|
||||
def lastParentObject = context.read(lastParent)
|
||||
if (isIterable(lastParentObject)
|
||||
&&
|
||||
containsOnlyEmptyElements(lastParentObject)
|
||||
&& isNotRoot(lastParent)) {
|
||||
context.delete(lastParent)
|
||||
return removeTrailingContainers(lastParent, context)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Exception occurred while trying to delete path [${matcherPath}]", e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private static String lastMatch(Matcher matcher) {
|
||||
|
||||
@@ -2753,6 +2753,64 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie
|
||||
|
||||
}
|
||||
|
||||
@Issue("#1125")
|
||||
def "should not generate assertions for [*] when all manual entries were passed"() {
|
||||
given:
|
||||
Contract contractDsl = Contract.make {
|
||||
request {
|
||||
method(GET())
|
||||
url '/operations'
|
||||
body(
|
||||
channedlId: "UC",
|
||||
operations: [
|
||||
[
|
||||
parameters : [
|
||||
[
|
||||
name : "#POID",
|
||||
value: '70000269814',
|
||||
type : "DECIMAL"
|
||||
],
|
||||
[
|
||||
name : "#OVID",
|
||||
value: "3",
|
||||
type : "DECIMAL"
|
||||
],
|
||||
[
|
||||
name : "#CAMC",
|
||||
value: "CC2PAY",
|
||||
type : "CHAR"
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
)
|
||||
bodyMatchers {
|
||||
jsonPath('$.operations[0].parameters[0].name', byEquality())
|
||||
jsonPath('$.operations[0].parameters[0].value', byRegex('[0-9]{11}'))
|
||||
jsonPath('$.operations[0].parameters[0].type', byEquality())
|
||||
jsonPath('$.operations[0].parameters[1].name', byEquality())
|
||||
jsonPath('$.operations[0].parameters[1].value', byEquality())
|
||||
jsonPath('$.operations[0].parameters[1].type', byEquality())
|
||||
jsonPath('$.operations[0].parameters[2].name', byEquality())
|
||||
jsonPath('$.operations[0].parameters[2].value', byEquality())
|
||||
jsonPath('$.operations[0].parameters[2].type', byEquality())
|
||||
}
|
||||
}
|
||||
|
||||
response {
|
||||
status 200
|
||||
}
|
||||
}
|
||||
when:
|
||||
String wireMockStub = new WireMockStubStrategy("Test",
|
||||
new ContractMetadata(null, false, 0, null, contractDsl), contractDsl)
|
||||
.toWireMockClientStub()
|
||||
|
||||
then:
|
||||
!wireMockStub.contains('''$.['operations'][*]''')
|
||||
stubMappingIsValidWireMockStub(wireMockStub)
|
||||
}
|
||||
|
||||
@Issue("#1257")
|
||||
def "should work with null request element on the client side and optional stub entry"() {
|
||||
given:
|
||||
|
||||
Reference in New Issue
Block a user