Added equality check to matchers

This commit is contained in:
Marcin Grzejszczak
2017-01-11 14:16:53 +01:00
parent 9ccc5bc0fd
commit 76966a985c
12 changed files with 172 additions and 60 deletions

View File

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

View File

@@ -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("\\\\", "\\")))
}
}

View File

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

View File

@@ -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])")')

View File

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