diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcQueryParamsWhen.java b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcQueryParamsWhen.java index 8ee7a2a8ae..c22d1451c6 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcQueryParamsWhen.java +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcQueryParamsWhen.java @@ -16,6 +16,10 @@ package org.springframework.cloud.contract.verifier.builder; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + import org.springframework.cloud.contract.spec.internal.MatchingStrategy; import org.springframework.cloud.contract.spec.internal.QueryParameter; import org.springframework.cloud.contract.spec.internal.Request; @@ -54,8 +58,19 @@ class MockMvcQueryParamsWhen implements When, MockMvcAcceptor, QueryParamsResolv } private void addQueryParameters(Url buildUrl) { - buildUrl.getQueryParameters().getParameters().stream() - .filter(this::allowedQueryParameter).forEach(this::addQueryParameter); + List queryParameters = buildUrl.getQueryParameters().getParameters().stream() + .filter(this::allowedQueryParameter) + .collect(Collectors.toList()); + Iterator iterator = queryParameters.iterator(); + while (iterator.hasNext()) { + QueryParameter parameter = iterator.next(); + String text = addQueryParameter(parameter); + if (iterator.hasNext()) { + this.blockBuilder.addLine(text); + } else { + this.blockBuilder.addIndented(text); + } + } } private boolean allowedQueryParameter(Object o) { @@ -68,10 +83,10 @@ class MockMvcQueryParamsWhen implements When, MockMvcAcceptor, QueryParamsResolv return true; } - private void addQueryParameter(QueryParameter queryParam) { - this.blockBuilder.addLine("." + QUERY_PARAM_METHOD + "(" + private String addQueryParameter(QueryParameter queryParam) { + return "." + QUERY_PARAM_METHOD + "(" + this.bodyParser.quotedLongText(queryParam.getName()) + "," - + this.bodyParser.quotedLongText(resolveParamValue(queryParam)) + ")"); + + this.bodyParser.quotedLongText(resolveParamValue(queryParam)) + ")"; } @Override diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.groovy deleted file mode 100644 index 6f5f6fdc52..0000000000 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.groovy +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder - -import groovy.json.JsonOutput -import groovy.transform.CompileStatic -import org.apache.commons.text.StringEscapeUtils - -import org.springframework.cloud.contract.spec.internal.DslProperty -import org.springframework.cloud.contract.spec.internal.FromFileProperty -import org.springframework.cloud.contract.spec.internal.Request -import org.springframework.cloud.contract.verifier.util.ContentUtils -import org.springframework.cloud.contract.verifier.util.MapConverter - -/** - * Representation of the request side to be used for response templating in - * the generated tests. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -@CompileStatic -class TestSideRequestTemplateModel { - /** - * Request URL - */ - final String url - - /** - * Map containing query parameters - */ - final Map> query - - /** - * List of path entries - */ - final Path path - - /** - * Map containing request headers - */ - final Map> headers - - /** - * Request body as it would be sent to the controller - */ - final String body - - /** - * Escaped request body that can be put into test - */ - final String escapedBody - - private TestSideRequestTemplateModel(String url, Map> query, Path path, Map> headers, String body, String escapedBody) { - this.url = url - this.query = query - this.path = path - this.headers = headers - this.body = body - this.escapedBody = escapedBody - } - - static TestSideRequestTemplateModel from(final Request request) { - String url = MapConverter.getTestSideValues(request.url ?: request.urlPath) - Path paths = new Path(buildPathsFromUrl(url)) - Map> query = (Map>) (request.url ?: request.urlPath) - .queryParameters?.parameters?.groupBy { it.name }?.collectEntries { - [(it.key): it.value.collect { MapConverter.getTestSideValues(it) }] - } - String fullUrl = (query == null || query.isEmpty()) ? url : - url + "?" + query.collect { String name, List values -> - return values.collect { "${name}=${it}"}.join("&") }.join("&") - Map> headers = (Map>) (request.headers?.entries?.groupBy { - it.name - }?.collectEntries { - List headerValues = [] - for (Object value : it.value) { - headerValues.add(MapConverter.getTestSideValues(value)) - } - [(it.key): headerValues] - }) - String escapedBody = trimmedAndEscapedBody(request.body) - String body = getBodyAsRawJson(request.body) - return new TestSideRequestTemplateModel(fullUrl, query, paths, headers, body, escapedBody) - } - - private static List buildPathsFromUrl(String url) { - String fakeUrl = "https://foo.bar" + (url.startsWith("/") ? url : "/" + url) - List paths = new URL(fakeUrl).path.split("/") as List - if (!paths.isEmpty()) { - paths.remove(0) - } - return paths - } - - private static String trimmedAndEscapedBody(Object body) { - String rawBody = getBodyAsRawJson(body) - return StringEscapeUtils.escapeJava(rawBody) - } - - private static String getBodyAsRawJson(Object body) { - Object bodyValue = extractServerValueFromBody(body) - if (bodyValue instanceof GString || bodyValue instanceof String) { - return bodyValue.toString() - } - else if (bodyValue instanceof FromFileProperty) { - return null - } - return bodyValue != null ? new JsonOutput().toJson(bodyValue) : bodyValue - } - - protected static Object extractServerValueFromBody(bodyValue) { - if (bodyValue instanceof GString) { - bodyValue = ContentUtils. - extractValue(bodyValue, { DslProperty dslProperty -> dslProperty.serverValue } as Closure) - } - else { - bodyValue = MapConverter.transformValues(bodyValue, { - it instanceof DslProperty ? it.serverValue : it - }) - } - return bodyValue - } -} - -@CompileStatic -class Path extends ArrayList { - - Path(List list) { - this.addAll(list) - } - - @Override - String toString() { - return "/" + this.join("/") - } -} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.java b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.java new file mode 100644 index 0000000000..c6b865449b --- /dev/null +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/TestSideRequestTemplateModel.java @@ -0,0 +1,227 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.contract.verifier.builder; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import groovy.json.JsonOutput; +import groovy.lang.GString; +import groovy.transform.CompileStatic; +import org.apache.commons.text.StringEscapeUtils; + +import org.springframework.cloud.contract.spec.internal.FromFileProperty; +import org.springframework.cloud.contract.spec.internal.Header; +import org.springframework.cloud.contract.spec.internal.QueryParameter; +import org.springframework.cloud.contract.spec.internal.QueryParameters; +import org.springframework.cloud.contract.spec.internal.Request; +import org.springframework.cloud.contract.spec.internal.Url; +import org.springframework.cloud.contract.verifier.util.ContentUtils; +import org.springframework.cloud.contract.verifier.util.MapConverter; + +/** + * Representation of the request side to be used for response templating in the generated + * tests. + * + * @author Marcin Grzejszczak + * @since 1.1.0 + */ +public class TestSideRequestTemplateModel { + + /** + * Request URL + */ + private final String url; + + /** + * Map containing query parameters + */ + private final Map> query; + + /** + * List of path entries + */ + private final Path path; + + /** + * Map containing request headers + */ + private final Map> headers; + + /** + * Request body as it would be sent to the controller + */ + private final String body; + + /** + * Escaped request body that can be put into test + */ + private final String escapedBody; + + private TestSideRequestTemplateModel(String url, Map> query, + Path path, Map> headers, String body, + String escapedBody) { + this.url = url; + this.query = query; + this.path = path; + this.headers = headers; + this.body = body; + this.escapedBody = escapedBody; + } + + public String getUrl() { + return this.url; + } + + public Map> getQuery() { + return this.query; + } + + public Path getPath() { + return this.path; + } + + public Map> getHeaders() { + return this.headers; + } + + public String getBody() { + return this.body; + } + + public String getEscapedBody() { + return this.escapedBody; + } + + public static TestSideRequestTemplateModel from(final Request request) { + Url urlPath = request.getUrl() != null ? request.getUrl() : request.getUrlPath(); + String url = MapConverter.getTestSideValues(urlPath).toString(); + Path paths = new Path(buildPathsFromUrl(url)); + QueryParameters queryParameters = urlPath.getQueryParameters(); + Map> query = query(queryParameters); + boolean queryParamsPresent = query == null || query.isEmpty(); + String fullUrl = fullUrl(url, query, queryParamsPresent); + boolean headersEntriesPresent = request.getHeaders() != null + && !request.getHeaders().getEntries().isEmpty(); + Map> headers = headers(request, headersEntriesPresent); + String escapedBody = trimmedAndEscapedBody(request.getBody()); + String body = getBodyAsRawJson(request.getBody()); + return new TestSideRequestTemplateModel(fullUrl, query, paths, headers, body, + escapedBody); + } + + private static Map> headers(Request request, + boolean headersEntriesPresent) { + if (!headersEntriesPresent) { + return new HashMap<>(); + } + return request.getHeaders().getEntries().stream() + .collect(Collectors.groupingBy(Header::getName, + Collectors.mapping( + (Function) o -> MapConverter + .getTestSideValues(o).toString(), + Collectors.toList()))); + } + + private static String fullUrl(String url, Map> query, + boolean queryParamsPresent) { + if (queryParamsPresent) { + return url; + } + String joinedParams = query.entrySet().stream() + .map(entry -> entry.getValue().stream().map(s -> entry.getKey() + "=" + s) + .collect(Collectors.joining("&"))) + .collect(Collectors.joining("&")); + return url + "?" + joinedParams; + } + + private static Map> query(QueryParameters queryParameters) { + if (queryParameters == null) { + return new HashMap<>(); + } + return queryParameters.getParameters().stream() + .collect(Collectors.groupingBy(QueryParameter::getName, Collectors + .mapping(MapConverter::getTestSideValues, Collectors.toList()))); + } + + private static List buildPathsFromUrl(String url) { + String fakeUrl = "https://foo.bar" + (url.startsWith("/") ? url : "/" + url); + List paths; + try { + paths = new LinkedList<>( + Arrays.asList(new URL(fakeUrl).getPath().split("/"))); + } + catch (MalformedURLException ex) { + throw new IllegalStateException(ex); + } + if (!paths.isEmpty()) { + paths.remove(0); + } + return paths; + } + + private static String trimmedAndEscapedBody(Object body) { + String rawBody = getBodyAsRawJson(body); + return StringEscapeUtils.escapeJava(rawBody); + } + + private static String getBodyAsRawJson(Object body) { + Object bodyValue = extractServerValueFromBody(body); + if (bodyValue instanceof GString || bodyValue instanceof String) { + return bodyValue.toString(); + } + else if (bodyValue instanceof FromFileProperty) { + return null; + } + return bodyValue != null ? new JsonOutput().toJson(bodyValue) : null; + } + + private static Object extractServerValueFromBody(Object bodyValue) { + if (bodyValue instanceof GString) { + bodyValue = ContentUtils.extractValue((GString) bodyValue, + ContentUtils.GET_TEST_SIDE_FUNCTION); + } + else { + bodyValue = MapConverter.transformValues(bodyValue, + ContentUtils.GET_TEST_SIDE); + } + return bodyValue; + } + +} + +@CompileStatic +class Path extends ArrayList { + + Path(List list) { + this.addAll(list); + } + + @Override + public String toString() { + return "/" + String.join("/", this); + } + +} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsEscapeHelper.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsEscapeHelper.java similarity index 62% rename from spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsEscapeHelper.groovy rename to spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsEscapeHelper.java index 360e5d106c..e1f21a5055 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsEscapeHelper.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsEscapeHelper.java @@ -14,15 +14,17 @@ * limitations under the License. */ -package org.springframework.cloud.contract.verifier.builder.handlebars +package org.springframework.cloud.contract.verifier.builder.handlebars; -import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel -import groovy.transform.CompileStatic -import org.apache.commons.text.StringEscapeUtils -import wiremock.com.github.jknack.handlebars.Helper -import wiremock.com.github.jknack.handlebars.Options +import java.io.IOException; +import java.util.Map; -import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel +import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel; +import org.apache.commons.text.StringEscapeUtils; +import wiremock.com.github.jknack.handlebars.Helper; +import wiremock.com.github.jknack.handlebars.Options; + +import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel; /** * A Handlebars helper for the {@code escapejsonbody} helper function. @@ -30,30 +32,31 @@ import org.springframework.cloud.contract.verifier.builder.TestSideRequestTempla * @author Marcin Grzejszczak * @since 1.1.0 */ -@CompileStatic -class HandlebarsEscapeHelper implements Helper> { +public class HandlebarsEscapeHelper implements Helper> { - public static final String NAME = "escapejsonbody" - public static final String REQUEST_MODEL_NAME = "request" + public static final String NAME = "escapejsonbody"; + + public static final String REQUEST_MODEL_NAME = "request"; @Override - Object apply(Map context, Options options) throws IOException { - Object model = context.get(REQUEST_MODEL_NAME) + public Object apply(Map context, Options options) throws IOException { + Object model = context.get(REQUEST_MODEL_NAME); if (model instanceof TestSideRequestTemplateModel) { - return StringEscapeUtils.escapeJson(returnObjectForTest(model).toString()) + return StringEscapeUtils.escapeJson(returnObjectForTest(model).toString()); } else if (model instanceof RequestTemplateModel) { - return StringEscapeUtils.escapeJson(returnObjectForStub(model).toString()) + return StringEscapeUtils.escapeJson(returnObjectForStub(model).toString()); } - throw new IllegalArgumentException("Unsupported model") + + throw new IllegalArgumentException("Unsupported model"); } private Object returnObjectForStub(Object model) { - return ((RequestTemplateModel) model).body + return ((RequestTemplateModel) model).getBody(); } private Object returnObjectForTest(Object model) { - return ((TestSideRequestTemplateModel) model).escapedBody + return ((TestSideRequestTemplateModel) model).getEscapedBody(); } } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsJsonPathHelper.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsJsonPathHelper.groovy deleted file mode 100644 index a3a07e388c..0000000000 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsJsonPathHelper.groovy +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2013-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.cloud.contract.verifier.builder.handlebars - -import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel -import com.github.tomakehurst.wiremock.extension.responsetemplating.helpers.WireMockHelpers -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath -import groovy.transform.CompileStatic -import wiremock.com.github.jknack.handlebars.Helper -import wiremock.com.github.jknack.handlebars.Options - -import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel - -/** - * A Handlebars helper for the {@code jsonpath} helper function. - * - * @author Marcin Grzejszczak - * @since 1.1.0 - */ -@CompileStatic -class HandlebarsJsonPathHelper implements Helper { - - public static final String NAME = "jsonpath" - public static final String REQUEST_MODEL_NAME = "request" - - @Override - Object apply(Object context, Options options) throws IOException { - if (context instanceof Map) { - // legacy - Map oldContext = (Map) context - String jsonPath = options.param(0) - Object model = oldContext.get(REQUEST_MODEL_NAME) - if (model instanceof TestSideRequestTemplateModel) { - return returnObjectForTest(model, jsonPath) - } - else if (model instanceof RequestTemplateModel) { - return returnObjectForStub(model, jsonPath) - } - throw new IllegalArgumentException("Unsupported model") - } - else if (context instanceof String) { - Object value = WireMockHelpers.jsonPath.apply(context, options) - if (testSideModel(options)) { - return processTestResponseValue(value) - } - return value - } - throw new IllegalArgumentException("Unsupported context") - } - - private boolean testSideModel(Options options) { - Object model = options.context.model() - if (!(model instanceof Map)) { - return false - } - Map map = (Map) model - return map.values().any { it instanceof TestSideRequestTemplateModel } - } - - private Object returnObjectForStub(Object model, String jsonPath) { - DocumentContext documentContext = JsonPath. - parse(((RequestTemplateModel) model).body) - return documentContext.read(jsonPath) - } - - private Object returnObjectForTest(TestSideRequestTemplateModel model, String jsonPath) { - String body = removeSurroundingQuotes(model.escapedBody).replace('\\"', '"') - DocumentContext documentContext = JsonPath.parse(body) - Object value = documentContext.read(jsonPath) - return processTestResponseValue(value) - } - - private Object processTestResponseValue(Object value) { - if (value instanceof Long) { - return String.valueOf(value) + "L" - } - return value - } - - private String removeSurroundingQuotes(String body) { - if (body.startsWith('"') && body.endsWith('"')) { - return body.substring(1, body.length() - 1) - } - return body - } - -} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsJsonPathHelper.java b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsJsonPathHelper.java new file mode 100644 index 0000000000..9173e18a4d --- /dev/null +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/handlebars/HandlebarsJsonPathHelper.java @@ -0,0 +1,109 @@ +/* + * Copyright 2013-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.contract.verifier.builder.handlebars; + +import java.io.IOException; +import java.util.Map; + +import com.github.tomakehurst.wiremock.extension.responsetemplating.RequestTemplateModel; +import com.github.tomakehurst.wiremock.extension.responsetemplating.helpers.WireMockHelpers; +import com.jayway.jsonpath.DocumentContext; +import com.jayway.jsonpath.JsonPath; +import wiremock.com.github.jknack.handlebars.Helper; +import wiremock.com.github.jknack.handlebars.Options; + +import org.springframework.cloud.contract.verifier.builder.TestSideRequestTemplateModel; + +/** + * A Handlebars helper for the {@code jsonpath} helper function. + * + * @author Marcin Grzejszczak + * @since 1.1.0 + */ +public class HandlebarsJsonPathHelper implements Helper { + + public static final String NAME = "jsonpath"; + + public static final String REQUEST_MODEL_NAME = "request"; + + @Override + public Object apply(Object context, Options options) throws IOException { + if (context instanceof Map) { + // legacy + Map oldContext = (Map) context; + String jsonPath = options.param(0); + Object model = oldContext.get(REQUEST_MODEL_NAME); + if (model instanceof TestSideRequestTemplateModel) { + return returnObjectForTest((TestSideRequestTemplateModel) model, + jsonPath); + } + else if (model instanceof RequestTemplateModel) { + return returnObjectForStub(model, jsonPath); + } + throw new IllegalArgumentException("Unsupported model"); + } + else if (context instanceof String) { + Object value = WireMockHelpers.jsonPath.apply(context, options); + if (testSideModel(options)) { + return processTestResponseValue(value); + } + return value; + } + throw new IllegalArgumentException("Unsupported context"); + } + + private boolean testSideModel(Options options) { + Object model = options.context.model(); + if (!(model instanceof Map)) { + return false; + } + + Map map = (Map) model; + return map.values().stream() + .anyMatch(o -> o instanceof TestSideRequestTemplateModel); + } + + private Object returnObjectForStub(Object model, String jsonPath) { + DocumentContext documentContext = JsonPath + .parse(((RequestTemplateModel) model).getBody()); + return documentContext.read(jsonPath); + } + + private Object returnObjectForTest(TestSideRequestTemplateModel model, + String jsonPath) { + String body = removeSurroundingQuotes(model.getEscapedBody()).replace("\\\"", + "\""); + DocumentContext documentContext = JsonPath.parse(body); + Object value = documentContext.read(jsonPath); + return processTestResponseValue(value); + } + + private Object processTestResponseValue(Object value) { + if (value instanceof Long) { + return (long) value + "L"; + } + return value; + } + + private String removeSurroundingQuotes(String body) { + if (body.startsWith("\"") && body.endsWith("\"")) { + return body.substring(1, body.length() - 1); + } + return body; + } + +} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentUtils.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentUtils.groovy index a592fcc1eb..6f3caade2a 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentUtils.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentUtils.groovy @@ -71,6 +71,20 @@ class ContentUtils { it instanceof DslProperty ? it.serverValue : it } + public static final Function GET_STUB_SIDE_FUNCTION = new Function() { + @Override + Object apply(Object it) { + return it instanceof DslProperty ? it.clientValue : it + } + } + + public static final Function GET_TEST_SIDE_FUNCTION = new Function() { + @Override + Object apply(Object it) { + return 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. @@ -238,6 +252,10 @@ class ContentUtils { ) } + static Object extractValue(GString bodyAsValue, Function valueProvider) { + return extractValue(bodyAsValue, UNKNOWN, { valueProvider.apply(it) }) + } + static Object extractValue(GString bodyAsValue, Closure valueProvider) { return extractValue(bodyAsValue, UNKNOWN, valueProvider) }