diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentUtils.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentUtils.groovy index 87e93b4e9e..d2916f36d5 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentUtils.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/ContentUtils.groovy @@ -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)) diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/DelegatingJsonVerifiable.java b/accurest-core/src/main/groovy/io/codearte/accurest/util/DelegatingJsonVerifiable.java index bafc287877..dae53a5fc1 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/util/DelegatingJsonVerifiable.java +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/DelegatingJsonVerifiable.java @@ -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)); diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonToJsonPathsConverter.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonToJsonPathsConverter.groovy index 8ab311fdb6..a3d0576cd2 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonToJsonPathsConverter.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/JsonToJsonPathsConverter.groovy @@ -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) } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/util/MapConverter.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/util/MapConverter.groovy index 477f0fef78..4f21f880ff 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/util/MapConverter.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/util/MapConverter.groovy @@ -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 diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcMethodBodyBuilderSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcMethodBodyBuilderSpec.groovy index c38b346d37..349b244f97 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcMethodBodyBuilderSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcMethodBodyBuilderSpec.groovy @@ -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) } + } + + + }