Added equality check to matchers
This commit is contained in:
@@ -312,7 +312,11 @@ abstract class MethodBodyBuilder {
|
||||
// for the rest we'll do JsonPath matching in brute force
|
||||
bodyMatchers.jsonPathMatchers().each {
|
||||
if (it.value()) {
|
||||
String method = "assertThat(parsedJson.read(${quotedAndEscaped(it.path())}, String.class)).matches(${quotedAndEscaped(it.value())})"
|
||||
String comparisonMethod = it.matchingType() == MatchingType.EQUALITY ? "isEqualTo" : "matches"
|
||||
String valueAsParam = it.value() instanceof String ? quotedAndEscaped(it.value().toString()) : it.value().toString()
|
||||
String classToCastTo = "${it.value().class.simpleName}.class"
|
||||
String path = quotedAndEscaped(it.path())
|
||||
String method = "assertThat(parsedJson.read(${path}, ${classToCastTo})).${comparisonMethod}(${valueAsParam})"
|
||||
bb.addLine(postProcessJsonPathCall(method))
|
||||
addColonIfRequired(bb)
|
||||
} else {
|
||||
|
||||
@@ -87,7 +87,7 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy {
|
||||
}
|
||||
if (request.matchers?.hasMatchers()) {
|
||||
request.matchers.jsonPathMatchers().each {
|
||||
String newPath = JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(it.path(), it.value())
|
||||
String newPath = JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(it)
|
||||
requestPattern.withRequestBody(WireMock.matchingJsonPath(newPath.replace("\\\\", "\\")))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,15 +21,14 @@ import com.toomuchcoding.jsonassert.JsonAssertion
|
||||
import groovy.json.JsonOutput
|
||||
import groovy.json.JsonSlurper
|
||||
import groovy.util.logging.Slf4j
|
||||
import org.springframework.cloud.contract.spec.internal.OptionalProperty
|
||||
import org.springframework.cloud.contract.spec.internal.BodyMatcher
|
||||
import org.springframework.cloud.contract.spec.internal.BodyMatchers
|
||||
import org.springframework.cloud.contract.spec.internal.MatchingType
|
||||
import org.springframework.cloud.contract.spec.internal.ExecutionProperty
|
||||
import org.springframework.cloud.contract.spec.internal.MatchingType
|
||||
import org.springframework.cloud.contract.spec.internal.OptionalProperty
|
||||
import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties
|
||||
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* I would like to apologize to anyone who is reading this class. Since JSON is a hectic structure
|
||||
* this class is also hectic. The idea is to traverse the JSON structure and build a set of
|
||||
@@ -73,8 +72,7 @@ class JsonToJsonPathsConverter {
|
||||
*/
|
||||
static def removeMatchingJsonPaths(def json, BodyMatchers bodyMatchers) {
|
||||
if (bodyMatchers?.hasMatchers()) {
|
||||
// remove all jsonpaths from the body - for those that remain we continue as usual
|
||||
bodyMatchers.jsonPathMatchers().findAll { it.matchingType() != MatchingType.EQUALITY }.each { BodyMatcher matcher ->
|
||||
bodyMatchers.jsonPathMatchers().each { BodyMatcher matcher ->
|
||||
JsonPath.parse(json).delete(matcher.path())
|
||||
}
|
||||
}
|
||||
@@ -82,21 +80,32 @@ class JsonToJsonPathsConverter {
|
||||
}
|
||||
|
||||
/**
|
||||
* For the given JSON path and regex pattern converts it into a JSON path
|
||||
* that checks the Pattern
|
||||
* For the given matcher converts it into a JSON path
|
||||
* that checks the regex pattern or equality
|
||||
*
|
||||
* @param path - JSON path
|
||||
* @param pattern - pattern to check for the last element of JSON path
|
||||
* @param bodyMatcher
|
||||
* @return JSON path that checks the regex for its last element
|
||||
*/
|
||||
static String convertJsonPathAndRegexToAJsonPath(String path, String pattern) {
|
||||
if (!pattern) {
|
||||
static String convertJsonPathAndRegexToAJsonPath(BodyMatcher bodyMatcher) {
|
||||
String path = bodyMatcher.path()
|
||||
Object value = bodyMatcher.value()
|
||||
if (!value) {
|
||||
return path
|
||||
}
|
||||
int lastIndexOfDot = path.lastIndexOf(".")
|
||||
String toLastDot = path.substring(0, lastIndexOfDot)
|
||||
String fromLastDot = path.substring(lastIndexOfDot + 1)
|
||||
return "${toLastDot}[?(@.${fromLastDot} =~ /(${pattern})/)]"
|
||||
String comparison = createComparison(bodyMatcher, value)
|
||||
return "${toLastDot}[?(@.${fromLastDot} ${comparison})]"
|
||||
}
|
||||
|
||||
private static String createComparison(BodyMatcher bodyMatcher, Object value) {
|
||||
if (bodyMatcher.matchingType() == MatchingType.EQUALITY) {
|
||||
String wrappedValue = value instanceof Number ? value : "'${value.toString()}'"
|
||||
return "== ${wrappedValue}"
|
||||
} else {
|
||||
return "=~ /(${value})/"
|
||||
}
|
||||
}
|
||||
|
||||
JsonPaths transformToJsonPathWithTestsSideValues(def json) {
|
||||
|
||||
@@ -51,7 +51,9 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements
|
||||
])
|
||||
stubMatchers {
|
||||
jsonPath('$.duck', byRegex("[0-9]{3}"))
|
||||
jsonPath('$.duck', byValue(123))
|
||||
jsonPath('$.alpha', byRegex(onlyAlphaUnicode()))
|
||||
jsonPath('$.alpha', byValue("abc"))
|
||||
jsonPath('$.number', byRegex(number()))
|
||||
jsonPath('$.aBoolean', byRegex(anyBoolean()))
|
||||
jsonPath('$.date', byDate())
|
||||
@@ -87,8 +89,11 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements
|
||||
testMatchers {
|
||||
// asserts the jsonpath value against manual regex
|
||||
jsonPath('$.duck', byRegex("[0-9]{3}"))
|
||||
// asserts the jsonpath value against the provided value
|
||||
jsonPath('$.duck', byValue(123))
|
||||
// asserts the jsonpath value against some default regex
|
||||
jsonPath('$.alpha', byRegex(onlyAlphaUnicode()))
|
||||
jsonPath('$.alpha', byValue("abc"))
|
||||
jsonPath('$.number', byRegex(number()))
|
||||
jsonPath('$.aBoolean', byRegex(anyBoolean()))
|
||||
// asserts vs inbuilt time related regex
|
||||
@@ -124,7 +129,9 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements
|
||||
def test = blockBuilder.toString()
|
||||
then:
|
||||
test.contains('assertThat(parsedJson.read("' + rootElement + '.duck", String.class)).matches("[0-9]{3}")')
|
||||
test.contains('assertThat(parsedJson.read("' + rootElement + '.duck", Integer.class)).isEqualTo(123)')
|
||||
test.contains('assertThat(parsedJson.read("' + rootElement + '.alpha", String.class)).matches("[\\\\p{L}]*")')
|
||||
test.contains('assertThat(parsedJson.read("' + rootElement + '.alpha", String.class)).isEqualTo("abc")')
|
||||
test.contains('assertThat(parsedJson.read("' + rootElement + '.number", String.class)).matches("-?\\\\d*(\\\\.\\\\d+)?")')
|
||||
test.contains('assertThat(parsedJson.read("' + rootElement + '.aBoolean", String.class)).matches("(true|false)")')
|
||||
test.contains('assertThat(parsedJson.read("' + rootElement + '.date", String.class)).matches("(\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])")')
|
||||
|
||||
@@ -24,6 +24,8 @@ import com.toomuchcoding.jsonassert.JsonAssertion
|
||||
import groovy.json.JsonOutput
|
||||
import groovy.json.JsonSlurper
|
||||
import net.minidev.json.JSONArray
|
||||
import org.springframework.cloud.contract.spec.internal.BodyMatcher
|
||||
import org.springframework.cloud.contract.spec.internal.MatchingType
|
||||
import spock.lang.Specification
|
||||
import spock.util.environment.RestoreSystemProperties
|
||||
|
||||
@@ -758,14 +760,59 @@ class JsonToJsonPathsConverterSpec extends Specification {
|
||||
String jsonPath = '$.a.b.c.d'
|
||||
String regexPattern = ".*"
|
||||
expect:
|
||||
'$.a.b.c[?(@.d =~ /(.*)/)]' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(jsonPath, regexPattern)
|
||||
'$.a.b.c[?(@.d =~ /(.*)/)]' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.REGEX, jsonPath, regexPattern))
|
||||
}
|
||||
|
||||
def "should return the path if no regex pattern is provided"() {
|
||||
def "should convert a json path with value to a equality checking json path without quotes for numbers"() {
|
||||
given:
|
||||
String jsonPath = '$.a.b.c.d'
|
||||
Integer value = 1234
|
||||
expect:
|
||||
'$.a.b.c[?(@.d == 1234)]' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.EQUALITY, jsonPath, value))
|
||||
}
|
||||
|
||||
def "should convert a json path with value to a equality checking json path with quotes for strings"() {
|
||||
given:
|
||||
String jsonPath = '$.a.b.c.d'
|
||||
String value = "foo"
|
||||
expect:
|
||||
'$.a.b.c[?(@.d == \'foo\')]' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.EQUALITY, jsonPath, value))
|
||||
}
|
||||
|
||||
def "should return the path if no value is provided"() {
|
||||
given:
|
||||
String jsonPath = '$.a.b.c.d'
|
||||
expect:
|
||||
'$.a.b.c.d' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(jsonPath, null)
|
||||
'$.a.b.c.d' == JsonToJsonPathsConverter.convertJsonPathAndRegexToAJsonPath(matcher(MatchingType.REGEX, jsonPath, null))
|
||||
}
|
||||
|
||||
private BodyMatcher matcher(final MatchingType matchingType, final String jsonPath, final Object value) {
|
||||
return new BodyMatcher() {
|
||||
@Override
|
||||
MatchingType matchingType() {
|
||||
return matchingType
|
||||
}
|
||||
|
||||
@Override
|
||||
String path() {
|
||||
return jsonPath
|
||||
}
|
||||
|
||||
@Override
|
||||
Object value() {
|
||||
return value
|
||||
}
|
||||
|
||||
@Override
|
||||
Integer minTypeOccurrence() {
|
||||
return null
|
||||
}
|
||||
|
||||
@Override
|
||||
Integer maxTypeOccurrence() {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void assertThatJsonPathsInMapAreValid(String json, JsonPaths pathAndValues) {
|
||||
|
||||
Reference in New Issue
Block a user