Assert size of collections on the request side; fixes gh-824
This commit is contained in:
@@ -128,7 +128,9 @@ class ContractsToYaml {
|
||||
request.matchers.body << new YamlContract.BodyStubMatcher(
|
||||
path: matcher.path(),
|
||||
type: stubMatcherType(matcher.matchingType()),
|
||||
value: matcher.value()?.toString()
|
||||
value: matcher.value()?.toString(),
|
||||
minOccurrence: matcher.minTypeOccurrence(),
|
||||
maxOccurrence: matcher.maxTypeOccurrence(),
|
||||
)
|
||||
}
|
||||
Object url = contract.request.url?.clientValue
|
||||
|
||||
@@ -104,6 +104,8 @@ class YamlContract {
|
||||
public StubMatcherType type
|
||||
public String value
|
||||
public PredefinedRegex predefined
|
||||
public Integer minOccurrence
|
||||
public Integer maxOccurrence
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
@@ -199,7 +201,7 @@ class YamlContract {
|
||||
|
||||
@CompileStatic
|
||||
static enum StubMatcherType {
|
||||
by_date, by_time, by_timestamp, by_regex, by_equality, by_null
|
||||
by_date, by_time, by_timestamp, by_regex, by_equality, by_type, by_null
|
||||
}
|
||||
|
||||
@CompileStatic
|
||||
|
||||
@@ -199,6 +199,12 @@ class YamlToContracts {
|
||||
case YamlContract.StubMatcherType.by_equality:
|
||||
value = byEquality()
|
||||
break
|
||||
case YamlContract.StubMatcherType.by_type:
|
||||
value = byType {
|
||||
if (matcher.minOccurrence != null) minOccurrence(matcher.minOccurrence)
|
||||
if (matcher.maxOccurrence != null) maxOccurrence(matcher.maxOccurrence)
|
||||
}
|
||||
break
|
||||
case YamlContract.StubMatcherType.by_null:
|
||||
// do nothing
|
||||
break
|
||||
|
||||
@@ -142,14 +142,16 @@ class JsonToJsonPathsConverter {
|
||||
static String convertJsonPathAndRegexToAJsonPath(BodyMatcher bodyMatcher, def body = null) {
|
||||
String path = bodyMatcher.path()
|
||||
Object value = bodyMatcher.value()
|
||||
if (value == null && bodyMatcher.matchingType() != MatchingType.EQUALITY) {
|
||||
if (value == null && bodyMatcher.matchingType() != MatchingType.EQUALITY &&
|
||||
bodyMatcher.matchingType() != MatchingType.TYPE) {
|
||||
return path
|
||||
}
|
||||
int lastIndexOfDot = lastIndexOfDot(path)
|
||||
String toLastDot = path.substring(0, lastIndexOfDot)
|
||||
String fromLastDot = path.substring(lastIndexOfDot + 1)
|
||||
String comparison = createComparison(bodyMatcher, value, body)
|
||||
return "${toLastDot}[?(@.${fromLastDot} ${comparison})]"
|
||||
String propertyName = "@.${fromLastDot}"
|
||||
String comparison = createComparison(propertyName, bodyMatcher, value, body)
|
||||
return "${toLastDot}[?(${comparison})]"
|
||||
}
|
||||
|
||||
private static int lastIndexOfDot(String path) {
|
||||
@@ -173,7 +175,7 @@ class JsonToJsonPathsConverter {
|
||||
return value
|
||||
}
|
||||
|
||||
private static String createComparison(BodyMatcher bodyMatcher, Object value, def body) {
|
||||
private static String createComparison(String propertyName, BodyMatcher bodyMatcher, Object value, def body) {
|
||||
if (bodyMatcher.matchingType() == MatchingType.EQUALITY) {
|
||||
Object convertedBody = body
|
||||
if (!body) {
|
||||
@@ -185,13 +187,25 @@ class JsonToJsonPathsConverter {
|
||||
}
|
||||
Object retrievedValue = JsonPath.parse(convertedBody).read(bodyMatcher.path())
|
||||
String wrappedValue = retrievedValue instanceof Number ? retrievedValue : "'${retrievedValue.toString()}'"
|
||||
return "== ${wrappedValue}"
|
||||
return "${propertyName} == ${wrappedValue}"
|
||||
} catch (PathNotFoundException e) {
|
||||
throw new IllegalStateException("Value [${bodyMatcher.path()}] not found in JSON [${JsonOutput.toJson(convertedBody)}]", e)
|
||||
}
|
||||
} else if (bodyMatcher.matchingType() == MatchingType.TYPE) {
|
||||
Integer min = bodyMatcher.minTypeOccurrence()
|
||||
Integer max = bodyMatcher.maxTypeOccurrence()
|
||||
String result = ""
|
||||
if (min != null) {
|
||||
result = "${propertyName}.size() >= ${min}"
|
||||
}
|
||||
if (max != null) {
|
||||
String maxResult = "${propertyName}.size() <= ${max}"
|
||||
result = result ? "${result} && ${maxResult}" : maxResult
|
||||
}
|
||||
return result
|
||||
} else {
|
||||
String convertedValue = value.toString().replace('/', '\\\\/')
|
||||
return "=~ /(${convertedValue})/"
|
||||
return "${propertyName} =~ /(${convertedValue})/"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1192,7 +1192,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub
|
||||
where:
|
||||
methodBuilderName | methodBuilder | endOfLineRegexSymbol
|
||||
"JaxRsClientSpockMethodRequestProcessingBodyBuilder"| { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$'
|
||||
"JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$'
|
||||
"JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) }| '$'
|
||||
}
|
||||
|
||||
private String stripped(String string) {
|
||||
|
||||
@@ -475,7 +475,7 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements
|
||||
bodyMatchers {
|
||||
jsonPath('$.items[*].id', byRegex(nonBlank()))
|
||||
jsonPath('$.items[*].title', byRegex(nonBlank()))
|
||||
jsonPath('$.items[*]', byType { minOccurrence(2); maxOccurrence(2) })
|
||||
jsonPath('$.items[*]', byType { occurrence(2) })
|
||||
}
|
||||
headers { header 'content-type', 'application/...json;charset=UTF-8' }
|
||||
}
|
||||
|
||||
@@ -239,6 +239,16 @@ class YamlContractConverterSpec extends Specification {
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[8].value() == patterns.isoTime()
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[9].path() == "\$.['key'].['complex.key']"
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[9].matchingType() == MatchingType.EQUALITY
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[10].path() == '$.valueWithMin'
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[10].matchingType() == MatchingType.TYPE
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[10].minTypeOccurrence() == 1
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[11].path() == '$.valueWithMax'
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[11].matchingType() == MatchingType.TYPE
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[11].maxTypeOccurrence() == 3
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[12].path() == '$.valueWithMinMax'
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[12].matchingType() == MatchingType.TYPE
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[12].minTypeOccurrence() == 1
|
||||
contract.request.bodyMatchers.jsonPathRegexMatchers[12].maxTypeOccurrence() == 3
|
||||
contract.request.cookies.entries.find { it.key == "foo" }.clientValue instanceof Pattern
|
||||
contract.request.cookies.entries.find { it.key == "bar" }.serverValue == new ExecutionProperty('equals($it)')
|
||||
and:
|
||||
|
||||
@@ -28,6 +28,20 @@ request:
|
||||
key:
|
||||
"complex.key": 'foo'
|
||||
nullValue: null
|
||||
valueWithMin:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
valueWithMax:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
valueWithMinMax:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
valueWithMinEmpty: []
|
||||
valueWithMaxEmpty: []
|
||||
matchers:
|
||||
url:
|
||||
regex: /get/[0-9]
|
||||
@@ -90,6 +104,16 @@ request:
|
||||
type: by_equality
|
||||
- path: $.nullvalue
|
||||
type: by_null
|
||||
- path: $.valueWithMin
|
||||
type: by_type
|
||||
minOccurrence: 1
|
||||
- path: $.valueWithMax
|
||||
type: by_type
|
||||
maxOccurrence: 3
|
||||
- path: $.valueWithMinMax
|
||||
type: by_type
|
||||
minOccurrence: 1
|
||||
maxOccurrence: 3
|
||||
response:
|
||||
status: 200
|
||||
cookies:
|
||||
|
||||
Reference in New Issue
Block a user