From 9550a9ff08f99cdfcd3d51d6a12c929252135b89 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Sun, 4 Oct 2015 22:16:25 +0200 Subject: [PATCH] [#42] Optional parameter --- .../accurest/dsl/internal/Common.groovy | 22 +++-- .../accurest/dsl/internal/Optional.groovy | 7 ++ .../accurest/util/ContentUtils.groovy | 13 ++- .../util/JsonToJsonPathsConverter.groovy | 2 +- .../MockMvcSpockMethodBuilderSpec.groovy | 84 +++++++++++++++++++ 5 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Optional.groovy diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Common.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Common.groovy index 6cb78b67ba..531dbec5ce 100644 --- a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Common.groovy +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Common.groovy @@ -16,16 +16,20 @@ class Common { @Delegate private final RegexPatterns regexPatterns = new RegexPatterns() Map convertObjectsToDslProperties(Map body) { - return body.collectEntries { + return (body.collectEntries { Map.Entry entry -> [(entry.key): toDslProperty(entry.value)] - } as Map + } as Map).findAll { + !(it.value.clientValue instanceof Optional || it.value.serverValue instanceof Optional) + } } - List convertObjectsToDslProperties(List body) { - return body.collect { + Collection convertObjectsToDslProperties(List body) { + return (body.collect { Object element -> toDslProperty(element) - } as List + } as List).findAll { + !(it instanceof Optional) + } } DslProperty toDslProperty(Object property) { @@ -53,6 +57,10 @@ class Common { return new DslProperty(client.clientValue, server.serverValue) } + DslProperty value(Object value) { + return new DslProperty(value) + } + DslProperty value(ServerDslProperty server, ClientDslProperty client) { assertThatSidesMatch(client.clientValue, server.serverValue) return new DslProperty(client.clientValue, server.serverValue) @@ -90,6 +98,10 @@ class Common { return new ServerDslProperty(serverValue) } + Optional optional() { + return new Optional() + } + void assertThatSidesMatch(Pattern pattern, String value) { assert value ==~ pattern } diff --git a/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Optional.groovy b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Optional.groovy new file mode 100644 index 0000000000..02e7a16323 --- /dev/null +++ b/accurest-core/src/main/groovy/io/codearte/accurest/dsl/internal/Optional.groovy @@ -0,0 +1,7 @@ +package io.codearte.accurest.dsl.internal + +/** + * Marker class to show that an element of message is optional + */ +class Optional { +} 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 c18a918c8b..c5261b43be 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 @@ -8,6 +8,7 @@ import io.codearte.accurest.dsl.internal.DslProperty import io.codearte.accurest.dsl.internal.ExecutionProperty import io.codearte.accurest.dsl.internal.Headers import io.codearte.accurest.dsl.internal.MatchingStrategy +import io.codearte.accurest.dsl.internal.Optional import org.codehaus.groovy.runtime.GStringImpl import java.util.regex.Matcher @@ -24,9 +25,11 @@ class ContentUtils { it instanceof DslProperty ? it.clientValue : it } - private static final Pattern TEMPORARY_PATTERN_HOLDER = Pattern.compile('REGEXP>>(.*)<<') + private static final Pattern TEMPORARY_PATTERN_HOLDER = Pattern.compile('.*REGEXP>>(.*)<<.*') private static final Pattern TEMPORARY_EXECUTION_PATTERN_HOLDER = Pattern.compile('EXECUTION>>(.*)<<') private static final String JSON_VALUE_PATTERN_FOR_REGEX = 'REGEXP>>%s<<' + private static final String JSON_VALUE_OPTIONAL = 'OPTIONAL>><<' + private static final Pattern OPTIONAL_PATTERN_HOLDER = Pattern.compile(JSON_VALUE_OPTIONAL) private static final String JSON_VALUE_PATTERN_FOR_EXECUTION = '"EXECUTION>>%s<<"' /** @@ -157,6 +160,10 @@ class ContentUtils { return String.format(JSON_VALUE_PATTERN_FOR_REGEX, pattern.pattern()) } + private static String transformJSONStringValue(Optional optional, Closure valueProvider) { + return JSON_VALUE_OPTIONAL + } + private static String transformJSONStringValue(ExecutionProperty property, Closure valueProvider) { return String.format(JSON_VALUE_PATTERN_FOR_EXECUTION, property.executionCommand) } @@ -216,6 +223,10 @@ class ContentUtils { String pattern = val[1] return new ExecutionProperty(pattern) } + Matcher optionalMatcher = OPTIONAL_PATTERN_HOLDER.matcher(string.trim()) + if (optionalMatcher.matches()) { + return new Optional() + } return string } 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 32affecef2..db8f264e30 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 @@ -30,7 +30,7 @@ class JsonToJsonPathsConverter { JsonPaths pathsAndValues = [] as Set Object convertedJson = MapConverter.getClientOrServerSideValues(json, clientSide) traverseRecursivelyForKey(convertedJson, ROOT_JSON_PATH_ELEMENT) { String key, Object value -> - if (value instanceof ExecutionProperty) { + if (value instanceof ExecutionProperty || value instanceof io.codearte.accurest.dsl.internal.Optional) { return } JsonPathEntry entry = getValueToInsert(key, value) diff --git a/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy b/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy index 7c16b662d7..2eb45c0475 100644 --- a/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy +++ b/accurest-core/src/test/groovy/io/codearte/accurest/builder/MockMvcSpockMethodBuilderSpec.groovy @@ -552,6 +552,90 @@ class MockMvcSpockMethodBuilderSpec extends Specification implements WireMockStu spockTest.contains('''$[?(@.message =~ /User not found by email = \\\\[[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,4}\\\\]/)]''') } + def "should omit an optional field from body resolution"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + priority 1 + request { + method 'POST' + url '/users/password' + headers { + header 'Content-Type': 'application/json' + } + body( + email: optional(), + callback_url: $(client(regex(hostname())), server('http://partners.com')) + ) + } + response { + status 404 + headers { + header 'Content-Type': 'application/json' + } + body( + code: optional(), + message: "User not found by email = [${value(server(regex(email())), client('not.existing@user.com'))}]" + ) + } + } + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def spockTest = blockBuilder.toString() + then: + !spockTest.contains('''body('{"email":''') + !spockTest.contains('''parsedJson.read(\'\'\'$[?(@.email''') + !spockTest.contains('''REGEXP''') + !spockTest.contains('''OPTIONAL''') + !spockTest.contains('''Optional''') + } + + def "should omit an optional field from body resolution with GString"() { + given: + GroovyDsl contractDsl = GroovyDsl.make { + priority 1 + request { + method 'POST' + url '/users/password' + headers { + header 'Content-Type': 'application/json' + } + body( + """ { + "email" : "${value(optional())}", + "callback_url" : "${value(client(regex(hostname())), server('http://partners.com'))}" + } + """ + ) + } + response { + status 404 + headers { + header 'Content-Type': 'application/json' + } + body( + """ { + "code" : "${value(optional())}", + "message" : "User not found by email = [${value(server(regex(email())), client('not.existing@user.com'))}]" + } + """ + ) + } + } + MockMvcSpockMethodBodyBuilder builder = new MockMvcSpockMethodBodyBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def spockTest = blockBuilder.toString() + then: + !spockTest.contains('''body('{"email":''') + !spockTest.contains('''parsedJson.read(\'\'\'$[?(@.code''') + !spockTest.contains('''REGEXP''') + !spockTest.contains('''OPTIONAL''') + !spockTest.contains('''Optional''') + } + @Issue('72') def "should make the execute method work"() { given: