Fixed the way we parse lists with regexps in responses (#224)

* Fixed the way we parse lists with regexps in responses

fixes #216
This commit is contained in:
Marcin Grzejszczak
2016-04-12 16:04:46 -04:00
parent 9b591edca8
commit 79634f48fc
5 changed files with 116 additions and 17 deletions

View File

@@ -27,8 +27,12 @@ class ContentUtils {
it instanceof DslProperty ? it.clientValue : it
}
public static final Closure GET_TEST_SIDE = {
it instanceof DslProperty ? it.serverValue : it
}
private static final Pattern TEMPORARY_PATTERN_HOLDER = Pattern.compile('.*REGEXP>>(.*)<<.*')
private static final Pattern TEMPORARY_EXECUTION_PATTERN_HOLDER = Pattern.compile('EXECUTION>>(.*)<<')
private static final Pattern TEMPORARY_EXECUTION_PATTERN_HOLDER = Pattern.compile('["]?EXECUTION>>(.*)<<["]?')
private static final Pattern TEMPORARY_OPTIONAL_PATTERN_HOLDER = Pattern.compile('OPTIONAL>>(.*)<<')
private static final String JSON_VALUE_PATTERN_FOR_REGEX = 'REGEXP>>%s<<'
private static final String JSON_VALUE_PATTERN_FOR_OPTIONAL = 'OPTIONAL>>%s<<'
@@ -150,23 +154,23 @@ class ContentUtils {
)
}
private static String transformJSONStringValue(Object obj, Closure valueProvider) {
return obj.toString()
protected static Object transformJSONStringValue(Object obj, Closure valueProvider) {
return obj
}
private static String transformJSONStringValue(DslProperty dslProperty, Closure valueProvider) {
protected static Object transformJSONStringValue(DslProperty dslProperty, Closure valueProvider) {
return transformJSONStringValue(valueProvider(dslProperty), valueProvider)
}
private static String transformJSONStringValue(Pattern pattern, Closure valueProvider) {
protected static Object transformJSONStringValue(Pattern pattern, Closure valueProvider) {
return String.format(JSON_VALUE_PATTERN_FOR_REGEX, pattern.pattern())
}
private static String transformJSONStringValue(OptionalProperty optional, Closure valueProvider) {
protected static Object transformJSONStringValue(OptionalProperty optional, Closure valueProvider) {
return String.format(JSON_VALUE_PATTERN_FOR_OPTIONAL, optional.value)
}
private static String transformJSONStringValue(ExecutionProperty property, Closure valueProvider) {
protected static Object transformJSONStringValue(ExecutionProperty property, Closure valueProvider) {
return String.format(JSON_VALUE_PATTERN_FOR_EXECUTION, property.executionCommand)
}
@@ -178,6 +182,12 @@ class ContentUtils {
return transformXMLStringValue(valueProvider(dslProperty), valueProvider)
}
protected static Object convertDslPropsToTemporaryRegexPatterns(parsedJson) {
MapConverter.transformValues(parsedJson, { Object value ->
return transformJSONStringValue(value, GET_TEST_SIDE)
})
}
private static Object convertAllTemporaryRegexPlaceholdersBackToPatterns(parsedJson) {
MapConverter.transformValues(parsedJson, { Object value ->
if (value instanceof String) {
@@ -212,7 +222,11 @@ class ContentUtils {
* @param string to match the regexps against
* @return object converted from temporary holders
*/
static Object returnParsedObject(String string) {
static Object returnParsedObject(Object object) {
if (!(object instanceof String)) {
return object
}
String string = (String) object
Matcher matcher = TEMPORARY_PATTERN_HOLDER.matcher(string.trim())
if (matcher.matches()) {
return Pattern.compile(patternFromMatchingGroup(matcher))

View File

@@ -137,6 +137,7 @@ class DelegatingJsonVerifiable implements MethodBufferingJsonVerifiable {
public MethodBufferingJsonVerifiable matches(String value) {
DelegatingJsonVerifiable readyToCheck = new FinishedDelegatingJsonVerifiable(delegate.matches(value), methodsBuffer);
if (delegate.isAssertingAValueInArray()) {
readyToCheck.appendMethodWithQuotedValue("matches", escapeJava(value));
readyToCheck.methodsBuffer.append(".value()");
} else {
readyToCheck.appendMethodWithQuotedValue("matches", escapeJava(value));

View File

@@ -29,9 +29,10 @@ class JsonToJsonPathsConverter {
}
JsonPaths pathsAndValues = [] as Set
Object convertedJson = MapConverter.getClientOrServerSideValues(json, clientSide)
Object jsonWithPatterns = ContentUtils.convertDslPropsToTemporaryRegexPatterns(convertedJson)
MethodBufferingJsonVerifiable methodBufferingJsonPathVerifiable =
new DelegatingJsonVerifiable(JsonAssertion.assertThat(JsonOutput.toJson(convertedJson)).withoutThrowingException())
traverseRecursivelyForKey(convertedJson, methodBufferingJsonPathVerifiable)
new DelegatingJsonVerifiable(JsonAssertion.assertThat(JsonOutput.toJson(jsonWithPatterns)).withoutThrowingException())
traverseRecursivelyForKey(jsonWithPatterns, methodBufferingJsonPathVerifiable)
{ MethodBufferingJsonVerifiable key, Object value ->
if (value instanceof ExecutionProperty || !(key instanceof FinishedDelegatingJsonVerifiable)) {
return
@@ -42,6 +43,7 @@ class JsonToJsonPathsConverter {
}
protected static def traverseRecursively(Class parentType, MethodBufferingJsonVerifiable key, def value, Closure closure) {
value = ContentUtils.returnParsedObject(value)
if (value instanceof String && value) {
try {
def json = new JsonSlurper().parseText(value)
@@ -91,7 +93,11 @@ class JsonToJsonPathsConverter {
private static MethodBufferingJsonVerifiable createAsserterFromListElement(MethodBufferingJsonVerifiable jsonPathVerifiable, def element) {
if (jsonPathVerifiable.isAssertingAValueInArray()) {
return jsonPathVerifiable.contains(element)
def object = ContentUtils.returnParsedObject(element)
if (object instanceof Pattern) {
return jsonPathVerifiable.matches((object as Pattern).pattern())
}
return jsonPathVerifiable.contains(object)
}
return jsonPathVerifiable
}
@@ -145,13 +151,14 @@ class JsonToJsonPathsConverter {
private static Map convertWithKey(Class parentType, MethodBufferingJsonVerifiable parentKey, Map map, Closure closureToExecute) {
return map.collectEntries {
Object entrykey, value ->
def convertedValue = ContentUtils.returnParsedObject(value)
[entrykey, traverseRecursively(parentType,
value instanceof List ? listContainsOnlyPrimitives(value) ?
convertedValue instanceof List ? listContainsOnlyPrimitives(convertedValue) ?
parentKey.arrayField(entrykey) :
parentKey.array(entrykey) :
value instanceof Map ? parentKey.field(new ShouldTraverse(entrykey)) :
valueToAsserter(parentKey.field(entrykey), value)
, value, closureToExecute)]
convertedValue instanceof Map ? parentKey.field(new ShouldTraverse(entrykey)) :
valueToAsserter(parentKey.field(entrykey), convertedValue)
, convertedValue, closureToExecute)]
}
}
@@ -160,12 +167,17 @@ class JsonToJsonPathsConverter {
}
protected static MethodBufferingJsonVerifiable valueToAsserter(MethodBufferingJsonVerifiable key, Object value) {
if (key instanceof FinishedDelegatingJsonVerifiable) {
return key
}
if (value instanceof Pattern) {
return key.matches((value as Pattern).pattern())
} else if (value instanceof OptionalProperty) {
return key.matches((value as OptionalProperty).optionalPattern())
} else if (value instanceof GString) {
return key.matches(RegexpBuilders.buildGStringRegexpForTestSide(value))
} else if (ContentUtils.returnParsedObject(value) instanceof ExecutionProperty) {
return key
}
return key.isEqualTo(value)
}

View File

@@ -1,12 +1,13 @@
package io.codearte.accurest.util
import groovy.json.JsonSlurper
import io.codearte.accurest.dsl.internal.DslProperty
/**
* @author Marcin Grzejszczak
*/
class MapConverter {
public static final boolean STUB_SIDE = true
public static final boolean TEST_SIDE = false

View File

@@ -8,7 +8,6 @@ import spock.lang.Specification
import spock.lang.Unroll
import java.util.regex.Pattern
/**
* @author Jakub Kubrynski
*/
@@ -1118,4 +1117,76 @@ World.'''"""
"MockMvcJUnitMethodBuilder" | { GroovyDsl dsl -> new MockMvcJUnitMethodBodyBuilder(dsl) }
}
@Issue('#216')
@Unroll
def "should parse JSON with arrays using #methodBuilderName"() {
given:
GroovyDsl contractDsl = GroovyDsl.make {
request {
method "GET"
urlPath('/auth/oauth/check_token') {
queryParameters {
parameter 'token':
value(
client(regex('^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}')),
server('6973b31d-7140-402a-bca6-1cdb954e03a7')
)
}
}
}
response {
status 200
body(
authorities: [
value(stub('ROLE_ADMIN'), test(regex('^[a-zA-Z0-9_\\- ]+$')))
]
)
}
}
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
then:
test.contains('''assertThatJson(parsedJson).array("authorities").matches("^[a-zA-Z0-9_\\\\- ]+\\$").value()''')
where:
methodBuilderName | methodBuilder
"MockMvcSpockMethodBuilder" | { GroovyDsl dsl -> new MockMvcSpockMethodBodyBuilder(dsl) }
"MockMvcJUnitMethodBuilder" | { GroovyDsl dsl -> new MockMvcJUnitMethodBodyBuilder(dsl) }
}
@Unroll
def "should work with execution property"() {
given:
GroovyDsl contractDsl = GroovyDsl.make {
request {
method 'PUT'
url '/fraudcheck'
}
response {
status 200
body(
fraudCheckStatus: "OK",
rejectionReason: $(client(null), server(execute('assertThatRejectionReasonIsNull($it)')))
)
}
}
MethodBodyBuilder builder = methodBuilder(contractDsl)
BlockBuilder blockBuilder = new BlockBuilder(" ")
when:
builder.appendTo(blockBuilder)
def test = blockBuilder.toString()
then:
!test.contains('''assertThatJson(parsedJson).field("rejectionReason").isEqualTo("assertThatRejectionReasonIsNull("''')
test.contains('''assertThatRejectionReasonIsNull(''')
where:
methodBuilderName | methodBuilder
"MockMvcSpockMethodBuilder" | { GroovyDsl dsl -> new MockMvcSpockMethodBodyBuilder(dsl) }
"MockMvcJUnitMethodBuilder" | { GroovyDsl dsl -> new MockMvcJUnitMethodBodyBuilder(dsl) }
}
}