From 0058b987aec91fe9ff63bb3537776e61792a2702 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Sat, 15 Dec 2018 14:06:17 +0100 Subject: [PATCH] Adds support for binary payloads (#818) with this change we're adding support for binary payloads both for HTTP and messaging. fixes #664 --- README.adoc | 7 +- docs/src/main/asciidoc/verifier_contract.adoc | 19 +- docs/src/main/asciidoc/verifier_setup.adoc | 10 +- .../loan/LoanApplicationServiceTests.java | 57 +- .../src/test/resources/binary/request.pdf | Bin 0 -> 14631 bytes .../src/test/resources/binary/response.pdf | Bin 0 -> 15767 bytes .../com/example/fraud/TestController.java | 75 +- .../java/com/example/fraud/BinaryBase.java | 29 + .../java/com/example/fraud/FraudBase.java | 3 +- .../java/com/example/fraud/FraudnameBase.java | 3 +- .../java/com/example/fraud/MultipartBase.java | 10 +- .../resources/contracts/binary/request.pdf | Bin 0 -> 14631 bytes .../resources/contracts/binary/response.pdf | Bin 0 -> 15767 bytes .../binary/shouldWorkWithBinaryPayload.groovy | 38 + ...kForMultipartAsBytesWithContentType.groovy | 52 + ...VerifierSampleStreamSourceApplication.java | 64 +- .../src/main/resources/application.properties | 4 + .../src/test/resources/contracts/input.pdf | Bin 0 -> 14631 bytes .../src/test/resources/contracts/output.pdf | Bin 0 -> 15767 bytes .../shouldWorkWithInputOutputBinary.groovy | 21 + .../cloud/contract/spec/internal/Body.groovy | 8 + .../contract/spec/internal/Common.groovy | 46 +- .../contract/spec/internal/DslProperty.groovy | 2 +- .../spec/internal/FromFileProperty.groovy | 69 + .../spec/internal/MatchingStrategy.groovy | 2 +- .../camel/StubRunnerCamelPredicate.java | 71 +- .../camel/StubRunnerCamelProcessor.java | 14 +- .../StubRunnerIntegrationMessageSelector.java | 77 +- .../StubRunnerIntegrationTransformer.java | 16 +- .../StubRunnerStreamMessageSelector.java | 69 +- .../stream/StubRunnerStreamTransformer.java | 16 +- .../camel/StubRunnerCamelPredicateSpec.groovy | 49 + ...unnerIntegrationMessageSelectorSpec.groovy | 46 + ...StubRunnerStreamMessageSelectorSpec.groovy | 69 + .../src/test/resources/request.pdf | Bin 0 -> 14631 bytes .../src/test/resources/response.pdf | Bin 0 -> 15767 bytes .../plugin/ContractVerifierExtension.groovy | 5 + .../plugin/ExtensionToProperties.groovy | 1 + .../plugin/GenerateServerTestsTask.groovy | 12 +- ...ngCloudContractVerifierGradlePlugin.groovy | 5 +- .../maven/verifier/GenerateTestsMojo.java | 26 +- spring-cloud-contract-verifier/pom.xml | 5 + .../cloud/contract/verifier/FileSaver.groovy | 17 +- .../contract/verifier/TestGenerator.groovy | 19 +- .../verifier/builder/CommunicationType.groovy | 31 + .../ExplicitJUnitMethodBodyBuilder.groovy | 6 +- .../builder/GeneratedClassDataForMethod.java | 47 + ...kMethodRequestProcessingBodyBuilder.groovy | 6 +- .../JUnitMessagingMethodBodyBuilder.groovy | 36 +- .../builder/JUnitMethodBodyBuilder.groovy | 29 +- .../verifier/builder/JavaTestGenerator.groovy | 33 +- .../JaxRsClientJUnitMethodBodyBuilder.groovy | 23 +- ...kMethodRequestProcessingBodyBuilder.groovy | 23 +- .../builder/MessagingMethodBodyBuilder.groovy | 34 +- .../verifier/builder/MethodBodyBuilder.groovy | 55 +- .../verifier/builder/MethodBuilder.groovy | 33 +- .../MockMvcJUnitMethodBodyBuilder.groovy | 5 +- .../RequestProcessingMethodBodyBuilder.groovy | 16 +- .../RestAssuredJUnitMethodBodyBuilder.groovy | 5 +- .../builder/SingleTestGenerator.groovy | 48 - .../verifier/builder/SingleTestGenerator.java | 64 + .../SpockMessagingMethodBodyBuilder.groovy | 28 +- ...kMethodRequestProcessingBodyBuilder.groovy | 23 +- .../TestSideRequestTemplateModel.groovy | 5 +- ...WebTestClientJUnitMethodBodyBuilder.groovy | 6 +- .../builder/imports/HttpImportProvider.groovy | 2 +- .../imports/MessagingImportProvider.groovy | 2 +- .../ContractVerifierConfigProperties.groovy | 5 + .../verifier/converter/YamlContract.groovy | 4 + .../verifier/converter/YamlToContracts.groovy | 4 + .../wiremock/BaseWireMockStubStrategy.groovy | 10 +- .../WireMockRequestStubStrategy.groovy | 36 +- .../WireMockResponseStubStrategy.groovy | 8 +- .../dsl/wiremock/WireMockStubStrategy.groovy | 9 +- .../HandlebarsTemplateProcessor.groovy | 133 +- .../contract/verifier/util/ContentType.groovy | 2 - .../verifier/util/ContentUtils.groovy | 115 +- .../internal/ContractVerifierMessage.java | 7 + .../ContractVerifierObjectMapper.java | 8 + .../verifier/util/ContractVerifierUtil.java | 55 + .../verifier/GeneratorScannerSpec.groovy | 9 +- .../builder/ContractHttpDocsSpec.groovy | 7 +- .../JaxRsClientMethodBuilderSpec.groovy | 124 +- .../MessagingMethodBodyBuilderSpec.groovy | 113 +- .../builder/MethodBodyBuilderSpec.groovy | 1662 +++++++++-------- ...vcMethodBodyBuilderWithMatchersSpec.groovy | 83 +- .../builder/SingleTestGeneratorSpec.groovy | 33 +- .../SpringTestMethodBodyBuildersSpec.groovy | 379 ++-- .../YamlMockMvcMethodBodyBuilderSpec.groovy | 241 +-- .../YamlContractConverterSpec.groovy | 49 +- .../verifier/dsl/WireMockGroovyDslSpec.groovy | 46 +- .../ContractVerifierObjectMapperSpec.groovy | 26 +- .../test/resources/body_builder/request.pdf | Bin 0 -> 14631 bytes .../test/resources/body_builder/response.pdf | Bin 0 -> 15767 bytes .../body_builder/worksWithPdf.groovy | 19 + .../resources/yml/contract_messaging_pdf.yml | 11 + .../src/test/resources/yml/contract_pdf.yml | 11 + .../src/test/resources/yml/request.pdf | Bin 0 -> 14631 bytes .../src/test/resources/yml/response.pdf | Bin 0 -> 15767 bytes .../StubRunnerStreamTransformerSpec.groovy | 27 + .../src/test/resources/request.pdf | Bin 0 -> 14631 bytes .../src/test/resources/response.pdf | Bin 0 -> 15767 bytes 102 files changed, 3282 insertions(+), 1550 deletions(-) create mode 100644 samples/standalone/dsl/http-client/src/test/resources/binary/request.pdf create mode 100644 samples/standalone/dsl/http-client/src/test/resources/binary/response.pdf create mode 100644 samples/standalone/dsl/http-server/src/test/java/com/example/fraud/BinaryBase.java create mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/binary/request.pdf create mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/binary/response.pdf create mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/binary/shouldWorkWithBinaryPayload.groovy create mode 100644 samples/standalone/dsl/http-server/src/test/resources/contracts/multipart/shouldWorkForMultipartAsBytesWithContentType.groovy create mode 100644 samples/standalone/messaging/stream-source/src/test/resources/contracts/input.pdf create mode 100644 samples/standalone/messaging/stream-source/src/test/resources/contracts/output.pdf create mode 100644 samples/standalone/messaging/stream-source/src/test/resources/contracts/shouldWorkWithInputOutputBinary.groovy create mode 100644 spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/FromFileProperty.groovy create mode 100644 spring-cloud-contract-stub-runner/src/test/resources/request.pdf create mode 100644 spring-cloud-contract-stub-runner/src/test/resources/response.pdf create mode 100644 spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/CommunicationType.groovy create mode 100644 spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/GeneratedClassDataForMethod.java delete mode 100644 spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy create mode 100644 spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java create mode 100644 spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtil.java create mode 100644 spring-cloud-contract-verifier/src/test/resources/body_builder/request.pdf create mode 100644 spring-cloud-contract-verifier/src/test/resources/body_builder/response.pdf create mode 100644 spring-cloud-contract-verifier/src/test/resources/body_builder/worksWithPdf.groovy create mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_messaging_pdf.yml create mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/contract_pdf.yml create mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/request.pdf create mode 100644 spring-cloud-contract-verifier/src/test/resources/yml/response.pdf create mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/resources/request.pdf create mode 100644 tests/spring-cloud-contract-stub-runner-stream/src/test/resources/response.pdf diff --git a/README.adoc b/README.adoc index 5179c04f12..b2f3292d59 100644 --- a/README.adoc +++ b/README.adoc @@ -741,7 +741,7 @@ Annotate your test class with `@AutoConfigureStubRunner`. In the annotation prov [source,groovy,indent=0] ---- @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment=WebEnvironment.NONE) +@SpringBootTest(webEnvironment = WebEnvironment.NONE) @AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL) public class LoanApplicationServiceTests { @@ -1226,7 +1226,7 @@ can also provide the offline work switch (`StubRunnerProperties.StubsMode.LOCAL` [source,groovy,indent=0] ---- @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment=WebEnvironment.NONE) +@SpringBootTest(webEnvironment = WebEnvironment.NONE) @AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL) public class LoanApplicationServiceTests { @@ -1323,9 +1323,8 @@ start the server side `FraudDetectionController`. ---- package com.example.fraud; -import org.junit.Before; - import io.restassured.module.mockmvc.RestAssuredMockMvc; +import org.junit.Before; public class FraudBase { @Before diff --git a/docs/src/main/asciidoc/verifier_contract.adoc b/docs/src/main/asciidoc/verifier_contract.adoc index 20577a29b4..935b183b8d 100644 --- a/docs/src/main/asciidoc/verifier_contract.adoc +++ b/docs/src/main/asciidoc/verifier_contract.adoc @@ -168,6 +168,23 @@ When test or stub generation takes place, the contents of the file is passed to of a request or a response. The name of the file needs to be a file with location relative to the folder in which the contract lays. +If you need to pass the contents of a file in a binary form +it's enough for you to use the `fileAsBytes` method in Groovy DSL or `bodyFromFileAsBytes` field in YAML. + +.Groovy DSL +[source,groovy,indent=0] +---- +include::{verifier_core_path}/src/test/resources/body_builder/worksWithPdf.groovy[indent=0] +---- + +.YAML +[source,yml,indent=0] +---- +include::{verifier_core_path}/src/test/resources/yml/contract_pdf.yml[indent=0] +---- + +IMPORTANT: You should use this approach whenever you want to work with binary payloads both for HTTP and messaging. + [[contract-dsl-http-top-level-elements]] ==== HTTP Top-Level Elements @@ -1645,7 +1662,7 @@ following code listing shows the `SingleTestGenerator` interface: [source,groovy] ---- -include::{verifier_core_path}/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy[indent=0,lines=17..-1] +include::{verifier_core_path}/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java[indent=0,lines=17..-1] ---- Again, you must provide a `spring.factories` file, such as the one shown in the following diff --git a/docs/src/main/asciidoc/verifier_setup.adoc b/docs/src/main/asciidoc/verifier_setup.adoc index 4c73c93c71..11dc4afd38 100644 --- a/docs/src/main/asciidoc/verifier_setup.adoc +++ b/docs/src/main/asciidoc/verifier_setup.adoc @@ -156,6 +156,7 @@ contracts { testFramework ='JUNIT' testMode = 'MockMvc' generatedTestSourcesDir = project.file("${project.buildDir}/generated-test-sources/contracts") + generatedTestResourcesDir = project.file("${project.buildDir}/generated-test-resources/contracts") contractsDslDir = "${project.rootDir}/src/test/resources/contracts" basePackageForTests = 'org.springframework.cloud.verifier.tests' stubsOutputDir = project.file("${project.buildDir}/stubs") @@ -242,7 +243,10 @@ should be skipped. By default, it is an empty array. GroovyDSL. By default, its value is `$rootDir/src/test/resources/contracts`. * *generatedTestSourcesDir*: Specifies the test source directory where tests generated from the Groovy DSL should be placed. By default its value is -`$buildDir/generated-test-sources/contractVerifier`. +`$buildDir/generated-test-sources/contracts`. +* *generatedTestResourcesDir*: Specifies the test resource directory where resources used by the tests generated +from the Groovy DSL should be placed. By default its value is +`$buildDir/generated-test-resources/contracts`. * *stubsOutputDir*: Specifies the directory where the generated WireMock stubs from the Groovy DSL should be placed. * *testFramework*: Specifies the target test framework to be used. Currently, Spock, JUnit 4 (`TestFramework.JUNIT`) and @@ -581,6 +585,10 @@ classes. use Spock classes, the class is `spock.lang.Specification`. * *contractsDirectory*: Specifies a directory containing contracts written with the GroovyDSL. The default directory is `/src/test/resources/contracts`. +* *generatedTestSourcesDir*: Specifies the test source directory where tests generated +from the Groovy DSL should be placed. By default its value is +`$buildDir/generated-test-sources/contracts`. +* *generatedTestResourcesDir*: Specifies the test resource directory where resources used by the tests generated * *testFramework*: Specifies the target test framework to be used. Currently, Spock, JUnit 4 (`TestFramework.JUNIT`) and JUnit 5 are supported with JUnit 4 being the default framework. * *packageWithBaseClasses*: Defines a package where all the base classes reside. This diff --git a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java b/samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java index ab8eeff9a8..a686189f75 100644 --- a/samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java +++ b/samples/standalone/dsl/http-client/src/test/java/com/example/loan/LoanApplicationServiceTests.java @@ -1,16 +1,9 @@ package com.example.loan; -import io.restassured.RestAssured; -import io.restassured.response.ResponseOptions; -import io.restassured.specification.RequestSpecification; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; -import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; -import org.springframework.test.context.junit4.SpringRunner; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; import com.example.loan.model.Client; import com.example.loan.model.LoanApplication; @@ -18,13 +11,28 @@ import com.example.loan.model.LoanApplicationResult; import com.example.loan.model.LoanApplicationStatus; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; +import io.restassured.RestAssured; +import io.restassured.response.ResponseOptions; +import io.restassured.specification.RequestSpecification; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; +import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; import static com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson; import static org.assertj.core.api.Assertions.assertThat; // tag::autoconfigure_stubrunner[] @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment=WebEnvironment.NONE) +@SpringBootTest(webEnvironment = WebEnvironment.NONE) @AutoConfigureStubRunner(ids = {"com.example:http-server-dsl:+:stubs:6565"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL) public class LoanApplicationServiceTests { @@ -93,7 +101,8 @@ public class LoanApplicationServiceTests { .header("Content-Type", "multipart/form-data") .multiPart("file1", "filename1", "content1".getBytes()) .multiPart("file2", "filename1", "content2".getBytes()) - .multiPart("test", "filename1", "{\n \"status\": \"test\"\n}".getBytes(), "application/json"); + .multiPart("test", "filename1", "{\n \"status\": \"test\"\n}" + .getBytes(), "application/json"); // when: ResponseOptions response = RestAssured.given().spec(request) @@ -107,4 +116,26 @@ public class LoanApplicationServiceTests { assertThatJson(parsedJson).field("['status']").isEqualTo("ok"); } + @Test + public void shouldSuccessfullyWorkWithBinary() throws IOException { + // given: + File request = new File(LoanApplicationServiceTests.class + .getResource("/binary/request.pdf").getFile()); + File response = new File(LoanApplicationServiceTests.class + .getResource("/binary/response.pdf").getFile()); + + // when: + ResponseEntity exchange = new RestTemplate().exchange( + RequestEntity.put(URI.create("http://localhost:6565/1")) + .header("Content-Type", "application/octet-stream") + .body(Files.readAllBytes(request.toPath())), byte[].class); + + // then: + assertThat(exchange.getStatusCodeValue()).isEqualTo(200); + assertThat(exchange.getHeaders().get("Content-Type").get(0)) + .isEqualTo("application/octet-stream"); + // and: + assertThat(exchange.getBody()).isEqualTo(Files.readAllBytes(response.toPath())); + } + } diff --git a/samples/standalone/dsl/http-client/src/test/resources/binary/request.pdf b/samples/standalone/dsl/http-client/src/test/resources/binary/request.pdf new file mode 100644 index 0000000000000000000000000000000000000000..69503635d87cbdfa660d5cd8be66d3e74b3b20e8 GIT binary patch literal 14631 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-client/src/test/resources/binary/response.pdf b/samples/standalone/dsl/http-client/src/test/resources/binary/response.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3b233056b758d1cc9bf3176e99a95add89ba607 GIT binary patch literal 15767 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/dsl/http-server/src/test/resources/contracts/binary/response.pdf b/samples/standalone/dsl/http-server/src/test/resources/contracts/binary/response.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3b233056b758d1cc9bf3176e99a95add89ba607 GIT binary patch literal 15767 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 literal 0 HcmV?d00001 diff --git a/samples/standalone/messaging/stream-source/src/test/resources/contracts/output.pdf b/samples/standalone/messaging/stream-source/src/test/resources/contracts/output.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3b233056b758d1cc9bf3176e99a95add89ba607 GIT binary patch literal 15767 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 { +class DslProperty implements Serializable { final T clientValue final T serverValue diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/FromFileProperty.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/FromFileProperty.groovy new file mode 100644 index 0000000000..b472c8f3d7 --- /dev/null +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/FromFileProperty.groovy @@ -0,0 +1,69 @@ +/* + * Copyright 2013-2017 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 + * + * http://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.spec.internal + +import groovy.transform.CompileStatic +import groovy.transform.EqualsAndHashCode +import groovy.transform.ToString + +import java.nio.charset.Charset + +/** + * Represents a property that will become a File content + * + * @since 2.1.0 + */ +@CompileStatic +@EqualsAndHashCode +@ToString(includePackage = false, includeNames = true) +class FromFileProperty implements Serializable { + + final File file + final Charset charset + final Class type + + FromFileProperty(File file, Class type) { + this(file, type, Charset.defaultCharset()) + } + + FromFileProperty(File file, Class type, Charset charset) { + this.file = file + this.type = type + this.charset = charset + } + + boolean isString() { + return this.type == String + } + + boolean isByte() { + return this.type == byte[] + } + + String asString() { + return new String(this.file.bytes, this.charset) + } + + String fileName() { + return this.file.getName() + } + + byte[] asBytes() { + return this.file.bytes + } + +} diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/MatchingStrategy.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/MatchingStrategy.groovy index 62601bc2c7..900fe621b6 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/MatchingStrategy.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/MatchingStrategy.groovy @@ -55,7 +55,7 @@ class MatchingStrategy extends DslProperty { enum Type { EQUAL_TO("equalTo"), CONTAINS("containing"), MATCHING("matching"), NOT_MATCHING("notMatching"), - EQUAL_TO_JSON("equalToJson"), EQUAL_TO_XML("equalToXml"), ABSENT("absent") + EQUAL_TO_JSON("equalToJson"), EQUAL_TO_XML("equalToXml"), ABSENT("absent"), BINARY_EQUAL_TO("binaryEqualTo") final String name diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java index a49bfcf935..55c5d179cf 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicate.java @@ -17,6 +17,7 @@ package org.springframework.cloud.contract.stubrunner.messaging.camel; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.regex.Pattern; @@ -34,8 +35,11 @@ import org.apache.commons.logging.LogFactory; import org.springframework.cloud.contract.spec.Contract; import org.springframework.cloud.contract.spec.internal.BodyMatcher; import org.springframework.cloud.contract.spec.internal.BodyMatchers; +import org.springframework.cloud.contract.spec.internal.FromFileProperty; import org.springframework.cloud.contract.spec.internal.Header; import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper; +import org.springframework.cloud.contract.verifier.util.ContentType; +import org.springframework.cloud.contract.verifier.util.ContentUtils; import org.springframework.cloud.contract.verifier.util.JsonPaths; import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter; import org.springframework.cloud.contract.verifier.util.MapConverter; @@ -90,8 +94,64 @@ class StubRunnerCamelPredicate implements Predicate { return null; } Object inputMessage = message.getBody(); - BodyMatchers matchers = groovyDsl.getInput().getBodyMatchers(); - Object dslBody = MapConverter.getStubSideValues(groovyDsl.getInput().getMessageBody()); + Object dslBody = MapConverter + .getStubSideValues(groovyDsl.getInput().getMessageBody()); + if (dslBody instanceof FromFileProperty) { + if (log.isDebugEnabled()) { + log.debug("Will compare file content"); + } + FromFileProperty property = (FromFileProperty) dslBody; + if (property.isString()) { + // continue processing as if body was pure string + dslBody = property.asString(); + } + else if (!(inputMessage instanceof byte[])) { + if (log.isDebugEnabled()) { + log.debug("Contract provided byte comparison, but the input message is of type [" + inputMessage.getClass() + "]. Can't compare the two."); + } + return null; + } + else { + boolean matches = Arrays.equals(property.asBytes(), (byte[]) inputMessage); + if (log.isDebugEnabled() && !matches) { + log.debug("Contract provided byte comparison, but the byte arrays don't match"); + } + return matches ? groovyDsl : null; + } + } + if (matchViaContent(groovyDsl, inputMessage, dslBody)) { + return groovyDsl; + } + return null; + } + + private boolean matchViaContent(Contract groovyDsl, Object inputMessage, Object dslBody) { + boolean matches; + ContentType type = ContentUtils + .getClientContentType(inputMessage, groovyDsl.getInput().getMessageHeaders()); + if (type == ContentType.JSON) { + BodyMatchers matchers = groovyDsl.getInput().getBodyMatchers(); + matches = matchesForJsonPayload(groovyDsl, inputMessage, matchers, dslBody); + } + else if (dslBody instanceof Pattern && inputMessage instanceof String) { + Pattern pattern = (Pattern) dslBody; + matches = pattern.matcher((String) inputMessage).matches(); + bodyUnmatchedLog(dslBody, matches, pattern); + } else { + matches = dslBody.equals(inputMessage); + bodyUnmatchedLog(dslBody, matches, inputMessage); + } + return matches; + } + + private void bodyUnmatchedLog(Object dslBody, boolean matches, Object pattern) { + if (log.isDebugEnabled() && !matches) { + log.debug("Body was supposed to " + unmatchedText(pattern) + " but the value is [" + dslBody + .toString() + "]"); + } + } + + private boolean matchesForJsonPayload(Contract groovyDsl, Object inputMessage, BodyMatchers matchers, Object dslBody) { Object matchingInputMessage = JsonToJsonPathsConverter .removeMatchingJsonPaths(dslBody, matchers); JsonPaths jsonPaths = JsonToJsonPathsConverter @@ -119,14 +179,11 @@ class StubRunnerCamelPredicate implements Predicate { } if (!unmatchedJsonPath.isEmpty()) { if (log.isDebugEnabled()) { - log.debug("Contract [" + groovyDsl + "] didn't much the body due to " + log.debug("Contract [" + groovyDsl + "] didn't match the body due to " + unmatchedJsonPath); } } - if (matches) { - return groovyDsl; - } - return null; + return matches; } private boolean matchesJsonPath(List unmatchedJsonPath, diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessor.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessor.java index 3c92811e83..d09beba2ce 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessor.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelProcessor.java @@ -23,6 +23,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.cloud.contract.spec.Contract; +import org.springframework.cloud.contract.spec.internal.FromFileProperty; import org.springframework.cloud.contract.spec.internal.Header; import org.springframework.cloud.contract.verifier.util.BodyExtractor; @@ -55,8 +56,7 @@ class StubRunnerCamelProcessor implements Processor { } return; } - input.setBody(BodyExtractor - .extractStubValueFrom(groovyDsl.getOutputMessage().getBody())); + input.setBody(outputBody(groovyDsl)); if (groovyDsl.getOutputMessage().getHeaders() != null) { for (Header entry : groovyDsl.getOutputMessage().getHeaders().getEntries()) { input.setHeader(entry.getName(), entry.getClientValue()); @@ -64,6 +64,16 @@ class StubRunnerCamelProcessor implements Processor { } } + private Object outputBody(Contract groovyDsl) { + Object outputBody = + BodyExtractor.extractClientValueFromBody(groovyDsl.getOutputMessage().getBody()); + if (outputBody instanceof FromFileProperty) { + FromFileProperty property = (FromFileProperty) outputBody; + return property.asBytes(); + } + return BodyExtractor.extractStubValueFrom(outputBody); + } + private void setStubRunnerDestinationHeader(Exchange exchange, StubRunnerCamelPayload body) { boolean outputPart = body.contract.getOutputMessage() != null; String url = DUMMY_BEAN_URL; diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelector.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelector.java index 33f97dd9c9..01946465d4 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelector.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelector.java @@ -17,6 +17,7 @@ package org.springframework.cloud.contract.stubrunner.messaging.integration; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -33,8 +34,11 @@ import org.apache.commons.logging.LogFactory; import org.springframework.cloud.contract.spec.Contract; import org.springframework.cloud.contract.spec.internal.BodyMatcher; import org.springframework.cloud.contract.spec.internal.BodyMatchers; +import org.springframework.cloud.contract.spec.internal.FromFileProperty; import org.springframework.cloud.contract.spec.internal.Header; import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper; +import org.springframework.cloud.contract.verifier.util.ContentType; +import org.springframework.cloud.contract.verifier.util.ContentUtils; import org.springframework.cloud.contract.verifier.util.JsonPaths; import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter; import org.springframework.cloud.contract.verifier.util.MapConverter; @@ -51,9 +55,10 @@ import org.springframework.messaging.Message; class StubRunnerIntegrationMessageSelector implements MessageSelector { private static final Map CACHE = - Collections.synchronizedMap(new WeakHashMap()); + Collections.synchronizedMap(new WeakHashMap<>()); - private static final Log log = LogFactory.getLog(StubRunnerIntegrationMessageSelector.class); + private static final Log log = LogFactory + .getLog(StubRunnerIntegrationMessageSelector.class); private final List groovyDsls; @@ -107,8 +112,64 @@ class StubRunnerIntegrationMessageSelector implements MessageSelector { return null; } Object inputMessage = message.getPayload(); - BodyMatchers matchers = groovyDsl.getInput().getBodyMatchers(); - Object dslBody = MapConverter.getStubSideValues(groovyDsl.getInput().getMessageBody()); + Object dslBody = MapConverter + .getStubSideValues(groovyDsl.getInput().getMessageBody()); + if (dslBody instanceof FromFileProperty) { + if (log.isDebugEnabled()) { + log.debug("Will compare file content"); + } + FromFileProperty property = (FromFileProperty) dslBody; + if (property.isString()) { + // continue processing as if body was pure string + dslBody = property.asString(); + } + else if (!(inputMessage instanceof byte[])) { + if (log.isDebugEnabled()) { + log.debug("Contract provided byte comparison, but the input message is of type [" + inputMessage.getClass() + "]. Can't compare the two."); + } + return null; + } + else { + boolean matches = Arrays.equals(property.asBytes(), (byte[]) inputMessage); + if (log.isDebugEnabled() && !matches) { + log.debug("Contract provided byte comparison, but the byte arrays don't match"); + } + return matches ? groovyDsl : null; + } + } + if (matchViaContent(groovyDsl, inputMessage, dslBody)) { + return groovyDsl; + } + return null; + } + + private boolean matchViaContent(Contract groovyDsl, Object inputMessage, Object dslBody) { + boolean matches; + ContentType type = ContentUtils + .getClientContentType(inputMessage, groovyDsl.getInput().getMessageHeaders()); + if (type == ContentType.JSON) { + BodyMatchers matchers = groovyDsl.getInput().getBodyMatchers(); + matches = matchesForJsonPayload(groovyDsl, inputMessage, matchers, dslBody); + } + else if (dslBody instanceof Pattern && inputMessage instanceof String) { + Pattern pattern = (Pattern) dslBody; + matches = pattern.matcher((String) inputMessage).matches(); + bodyUnmatchedLog(dslBody, matches, pattern); + } else { + matches = dslBody.equals(inputMessage); + bodyUnmatchedLog(dslBody, matches, inputMessage); + } + return matches; + } + + private void bodyUnmatchedLog(Object dslBody, boolean matches, Object pattern) { + if (log.isDebugEnabled() && !matches) { + log.debug("Body was supposed to " + unmatchedText(pattern) + " but the value is [" + dslBody + .toString() + "]"); + } + } + + private boolean matchesForJsonPayload(Contract groovyDsl, Object inputMessage, BodyMatchers matchers, Object dslBody) { Object matchingInputMessage = JsonToJsonPathsConverter .removeMatchingJsonPaths(dslBody, matchers); JsonPaths jsonPaths = JsonToJsonPathsConverter @@ -136,14 +197,11 @@ class StubRunnerIntegrationMessageSelector implements MessageSelector { } if (!unmatchedJsonPath.isEmpty()) { if (log.isDebugEnabled()) { - log.debug("Contract [" + groovyDsl + "] didn't much the body due to " + log.debug("Contract [" + groovyDsl + "] didn't match the body due to " + unmatchedJsonPath); } } - if (matches) { - return groovyDsl; - } - return null; + return matches; } private boolean matchesJsonPath(List unmatchedJsonPath, @@ -189,5 +247,4 @@ class StubRunnerIntegrationMessageSelector implements MessageSelector { ? "match pattern [" + ((Pattern) expectedValue).pattern() + "]" : "be equal to [" + expectedValue + "]"; } - } diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationTransformer.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationTransformer.java index 6438d31ee2..54c7bdcaa9 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationTransformer.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationTransformer.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import org.springframework.cloud.contract.spec.Contract; +import org.springframework.cloud.contract.spec.internal.FromFileProperty; import org.springframework.cloud.contract.verifier.util.BodyExtractor; import org.springframework.integration.transformer.GenericTransformer; import org.springframework.messaging.Message; @@ -51,17 +52,26 @@ class StubRunnerIntegrationTransformer if (groovyDsl == null || groovyDsl.getOutputMessage() == null) { return source; } - String payload = BodyExtractor - .extractStubValueFrom(groovyDsl.getOutputMessage().getBody()); + Object outputBody = outputBody(groovyDsl); Map headers = groovyDsl.getOutputMessage().getHeaders() .asStubSideMap(); MessageHeaders messageHeaders = new MessageHeaders(headers); - Message message = MessageBuilder.createMessage(payload, + Message message = MessageBuilder.createMessage(outputBody, messageHeaders); this.selector.updateCache(message, groovyDsl); return message; } + private Object outputBody(Contract groovyDsl) { + Object outputBody = + BodyExtractor.extractClientValueFromBody(groovyDsl.getOutputMessage().getBody()); + if (outputBody instanceof FromFileProperty) { + FromFileProperty property = (FromFileProperty) outputBody; + return property.asBytes(); + } + return BodyExtractor.extractStubValueFrom(outputBody); + } + Contract matchingContract(Message source) { return this.selector.matchingContract(source); } diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelector.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelector.java index b1fb8c5ef0..3de6c7e08f 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelector.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelector.java @@ -17,6 +17,7 @@ package org.springframework.cloud.contract.stubrunner.messaging.stream; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -33,8 +34,11 @@ import org.apache.commons.logging.LogFactory; import org.springframework.cloud.contract.spec.Contract; import org.springframework.cloud.contract.spec.internal.BodyMatcher; import org.springframework.cloud.contract.spec.internal.BodyMatchers; +import org.springframework.cloud.contract.spec.internal.FromFileProperty; import org.springframework.cloud.contract.spec.internal.Header; import org.springframework.cloud.contract.verifier.messaging.internal.ContractVerifierObjectMapper; +import org.springframework.cloud.contract.verifier.util.ContentType; +import org.springframework.cloud.contract.verifier.util.ContentUtils; import org.springframework.cloud.contract.verifier.util.JsonPaths; import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter; import org.springframework.cloud.contract.verifier.util.MapConverter; @@ -51,7 +55,7 @@ import org.springframework.messaging.Message; class StubRunnerStreamMessageSelector implements MessageSelector { private static final Map CACHE = - Collections.synchronizedMap(new WeakHashMap()); + Collections.synchronizedMap(new WeakHashMap<>()); private static final Log log = LogFactory .getLog(StubRunnerStreamMessageSelector.class); @@ -108,9 +112,63 @@ class StubRunnerStreamMessageSelector implements MessageSelector { return null; } Object inputMessage = message.getPayload(); - BodyMatchers matchers = groovyDsl.getInput().getBodyMatchers(); Object dslBody = MapConverter .getStubSideValues(groovyDsl.getInput().getMessageBody()); + if (dslBody instanceof FromFileProperty) { + if (log.isDebugEnabled()) { + log.debug("Will compare file content"); + } + FromFileProperty property = (FromFileProperty) dslBody; + if (property.isString()) { + // continue processing as if body was pure string + dslBody = property.asString(); + } + else if (!(inputMessage instanceof byte[])) { + if (log.isDebugEnabled()) { + log.debug("Contract provided byte comparison, but the input message is of type [" + inputMessage.getClass() + "]. Can't compare the two."); + } + return null; + } + else { + boolean matches = Arrays.equals(property.asBytes(), (byte[]) inputMessage); + if (log.isDebugEnabled() && !matches) { + log.debug("Contract provided byte comparison, but the byte arrays don't match"); + } + return matches ? groovyDsl : null; + } + } + if (matchViaContent(groovyDsl, inputMessage, dslBody)) { + return groovyDsl; + } + return null; + } + + private boolean matchViaContent(Contract groovyDsl, Object inputMessage, Object dslBody) { + boolean matches; + ContentType type = ContentUtils.getClientContentType(inputMessage, groovyDsl.getInput().getMessageHeaders()); + if (type == ContentType.JSON) { + BodyMatchers matchers = groovyDsl.getInput().getBodyMatchers(); + matches = matchesForJsonPayload(groovyDsl, inputMessage, matchers, dslBody); + } + else if (dslBody instanceof Pattern && inputMessage instanceof String) { + Pattern pattern = (Pattern) dslBody; + matches = pattern.matcher((String) inputMessage).matches(); + bodyUnmatchedLog(dslBody, matches, pattern); + } else { + matches = dslBody.equals(inputMessage); + bodyUnmatchedLog(dslBody, matches, inputMessage); + } + return matches; + } + + private void bodyUnmatchedLog(Object dslBody, boolean matches, Object pattern) { + if (log.isDebugEnabled() && !matches) { + log.debug("Body was supposed to " + unmatchedText(pattern) + " but the value is [" + dslBody + .toString() + "]"); + } + } + + private boolean matchesForJsonPayload(Contract groovyDsl, Object inputMessage, BodyMatchers matchers, Object dslBody) { Object matchingInputMessage = JsonToJsonPathsConverter .removeMatchingJsonPaths(dslBody, matchers); JsonPaths jsonPaths = JsonToJsonPathsConverter @@ -138,14 +196,11 @@ class StubRunnerStreamMessageSelector implements MessageSelector { } if (!unmatchedJsonPath.isEmpty()) { if (log.isDebugEnabled()) { - log.debug("Contract [" + groovyDsl + "] didn't much the body due to " + log.debug("Contract [" + groovyDsl + "] didn't match the body due to " + unmatchedJsonPath); } } - if (matches) { - return groovyDsl; - } - return null; + return matches; } private boolean matchesJsonPath(List unmatchedJsonPath, diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamTransformer.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamTransformer.java index f5923438f6..0743484ed8 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamTransformer.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamTransformer.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import org.springframework.cloud.contract.spec.Contract; +import org.springframework.cloud.contract.spec.internal.FromFileProperty; import org.springframework.cloud.contract.verifier.util.BodyExtractor; import org.springframework.integration.transformer.GenericTransformer; import org.springframework.messaging.Message; @@ -50,17 +51,26 @@ class StubRunnerStreamTransformer implements GenericTransformer, Mess if (groovyDsl == null || groovyDsl.getOutputMessage() == null) { return source; } - String payload = BodyExtractor - .extractStubValueFrom(groovyDsl.getOutputMessage().getBody()); + byte[] outputBody = outputBodyAsBytes(groovyDsl); Map headers = groovyDsl.getOutputMessage().getHeaders() .asStubSideMap(); MessageHeaders messageHeaders = new MessageHeaders(headers); - Message message = MessageBuilder.createMessage(payload.getBytes(), + Message message = MessageBuilder.createMessage(outputBody, messageHeaders); this.selector.updateCache(message, groovyDsl); return message; } + private byte[] outputBodyAsBytes(Contract groovyDsl) { + Object outputBody = + BodyExtractor.extractClientValueFromBody(groovyDsl.getOutputMessage().getBody()); + if (outputBody instanceof FromFileProperty) { + FromFileProperty property = (FromFileProperty) outputBody; + return property.asBytes(); + } + return BodyExtractor.extractStubValueFrom(outputBody).getBytes(); + } + Contract matchingContract(Message source) { return this.selector.matchingContract(source); } diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicateSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicateSpec.groovy index c202dd93a0..352eaea8c9 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicateSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/camel/StubRunnerCamelPredicateSpec.groovy @@ -87,6 +87,7 @@ class StubRunnerCamelPredicateSpec extends Specification { expect: !predicate.matches(exchange) } + def "should return true if headers and body match"() { given: Contract dsl = Contract.make { @@ -137,4 +138,52 @@ class StubRunnerCamelPredicateSpec extends Specification { expect: predicate.matches(exchange) } + + def "should return true if headers and byte body matches"() { + given: + Contract dsl = Contract.make { + input { + messageFrom "foo" + messageHeaders { + header("foo", 123) + messagingContentType(applicationOctetStream()) + } + messageBody(fileAsBytes("request.pdf")) + } + } + and: + StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate([dsl]) + exchange.in = message + message.headers = [ + foo: 123, + contentType: "application/octet-stream" + ] + message.body = StubRunnerCamelPredicate.getResource("/request.pdf").bytes + expect: + predicate.matches(exchange) + } + + def "should return false if byte body types don't match for binary"() { + given: + Contract dsl = Contract.make { + input { + messageFrom "foo" + messageHeaders { + header("foo", 123) + messagingContentType(applicationOctetStream()) + } + messageBody(fileAsBytes("request.pdf")) + } + } + and: + StubRunnerCamelPredicate predicate = new StubRunnerCamelPredicate([dsl]) + exchange.in = message + message.headers = [ + foo: 123, + contentType: "application/octet-stream" + ] + message.body = "hello world" + expect: + !predicate.matches(exchange) + } } diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelectorSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelectorSpec.groovy index 91121462ab..896ceda7f7 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelectorSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/integration/StubRunnerIntegrationMessageSelectorSpec.groovy @@ -93,6 +93,52 @@ class StubRunnerIntegrationMessageSelectorSpec extends Specification { !predicate.accept(message) } + def "should return true if headers and byte body matches"() { + given: + Contract dsl = Contract.make { + input { + messageFrom "foo" + messageHeaders { + header("foo", 123) + messagingContentType(applicationOctetStream()) + } + messageBody(fileAsBytes("request.pdf")) + } + } + and: + StubRunnerIntegrationMessageSelector predicate = new StubRunnerIntegrationMessageSelector(dsl) + message.headers >> [ + foo: 123, + contentType: "application/octet-stream" + ] + message.payload >> StubRunnerIntegrationMessageSelector.getResource("/request.pdf").bytes + expect: + predicate.accept(message) + } + + def "should return false if byte body types don't match for binary"() { + given: + Contract dsl = Contract.make { + input { + messageFrom "foo" + messageHeaders { + header("foo", 123) + messagingContentType(applicationOctetStream()) + } + messageBody(fileAsBytes("request.pdf")) + } + } + and: + StubRunnerIntegrationMessageSelector predicate = new StubRunnerIntegrationMessageSelector(dsl) + message.headers >> [ + foo: 123, + contentType: "application/octet-stream" + ] + message.payload >> "hello world" + expect: + !predicate.accept(message) + } + def "should return true if headers and body match"() { given: Contract dsl = Contract.make { diff --git a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelectorSpec.groovy b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelectorSpec.groovy index ae164a5752..4050a32890 100644 --- a/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelectorSpec.groovy +++ b/spring-cloud-contract-stub-runner/src/test/groovy/org/springframework/cloud/contract/stubrunner/messaging/stream/StubRunnerStreamMessageSelectorSpec.groovy @@ -123,6 +123,75 @@ class StubRunnerStreamMessageSelectorSpec extends Specification { predicate.accept(message) } + def "should return true if headers and text body matches"() { + given: + Contract dsl = Contract.make { + input { + messageFrom "foo" + messageHeaders { + header("foo", 123) + messagingContentType(textPlain()) + } + messageBody($(c(regex("[0-9]{3}")), p("123"))) + } + } + and: + StubRunnerStreamMessageSelector predicate = new StubRunnerStreamMessageSelector(dsl) + message.headers >> [ + foo: 123, + contentType: "text/plain" + ] + message.payload >> "123" + expect: + predicate.accept(message) + } + + def "should return true if headers and byte body matches"() { + given: + Contract dsl = Contract.make { + input { + messageFrom "foo" + messageHeaders { + header("foo", 123) + messagingContentType(applicationOctetStream()) + } + messageBody(fileAsBytes("request.pdf")) + } + } + and: + StubRunnerStreamMessageSelector predicate = new StubRunnerStreamMessageSelector(dsl) + message.headers >> [ + foo: 123, + contentType: "application/octet-stream" + ] + message.payload >> StubRunnerStreamMessageSelectorSpec.getResource("/request.pdf").bytes + expect: + predicate.accept(message) + } + + def "should return false if byte body types don't match for binary"() { + given: + Contract dsl = Contract.make { + input { + messageFrom "foo" + messageHeaders { + header("foo", 123) + messagingContentType(applicationOctetStream()) + } + messageBody(fileAsBytes("request.pdf")) + } + } + and: + StubRunnerStreamMessageSelector predicate = new StubRunnerStreamMessageSelector(dsl) + message.headers >> [ + foo: 123, + contentType: "application/octet-stream" + ] + message.payload >> "hello world" + expect: + !predicate.accept(message) + } + def "should return true if headers and body using matchers match"() { given: Contract dsl = Contract.make { diff --git a/spring-cloud-contract-stub-runner/src/test/resources/request.pdf b/spring-cloud-contract-stub-runner/src/test/resources/request.pdf new file mode 100644 index 0000000000000000000000000000000000000000..69503635d87cbdfa660d5cd8be66d3e74b3b20e8 GIT binary patch literal 14631 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-stub-runner/src/test/resources/response.pdf b/spring-cloud-contract-stub-runner/src/test/resources/response.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3b233056b758d1cc9bf3176e99a95add89ba607 GIT binary patch literal 15767 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 { addIdeaTestSources(project, extension) } - private addIdeaTestSources(Project project, extension) { + private addIdeaTestSources(Project project, ContractVerifierExtension extension) { def hasIdea = new File(project.rootDir, ".idea").exists() if (hasIdea) { project.apply(plugin: 'idea') project.idea { module { testSourceDirs += extension.generatedTestSourcesDir + testSourceDirs += extension.generatedTestResourcesDir testSourceDirs += extension.contractsDslDir } } @@ -86,6 +87,8 @@ class SpringCloudContractVerifierGradlePlugin implements Plugin { extension.with { generatedTestSourcesDir = generatedTestSourcesDir ?: project.file("${project.buildDir}/generated-test-sources/contracts") generatedTestSourcesDir.mkdirs() + generatedTestResourcesDir = generatedTestResourcesDir ?: project.file("${project.buildDir}/generated-test-resources/contracts") + generatedTestResourcesDir.mkdirs() contractsDslDir = contractsDslDir ?: defaultContractsDir() //TODO: Use sourceset contractsDslDir.mkdirs() stubsOutputDir = stubsOutputDir ?: project.file("${project.buildDir}/stubs/") diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java index 6836c9b6a9..d69c84016e 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/src/main/java/org/springframework/cloud/contract/maven/verifier/GenerateTestsMojo.java @@ -15,15 +15,15 @@ */ package org.springframework.cloud.contract.maven.verifier; -import javax.inject.Inject; import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.inject.Inject; + import org.apache.maven.model.Dependency; +import org.apache.maven.model.Resource; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -33,6 +33,7 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.eclipse.aether.RepositorySystemSession; + import org.springframework.cloud.contract.maven.verifier.stubrunner.AetherStubDownloaderFactory; import org.springframework.cloud.contract.spec.ContractVerifierException; import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties; @@ -57,6 +58,9 @@ public class GenerateTestsMojo extends AbstractMojo { @Parameter(defaultValue = "${project.build.directory}/generated-test-sources/contracts") private File generatedTestSourcesDir; + @Parameter(defaultValue = "${project.build.directory}/generated-test-resources/contracts") + private File generatedTestResourcesDir; + @Parameter private String basePackageForTests; @@ -260,12 +264,16 @@ public class GenerateTestsMojo extends AbstractMojo { this.contractsRepositoryPassword, this.contractsRepositoryProxyHost, this.contractsRepositoryProxyPort, this.deleteStubsAfterTest, this.contractsProperties).downloadAndUnpackContractsIfRequired(config, - this.contractsDirectory); + this.contractsDirectory); getLog().info( "Directory with contract is present at [" + contractsDirectory + "]"); setupConfig(config, contractsDirectory); this.project .addTestCompileSourceRoot(this.generatedTestSourcesDir.getAbsolutePath()); + Resource resource = new Resource(); + resource.setDirectory(this.generatedTestResourcesDir.getAbsolutePath()); + this.project + .addTestResource(resource); if (getLog().isInfoEnabled()) { getLog().info("Test Source directory: " + this.generatedTestSourcesDir.getAbsolutePath() + " added."); @@ -293,6 +301,7 @@ public class GenerateTestsMojo extends AbstractMojo { File contractsDirectory) { config.setContractsDslDir(contractsDirectory); config.setGeneratedTestSourcesDir(this.generatedTestSourcesDir); + config.setGeneratedTestResourcesDir(this.generatedTestResourcesDir); config.setTestFramework(this.testFramework); config.setTestMode(this.testMode); config.setBasePackageForTests(this.basePackageForTests); @@ -311,15 +320,6 @@ public class GenerateTestsMojo extends AbstractMojo { } } - private URL fileToUrl(File contractsDirectory) { - try { - return contractsDirectory.toURI().toURL(); - } - catch (MalformedURLException e) { - throw new IllegalStateException(e); - } - } - public Map mappingsToMap() { Map map = new HashMap<>(); if (this.baseClassMappings == null) { diff --git a/spring-cloud-contract-verifier/pom.xml b/spring-cloud-contract-verifier/pom.xml index d41c4d169f..38c0ea8d11 100644 --- a/spring-cloud-contract-verifier/pom.xml +++ b/spring-cloud-contract-verifier/pom.xml @@ -209,8 +209,13 @@ addSources + addTestSources + generateStubs compile + generateTestStubs compileTests + removeStubs + removeTestStubs diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/FileSaver.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/FileSaver.groovy index f9685f60a4..068d25daee 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/FileSaver.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/FileSaver.groovy @@ -46,13 +46,20 @@ class FileSaver { this.properties = properties } - void saveClassFile(String fileName, String basePackageClass, String includedDirectoryRelativePath, byte[] classBytes) { - Path testBaseDir = Paths.get(targetDirectory.absolutePath, packageToDirectory(basePackageClass), - beforeLast(includedDirectoryRelativePath, File.separator)) - Files.createDirectories(testBaseDir) - Path classPath = Paths.get(testBaseDir.toString(), capitalize(fileName) + generator.fileExtension(this.properties)).toAbsolutePath() + void saveClassFile(Path classPath, byte[] classBytes) { log.info("Creating new class file [$classPath]") Files.write(classPath, classBytes, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING) } + protected Path pathToClass(Path testBaseDir, String fileName) { + Paths.get(testBaseDir.toString(), capitalize(fileName) + generator.fileExtension(this.properties)).toAbsolutePath() + } + + protected Path generateTestBaseDir(String basePackageClass, String includedDirectoryRelativePath) { + Path testBaseDir = Paths.get(targetDirectory.absolutePath, packageToDirectory(basePackageClass), + beforeLast(includedDirectoryRelativePath, File.separator)) + Files.createDirectories(testBaseDir) + return testBaseDir + } + } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy index daa492d536..ca01686508 100755 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/TestGenerator.groovy @@ -16,16 +16,10 @@ package org.springframework.cloud.contract.verifier -import java.nio.charset.StandardCharsets -import java.nio.file.Path -import java.util.concurrent.atomic.AtomicInteger - import groovy.transform.CompileStatic import groovy.transform.PackageScope import org.apache.commons.logging.Log import org.apache.commons.logging.LogFactory -import wiremock.com.google.common.collect.ListMultimap - import org.springframework.cloud.contract.spec.ContractVerifierException import org.springframework.cloud.contract.verifier.builder.JavaTestGenerator import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator @@ -35,13 +29,17 @@ import org.springframework.cloud.contract.verifier.file.ContractFileScannerBuild import org.springframework.cloud.contract.verifier.file.ContractMetadata import org.springframework.core.io.support.SpringFactoriesLoader import org.springframework.util.StringUtils +import wiremock.com.google.common.collect.ListMultimap + +import java.nio.charset.StandardCharsets +import java.nio.file.Path +import java.util.concurrent.atomic.AtomicInteger import static org.springframework.cloud.contract.verifier.util.NamesUtil.afterLast import static org.springframework.cloud.contract.verifier.util.NamesUtil.beforeLast import static org.springframework.cloud.contract.verifier.util.NamesUtil.convertIllegalPackageChars import static org.springframework.cloud.contract.verifier.util.NamesUtil.directoryToPackage import static org.springframework.cloud.contract.verifier.util.NamesUtil.toLastDot - /** * @author Jakub Kubrynski, codearte.io */ @@ -128,8 +126,11 @@ class TestGenerator { def className = afterLast(includedDirectoryRelativePath.toString(), File.separator) + resolveNameSuffix() def convertedClassName = convertIllegalPackageChars(className) def packageName = buildPackage(basePackageNameForClass, includedDirectoryRelativePath) - def classBytes = generator.buildClass(configProperties, contracts, convertedClassName, packageName, includedDirectoryRelativePath).getBytes(StandardCharsets.UTF_8) - saver.saveClassFile(convertedClassName, basePackageNameForClass, convertIllegalPackageChars(includedDirectoryRelativePath.toString()), classBytes) + Path dir = saver.generateTestBaseDir(basePackageNameForClass, convertIllegalPackageChars(includedDirectoryRelativePath.toString())) + Path classPath = saver.pathToClass(dir, convertedClassName) + def classBytes = generator.buildClass(configProperties, contracts, includedDirectoryRelativePath, + new SingleTestGenerator.GeneratedClassData(className, packageName, classPath)).getBytes(StandardCharsets.UTF_8) + saver.saveClassFile(classPath, classBytes) counter.incrementAndGet() } } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/CommunicationType.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/CommunicationType.groovy new file mode 100644 index 0000000000..23729394b2 --- /dev/null +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/CommunicationType.groovy @@ -0,0 +1,31 @@ +/* + * Copyright 2013-2018 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 + * + * http://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.transform.CompileStatic + +/** + * Describes the type of communication + * + * @author Marcin Grzejszczak + * @since 2.1.0 + */ +@CompileStatic +enum CommunicationType { + REQUEST, RESPONSE, INPUT, OUTPUT +} \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/ExplicitJUnitMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/ExplicitJUnitMethodBodyBuilder.groovy index c78e07b3fc..6dd3493417 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/ExplicitJUnitMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/ExplicitJUnitMethodBodyBuilder.groovy @@ -32,8 +32,10 @@ import org.springframework.cloud.contract.verifier.config.ContractVerifierConfig @PackageScope class ExplicitJUnitMethodBodyBuilder extends RestAssuredJUnitMethodBodyBuilder { - ExplicitJUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + ExplicitJUnitMethodBodyBuilder(Contract stubDefinition, + ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/GeneratedClassDataForMethod.java b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/GeneratedClassDataForMethod.java new file mode 100644 index 0000000000..0a341b0dbe --- /dev/null +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/GeneratedClassDataForMethod.java @@ -0,0 +1,47 @@ +/* + * Copyright 2013-2018 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 + * + * http://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; + +/** + * @author Marcin Grzejszczak + * @since + */ +class GeneratedClassDataForMethod { + final SingleTestGenerator.GeneratedClassData generatedClassData; + final String methodName; + + GeneratedClassDataForMethod(SingleTestGenerator.GeneratedClassData generatedClassData, + String methodName) { + this.generatedClassData = generatedClassData; + this.methodName = methodName; + } + + private SingleTestGenerator.GeneratedClassData assertClassData() { + if (this.generatedClassData == null) { + throw new IllegalStateException("No metadata was found for the generated test class"); + } + return this.generatedClassData; + } + + String className() { + return assertClassData().className; + } + + java.nio.file.Path testClassPath() { + return assertClassData().testClassPath; + } +} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/HttpSpockMethodRequestProcessingBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/HttpSpockMethodRequestProcessingBodyBuilder.groovy index ef7709e928..c7b55a5765 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/HttpSpockMethodRequestProcessingBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/HttpSpockMethodRequestProcessingBodyBuilder.groovy @@ -36,8 +36,10 @@ import java.util.regex.Pattern @TypeChecked class HttpSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequestProcessingBodyBuilder { - HttpSpockMethodRequestProcessingBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + HttpSpockMethodRequestProcessingBodyBuilder(Contract stubDefinition, + ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy index 9a490dd615..887e67991b 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMessagingMethodBodyBuilder.groovy @@ -25,6 +25,7 @@ import groovy.transform.TypeChecked import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.internal.Cookie import org.springframework.cloud.contract.spec.internal.ExecutionProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Header import org.springframework.cloud.contract.spec.internal.Input import org.springframework.cloud.contract.spec.internal.NamedProperty @@ -50,8 +51,10 @@ import static org.springframework.cloud.contract.verifier.config.TestFramework.J @TypeChecked class JUnitMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { - JUnitMessagingMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + JUnitMessagingMethodBodyBuilder(Contract stubDefinition, + ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override @@ -82,6 +85,15 @@ class JUnitMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { return "" } + @Override + protected String getResponseBodyPropertyComparisonString(String property, FromFileProperty value) { + if (value.isByte()) { + return "assertThat(response.getPayloadAsByteArray()).isEqualTo(" + + readBytesFromFileString(value, CommunicationType.RESPONSE) + ")" + } + return getResponseBodyPropertyComparisonString(property, value.asString()) + } + @Override protected void processBodyElement(BlockBuilder blockBuilder, String property, ExecutionProperty exec) { blockBuilder.addLine("${exec.insertValue("parsedJson.read('\\\$$property')")}") @@ -196,15 +208,27 @@ class JUnitMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { protected String getInputString() { String request = 'ContractVerifierMessage inputMessage = contractVerifierMessaging.create(' if (inputMessage.messageBody) { - request = "${request}\n\t\t\t\t\"${escapeJava(bodyAsString)}\"\n" + request = "${request}${getBodyAsString()}" } if (inputMessage.messageHeaders) { - request = "${request}\t\t\t\t, headers()" + request = "${request}${indentHeadersString()}" } inputMessage.messageHeaders?.executeForEachHeader { Header header -> - request = "${request}\n\t\t\t\t\t\t${getHeaderString(header)}" + request = "${request}${indentedHeaderString(header)}" } - return "${request}\n\t\t\t)" + return finishIndentation(request) + } + + private String indentHeadersString() { + return "\t\t\t\t, headers()" + } + + private String indentedHeaderString(Header header) { + return "\n\t\t\t\t\t\t${getHeaderString(header)}" + } + + private String finishIndentation(String text) { + return "${text}\n\t\t\t)" } @Override diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMethodBodyBuilder.groovy index b8ff6f9e10..282575ff39 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JUnitMethodBodyBuilder.groovy @@ -16,24 +16,26 @@ package org.springframework.cloud.contract.verifier.builder + +import java.util.regex.Pattern + import groovy.json.StringEscapeUtils import groovy.transform.PackageScope import groovy.transform.TypeChecked + import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.internal.Cookie import org.springframework.cloud.contract.spec.internal.ExecutionProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Header import org.springframework.cloud.contract.spec.internal.NamedProperty import org.springframework.cloud.contract.spec.internal.Request import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties import org.springframework.cloud.contract.verifier.util.RegexpBuilders -import java.util.regex.Pattern - import static groovy.json.StringEscapeUtils.escapeJava import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT import static org.springframework.cloud.contract.verifier.util.ContentUtils.getJavaMultipartFileParameterContent - /** * Root class for JUnit method building * @@ -48,8 +50,9 @@ import static org.springframework.cloud.contract.verifier.util.ContentUtils.getJ @PackageScope abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder { - JUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + JUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override @@ -117,6 +120,15 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder return property.replaceAll('(get\\(\\\\")(.*)(\\\\"\\))', '$2') } + @Override + protected String getResponseBodyPropertyComparisonString(String property, FromFileProperty value) { + if (value.isByte()) { + return "assertThat(response.getBody().asByteArray()).isEqualTo(" + + readBytesFromFileString(value, CommunicationType.RESPONSE) + ")" + } + return getResponseBodyPropertyComparisonString(property, value.asString()) + } + @Override protected String getParsedXmlResponseBodyString(String responseString) { return "Object responseBody = new XmlSlurper().parseText($responseString);" @@ -160,6 +172,11 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder String value if (body instanceof ExecutionProperty) { value = body.toString() + } else if (body instanceof FromFileProperty) { + FromFileProperty fileProperty = (FromFileProperty) body + value = fileProperty.isByte() ? + readBytesFromFileString(fileProperty, CommunicationType.REQUEST) : + readStringFromFileString(fileProperty, CommunicationType.REQUEST) } else { value = "\"$body\"" } @@ -168,7 +185,7 @@ abstract class JUnitMethodBodyBuilder extends RequestProcessingMethodBodyBuilder @Override protected String getMultipartFileParameterContent(String propertyName, NamedProperty propertyValue) { - return getJavaMultipartFileParameterContent(propertyName, propertyValue) + return getJavaMultipartFileParameterContent(propertyName, propertyValue, { FromFileProperty fileProp -> readBytesFromFileString(fileProp, CommunicationType.REQUEST) }) } @Override diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.groovy index a20e8d4107..db6213e389 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JavaTestGenerator.groovy @@ -16,6 +16,8 @@ package org.springframework.cloud.contract.verifier.builder +import groovy.transform.CompileStatic + import java.lang.invoke.MethodHandles import groovy.transform.Canonical @@ -40,26 +42,31 @@ import static org.springframework.cloud.contract.verifier.util.NamesUtil.capital * * @since 1.1.0 */ +@CompileStatic class JavaTestGenerator implements SingleTestGenerator { private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()) private static final String JSON_ASSERT_STATIC_IMPORT = 'com.toomuchcoding.jsonassert.JsonAssertion.assertThatJson' private static final String JSON_ASSERT_CLASS = 'com.toomuchcoding.jsonassert.JsonAssertion' + @Deprecated + // TODO: Remove in next major private static final String REST_ASSURED_2_0_CLASS = 'com.jayway.restassured.RestAssured' @PackageScope ClassPresenceChecker checker = new ClassPresenceChecker() @Override - String buildClass(ContractVerifierConfigProperties configProperties, Collection listOfFiles, String className, String classPackage, String includedDirectoryRelativePath) { + String buildClass(ContractVerifierConfigProperties configProperties, Collection listOfFiles, String includedDirectoryRelativePath, GeneratedClassData generatedClassData) { + String className = generatedClassData.className + String classPackage = generatedClassData.classPackage ClassBuilder clazz = ClassBuilder.createClass(capitalize(className), classPackage, configProperties, includedDirectoryRelativePath) if (configProperties.imports) { - configProperties.imports.each { + configProperties.imports.each { String it -> clazz.addImport(it) } } if (configProperties.staticImports) { - configProperties.staticImports.each { + configProperties.staticImports.each { String it -> clazz.addStaticImport(it) } } @@ -68,15 +75,19 @@ class JavaTestGenerator implements SingleTestGenerator { clazz.addClassLevelAnnotation(configProperties.testFramework.getOrderAnnotation()) } addJsonPathRelatedImports(clazz) - processContractFiles(listOfFiles, configProperties, clazz) + processContractFiles(listOfFiles, configProperties, clazz, generatedClassData) return clazz.build() } - private void processContractFiles(Collection listOfFiles, - ContractVerifierConfigProperties configProperties, ClassBuilder clazz) { + @Override + String buildClass(ContractVerifierConfigProperties configProperties, Collection listOfFiles, String className, String classPackage, String includedDirectoryRelativePath) { + return buildClass(configProperties, listOfFiles, includedDirectoryRelativePath, new GeneratedClassData(className, classPackage, null)) + } + + private void processContractFiles(Collection listOfFiles, ContractVerifierConfigProperties configProperties, ClassBuilder clazz, GeneratedClassData generatedClassData) { Map contracts = mapContractsToTheirTestTypes(listOfFiles) boolean conditionalImportsAdded = false - boolean toIgnore = listOfFiles.ignored.find {it} + boolean toIgnore = listOfFiles.find { it.ignored } contracts.each {ParsedDsl key, TestType value -> if (!conditionalImportsAdded) { clazz.addImports(getImports(configProperties.testFramework)) @@ -93,7 +104,8 @@ class JavaTestGenerator implements SingleTestGenerator { conditionalImportsAdded = true } toIgnore = toIgnore ? true : key.groovyDsl.ignored - clazz.addMethod(MethodBuilder.createTestMethod(key.contract, key.stubsFile, key.groovyDsl, configProperties)) + clazz.addMethod(MethodBuilder.createTestMethod(key.contract, key.stubsFile, + key.groovyDsl, configProperties, generatedClassData)) } if (toIgnore) { @@ -102,7 +114,7 @@ class JavaTestGenerator implements SingleTestGenerator { } private void addRule(ContractVerifierConfigProperties configProperties, ClassBuilder clazz) { - clazz.addImport(getRuleImport()) + clazz.addImport(getRuleImport(configProperties.testFramework)) if (configProperties.testFramework.annotationLevelRules()) { clazz.addClassLevelAnnotation(configProperties.testFramework .getRuleAnnotation(configProperties.ruleClassForTests)) @@ -139,7 +151,7 @@ class JavaTestGenerator implements SingleTestGenerator { if (log.isDebugEnabled()) { log.debug("Stub content from file [${stubsFile.text}]") } - List stubContents = metadata.convertedContract + Collection stubContents = metadata.convertedContract Map entries = stubContents.collectEntries { Contract stubContent -> TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP return [(new ParsedDsl(metadata, stubContent, stubsFile)): testType] @@ -151,6 +163,7 @@ class JavaTestGenerator implements SingleTestGenerator { @Canonical @EqualsAndHashCode(includeFields = true) + @CompileStatic private static class ParsedDsl { ContractMetadata contract Contract groovyDsl diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientJUnitMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientJUnitMethodBodyBuilder.groovy index 155f8972f3..527df7ebc3 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientJUnitMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientJUnitMethodBodyBuilder.groovy @@ -21,6 +21,7 @@ import groovy.transform.TypeChecked import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.internal.Cookie import org.springframework.cloud.contract.spec.internal.DslProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Header import org.springframework.cloud.contract.spec.internal.NotToEscapePattern import org.springframework.cloud.contract.spec.internal.QueryParameter @@ -47,8 +48,10 @@ import static org.springframework.cloud.contract.verifier.config.TestFramework.J @PackageScope class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder { - JaxRsClientJUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + JaxRsClientJUnitMethodBodyBuilder(Contract stubDefinition, + ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override @@ -109,9 +112,19 @@ class JaxRsClientJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder { String method = request.method.serverValue.toString().toLowerCase() if (request.body) { String contentType = getHeader('Content-Type') ?: getRequestContentType().mimeType - String body = request.body?.serverValue instanceof ExecutionProperty ? - request.body?.serverValue?.toString() : "\"${bodyAsString}\"" - bb.addLine(".method(\"${method.toUpperCase()}\", entity(${body}, \"$contentType\"))") + Object body = request.body.serverValue + String value + if (body instanceof ExecutionProperty) { + value = body.toString() + } else if (body instanceof FromFileProperty) { + FromFileProperty fileProperty = (FromFileProperty) body + value = fileProperty.isByte() ? + readBytesFromFileString(fileProperty, CommunicationType.REQUEST) : + readStringFromFileString(fileProperty, CommunicationType.REQUEST) + } else { + value = "\"${getBodyAsString()}\"" + } + bb.addLine(".method(\"${method.toUpperCase()}\", entity(${value}, \"$contentType\"))") } else { bb.addLine(".method(\"${method.toUpperCase()}\")") } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientSpockMethodRequestProcessingBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientSpockMethodRequestProcessingBodyBuilder.groovy index f483785f96..abaec03f84 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientSpockMethodRequestProcessingBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientSpockMethodRequestProcessingBodyBuilder.groovy @@ -21,6 +21,7 @@ import groovy.transform.TypeChecked import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.internal.Cookie import org.springframework.cloud.contract.spec.internal.DslProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Header import org.springframework.cloud.contract.spec.internal.NotToEscapePattern import org.springframework.cloud.contract.spec.internal.QueryParameter @@ -44,8 +45,10 @@ import java.util.regex.Pattern @TypeChecked class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequestProcessingBodyBuilder { - JaxRsClientSpockMethodRequestProcessingBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + JaxRsClientSpockMethodRequestProcessingBodyBuilder(Contract stubDefinition, + ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override @@ -114,9 +117,19 @@ class JaxRsClientSpockMethodRequestProcessingBodyBuilder extends SpockMethodRequ String method = request.method.serverValue.toString().toLowerCase() if (request.body) { String contentType = getHeader('Content-Type') ?: getRequestContentType().mimeType - String body = request.body?.serverValue instanceof ExecutionProperty ? - request.body?.serverValue?.toString() : "'${bodyAsString}'" - bb.addLine(".method('${method.toUpperCase()}', entity(${body}, '$contentType'))") + Object body = request.body.serverValue + String value + if (body instanceof ExecutionProperty) { + value = body.toString() + } else if (body instanceof FromFileProperty) { + FromFileProperty fileProperty = (FromFileProperty) body + value = fileProperty.isByte() ? + readBytesFromFileString(fileProperty, CommunicationType.REQUEST) : + readStringFromFileString(fileProperty, CommunicationType.REQUEST) + } else { + value = "'${bodyAsString}'" + } + bb.addLine(".method('${method.toUpperCase()}', entity(${value}, '$contentType'))") } else { bb.addLine(".method('${method.toUpperCase()}')") } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilder.groovy index a1d16f8e3b..ececd3fcff 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilder.groovy @@ -19,13 +19,16 @@ package org.springframework.cloud.contract.verifier.builder import groovy.json.JsonOutput import groovy.transform.PackageScope import groovy.transform.TypeChecked + import org.springframework.cloud.contract.spec.Contract +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Input import org.springframework.cloud.contract.spec.internal.OutputMessage import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties import org.springframework.cloud.contract.verifier.util.ContentType import org.springframework.cloud.contract.verifier.util.ContentUtils +import static org.apache.commons.text.StringEscapeUtils.escapeJava import static org.springframework.cloud.contract.verifier.util.ContentUtils.recognizeContentTypeFromContent import static org.springframework.cloud.contract.verifier.util.ContentUtils.recognizeContentTypeFromHeader @@ -46,8 +49,10 @@ abstract class MessagingMethodBodyBuilder extends MethodBodyBuilder { protected final Input inputMessage protected final OutputMessage outputMessage - MessagingMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(configProperties, stubDefinition) + MessagingMethodBodyBuilder(Contract stubDefinition, + ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(configProperties, stubDefinition, classDataForMethod) this.inputMessage = stubDefinition.input this.outputMessage = stubDefinition.outputMessage } @@ -101,6 +106,11 @@ abstract class MessagingMethodBodyBuilder extends MethodBodyBuilder { processHeaderElement(blockBuilder, property, gstringValue) } + @Override + protected String getResponseBodyPropertyComparisonString(String property, FromFileProperty value) { + return null + } + protected ContentType getResponseContentType() { ContentType contentType = recognizeContentTypeFromHeader(outputMessage.headers) if (contentType == ContentType.UNKNOWN) { @@ -111,9 +121,27 @@ abstract class MessagingMethodBodyBuilder extends MethodBodyBuilder { protected String getBodyAsString() { Object bodyValue = extractServerValueFromBody(inputMessage.messageBody.serverValue) + if (bodyValue instanceof FromFileProperty) { + FromFileProperty fileProperty = (FromFileProperty) bodyValue + return fileProperty.isByte() ? + indentBody(readBytesFromFileString(fileProperty, CommunicationType.REQUEST)) : + indentStringBody(readStringFromFileString(fileProperty, CommunicationType.REQUEST)) + } String json = new JsonOutput().toJson(bodyValue) json = convertUnicodeEscapesIfRequired(json) - return trimRepeatedQuotes(json) + return indentStringBody(trimRepeatedQuotes(json)) + } + + protected String indentBody(String text) { + return "\n\t\t\t\t${text}\n" + } + + protected String indentStringBody(String text) { + return indentBody("${quotes()}${escapeJava(text)}${quotes()}") + } + + protected String quotes() { + return "\"" } } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilder.groovy index 40a4b74653..8541fb1199 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilder.groovy @@ -16,8 +16,6 @@ package org.springframework.cloud.contract.verifier.builder -import org.springframework.cloud.contract.spec.internal.Cookie - import java.util.regex.Pattern import com.jayway.jsonpath.DocumentContext @@ -33,8 +31,10 @@ import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.ContractTemplate import org.springframework.cloud.contract.spec.internal.BodyMatcher import org.springframework.cloud.contract.spec.internal.BodyMatchers +import org.springframework.cloud.contract.spec.internal.Cookie import org.springframework.cloud.contract.spec.internal.DslProperty import org.springframework.cloud.contract.spec.internal.ExecutionProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Header import org.springframework.cloud.contract.spec.internal.MatchingStrategy import org.springframework.cloud.contract.spec.internal.MatchingType @@ -76,12 +76,42 @@ abstract class MethodBodyBuilder { protected final TemplateProcessor templateProcessor protected final ContractTemplate contractTemplate protected final Contract contract + protected final GeneratedClassDataForMethod classDataForMethod - protected MethodBodyBuilder(ContractVerifierConfigProperties configProperties, Contract contract) { + protected MethodBodyBuilder(ContractVerifierConfigProperties configProperties, Contract contract, GeneratedClassDataForMethod classDataForMethod) { this.configProperties = configProperties this.templateProcessor = processor() this.contractTemplate = template() this.contract = contract + this.classDataForMethod = classDataForMethod + } + + private String byteBodyToAFileForTestMethod(FromFileProperty property, CommunicationType side) { + String newFileName = this.classDataForMethod.methodName + "_" + side.name().toLowerCase() + "_" + property.fileName() + File newFile = new File(this.classDataForMethod.testClassPath().parent.toFile(), newFileName) + // for IDE + newFile.bytes = property.asBytes() + // for plugin + generatedTestResourcesFileBytes(property, newFile) + return newFileName + } + + private void generatedTestResourcesFileBytes(FromFileProperty property, File newFile) { + java.nio.file.Path relativePath = this.configProperties.generatedTestSourcesDir. + toPath().relativize(newFile.toPath()) + File newFileInGeneratedTestSources = new File(this.configProperties.generatedTestResourcesDir, relativePath. + toString()) + newFileInGeneratedTestSources.parentFile.mkdirs() + newFileInGeneratedTestSources.bytes = property.asBytes() + } + + protected String readBytesFromFileString(FromFileProperty property, CommunicationType side) { + String fileName = byteBodyToAFileForTestMethod(property, side) + return "fileToBytes(this, \"${fileName}\")" + } + + protected String readStringFromFileString(FromFileProperty property, CommunicationType side) { + return "new String(" + readBytesFromFileString(property, side) + ")" } private TemplateProcessor processor() { @@ -128,6 +158,12 @@ abstract class MethodBodyBuilder { */ protected abstract String getResponseBodyPropertyComparisonString(String property, Object value) + /** + * Builds the code that for the given {@code property} will compare it to + * the given byte[] {@code value} + */ + protected abstract String getResponseBodyPropertyComparisonString(String property, FromFileProperty value) + /** * Builds the code that for the given {@code property} will compare it to * the given String {@code value} @@ -340,6 +376,10 @@ abstract class MethodBodyBuilder { protected void validateResponseBodyBlock(BlockBuilder bb, BodyMatchers bodyMatchers, Object responseBody) { ContentType contentType = getResponseContentType() Object convertedResponseBody = responseBody + if (convertedResponseBody instanceof FromFileProperty) { + byteResponseBodyCheck(bb, convertedResponseBody) + return + } if (convertedResponseBody instanceof GString) { convertedResponseBody = extractValue(convertedResponseBody as GString, contentType, { Object o -> o instanceof DslProperty ? o.serverValue : o }) } @@ -359,6 +399,11 @@ abstract class MethodBodyBuilder { } } + private void byteResponseBodyCheck(BlockBuilder bb, FromFileProperty convertedResponseBody) { + processText(bb, "", convertedResponseBody) + addColonIfRequired(bb) + } + private void simpleTextResponseBodyCheck(BlockBuilder bb, convertedResponseBody) { bb.addLine(getSimpleResponseBodyString(getResponseAsString())) processText(bb, "", convertedResponseBody) @@ -765,6 +810,4 @@ abstract class MethodBodyBuilder { processBodyElement(blockBuilder, property, prop, listElement) } } - - -} +} \ No newline at end of file diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBuilder.groovy index 33961ad71f..b75f75a1bf 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MethodBuilder.groovy @@ -19,6 +19,7 @@ package org.springframework.cloud.contract.verifier.builder import groovy.transform.CompileStatic import groovy.transform.PackageScope import groovy.util.logging.Commons + import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties import org.springframework.cloud.contract.verifier.config.TestMode @@ -44,24 +45,28 @@ class MethodBuilder { private final String methodName private final Contract stubContent private final ContractVerifierConfigProperties configProperties + private final GeneratedClassDataForMethod generatedClassDataForMethod private final boolean ignored - private MethodBuilder(String methodName, Contract stubContent, ContractVerifierConfigProperties configProperties, boolean ignored) { + private MethodBuilder(String methodName, Contract stubContent, ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod generatedClassDataForMethod, boolean ignored) { this.ignored = ignored this.stubContent = stubContent this.methodName = methodName this.configProperties = configProperties + this.generatedClassDataForMethod = generatedClassDataForMethod } /** * A factory method that creates a {@link MethodBuilder} for the given arguments */ - static MethodBuilder createTestMethod(ContractMetadata contract, File stubsFile, Contract stubContent, ContractVerifierConfigProperties configProperties) { + static MethodBuilder createTestMethod(ContractMetadata contract, File stubsFile, Contract stubContent, ContractVerifierConfigProperties configProperties, SingleTestGenerator.GeneratedClassData generatedClassData) { if (log.isDebugEnabled()) { log.debug("Stub content Groovy DSL [$stubContent]") } - String methodName = MethodBuilder.methodName(contract, stubsFile, stubContent) - return new MethodBuilder(methodName, stubContent, configProperties, contract.ignored || stubContent.ignored) + String methodName = methodName(contract, stubsFile, stubContent) + return new MethodBuilder(methodName, stubContent, configProperties, + new GeneratedClassDataForMethod(generatedClassData, methodName), contract.ignored || stubContent.ignored) } static String methodName(ContractMetadata contract, File stubsFile, Contract stubContent) { @@ -108,30 +113,30 @@ class MethodBuilder { private MethodBodyBuilder getMethodBodyBuilder() { if (stubContent.input || stubContent.outputMessage) { if (isJUnitType()) { - return new JUnitMessagingMethodBodyBuilder(stubContent, configProperties) + return new JUnitMessagingMethodBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod) } - return new SpockMessagingMethodBodyBuilder(stubContent, configProperties) + return new SpockMessagingMethodBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod) } if (configProperties.testMode == TestMode.JAXRSCLIENT) { if (isJUnitType()) { - return new JaxRsClientJUnitMethodBodyBuilder(stubContent, configProperties) + return new JaxRsClientJUnitMethodBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod) } - return new JaxRsClientSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties) + return new JaxRsClientSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod) } else if (configProperties.testMode == TestMode.WEBTESTCLIENT) { if (isJUnitType()) { - return new WebTestClientJUnitMethodBodyBuilder(stubContent, configProperties) + return new WebTestClientJUnitMethodBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod) } - return new HttpSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties) + return new HttpSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod) } else if (configProperties.testMode == TestMode.EXPLICIT) { if (isJUnitType()) { - return new ExplicitJUnitMethodBodyBuilder(stubContent, configProperties) + return new ExplicitJUnitMethodBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod) } // in Groovy we're using def so we don't have to update the imports - return new HttpSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties) + return new HttpSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod) } else if (configProperties.testFramework == SPOCK) { - return new HttpSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties) + return new HttpSpockMethodRequestProcessingBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod) } - return new MockMvcJUnitMethodBodyBuilder(stubContent, configProperties) + return new MockMvcJUnitMethodBodyBuilder(stubContent, configProperties, this.generatedClassDataForMethod) } private boolean isJUnitType() { diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcJUnitMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcJUnitMethodBodyBuilder.groovy index 63d631fe61..e76aa14e87 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcJUnitMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcJUnitMethodBodyBuilder.groovy @@ -32,8 +32,9 @@ import org.springframework.cloud.contract.verifier.config.ContractVerifierConfig @PackageScope class MockMvcJUnitMethodBodyBuilder extends RestAssuredJUnitMethodBodyBuilder { - MockMvcJUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + MockMvcJUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RequestProcessingMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RequestProcessingMethodBodyBuilder.groovy index d548d76302..502e3d5222 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RequestProcessingMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RequestProcessingMethodBodyBuilder.groovy @@ -24,6 +24,7 @@ import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.internal.BodyMatchers import org.springframework.cloud.contract.spec.internal.Cookie import org.springframework.cloud.contract.spec.internal.ExecutionProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Header import org.springframework.cloud.contract.spec.internal.MatchingStrategy import org.springframework.cloud.contract.spec.internal.NamedProperty @@ -57,8 +58,8 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder { private static final String DOUBLE_QUOTE = '"' private static final String QUERY_PARAM_METHOD = 'queryParam' - RequestProcessingMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(configProperties, stubDefinition) + RequestProcessingMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties, GeneratedClassDataForMethod classDataForMethod) { + super(configProperties, stubDefinition, classDataForMethod) this.request = stubDefinition.request this.response = stubDefinition.response } @@ -118,8 +119,15 @@ abstract class RequestProcessingMethodBodyBuilder extends MethodBodyBuilder { } if (request.body) { - Object body = request.body?.serverValue instanceof ExecutionProperty ? - request.body?.serverValue : bodyAsString + Object body = null + switch (request.body.serverValue) { + case ExecutionProperty: + case FromFileProperty: + body = request.body?.serverValue + break; + default: + body = getBodyAsString() + } bb.addLine(getBodyString(body)) } if (request.multipart) { diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RestAssuredJUnitMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RestAssuredJUnitMethodBodyBuilder.groovy index e2f4347a7c..31c512e951 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RestAssuredJUnitMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/RestAssuredJUnitMethodBodyBuilder.groovy @@ -38,8 +38,9 @@ import java.util.regex.Pattern @PackageScope class RestAssuredJUnitMethodBodyBuilder extends JUnitMethodBodyBuilder { - RestAssuredJUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + RestAssuredJUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy deleted file mode 100644 index 8a2c032baa..0000000000 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.groovy +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013-2017 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 - * - * http://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 org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.file.ContractMetadata -/** - * Builds a single test. - * - * @since 1.1.0 - */ -interface SingleTestGenerator { - - /** - * Creates contents of a single test class in which all test scenarios from - * the contract metadata should be placed. - * - * @param properties - properties passed to the plugin - * @param listOfFiles - list of parsed contracts with additional metadata - * @param className - the name of the generated test class - * @param classPackage - the name of the package in which the test class should be stored - * @param includedDirectoryRelativePath - relative path to the included directory - * @return contents of a single test class - */ - String buildClass(ContractVerifierConfigProperties properties, Collection listOfFiles, - String className, String classPackage, String includedDirectoryRelativePath) - - /** - * Extension that should be appended to the generated test class. E.g. {@code .java} or {@code .php} - * - * @param properties - properties passed to the plugin - */ - String fileExtension(ContractVerifierConfigProperties properties) -} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java new file mode 100644 index 0000000000..1f2de9e11d --- /dev/null +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGenerator.java @@ -0,0 +1,64 @@ +package org.springframework.cloud.contract.verifier.builder; + +import java.util.Collection; + +import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties; +import org.springframework.cloud.contract.verifier.file.ContractMetadata; + +/** + * Builds a single test. + * + * @since 1.1.0 + */ +public interface SingleTestGenerator { + /** + * Creates contents of a single test class in which all test scenarios from + * the contract metadata should be placed. + * + * @param properties - properties passed to the plugin + * @param listOfFiles - list of parsed contracts with additional metadata + * @param className - the name of the generated test class + * @param classPackage - the name of the package in which the test class should be stored + * @param includedDirectoryRelativePath - relative path to the included directory + * @return contents of a single test class + * @deprecated use {@link SingleTestGenerator#buildClass(ContractVerifierConfigProperties, Collection, String, GeneratedClassData)} + */ + @Deprecated + String buildClass(ContractVerifierConfigProperties properties, + Collection listOfFiles, String className, String classPackage, String includedDirectoryRelativePath); + + /** + * Creates contents of a single test class in which all test scenarios from + * the contract metadata should be placed. + * + * @param properties - properties passed to the plugin + * @param listOfFiles - list of parsed contracts with additional metadata + * @param generatedClassData - information about the generated class + * @param includedDirectoryRelativePath - relative path to the included directory + * @return contents of a single test class + */ + default String buildClass(ContractVerifierConfigProperties properties, + Collection listOfFiles, String includedDirectoryRelativePath, GeneratedClassData generatedClassData) { + return buildClass(properties, listOfFiles, generatedClassData.className, generatedClassData.classPackage, includedDirectoryRelativePath); + } + + /** + * Extension that should be appended to the generated test class. E.g. {@code .java} or {@code .php} + * + * @param properties - properties passed to the plugin + */ + String fileExtension(ContractVerifierConfigProperties properties); + + class GeneratedClassData { + public final String className; + public final String classPackage; + public final java.nio.file.Path testClassPath; + + public GeneratedClassData(String className, String classPackage, + java.nio.file.Path testClassPath) { + this.className = className; + this.classPackage = classPackage; + this.testClassPath = testClassPath; + } + } +} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy index 1c2777587d..fd046101bb 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMessagingMethodBodyBuilder.groovy @@ -22,6 +22,7 @@ import groovy.transform.TypeChecked import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.internal.Cookie import org.springframework.cloud.contract.spec.internal.ExecutionProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Header import org.springframework.cloud.contract.spec.internal.Input import org.springframework.cloud.contract.spec.internal.NamedProperty @@ -41,8 +42,10 @@ import static org.apache.commons.text.StringEscapeUtils.escapeJava @TypeChecked class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { - SpockMessagingMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + SpockMessagingMethodBodyBuilder(Contract stubDefinition, + ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override @@ -160,6 +163,15 @@ class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { return "" } + @Override + protected String getResponseBodyPropertyComparisonString(String property, FromFileProperty value) { + if (value.isByte()) { + return "response.payloadAsByteArray == " + + readBytesFromFileString(value, CommunicationType.RESPONSE) + } + return getResponseBodyPropertyComparisonString(property, value.asString()) + } + @Override protected String getPropertyInListString(String property, Integer listIndex) { return "$property[$listIndex]" ?: '' @@ -184,7 +196,7 @@ class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { protected String getInputString() { String request = 'ContractVerifierMessage inputMessage = contractVerifierMessaging.create(' if (inputMessage.messageBody) { - request = "${request}'''${bodyAsString}'''\n " + request = "${request}${getBodyAsString()}\n " } if (inputMessage.messageHeaders) { request = "${request},[\n" @@ -200,6 +212,16 @@ class SpockMessagingMethodBodyBuilder extends MessagingMethodBodyBuilder { return "${request})" } + @Override + protected String indentBody(String text) { + return "\n ${text}\n" + } + + @Override + protected String quotes() { + return "'''" + } + @Override protected String getHeaderString(Header header) { return "${getTestSideValue(header.name)}: ${getTestSideValue(header.serverValue)}" diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMethodRequestProcessingBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMethodRequestProcessingBodyBuilder.groovy index 3cef2d4487..e904b2b59d 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMethodRequestProcessingBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/SpockMethodRequestProcessingBodyBuilder.groovy @@ -21,6 +21,7 @@ import groovy.transform.PackageScope import groovy.transform.TypeChecked import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.internal.Cookie +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Header import org.springframework.cloud.contract.spec.internal.NamedProperty import org.springframework.cloud.contract.spec.internal.Request @@ -45,8 +46,10 @@ import static org.springframework.cloud.contract.verifier.util.ContentUtils.getG @TypeChecked abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessingMethodBodyBuilder { - SpockMethodRequestProcessingBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + SpockMethodRequestProcessingBodyBuilder(Contract stubDefinition, + ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override @@ -104,6 +107,15 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing return "def responseBody = new XmlSlurper().parseText($responseString)" } + @Override + protected String getResponseBodyPropertyComparisonString(String property, FromFileProperty value) { + if (value.isByte()) { + return "response.body.asByteArray() == " + + readBytesFromFileString(value, CommunicationType.RESPONSE) + } + return getResponseBodyPropertyComparisonString(property, value.asString()) + } + @Override protected String getSimpleResponseBodyString(String responseString) { return "def responseBody = ($responseString)" @@ -134,6 +146,11 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing String value if (body instanceof ExecutionProperty) { value = body.toString() + } else if (body instanceof FromFileProperty) { + FromFileProperty fileProperty = (FromFileProperty) body + value = fileProperty.isByte() ? + readBytesFromFileString(fileProperty, CommunicationType.REQUEST) : + readStringFromFileString(fileProperty, CommunicationType.REQUEST) } else { value = "'''$body'''" } @@ -142,7 +159,7 @@ abstract class SpockMethodRequestProcessingBodyBuilder extends RequestProcessing @Override protected String getMultipartFileParameterContent(String propertyName, NamedProperty propertyValue) { - return getGroovyMultipartFileParameterContent(propertyName, propertyValue) + return getGroovyMultipartFileParameterContent(propertyName, propertyValue, { FromFileProperty fileProp -> readBytesFromFileString(fileProp, CommunicationType.REQUEST) }) } @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 index e66bff6ecd..0e0294e459 100644 --- 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 @@ -2,14 +2,13 @@ package org.springframework.cloud.contract.verifier.builder import groovy.json.JsonOutput import groovy.transform.CompileStatic -import groovy.transform.Immutable 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. @@ -100,6 +99,8 @@ class TestSideRequestTemplateModel { 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 } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/WebTestClientJUnitMethodBodyBuilder.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/WebTestClientJUnitMethodBodyBuilder.groovy index ff2e714ced..da3e871b5a 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/WebTestClientJUnitMethodBodyBuilder.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/WebTestClientJUnitMethodBodyBuilder.groovy @@ -17,8 +17,10 @@ import org.springframework.cloud.contract.verifier.config.ContractVerifierConfig @PackageScope class WebTestClientJUnitMethodBodyBuilder extends RestAssuredJUnitMethodBodyBuilder { - WebTestClientJUnitMethodBodyBuilder(Contract stubDefinition, ContractVerifierConfigProperties configProperties) { - super(stubDefinition, configProperties) + WebTestClientJUnitMethodBodyBuilder(Contract stubDefinition, + ContractVerifierConfigProperties configProperties, + GeneratedClassDataForMethod classDataForMethod) { + super(stubDefinition, configProperties, classDataForMethod) } @Override diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/imports/HttpImportProvider.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/imports/HttpImportProvider.groovy index 2a5002e592..acd6129c0e 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/imports/HttpImportProvider.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/imports/HttpImportProvider.groovy @@ -81,6 +81,6 @@ class HttpImportProvider { */ List getStaticImports(TestFramework testFramework, TestMode testMode) { return TEST_MODE_SPECIFIC_IMPORTS.get(testMode).staticImports + - FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.get(new Tuple2(testFramework, testMode)).staticImports + FRAMEWORK_AND_TEST_MODE_SPECIFIC_IMPORTS.get(new Tuple2(testFramework, testMode)).staticImports + ['org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes'] } } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/imports/MessagingImportProvider.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/imports/MessagingImportProvider.groovy index 49897b3f0a..b9c56b16e6 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/imports/MessagingImportProvider.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/builder/imports/MessagingImportProvider.groovy @@ -27,6 +27,6 @@ class MessagingImportProvider { * @return list of static imports for messaging test contracts. */ static List getStaticImports() { - return ['org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers'] + return ['org.springframework.cloud.contract.verifier.messaging.util.ContractVerifierMessagingUtil.headers','org.springframework.cloud.contract.verifier.util.ContractVerifierUtil.fileToBytes'] } } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.groovy index c215ef730d..03521ed7d4 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/config/ContractVerifierConfigProperties.groovy @@ -113,6 +113,11 @@ class ContractVerifierConfigProperties { */ File generatedTestSourcesDir + /** + * Test resource directory where additional resources for tests will be set + */ + File generatedTestResourcesDir + /** * Dir where the generated stubs from the contracts should be placed. * You can then mention them in your packaging task to create jar with stubs diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContract.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContract.groovy index c7206e6591..cdbaa232dc 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContract.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContract.groovy @@ -51,6 +51,7 @@ class YamlContract { public Map cookies = [:] public Object body public String bodyFromFile + public String bodyFromFileAsBytes public StubMatchers matchers = new StubMatchers() public Multipart multipart } @@ -215,6 +216,7 @@ class YamlContract { public Map cookies = [:] public Object body public String bodyFromFile + public String bodyFromFileAsBytes public TestMatchers matchers = new TestMatchers() public Boolean async public Integer fixedDelayMilliseconds @@ -238,6 +240,7 @@ class YamlContract { public Map messageHeaders = [:] public Object messageBody public String messageBodyFromFile + public String messageBodyFromFileAsBytes public String assertThat public StubMatchers matchers = new StubMatchers() } @@ -250,6 +253,7 @@ class YamlContract { public Map headers = [:] public Object body public String bodyFromFile + public String bodyFromFileAsBytes public String assertThat public TestMatchers matchers = new TestMatchers() } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlToContracts.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlToContracts.groovy index a4c236e0ba..da1058b494 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlToContracts.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlToContracts.groovy @@ -126,6 +126,7 @@ class YamlToContracts { } if (yamlContract.request.body != null) body(yamlContract.request.body) if (yamlContract.request.bodyFromFile != null) body(file(yamlContract.request.bodyFromFile)) + if (yamlContract.request.bodyFromFileAsBytes != null) body(fileAsBytes(yamlContract.request.bodyFromFileAsBytes)) if (yamlContract.request.multipart) { Map multipartMap = [:] Map multiPartParams = yamlContract.request @@ -249,6 +250,7 @@ class YamlToContracts { } } if (yamlContract.response.bodyFromFile) body(file(yamlContract.response.bodyFromFile)) + if (yamlContract.response.bodyFromFileAsBytes) body(fileAsBytes(yamlContract.response.bodyFromFileAsBytes)) if (yamlContract.response.async) async() if (yamlContract.response.fixedDelayMilliseconds) fixedDelayMilliseconds(yamlContract.response.fixedDelayMilliseconds) bodyMatchers { @@ -309,6 +311,7 @@ class YamlToContracts { } if (yamlContract.input.messageBody) messageBody(yamlContract.input.messageBody) if (yamlContract.input.messageBodyFromFile) messageBody(file(yamlContract.input.messageBodyFromFile)) + if (yamlContract.input.messageBodyFromFileAsBytes) messageBody(fileAsBytes(yamlContract.input.messageBodyFromFileAsBytes)) bodyMatchers { yamlContract.input.matchers.body?.each { YamlContract.BodyStubMatcher matcher -> MatchingTypeValue value = null @@ -354,6 +357,7 @@ class YamlToContracts { } if (outputMsg.body) body(outputMsg.body) if (outputMsg.bodyFromFile) body(file(outputMsg.bodyFromFile)) + if (outputMsg.bodyFromFileAsBytes) body(fileAsBytes(outputMsg.bodyFromFileAsBytes)) if (outputMsg.matchers) { bodyMatchers { yamlContract.outputMessage?.matchers?.body?.each { YamlContract.BodyTestMatcher testMatcher -> diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.groovy index a1e63c7455..fd70074d77 100755 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/BaseWireMockStubStrategy.groovy @@ -26,6 +26,7 @@ import org.json.JSONObject import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.ContractTemplate import org.springframework.cloud.contract.spec.internal.DslProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Headers import org.springframework.cloud.contract.verifier.template.HandlebarsTemplateProcessor import org.springframework.cloud.contract.verifier.template.TemplateProcessor @@ -34,8 +35,8 @@ import org.springframework.cloud.contract.verifier.util.ContentUtils import org.springframework.cloud.contract.verifier.util.MapConverter import static org.springframework.cloud.contract.verifier.util.ContentUtils.extractValue -import static org.springframework.cloud.contract.verifier.util.ContentUtils.getClientContentType import static org.springframework.cloud.contract.verifier.util.MapConverter.transformValues + /** * Common abstraction over WireMock Request / Response conversion implementations * @@ -85,6 +86,13 @@ abstract class BaseWireMockStubStrategy { return parseBody(value.toString(), contentType) } + /** + * Return body as String from file + */ + String parseBody(FromFileProperty value, ContentType contentType) { + return value.asString() + } + /** * For the given {@link ContentType} returns the Boolean version of the body */ diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.groovy index 1d38c822f5..514220c36f 100755 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockRequestStubStrategy.groovy @@ -16,8 +16,11 @@ package org.springframework.cloud.contract.verifier.dsl.wiremock +import java.util.regex.Pattern + import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.http.RequestMethod +import com.github.tomakehurst.wiremock.matching.ContentPattern import com.github.tomakehurst.wiremock.matching.RequestPattern import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder import com.github.tomakehurst.wiremock.matching.StringValuePattern @@ -33,19 +36,18 @@ import groovy.util.logging.Commons import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.internal.Body import org.springframework.cloud.contract.spec.internal.DslProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.MatchingStrategy import org.springframework.cloud.contract.spec.internal.NamedProperty import org.springframework.cloud.contract.spec.internal.OptionalProperty import org.springframework.cloud.contract.spec.internal.QueryParameters import org.springframework.cloud.contract.spec.internal.RegexPatterns import org.springframework.cloud.contract.spec.internal.Request -import org.springframework.cloud.contract.verifier.util.MapConverter import org.springframework.cloud.contract.verifier.util.ContentType import org.springframework.cloud.contract.verifier.util.ContentUtils import org.springframework.cloud.contract.verifier.util.JsonPaths import org.springframework.cloud.contract.verifier.util.JsonToJsonPathsConverter - -import java.util.regex.Pattern +import org.springframework.cloud.contract.verifier.util.MapConverter import static org.springframework.cloud.contract.verifier.util.RegexpBuilders.buildGStringRegexpForStubSide import static org.springframework.cloud.contract.verifier.util.RegexpBuilders.buildJSONRegexpMatch @@ -97,8 +99,9 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { if (!request.body) { return } + MatchingStrategy matchingStrategy = getMatchingStrategyFromBody(request.body) if (contentType == ContentType.JSON) { - def originalBody = getMatchingStrategyFromBody(request.body)?.clientValue + def originalBody = matchingStrategy?.clientValue def body = JsonToJsonPathsConverter.removeMatchingJsonPaths(originalBody, request.bodyMatchers) JsonPaths values = JsonToJsonPathsConverter.transformToJsonPathWithStubsSideValuesAndNoArraySizeCheck(body) if ((values.empty && !request.bodyMatchers?.hasMatchers()) || onlySizeAssertionsArePresent(values)) { @@ -117,14 +120,17 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { } else if (contentType == ContentType.XML) { requestPattern.withRequestBody(WireMock.equalToXml(getMatchingStrategy(request.body.clientValue).clientValue.toString())) } else if (containsPattern(request?.body)) { - MatchingStrategy matchingStrategy = appendBodyRegexpMatchPattern(request.body) - requestPattern.withRequestBody(convertToValuePattern(matchingStrategy, contentType)) + requestPattern.withRequestBody(convertToValuePattern(appendBodyRegexpMatchPattern(request.body), contentType)) } else { - requestPattern.withRequestBody(convertToValuePattern( - getMatchingStrategy(request.body.clientValue), contentType)) + requestBodyGuessedFromMatchingStrategy(requestPattern, contentType) } } + private RequestPatternBuilder requestBodyGuessedFromMatchingStrategy(RequestPatternBuilder requestPattern, ContentType contentType) { + return requestPattern.withRequestBody(convertToValuePattern( + getMatchingStrategy(request.body.clientValue), contentType)) + } + private boolean onlySizeAssertionsArePresent(JsonPaths values) { return !values.empty && !request.bodyMatchers?.hasMatchers() && values.every { it.assertsSize() } } @@ -152,7 +158,7 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { return } request.headers.entries.each { - requestPattern.withHeader(it.name, convertToValuePattern(it.clientValue, contentType)) + requestPattern.withHeader(it.name, (StringValuePattern) convertToValuePattern(it.clientValue, contentType)) } } @@ -161,7 +167,7 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { return } request.cookies.entries.each { - requestPattern.withCookie(it.key, convertToValuePattern(it.clientValue, contentType)) + requestPattern.withCookie(it.key, (StringValuePattern) convertToValuePattern(it.clientValue, contentType)) } } @@ -210,12 +216,12 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { private void appendQueryParameters(RequestPatternBuilder requestPattern, ContentType contentType) { QueryParameters queryParameters = request?.urlPath?.queryParameters ?: request?.url?.queryParameters queryParameters?.parameters?.each { - requestPattern.withQueryParam(it.name, convertToValuePattern(it.clientValue, contentType)) + requestPattern.withQueryParam(it.name, (StringValuePattern) convertToValuePattern(it.clientValue, contentType)) } } @TypeChecked(TypeCheckingMode.SKIP) - private static StringValuePattern convertToValuePattern(Object object, ContentType contentType) { + private static ContentPattern convertToValuePattern(Object object, ContentType contentType) { switch (object) { case Pattern: Pattern value = object as Pattern @@ -256,6 +262,8 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { StringEscapeUtils.unescapeJavaScript(it.toString()) }.join("&") } + } else if (bodyValue instanceof FromFileProperty) { + return bodyValue.isByte() ? bodyValue.asBytes() : bodyValue.asString() } return bodyValue } @@ -289,6 +297,10 @@ class WireMockRequestStubStrategy extends BaseWireMockStubStrategy { return tryToFindMachingStrategy(bodyValue) } + private MatchingStrategy getMatchingStrategy(FromFileProperty bodyValue) { + return new MatchingStrategy(bodyValue, MatchingStrategy.Type.BINARY_EQUAL_TO) + } + private MatchingStrategy tryToFindMachingStrategy(Object bodyValue) { return new MatchingStrategy(MapConverter.transformToClientValues(bodyValue), getEqualsTypeFromContentTypeHeader()) } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategy.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategy.groovy index 606d36a4fe..211fddd54d 100755 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategy.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockResponseStubStrategy.groovy @@ -25,10 +25,10 @@ import groovy.transform.PackageScope import groovy.transform.TypeChecked import org.springframework.cloud.contract.spec.Contract +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Request import org.springframework.cloud.contract.spec.internal.Response import org.springframework.cloud.contract.verifier.util.ContentType -import org.springframework.cloud.contract.verifier.util.ContentUtils import org.springframework.cloud.contract.verifier.util.MapConverter import org.springframework.core.io.support.SpringFactoriesLoader @@ -90,7 +90,11 @@ class WireMockResponseStubStrategy extends BaseWireMockStubStrategy { if (contentType == ContentType.UNKNOWN) { contentType = recognizeContentTypeFromContent(body) } - builder.withBody(parseBody(body, contentType)) + if (body instanceof FromFileProperty && body.isByte()) { + builder.withBody(body.asBytes()) + } else { + builder.withBody(parseBody(body, contentType)) + } } } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubStrategy.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubStrategy.groovy index a55941eae4..0a8f7e2377 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubStrategy.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/dsl/wiremock/WireMockStubStrategy.groovy @@ -16,21 +16,17 @@ package org.springframework.cloud.contract.verifier.dsl.wiremock -import groovy.transform.CompileDynamic -import groovy.transform.CompileStatic -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.file.ContractMetadata - import com.github.tomakehurst.wiremock.http.ResponseDefinition import com.github.tomakehurst.wiremock.matching.RequestPattern import com.github.tomakehurst.wiremock.stubbing.StubMapping +import org.springframework.cloud.contract.spec.Contract +import org.springframework.cloud.contract.verifier.file.ContractMetadata /** * Converts a {@link ContractMetadata} into a WireMock stub * * @since 1.0.0 */ -@CompileStatic class WireMockStubStrategy { private static final String STEP_START = "Started" @@ -54,7 +50,6 @@ class WireMockStubStrategy { /** * Converts {@link ContractMetadata} to String version of {@link StubMapping} */ - @CompileDynamic String toWireMockClientStub() { StubMapping stubMapping = new StubMapping() diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/template/HandlebarsTemplateProcessor.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/template/HandlebarsTemplateProcessor.groovy index f7c0192526..a0aa7006d6 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/template/HandlebarsTemplateProcessor.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/template/HandlebarsTemplateProcessor.groovy @@ -32,8 +32,7 @@ class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate private static final String LEGACY_JSON_PATH_TEMPLATE_NAME = HandlebarsJsonPathHelper.NAME private static final String JSON_PATH_TEMPLATE_NAME = WireMockHelpers.jsonPath.name() - @Delegate - private final ContractTemplate contractTemplate = new CompositeContractTemplate() + final ContractTemplate contractTemplate = new CompositeContractTemplate() @Override String transform(Request request, String testContents) { @@ -98,5 +97,135 @@ class HandlebarsTemplateProcessor implements TemplateProcessor, ContractTemplate throw new RuntimeException(e) } } + + @Override + boolean startsWithTemplate(String text) { + return this.contractTemplate.startsWithTemplate(text) + } + + @Override + boolean startsWithEscapedTemplate(String text) { + return this.contractTemplate.startsWithEscapedTemplate(text) + } + + @Override + String openingTemplate() { + return this.contractTemplate.openingTemplate() + } + + @Override + String closingTemplate() { + return this.contractTemplate.closingTemplate() + } + + @Override + String escapedOpeningTemplate() { + return this.contractTemplate.escapedOpeningTemplate() + } + + @Override + String escapedClosingTemplate() { + return this.contractTemplate.escapedClosingTemplate() + } + + @Override + String url() { + return this.contractTemplate.url() + } + + @Override + String query(String key) { + return this.contractTemplate.query(key) + } + + @Override + String query(String key, int index) { + return this.contractTemplate.query(key, index) + } + + @Override + String path() { + return this.contractTemplate.path() + } + + @Override + String path(int index) { + return this.contractTemplate.path(index) + } + + @Override + String header(String key) { + return this.contractTemplate.header(key) + } + + @Override + String header(String key, int index) { + return this.contractTemplate.header(key, index) + } + + @Override + String cookie(String key) { + return this.contractTemplate.cookie(key) + } + + @Override + String body() { + return this.contractTemplate.body() + } + + @Override + String body(String jsonPath) { + return this.contractTemplate.body(jsonPath) + } + + @Override + String escapedUrl() { + return this.contractTemplate.escapedUrl() + } + + @Override + String escapedQuery(String key) { + return this.contractTemplate.escapedQuery(key) + } + + @Override + String escapedQuery(String key, int index) { + return this.contractTemplate.escapedQuery(key, index) + } + + @Override + String escapedPath() { + return this.contractTemplate.escapedPath() + } + + @Override + String escapedPath(int index) { + return this.contractTemplate.escapedPath(index) + } + + @Override + String escapedHeader(String key) { + return this.contractTemplate.escapedHeader(key) + } + + @Override + String escapedHeader(String key, int index) { + return this.contractTemplate.escapedHeader(key, index) + } + + @Override + String escapedCookie(String key) { + return this.contractTemplate.escapedCookie(key) + } + + @Override + String escapedBody() { + return this.contractTemplate.escapedBody() + } + + @Override + String escapedBody(String jsonPath) { + return this.contractTemplate.escapedBody(jsonPath) + } } diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentType.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentType.groovy index 77684f2b92..80225b01b8 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentType.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContentType.groovy @@ -15,7 +15,6 @@ */ package org.springframework.cloud.contract.verifier.util - /** * Represents content type. Used to pick the way bodies are parsed. * @@ -34,5 +33,4 @@ enum ContentType { ContentType(String mimeType) { this.mimeType = mimeType } - } \ No newline at end of file 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 e0a5a7fb8f..bcede3d4ad 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 @@ -16,38 +16,40 @@ package org.springframework.cloud.contract.verifier.util +import java.util.regex.Matcher +import java.util.regex.Pattern + import groovy.json.JsonException import groovy.json.JsonOutput import groovy.json.JsonSlurper -import groovy.transform.TypeChecked -import groovy.util.logging.Commons -import org.apache.commons.lang3.StringEscapeUtils +import groovy.transform.CompileStatic +import org.apache.commons.logging.Log +import org.apache.commons.logging.LogFactory import org.codehaus.groovy.runtime.GStringImpl + import org.springframework.cloud.contract.spec.internal.DslProperty import org.springframework.cloud.contract.spec.internal.ExecutionProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.Header import org.springframework.cloud.contract.spec.internal.Headers import org.springframework.cloud.contract.spec.internal.MatchingStrategy import org.springframework.cloud.contract.spec.internal.NamedProperty import org.springframework.cloud.contract.spec.internal.OptionalProperty -import java.util.regex.Matcher -import java.util.regex.Pattern - import static org.apache.commons.text.StringEscapeUtils.escapeJava import static org.apache.commons.text.StringEscapeUtils.escapeJson import static org.apache.commons.text.StringEscapeUtils.escapeXml11 import static org.apache.commons.text.StringEscapeUtils.unescapeXml - /** * A utility class that can operate on a message body basing on the provided Content Type. * * @since 1.0.0 */ -@TypeChecked -@Commons +@CompileStatic class ContentUtils { + private static final Log log = LogFactory.getLog(ContentUtils) + public static final Closure GET_STUB_SIDE = { it instanceof DslProperty ? it.clientValue : it } @@ -134,9 +136,44 @@ class ContentUtils { } static ContentType getClientContentType(Object bodyAsValue) { + if (bodyAsValue instanceof GString) { + return getClientContentType((GString) bodyAsValue) + } else if (bodyAsValue instanceof String) { + return getClientContentType((String) bodyAsValue) + } else if (bodyAsValue instanceof Map) { + return getClientContentType((Map) bodyAsValue) + } else if (bodyAsValue instanceof List) { + return getClientContentType((List) bodyAsValue) + } else if (bodyAsValue instanceof MatchingStrategy) { + return ContentType.UNKNOWN + } else if (bodyAsValue instanceof FromFileProperty) { + return ContentType.UNKNOWN + } + return tryToGuessContentType(bodyAsValue) + } + + private static ContentType tryToGuessContentType(Object bodyAsValue) { + try { + if (log.isDebugEnabled()) { + log.debug("No content type passed, will try to guess the type of payload") + } + return getClientContentType(JsonOutput.toJson(bodyAsValue)) + } catch (Exception ex) { + if (log.isTraceEnabled()) { + log.trace("Failed to assume that body [" + bodyAsValue + "] is json") + } + } return ContentType.UNKNOWN } + static ContentType getClientContentType(Object bodyAsValue, Headers headers) { + ContentType contentType = recognizeContentTypeFromHeader(headers) + if (contentType == ContentType.UNKNOWN) { + return getClientContentType(bodyAsValue) + } + return contentType; + } + static ContentType getClientContentType(Map bodyAsValue) { try { JsonOutput.toJson(bodyAsValue) @@ -194,6 +231,15 @@ class ContentUtils { } protected static Object transformJSONStringValue(Object obj, Closure valueProvider) { + if (obj instanceof DslProperty) { + return transformJSONStringValue((DslProperty) obj, valueProvider) + } else if (obj instanceof Pattern) { + return transformJSONStringValue((Pattern) obj, valueProvider) + } else if (obj instanceof OptionalProperty) { + return transformJSONStringValue((OptionalProperty) obj, valueProvider) + } else if (obj instanceof ExecutionProperty) { + return transformJSONStringValue((ExecutionProperty) obj, valueProvider) + } return obj } @@ -214,6 +260,9 @@ class ContentUtils { } private static String transformXMLStringValue(Object obj, Closure valueProvider) { + if (obj instanceof DslProperty) { + return transformJSONStringValue((DslProperty) obj, valueProvider) + } return escapeXml11(unescapeXml(obj.toString())) } @@ -288,7 +337,8 @@ class ContentUtils { } static ContentType recognizeContentTypeFromHeader(Headers headers, Closure closure) { - Header header = headers?.entries?.find { it.name == "Content-Type" } + Header header = headers?.entries?.find { it.name == "Content-Type" || + it.name == "contentType" } String content = closure(header)?.toString() if (content?.contains("json")) { return ContentType.JSON @@ -337,6 +387,10 @@ class ContentUtils { return ContentType.JSON } + static ContentType recognizeContentTypeFromContent(byte[] bytes) { + return ContentType.UNKNOWN + } + static ContentType recognizeContentTypeFromContent(List jsonList) { return ContentType.JSON } @@ -354,7 +408,20 @@ class ContentUtils { return ContentType.TEXT } - static ContentType recognizeContentTypeFromContent(Object gstring) { + static ContentType recognizeContentTypeFromContent(Object object) { + if (object instanceof GString) { + return recognizeContentTypeFromContent((GString) object) + } else if (object instanceof Map) { + return recognizeContentTypeFromContent((Map) object) + } else if (object instanceof byte[]) { + return recognizeContentTypeFromContent((byte[]) object) + } else if (object instanceof List) { + return recognizeContentTypeFromContent((List) object) + } else if (object instanceof String) { + return recognizeContentTypeFromContent((String) object) + } else if (object instanceof Number) { + return recognizeContentTypeFromContent((Number) object) + } return ContentType.UNKNOWN } @@ -403,14 +470,16 @@ class ContentUtils { return ContentType.UNKNOWN } - static String getGroovyMultipartFileParameterContent(String propertyName, NamedProperty propertyValue) { + static String getGroovyMultipartFileParameterContent(String propertyName, NamedProperty propertyValue, + Closure bytesFromFile) { return "'$propertyName', ${namedPropertyName(propertyValue, "'")}, " + - "${groovyNamedPropertyValue(propertyValue, "'")}" + namedContentTypeNameIfPresent(propertyValue, "'") + "${groovyNamedPropertyValue(propertyValue, "'", bytesFromFile)}" + namedContentTypeNameIfPresent(propertyValue, "'") } - static String getJavaMultipartFileParameterContent(String propertyName, NamedProperty propertyValue) { + static String getJavaMultipartFileParameterContent(String propertyName, NamedProperty propertyValue, + Closure bytesFromFile) { return """"${escapeJava(propertyName)}", ${namedPropertyName(propertyValue, '"')}, """ + - """${javaNamedPropertyValue(propertyValue, '"')}${namedContentTypeNameIfPresent(propertyValue, '"')}""" + """${javaNamedPropertyValue(propertyValue, '"', bytesFromFile)}${namedContentTypeNameIfPresent(propertyValue, '"')}""" } static String namedPropertyName(NamedProperty property, String quote) { @@ -427,22 +496,34 @@ class ContentUtils { return ", " + contentType } - static String groovyNamedPropertyValue(NamedProperty property, String quote) { + static String groovyNamedPropertyValue(NamedProperty property, String quote, Closure bytesFromFile) { if (property.value.serverValue instanceof ExecutionProperty) { return property.value.serverValue.toString() } else if (property.value.serverValue instanceof byte[]) { byte[] bytes = (byte[]) property.value.serverValue return "[" + bytes.collect { it }.join(", ") + "] as byte[]" + } else if (property.value.serverValue instanceof FromFileProperty) { + FromFileProperty fromFileProperty = (FromFileProperty) property.value.serverValue + if (fromFileProperty.isByte()) { + return bytesFromFile(fromFileProperty) + } + return "[" + fromFileProperty.asBytes().collect { it }.join(", ") + "] as byte[]" } return quote + escapeJava(property.value.serverValue.toString()) + quote + ".bytes" } - static String javaNamedPropertyValue(NamedProperty property, String quote) { + static String javaNamedPropertyValue(NamedProperty property, String quote, Closure bytesFromFile) { if (property.value.serverValue instanceof ExecutionProperty) { return property.value.serverValue.toString() } else if (property.value.serverValue instanceof byte[]) { byte[] bytes = (byte[]) property.value.serverValue return "new byte[] {" + bytes.collect { it }.join(", ") + "}" + } else if (property.value.serverValue instanceof FromFileProperty) { + FromFileProperty fromFileProperty = (FromFileProperty) property.value.serverValue + if (fromFileProperty.isByte()) { + return bytesFromFile(fromFileProperty) + } + return "new byte[] {" + fromFileProperty.asBytes().collect { it }.join(", ") + "}" } return quote + escapeJava(property.value.serverValue.toString()) + quote + ".getBytes()" } diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessage.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessage.java index d475a255f0..ce00e1248c 100644 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessage.java +++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierMessage.java @@ -50,6 +50,13 @@ public class ContractVerifierMessage { this.payload = payload; } + public byte[] getPayloadAsByteArray() { + if (this.payload instanceof byte[]) { + return (byte[]) this.payload; + } + throw new IllegalStateException("Payload [" + this.payload.getClass() + "]" + "is not instance of byte[]"); + } + public Map getHeaders() { return this.headers; } diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapper.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapper.java index 291af46791..f04ab0fbff 100644 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapper.java +++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapper.java @@ -47,4 +47,12 @@ public class ContractVerifierObjectMapper { return this.objectMapper.writeValueAsString(payload); } + public byte[] writeValueAsBytes(Object payload) throws JsonProcessingException { + if (payload instanceof String) { + return payload.toString().getBytes(); + } else if (payload instanceof byte[]) { + return (byte[]) payload; + } + return this.objectMapper.writeValueAsBytes(payload); + } } diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtil.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtil.java new file mode 100644 index 0000000000..c2480b254e --- /dev/null +++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/ContractVerifierUtil.java @@ -0,0 +1,55 @@ +/* + * Copyright 2013-2018 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 + * + * http://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.util; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * Helper class for the generated tests + * + * @author Marcin Grzejszczak + * @since 2.1.0 + */ +public class ContractVerifierUtil { + + /** + * Helper method to convert a file to bytes + * + * @param testClass - test class relative to which the file is stored + * @param relativePath - relative path to the file + * @return bytes of the file + */ + public static byte[] fileToBytes(Object testClass, String relativePath) { + try { + URL url = testClass.getClass().getResource(relativePath); + if (url == null) { + throw new FileNotFoundException(relativePath); + } + return Files.readAllBytes(Paths.get(url.toURI())); + } + catch (IOException | URISyntaxException ex) { + throw new IllegalStateException(ex); + } + } + +} diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/GeneratorScannerSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/GeneratorScannerSpec.groovy index 99c5967c3c..a5d185a206 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/GeneratorScannerSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/GeneratorScannerSpec.groovy @@ -19,6 +19,7 @@ package org.springframework.cloud.contract.verifier import spock.lang.Specification import org.springframework.cloud.contract.verifier.builder.JavaTestGenerator +import org.springframework.cloud.contract.verifier.builder.SingleTestGenerator import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK @@ -36,7 +37,7 @@ class GeneratorScannerSpec extends Specification { when: testGenerator.generateTestClasses("org.springframework.cloud.contract.verifier") then: - 6 * classGenerator.buildClass(_, _, _, _, _) >> "qwerty" + 6 * classGenerator.buildClass(_, _, _, _) >> "qwerty" } def "should create class with full package"() { @@ -47,9 +48,9 @@ class GeneratorScannerSpec extends Specification { when: testGenerator.generateTestClasses("org.springframework.cloud.contract.verifier") then: - 1 * classGenerator.buildClass(_, _, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier', _) >> "spec" - 1 * classGenerator.buildClass(_, _, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier.v1', _) >> "spec1" - 1 * classGenerator.buildClass(_, _, 'exceptionsSpec', 'org.springframework.cloud.contract.verifier.v2', _) >> "spec2" + 1 * classGenerator.buildClass(_, _, _, { SingleTestGenerator.GeneratedClassData it -> it.className == 'exceptionsSpec' && it.classPackage == 'org.springframework.cloud.contract.verifier'} ) >> "spec" + 1 * classGenerator.buildClass(_, _, _, { SingleTestGenerator.GeneratedClassData it -> it.className == 'exceptionsSpec' && it.classPackage == 'org.springframework.cloud.contract.verifier.v1'} ) >> "spec1" + 1 * classGenerator.buildClass(_, _, _, { SingleTestGenerator.GeneratedClassData it -> it.className == 'exceptionsSpec' && it.classPackage == 'org.springframework.cloud.contract.verifier.v2'} ) >> "spec2" } } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy index f2e55f0d39..07493ae333 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/ContractHttpDocsSpec.groovy @@ -16,10 +16,11 @@ package org.springframework.cloud.contract.verifier.builder -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties import spock.lang.Shared import spock.lang.Specification +import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties + /** * Tests used for the documentation * @@ -303,7 +304,9 @@ class ContractHttpDocsSpec extends Specification { def 'should convert dsl with optionals to proper Spock test'() { given: BlockBuilder blockBuilder = new BlockBuilder(" ") - new HttpSpockMethodRequestProcessingBodyBuilder(optionals, properties).appendTo(blockBuilder) + new HttpSpockMethodRequestProcessingBodyBuilder(optionals, properties, new GeneratedClassDataForMethod( + new SingleTestGenerator.GeneratedClassData("foo", "bar", new File(".").toPath()), "method")) + .appendTo(blockBuilder) expect: String expectedTest = // tag::optionals_test[] diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy index 30e57fa29a..708c0ec7cf 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/JaxRsClientMethodBuilderSpec.groovy @@ -33,7 +33,9 @@ import spock.util.environment.RestoreSystemProperties class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStubVerifier { @Shared ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(assertJsonSize: true) - + @Shared GeneratedClassDataForMethod generatedClassDataForMethod = new GeneratedClassDataForMethod( + new SingleTestGenerator.GeneratedClassData("foo", "bar", new File(".").toPath()), "method") + @Shared // tag::contract_with_cookies[] Contract contractDslWithCookiesValue = Contract.make { @@ -127,8 +129,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } @Issue("#187") @@ -162,8 +164,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } @Issue("#79") @@ -199,8 +201,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } @Issue("#79") @@ -239,8 +241,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } @Issue("#82") @@ -270,8 +272,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyString - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | """entity('{\"items\":[\"HOP\"]}', 'application/json')""" - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | 'entity("{\\"items\\":[\\"HOP\\"]}", "application/json")' + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | """entity('{\"items\":[\"HOP\"]}', 'application/json')""" + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'entity("{\\"items\\":[\\"HOP\\"]}", "application/json")' } @Issue("#88") @@ -301,8 +303,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyString - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | """entity('property1=VAL1', 'application/octet-stream')""" - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | 'entity("property1=VAL1", "application/octet-stream")' + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | """entity('property1=VAL1', 'application/octet-stream')""" + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'entity("property1=VAL1", "application/octet-stream")' } def "should generate assertions for array in response body with #methodBuilderName"() { @@ -336,8 +338,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } def "should generate assertions for array inside response body element with #methodBuilderName"() { @@ -370,8 +372,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } def "should generate assertions for nested objects in response body with #methodBuilderName"() { @@ -404,8 +406,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } def "should generate regex assertions for map objects in response body with #methodBodyName"() { @@ -443,8 +445,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } def "should generate regex assertions for string objects in response body with #methodBuilderName"() { @@ -475,8 +477,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } def "should ignore 'Accept' header and use 'request' method with #methodBuilderName"() { @@ -505,8 +507,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | requestString - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | "request('text/plain')" - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | 'request("text/plain")' + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | "request('text/plain')" + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'request("text/plain")' } def "should ignore 'Content-Type' header and use 'entity' method with #methodBuilderName"() { @@ -540,8 +542,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | requestStrings - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ["""entity('', 'text/plain')""", """header('Timer', '123')"""] - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | ['entity("\\"\\"", "text/plain")', 'header("Timer", "123")'] + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ["""entity('', 'text/plain')""", """header('Timer', '123')"""] + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['entity("\\"\\"", "text/plain")', 'header("Timer", "123")'] } def "should generate a call with an url path and query parameters with #methodBuilderName"() { @@ -596,8 +598,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | modifyStringIfRequired - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String paramString -> paramString } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { String paramString -> paramString.replace("'", "\"") } + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String paramString -> paramString } + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String paramString -> paramString.replace("'", "\"") } } @Issue('#169') @@ -653,8 +655,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | modifyStringIfRequired - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String paramString -> paramString } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { String paramString -> paramString.replace("'", "\"") } + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String paramString -> paramString } + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String paramString -> paramString.replace("'", "\"") } } def "should generate test for empty body with #methodBuilderName"() { @@ -683,8 +685,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyString - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | "entity('', 'application/octet-stream')" - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | 'entity("", "application/octet-stream"' + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | "entity('', 'application/octet-stream')" + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'entity("", "application/octet-stream"' } def "should not parse the response body if there is no response body specified in the contract"() { @@ -711,8 +713,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyParsingString - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | "String responseAsString = response.readEntity(String)" - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | "String responseAsString = response.readEntity(String.class);" + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | "String responseAsString = response.readEntity(String)" + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | "String responseAsString = response.readEntity(String.class);" } def "should generate test for String in response body with #methodBodyName"() { @@ -741,8 +743,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyDefinitionString | bodyEvaluationString - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | "String responseAsString = response.readEntity(String)" | 'responseBody == "test"' - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | 'String responseBody = responseAsString;' | 'assertThat(responseBody).isEqualTo("test");' + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | "String responseAsString = response.readEntity(String)" | 'responseBody == "test"' + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'String responseBody = responseAsString;' | 'assertThat(responseBody).isEqualTo("test");' } @Issue('#171') @@ -776,8 +778,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | methodString - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ".method('GET')" - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | 'method("GET")' + "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ".method('GET')" + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'method("GET")' } def "should generate a call with an url path and query parameters with JUnit - we'll put it into docs"() { @@ -809,7 +811,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub """ } } - MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -866,7 +868,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub ]) } } - MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -909,7 +911,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub ]) } } - MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -942,7 +944,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub ]) } } - MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.then(blockBuilder) @@ -966,7 +968,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub body(value(stub("HELLO FROM STUB"), server(regex(".*")))) } } - MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -991,7 +993,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub body(value(stub("HELLO FROM STUB"), server(regex(".*")))) } } - MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1016,7 +1018,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub body(value(stub("HELLO FROM STUB"), server(execute('foo($it)')))) } } - MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1039,7 +1041,7 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub body(value(stub("HELLO FROM STUB"), server(execute('foo($it)')))) } } - MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1086,8 +1088,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } @Issue('#149') @@ -1189,8 +1191,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToRun(methodBuilderName, lines.join("\n")) where: methodBuilderName | methodBuilder | endOfLineRegexSymbol - "JaxRsClientSpockMethodRequestProcessingBodyBuilder"| { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | '$' + "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) } | '$' } private String stripped(String string) { @@ -1231,8 +1233,8 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientSpockMethodRequestProcessingBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "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) } } @Issue('#261') @@ -1272,7 +1274,7 @@ DATA SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#261') @@ -1305,12 +1307,12 @@ DATA SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } + "JaxRsClientJUnitMethodBodyBuilder" | { org.springframework.cloud.contract.spec.Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def "should generate test for cookies with string value in JAX-RS JUnit test"() { given: - MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDslWithCookiesValue, properties) + MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDslWithCookiesValue, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1325,7 +1327,7 @@ DATA def "should generate test for cookies with pattern in JAX-RS JUnit test"() { given: - MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDslWithCookiesPattern, properties) + MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDslWithCookiesPattern, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1340,7 +1342,7 @@ DATA def "should not generate cookie assertions with absent value in JAX-RS JUnit test"() { given: - MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDslWithAbsentCookies, properties) + MethodBodyBuilder builder = new JaxRsClientJUnitMethodBodyBuilder(contractDslWithAbsentCookies, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1353,7 +1355,7 @@ DATA def "should generate test for cookies with string value in JAX-RS Spock test"() { given: - MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDslWithCookiesValue, properties) + MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDslWithCookiesValue, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1368,7 +1370,7 @@ DATA def "should generate test for cookies with pattern in JAX-RS Spock test"() { given: - MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDslWithCookiesPattern, properties) + MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDslWithCookiesPattern, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1383,7 +1385,7 @@ DATA def "should not generate cookie assertions with absent value in JAX-RS Spock test"() { given: - MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDslWithAbsentCookies, properties) + MethodBodyBuilder builder = new JaxRsClientSpockMethodRequestProcessingBodyBuilder(contractDslWithAbsentCookies, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy index 91f515947a..204dfe0c3a 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MessagingMethodBodyBuilderSpec.groovy @@ -28,7 +28,10 @@ import spock.lang.Specification */ class MessagingMethodBodyBuilderSpec extends Specification { - @Shared ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(assertJsonSize: true) + @Shared ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(assertJsonSize: true, generatedTestSourcesDir: new File("."), + generatedTestResourcesDir: new File(".")) + @Shared GeneratedClassDataForMethod generatedClassDataForMethod = new GeneratedClassDataForMethod( + new SingleTestGenerator.GeneratedClassData("foo", "bar", new File("target/test.java").toPath()), "method") def "should work for triggered based messaging with Spock"() { given: @@ -48,7 +51,7 @@ def contractDsl = Contract.make { } } // end::trigger_method_dsl[] - MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -90,7 +93,7 @@ def contractDsl = Contract.make { } } } - MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -142,7 +145,7 @@ def contractDsl = Contract.make { } } // end::trigger_message_dsl[] - MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -195,7 +198,7 @@ and: } } } - MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -243,7 +246,7 @@ def contractDsl = Contract.make { } } // end::trigger_no_output_dsl[] - MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -284,7 +287,7 @@ then: assertThat('bookWasDeleted()') } } - MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -329,7 +332,7 @@ then: ]) } } - MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -378,7 +381,7 @@ then: ]) } } - MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -431,7 +434,7 @@ Contract.make { } } // end::consumer_producer[] - MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -478,7 +481,7 @@ Contract.make { ]) } } - MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -522,7 +525,7 @@ Contract.make { ]) } } - MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -614,8 +617,8 @@ Contract.make { (error.message ? error.message : error.cause.message).contains('''doesn't match the JSON path [$[?(@.['shouldFail'] =~ ''') where: methodBuilderName | methodBuilder | endOfLineRegExSymbol - "SpockMessagingMethodBodyBuilder" | { Contract dsl -> new SpockMessagingMethodBodyBuilder(dsl, properties) } | '\\$' - "JUnitMessagingMethodBodyBuilder" | { Contract dsl -> new JUnitMessagingMethodBodyBuilder(dsl, properties) } | '$' + "SpockMessagingMethodBodyBuilder" | { Contract dsl -> new SpockMessagingMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + "JUnitMessagingMethodBodyBuilder" | { Contract dsl -> new JUnitMessagingMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' } @Issue("587") @@ -639,7 +642,7 @@ Contract.make { ]) } } - MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -674,7 +677,7 @@ Contract.make { ]) } } - MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -717,7 +720,7 @@ Contract.make { ]) } } - MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -760,7 +763,7 @@ Contract.make { ]) } } - MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new SpockMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -803,7 +806,7 @@ Contract.make { ]) } } - MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new JUnitMessagingMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -860,7 +863,7 @@ Contract.make { test == expectedTest where: methodBuilderName | methodBuilder | expectedTest - "SpockMessagingMethodBodyBuilder" | { Contract dsl -> new SpockMessagingMethodBodyBuilder(dsl, properties) } | ''' when: + "SpockMessagingMethodBodyBuilder" | { Contract dsl -> new SpockMessagingMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ''' when: foo() then: @@ -871,7 +874,7 @@ Contract.make { DocumentContext parsedJson = JsonPath.parse(contractVerifierObjectMapper.writeValueAsString(response.payload)) assertThatJson(parsedJson).field("['field']").isEqualTo("value") ''' - "JUnitMessagingMethodBodyBuilder" | { Contract dsl -> new JUnitMessagingMethodBodyBuilder(dsl, properties) } | ''' // when: + "JUnitMessagingMethodBodyBuilder" | { Contract dsl -> new JUnitMessagingMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ''' // when: foo(); // then: @@ -885,4 +888,72 @@ Contract.make { ''' } + @Issue('#664') + def "should generate tests for messages having binary payloads [#methodBuilderName]"() { + given: + Contract contractDsl = Contract.make { + label 'shouldPublishMessage' + input { + messageFrom("foo") + messageBody(fileAsBytes("body_builder/request.pdf")) + messageHeaders { + messagingContentType(applicationOctetStream()) + } + } + outputMessage { + sentTo('messageExchange') + body(fileAsBytes("body_builder/response.pdf")) + headers { + messagingContentType(applicationOctetStream()) + } + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def test = blockBuilder.toString() + then: + !test.contains('cursor') + !test.contains('REGEXP>>') + test == expectedTest + where: + methodBuilderName | methodBuilder | expectedTest + "SpockMessagingMethodBodyBuilder" | { Contract dsl -> new SpockMessagingMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ''' given: + ContractVerifierMessage inputMessage = contractVerifierMessaging.create( + fileToBytes(this, "method_request_request.pdf") + + ,[ + "contentType": "application/octet-stream" + ]) + + when: + contractVerifierMessaging.send(inputMessage, 'foo') + + then: + ContractVerifierMessage response = contractVerifierMessaging.receive('messageExchange') + assert response != null + response.getHeader('contentType')?.toString() == 'application/octet-stream\' + and: + response.payloadAsByteArray == fileToBytes(this, "method_response_response.pdf") +''' + "JUnitMessagingMethodBodyBuilder" | { Contract dsl -> new JUnitMessagingMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ''' // given: + ContractVerifierMessage inputMessage = contractVerifierMessaging.create( +\t\t\t\tfileToBytes(this, "method_request_request.pdf") +\t\t\t\t, headers() +\t\t\t\t\t\t.header("contentType", "application/octet-stream") +\t\t\t); + + // when: + contractVerifierMessaging.send(inputMessage, "foo"); + + // then: + ContractVerifierMessage response = contractVerifierMessaging.receive("messageExchange"); + assertThat(response).isNotNull(); + assertThat(response.getHeader("contentType")).isNotNull(); + assertThat(response.getHeader("contentType").toString()).isEqualTo("application/octet-stream"); + // and: + assertThat(response.getPayloadAsByteArray()).isEqualTo(fileToBytes(this, "method_response_response.pdf")); +''' + } } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy index fd2b37d0bd..b1603e15a0 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MethodBodyBuilderSpec.groovy @@ -16,552 +16,563 @@ package org.springframework.cloud.contract.verifier.builder +import java.lang.reflect.InvocationTargetException + import org.junit.Rule -import org.springframework.boot.test.rule.OutputCapture -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties -import org.springframework.cloud.contract.verifier.dsl.WireMockStubVerifier -import org.springframework.cloud.contract.verifier.util.SyntaxChecker import spock.lang.Issue import spock.lang.Shared import spock.lang.Specification -import java.lang.reflect.InvocationTargetException +import org.springframework.boot.test.rule.OutputCapture +import org.springframework.cloud.contract.spec.Contract +import org.springframework.cloud.contract.verifier.config.ContractVerifierConfigProperties +import org.springframework.cloud.contract.verifier.dsl.WireMockStubVerifier +import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter +import org.springframework.cloud.contract.verifier.util.SyntaxChecker class MethodBodyBuilderSpec extends Specification implements WireMockStubVerifier { - @Rule - OutputCapture capture = new OutputCapture() + @Rule + OutputCapture capture = new OutputCapture() - @Shared - ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( - assertJsonSize: true - ) + @Shared GeneratedClassDataForMethod classDataForMethod = new GeneratedClassDataForMethod( + new SingleTestGenerator.GeneratedClassData("ClassName", "com.example", + new File("target/test.java").toPath()), + "some_method" + ) - @Issue('#251') - def 'should work with execute and arrays [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/foo' - headers { - accept(applicationJson()) - contentType(applicationJson()) - } - } - response { - status OK() - body([ - myArray: [ - [ - notABugGeneratedHere : $(c('foo'), p(execute('assertThat((String)$it).isEqualTo("foo")'))), - anotherArrayNeededForBug : [ - [ - optionalNotEmpty: $(c('foo'), p(execute('assertThat((String)$it).isEqualTo("12")'))) - ] - ], - yetAnotherArrayNeededForBug: [ - [ - optionalNotEmpty: $(c('foo'), p(execute('assertThat((String)$it).isEqualTo("22")'))) - ] - ] - ], - [ - anotherArrayNeededForBug2: [ - [ - optionalNotEmpty: $(c('foo'), p(execute('assertThat((String)$it).isEqualTo("122")'))) - ] - ] - ], - ] - ]) - headers { - contentType(applicationJson()) - } - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - def test = blockBuilder.toString() - then: - test.contains('$.myArray.[0].anotherArrayNeededForBug.[0].optionalNotEmpty') - !test.contains('cursor') - !test.contains('REGEXP>>') - and: - SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) - and: - String jsonSample = '''\ + @Shared + ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( + assertJsonSize: true, generatedTestSourcesDir: new File("."), + generatedTestResourcesDir: new File(".") + ) + + @Issue('#251') + def 'should work with execute and arrays [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method 'GET' + urlPath '/foo' + headers { + accept(applicationJson()) + contentType(applicationJson()) + } + } + response { + status OK() + body([ + myArray: [ + [ + notABugGeneratedHere : $(c('foo'), p(execute('assertThat((String)$it).isEqualTo("foo")'))), + anotherArrayNeededForBug : [ + [ + optionalNotEmpty: $(c('foo'), p(execute('assertThat((String)$it).isEqualTo("12")'))) + ] + ], + yetAnotherArrayNeededForBug: [ + [ + optionalNotEmpty: $(c('foo'), p(execute('assertThat((String)$it).isEqualTo("22")'))) + ] + ] + ], + [ + anotherArrayNeededForBug2: [ + [ + optionalNotEmpty: $(c('foo'), p(execute('assertThat((String)$it).isEqualTo("122")'))) + ] + ] + ], + ] + ]) + headers { + contentType(applicationJson()) + } + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def test = blockBuilder.toString() + then: + test.contains('$.myArray.[0].anotherArrayNeededForBug.[0].optionalNotEmpty') + !test.contains('cursor') + !test.contains('REGEXP>>') + and: + SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) + and: + String jsonSample = '''\ String json = "{\\"myArray\\":[{\\"notABugGeneratedHere\\":\\"foo\\",\\"anotherArrayNeededForBug\\":[{\\"optionalNotEmpty\\":\\"12\\"}],\\"yetAnotherArrayNeededForBug\\":[{\\"optionalNotEmpty\\":\\"22\\"}]},{\\"anotherArrayNeededForBug2\\":[{\\"optionalNotEmpty\\":\\"122\\"}]}]}"; DocumentContext parsedJson = JsonPath.parse(json); ''' - and: - LinkedList lines = [] as LinkedList - test.eachLine { if (it.contains("assertThatJson") || it.contains("assertThat((String")) lines << it else it } - lines.addFirst(jsonSample) - SyntaxChecker.tryToRun(methodBuilderName, lines.join("\n")) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + and: + LinkedList lines = [] as LinkedList + test.eachLine { + if (it.contains("assertThatJson") || it.contains("assertThat((String")) lines << it else it + } + lines.addFirst(jsonSample) + SyntaxChecker.tryToRun(methodBuilderName, lines.join("\n")) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#588') - def 'should work patterns in GString [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url("/${regex('\\d+')}") - } - response { - status 200 - body([ - ok: true - ]) - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(' ') - when: - builder.appendTo(blockBuilder) - def test = blockBuilder.toString() - then: - !test.contains('d+') - !test.contains('REGEXP>>') - and: - SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + @Issue('#588') + def 'should work patterns in GString [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method GET() + url("/${regex('\\d+')}") + } + response { + status 200 + body([ + ok: true + ]) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(' ') + when: + builder.appendTo(blockBuilder) + def test = blockBuilder.toString() + then: + !test.contains('d+') + !test.contains('REGEXP>>') + and: + SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#521') - def 'should always escape generated chars [#methodBuilderName]'() { - expect: - [1..200].each { - Contract contractDsl = Contract.make { - request { - method GET() - urlPath('/v1/users') { - queryParameters { - parameter 'userId': value(regex(nonBlank())) - } - } - } - response { - status 200 - body([ - ok: value(regex(nonBlank())) - ]) - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") + @Issue('#521') + def 'should always escape generated chars [#methodBuilderName]'() { + expect: + [1..200].each { + Contract contractDsl = Contract.make { + request { + method GET() + urlPath('/v1/users') { + queryParameters { + parameter 'userId': value(regex(nonBlank())) + } + } + } + response { + status 200 + body([ + ok: value(regex(nonBlank())) + ]) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") - builder.appendTo(blockBuilder) - def test = blockBuilder.toString() + builder.appendTo(blockBuilder) + def test = blockBuilder.toString() - assert !test.contains('REGEXP>>') - SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) - } - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + assert !test.contains('REGEXP>>') + SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) + } + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#269') - def 'should work with execute and keys with dots [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - urlPath '/foo' - } - response { - status OK() - body( - foo: ["my.dotted.response": $(c('foo'), p(execute('"foo".equals($it)')))] - ) - headers { - contentType(applicationJson()) - } - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - def test = blockBuilder.toString() - then: - test.contains('''$.foo.['my.dotted.response']''') - !test.contains('cursor') - !test.contains('REGEXP>>') - and: - SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) - and: - String jsonSample = '''\ + @Issue('#269') + def 'should work with execute and keys with dots [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method 'GET' + urlPath '/foo' + } + response { + status OK() + body( + foo: ["my.dotted.response": $(c('foo'), p(execute('"foo".equals($it)')))] + ) + headers { + contentType(applicationJson()) + } + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def test = blockBuilder.toString() + then: + test.contains('''$.foo.['my.dotted.response']''') + !test.contains('cursor') + !test.contains('REGEXP>>') + and: + SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) + and: + String jsonSample = '''\ String json = "{\\"foo\\":{\\"my.dotted.response\\":\\"foo\\"}}"; DocumentContext parsedJson = JsonPath.parse(json); ''' - and: - LinkedList lines = [] as LinkedList - test.eachLine { if (it.contains('"foo".equals')) lines << it else it } - lines.addFirst(jsonSample) - SyntaxChecker.tryToRun(methodBuilderName, lines.join("\n")) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + and: + LinkedList lines = [] as LinkedList + test.eachLine { if (it.contains('"foo".equals')) lines << it else it } + lines.addFirst(jsonSample) + SyntaxChecker.tryToRun(methodBuilderName, lines.join("\n")) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#289') - def 'should fail on nonexistent field [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/something' - headers { - contentType(applicationJson()) - } - } - response { - status OK() - headers { - contentType(applicationJson()) - } - body([ - doesNotExist: $(p(anyAlphaUnicode()), c("123")) - ]) - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - def test = blockBuilder.toString() - then: - SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) - and: - String jsonSample = '''\ + @Issue('#289') + def 'should fail on nonexistent field [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method 'GET' + url '/something' + headers { + contentType(applicationJson()) + } + } + response { + status OK() + headers { + contentType(applicationJson()) + } + body([ + doesNotExist: $(p(anyAlphaUnicode()), c("123")) + ]) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def test = blockBuilder.toString() + then: + SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) + and: + String jsonSample = '''\ String json = "{}"; DocumentContext parsedJson = JsonPath.parse(json); ''' - and: - LinkedList lines = [] as LinkedList - test.eachLine { if (it.contains('assertThatJson')) lines << it else it } - lines.addFirst(jsonSample) - try { - SyntaxChecker.tryToRun(methodBuilderName, lines.join("\n")) - } catch (IllegalStateException e) { - assert e.message.contains("Parsed JSON [{}] doesn't match the JSON path") - } catch (InvocationTargetException e1) { - assert e1.cause.message.contains("Parsed JSON [{}] doesn't match the JSON path") - } - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + and: + LinkedList lines = [] as LinkedList + test.eachLine { if (it.contains('assertThatJson')) lines << it else it } + lines.addFirst(jsonSample) + try { + SyntaxChecker.tryToRun(methodBuilderName, lines.join("\n")) + } catch (IllegalStateException e) { + assert e.message.contains("Parsed JSON [{}] doesn't match the JSON path") + } catch (InvocationTargetException e1) { + assert e1.cause.message.contains("Parsed JSON [{}] doesn't match the JSON path") + } + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#313') - def 'should allow to use execute in request body [#methodBuilderName]'() { - given: - //tag::body_execute[] - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/something' - body( - $(c('foo'), p(execute('hashCode()'))) - ) - } - response { - status OK() - } - } - //end::body_execute[] - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - def test = blockBuilder.toString() - then: - SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) - !test.contains("executionCommand") - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + @Issue('#313') + def 'should allow to use execute in request body [#methodBuilderName]'() { + given: + //tag::body_execute[] + Contract contractDsl = Contract.make { + request { + method 'GET' + url '/something' + body( + $(c('foo'), p(execute('hashCode()'))) + ) + } + response { + status OK() + } + } + //end::body_execute[] + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def test = blockBuilder.toString() + then: + SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) + !test.contains("executionCommand") + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#318') - def 'should assert the response headers properly [#methodBuilderName]'() { - given: - def contractDsl = org.springframework.cloud.contract.spec.Contract.make { - request { - method 'POST' - urlPath '/documents/app_statement_v1' - headers { - contentType(applicationPdf()) - } - body([ - PESEL : '77100604360', - CLIENT_NAME : 'STANISLAW STASZIC', - STATEMENT_NUMBER: '00200001/C4/2017/1' - ]) - } - response { - status OK() - headers { - contentType(applicationPdf()) - header('Content-Length': 4) - } + @Issue('#318') + def 'should assert the response headers properly [#methodBuilderName]'() { + given: + def contractDsl = org.springframework.cloud.contract.spec.Contract.make { + request { + method 'POST' + urlPath '/documents/app_statement_v1' + headers { + contentType(applicationPdf()) + } + body([ + PESEL : '77100604360', + CLIENT_NAME : 'STANISLAW STASZIC', + STATEMENT_NUMBER: '00200001/C4/2017/1' + ]) + } + response { + status OK() + headers { + contentType(applicationPdf()) + header('Content-Length': 4) + } - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - def test = blockBuilder.toString() - then: - SyntaxChecker.tryToCompile(methodBuilderName, test) - asserter(test) - where: - methodBuilderName | methodBuilder | asserter - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String testBody -> testBody.contains("response.header('Content-Length') == 4") && testBody.contains("response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application/pdf.*')") } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { String testBody -> testBody.contains('assertThat(response.header("Content-Length")).isEqualTo(4);') && testBody.contains('assertThat(response.header("Content-Type")).matches("application/pdf.*");') } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String testBody -> testBody.contains("response.getHeaderString('Content-Length') == 4") && testBody.contains(" response.getHeaderString('Content-Type') ==~ java.util.regex.Pattern.compile('application/pdf.*')") } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { String testBody -> testBody.contains('assertThat(response.getHeaderString("Content-Length")).isEqualTo(4);') && testBody.contains('assertThat(response.getHeaderString("Content-Type")).matches("application/pdf.*");') } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | { String testBody -> testBody.contains('assertThat(response.header("Content-Length")).isEqualTo(4);') && testBody.contains('assertThat(response.header("Content-Type")).matches("application/pdf.*");') } - } + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + def test = blockBuilder.toString() + then: + SyntaxChecker.tryToCompile(methodBuilderName, test) + asserter(test) + where: + methodBuilderName | methodBuilder | asserter + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } | { String testBody -> testBody.contains("response.header('Content-Length') == 4") && testBody.contains("response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application/pdf.*')") } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String testBody -> testBody.contains('assertThat(response.header("Content-Length")).isEqualTo(4);') && testBody.contains('assertThat(response.header("Content-Type")).matches("application/pdf.*");') } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } | { String testBody -> testBody.contains("response.getHeaderString('Content-Length') == 4") && testBody.contains(" response.getHeaderString('Content-Type') ==~ java.util.regex.Pattern.compile('application/pdf.*')") } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String testBody -> testBody.contains('assertThat(response.getHeaderString("Content-Length")).isEqualTo(4);') && testBody.contains('assertThat(response.getHeaderString("Content-Type")).matches("application/pdf.*");') } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String testBody -> testBody.contains('assertThat(response.header("Content-Length")).isEqualTo(4);') && testBody.contains('assertThat(response.header("Content-Type")).matches("application/pdf.*");') } + } - def 'should put L on long values [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url 'test' - } - response { - status OK() - body( - 'createdAt': 1502766000000, - 'updatedAt': 1499476115000 - ) - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - then: - blockBuilder.toString().contains("""assertThatJson(parsedJson).field("['createdAt']").isEqualTo(1502766000000L)""") - blockBuilder.toString().contains("""assertThatJson(parsedJson).field("['updatedAt']").isEqualTo(1499476115000L)""") - and: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString()) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + def 'should put L on long values [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method GET() + url 'test' + } + response { + status OK() + body( + 'createdAt': 1502766000000, + 'updatedAt': 1499476115000 + ) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("""assertThatJson(parsedJson).field("['createdAt']").isEqualTo(1502766000000L)""") + blockBuilder.toString().contains("""assertThatJson(parsedJson).field("['updatedAt']").isEqualTo(1499476115000L)""") + and: + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString()) + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#424') - def 'should not put an absent header to the request [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/mytest' - headers { - header('myheader', absent()) - } - } - response { - status OK() - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(' ') - when: - builder.appendTo(blockBuilder) - then: - !blockBuilder.toString().contains('myheader') - and: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString()) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + @Issue('#424') + def 'should not put an absent header to the request [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method 'GET' + url '/mytest' + headers { + header('myheader', absent()) + } + } + response { + status OK() + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(' ') + when: + builder.appendTo(blockBuilder) + then: + !blockBuilder.toString().contains('myheader') + and: + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString()) + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#458') - def 'should reference request from body when body is a string [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/mytest' - body("""{ "name": "My name" }""") - } - response { - status OK() - body fromRequest().body('$.name') - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(' ') - when: - builder.appendTo(blockBuilder) - then: - String test = blockBuilder.toString() - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - responseAsserter(test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder | responseAsserter - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String string -> string.contains('responseBody == "My name"') } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { String string -> string.contains('assertThat(responseBody).isEqualTo("My name");') } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String string -> string.contains('responseBody == "My name"') } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { String string -> string.contains('assertThat(responseBody).isEqualTo("My name");') } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | { String string -> string.contains('assertThat(responseBody).isEqualTo("My name");') } - } + @Issue('#458') + def 'should reference request from body when body is a string [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method 'GET' + url '/mytest' + body("""{ "name": "My name" }""") + } + response { + status OK() + body fromRequest().body('$.name') + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(' ') + when: + builder.appendTo(blockBuilder) + then: + String test = blockBuilder.toString() + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) + responseAsserter(test) + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder | responseAsserter + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } | { String string -> string.contains('responseBody == "My name"') } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String string -> string.contains('assertThat(responseBody).isEqualTo("My name");') } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } | { String string -> string.contains('responseBody == "My name"') } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String string -> string.contains('assertThat(responseBody).isEqualTo("My name");') } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String string -> string.contains('assertThat(responseBody).isEqualTo("My name");') } + } - @Issue('#559') - def 'should reference request from body without escaping of non-string [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url('/mytest') { - queryParameters { - parameter('foo', 'bar') - parameter('number', 1) - } - } - body("""{ "name": "My name" }""") - } - response { - status OK() - body( - foo: fromRequest().query('foo'), - number: fromRequest().query('number') - ) - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - then: - String test = blockBuilder.toString() - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - test.contains('''assertThatJson(parsedJson).field("['foo']").isEqualTo("bar")''') - test.contains('''assertThatJson(parsedJson).field("['number']").isEqualTo(1)''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + @Issue('#559') + def 'should reference request from body without escaping of non-string [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method 'GET' + url('/mytest') { + queryParameters { + parameter('foo', 'bar') + parameter('number', 1) + } + } + body("""{ "name": "My name" }""") + } + response { + status OK() + body( + foo: fromRequest().query('foo'), + number: fromRequest().query('number') + ) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + String test = blockBuilder.toString() + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) + test.contains('''assertThatJson(parsedJson).field("['foo']").isEqualTo("bar")''') + test.contains('''assertThatJson(parsedJson).field("['number']").isEqualTo(1)''') + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#702') - def 'should generate proper type for large numbers [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'PUT' - urlPath '/example/create' - headers { - contentType applicationJson() - } - body( - [ - "name" : $(consumer(~/.+/), producer('string-1')), - "updatedTs" : $(consumer(~/\d{13}/), producer(1531916906000L)), - "isDisabled": $(consumer(regex(anyBoolean())), producer(true)) - ] - ) - } + @Issue('#702') + def 'should generate proper type for large numbers [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method 'PUT' + urlPath '/example/create' + headers { + contentType applicationJson() + } + body( + [ + "name" : $(consumer(~/.+/), producer('string-1')), + "updatedTs" : $(consumer(~/\d{13}/), producer(1531916906000L)), + "isDisabled": $(consumer(regex(anyBoolean())), producer(true)) + ] + ) + } - response { - status 200 - headers { - contentType applicationJsonUtf8() - } - body( - [ - "id" : $(consumer(2222L), producer(~/\d+/)), - "name" : fromRequest().body('name'), - "updatedTs" : fromRequest().body('updatedTs'), - "isDisabled": fromRequest().body('isDisabled') - ] - ) - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - then: - String test = blockBuilder.toString() - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - test.contains('''assertThatJson(parsedJson).field("['updatedTs']").isEqualTo(1531916906000L)''') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + response { + status 200 + headers { + contentType applicationJsonUtf8() + } + body( + [ + "id" : $(consumer(2222L), producer(~/\d+/)), + "name" : fromRequest().body('name'), + "updatedTs" : fromRequest().body('updatedTs'), + "isDisabled": fromRequest().body('isDisabled') + ] + ) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + String test = blockBuilder.toString() + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) + test.contains('''assertThatJson(parsedJson).field("['updatedTs']").isEqualTo(1531916906000L)''') + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#465') - def "should work for '/' url for [#methodBuilderName]"() { - given: - Contract contractDsl = Contract.make { - description(""" + @Issue('#465') + def "should work for '/' url for [#methodBuilderName]"() { + given: + Contract contractDsl = Contract.make { + description(""" Represents a request to the shouldReturnName service given: @@ -571,305 +582,348 @@ DocumentContext parsedJson = JsonPath.parse(json); then: return Ryan """) - request { - method 'GET' - url '/' - } - response { - status OK() - body('Ryan') - headers { - contentType(textHtml()) - } - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - String test = blockBuilder.toString() - then: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + request { + method 'GET' + url '/' + } + response { + status OK() + body('Ryan') + headers { + contentType(textHtml()) + } + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + String test = blockBuilder.toString() + then: + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - def 'should use fixed delay milliseconds in the generated test [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url 'test' - } - response { - status OK() - async() - fixedDelayMilliseconds(10000) - body(a: 'foo') - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - then: - blockBuilder.toString().contains(""".timeout(10000)""") - and: - SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - } + def 'should use fixed delay milliseconds in the generated test [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method GET() + url 'test' + } + response { + status OK() + async() + fixedDelayMilliseconds(10000) + body(a: 'foo') + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains(""".timeout(10000)""") + and: + SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#493') - def 'should not escape a form URL encoded request body [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url '/api/form-endpoint' - headers { - header("Content-Type": 'application/x-www-form-urlencoded') - } - body('a=abc&b=123') - } - response { - status OK() - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(' ') - when: - builder.appendTo(blockBuilder) - then: - String test = blockBuilder.toString() - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('a=abc&b=123') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + @Issue('#493') + def 'should not escape a form URL encoded request body [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method 'POST' + url '/api/form-endpoint' + headers { + header("Content-Type": 'application/x-www-form-urlencoded') + } + body('a=abc&b=123') + } + response { + status OK() + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(' ') + when: + builder.appendTo(blockBuilder) + then: + String test = blockBuilder.toString() + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) + !test.contains('a=abc&b=123') + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#578') - def 'should work for form parameters [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method POST() - urlPath('/oauth/token') - headers { - header(authorization(), anyNonBlankString()) - header(contentType(), applicationFormUrlencoded()) - header(accept(), applicationJson()) - } - body([ - username : 'user', - password : 'password', - grant_type: 'password' - ]) - } - response { - status 200 - headers { - header(contentType(), applicationJson()) - } - body([ - refresh_token: 'RANDOM_REFRESH_TOKEN', - access_token : 'RANDOM_ACCESS_TOKEN', - token_type : 'bearer', - expires_in : 3600, - scope : ['task'], - user : [ - id : 1, - username: 'user', - name : 'User' - ] - ]) - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - then: - String test = blockBuilder.toString() - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - test.contains('username=user&password=password&grant_type=password') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + @Issue('#578') + def 'should work for form parameters [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method POST() + urlPath('/oauth/token') + headers { + header(authorization(), anyNonBlankString()) + header(contentType(), applicationFormUrlencoded()) + header(accept(), applicationJson()) + } + body([ + username : 'user', + password : 'password', + grant_type: 'password' + ]) + } + response { + status 200 + headers { + header(contentType(), applicationJson()) + } + body([ + refresh_token: 'RANDOM_REFRESH_TOKEN', + access_token : 'RANDOM_ACCESS_TOKEN', + token_type : 'bearer', + expires_in : 3600, + scope : ['task'], + user : [ + id : 1, + username: 'user', + name : 'User' + ] + ]) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + String test = blockBuilder.toString() + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) + test.contains('username=user&password=password&grant_type=password') + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#493') - def 'should not escape a form URL encoded request body another try [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method POST() - urlPath('/oauth/token') - headers { - header(authorization(), anyNonBlankString()) - header(contentType(), 'application/x-www-form-urlencoded; charset=UTF-8') - header(accept(), anyNonBlankString()) - } - body('username=user&password=password&grant_type=password') - } - response { - status 200 - headers { - header(contentType(), applicationJsonUtf8()) - } - body([ - refresh_token: 'RANDOM_REFRESH_TOKEN', - access_token : 'RANDOM_ACCESS_TOKEN', - token_type : 'bearer', - expires_in : 3600, - scope : ['task'], - user : [ - id : 1, - username: 'user', - name : 'User' - ] - ]) - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(' ') - when: - builder.appendTo(blockBuilder) - then: - String test = blockBuilder.toString() - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) - !test.contains('&') - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + @Issue('#493') + def 'should not escape a form URL encoded request body another try [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method POST() + urlPath('/oauth/token') + headers { + header(authorization(), anyNonBlankString()) + header(contentType(), 'application/x-www-form-urlencoded; charset=UTF-8') + header(accept(), anyNonBlankString()) + } + body('username=user&password=password&grant_type=password') + } + response { + status 200 + headers { + header(contentType(), applicationJsonUtf8()) + } + body([ + refresh_token: 'RANDOM_REFRESH_TOKEN', + access_token : 'RANDOM_ACCESS_TOKEN', + token_type : 'bearer', + expires_in : 3600, + scope : ['task'], + user : [ + id : 1, + username: 'user', + name : 'User' + ] + ]) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(' ') + when: + builder.appendTo(blockBuilder) + then: + String test = blockBuilder.toString() + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, test) + !test.contains('&') + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - @Issue('#509') - def 'classToCheck() should return class of object'() { - given: - Contract contractDsl = Contract.make { - request { - method 'POST' - url '/api/users' - } - response { - status OK() - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - when: - Map map = new LinkedHashMap<>() - Integer number = Integer.valueOf(42) - List list = new ArrayList<>() - Set set = new HashSet<>() - then: - builder.classToCheck(map) == Map.class - and: - builder.classToCheck(number) == Integer.class - and: - builder.classToCheck(list) == List.class - and: - builder.classToCheck(set) == Set.class - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + @Issue('#509') + def 'classToCheck() should return class of object'() { + given: + Contract contractDsl = Contract.make { + request { + method 'POST' + url '/api/users' + } + response { + status OK() + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + when: + Map map = new LinkedHashMap<>() + Integer number = Integer.valueOf(42) + List list = new ArrayList<>() + Set set = new HashSet<>() + then: + builder.classToCheck(map) == Map.class + and: + builder.classToCheck(number) == Integer.class + and: + builder.classToCheck(list) == List.class + and: + builder.classToCheck(set) == Set.class + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - def 'should assert null values without matchers [#methodBuilderName]'() { - given: - Contract contractDsl = Contract.make { - request { - method GET() - url 'test' - } - response { - status OK() - body([ - nullValue: null - ]) - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - then: - blockBuilder.toString().contains("""assertThatJson(parsedJson).field("['nullValue']").isNull()""") - and: - SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString()) - and: - stubMappingIsValidWireMockStub(contractDsl) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + def 'should assert null values without matchers [#methodBuilderName]'() { + given: + Contract contractDsl = Contract.make { + request { + method GET() + url 'test' + } + response { + status OK() + body([ + nullValue: null + ]) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + blockBuilder.toString().contains("""assertThatJson(parsedJson).field("['nullValue']").isNull()""") + and: + SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString()) + and: + stubMappingIsValidWireMockStub(contractDsl) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } - def 'should not escape a regex pattern when matching raw body value [#methodBuilderName]'() { - def pattern = "\\d+\\w?" - def escapedPattern = "\\\\d+\\\\w?" + def 'should not escape a regex pattern when matching raw body value [#methodBuilderName]'() { + def pattern = "\\d+\\w?" + def escapedPattern = "\\\\d+\\\\w?" - given: - Contract contractDsl = Contract.make { - request { - method 'GET' - url '/api/arbitrary-url' - } - response { - status OK() - body(value(stub("1"), test(regex(pattern)))) - } - } - MethodBodyBuilder builder = methodBuilder(contractDsl) - BlockBuilder blockBuilder = new BlockBuilder(" ") - when: - builder.appendTo(blockBuilder) - then: - String test = blockBuilder.toString() - test.contains(escapedPattern) - where: - methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - } + given: + Contract contractDsl = Contract.make { + request { + method 'GET' + url '/api/arbitrary-url' + } + response { + status OK() + body(value(stub("1"), test(regex(pattern)))) + } + } + MethodBodyBuilder builder = methodBuilder(contractDsl) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + String test = blockBuilder.toString() + test.contains(escapedPattern) + where: + methodBuilderName | methodBuilder + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } + } + + @Issue("#664") + def 'should work with binary payload for [#methodBuilderName]'() { + given: + File root = new File("src/test/resources/body_builder/") + Contract contract = ContractVerifierDslConverter.convertAsCollection(root, + new File(root, "worksWithPdf.groovy")).first() + MethodBodyBuilder builder = methodBuilder(contract) + BlockBuilder blockBuilder = new BlockBuilder(" ") + when: + builder.appendTo(blockBuilder) + then: + String test = blockBuilder.toString() + requestMatcher(test) + responseMatcher(test) + where: + methodBuilderName | methodBuilder | requestMatcher | responseMatcher + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } | { String string -> + string.contains('.body(fileToBytes(this, "some_method_request_request.pdf"))') + } | { String string -> + string.contains('response.body.asByteArray() == fileToBytes(this, "some_method_response_response.pdf")') + } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String string -> + string.contains('.body(fileToBytes(this, "some_method_request_request.pdf"));') + } | { String string -> + string.contains('assertThat(response.getBody().asByteArray()).isEqualTo(fileToBytes(this, "some_method_response_response.pdf"));') + } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, classDataForMethod) } | { String string -> + string.contains('entity(fileToBytes(this, "some_method_request_request.pdf")') + } | { String string -> + string.contains('response.body.asByteArray() == fileToBytes(this, "some_method_response_response.pdf")') + } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String string -> + string.contains('entity(fileToBytes(this, "some_method_request_request.pdf")') + } | { String string -> + string.contains('assertThat(response.getBody().asByteArray()).isEqualTo(fileToBytes(this, "some_method_response_response.pdf"));') + } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, classDataForMethod) } | { String string -> + string.contains('.body(fileToBytes(this, "some_method_request_request.pdf"));') + } | { String string -> + string.contains('assertThat(response.getBody().asByteArray()).isEqualTo(fileToBytes(this, "some_method_response_response.pdf"));') + } + } } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy index 828337de3e..49627b3a5b 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderWithMatchersSpec.groovy @@ -36,6 +36,9 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements assertJsonSize: true ) + @Shared GeneratedClassDataForMethod generatedClassDataForMethod = new GeneratedClassDataForMethod( + new SingleTestGenerator.GeneratedClassData("foo", "bar", new File(".").toPath()), "method") + @Issue('#185') def 'should allow to set dynamic values via stub / test matchers for [#methodBuilderName]'() { given: @@ -203,11 +206,11 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements } where: methodBuilderName | methodBuilder | rootElement - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '$' - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | '$' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '$' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' } @Issue('#217') @@ -273,11 +276,11 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements } where: methodBuilderName | methodBuilder | rootElement - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '$' - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | '$' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '$' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' } @@ -328,11 +331,11 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements } where: methodBuilderName | methodBuilder | rootElement - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '$' - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | '$' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '$' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' } @Issue('#217') @@ -364,11 +367,11 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements test.contains('foo(parsedJson.read("' + rootElement + '.phoneNumbers[*].number")') where: methodBuilderName | methodBuilder | rootElement - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '$' - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | '$' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '$' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' } @Issue('#217') @@ -400,11 +403,11 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements e.message.contains('Entry for the provided JSON path <$.nonExistingPhoneNumbers[*].number> doesn\'t exist in the body') where: methodBuilderName | methodBuilder | rootElement - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '$' - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | '$' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '$' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' } @Issue('#229') @@ -440,11 +443,11 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements test.contains('assertThat(parsedJson.read("' + rootElement + '[0][0].access_token", String.class)).isEqualTo("123")') where: methodBuilderName | methodBuilder | rootElement - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '$' - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | '$' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '$' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' } @Issue('#391') @@ -488,11 +491,11 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements !test.contains('''assertThatJson(parsedJson).array("['items']").isEmpty()''') where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#391') @@ -532,11 +535,11 @@ class MockMvcMethodBodyBuilderWithMatchersSpec extends Specification implements !test.contains('''assertThatJson(parsedJson).array("['items']").isEmpty()''') where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy index d3756bde5c..05d10f3f1b 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SingleTestGeneratorSpec.groovy @@ -171,7 +171,7 @@ class SingleTestGeneratorSpec extends Specification { def 'should build test class for #testFramework'() { given: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework =testFramework + properties.testFramework = testFramework properties.testMode = mode ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, order, convertAsCollection(new File('/'), file)) contract.ignored >> true @@ -197,7 +197,7 @@ class SingleTestGeneratorSpec extends Specification { def 'should build test class for #testFramework when the path contains bizarre signs'() { given: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework =testFramework + properties.testFramework = testFramework properties.basePackageForTests = 'org.springframework.cloud.contract.verifier.tests' and: File newFolder = tmpFolder.newFolder('META_INF') @@ -208,6 +208,7 @@ class SingleTestGeneratorSpec extends Specification { writeContract(newFile) properties.contractsDslDir = newFolder properties.generatedTestSourcesDir = newFolder.parentFile + properties.generatedTestResourcesDir = newFolder.parentFile when: int size = new TestGenerator(properties).generate() then: @@ -516,7 +517,7 @@ class SingleTestGeneratorSpec extends Specification { ''') and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework =testFramework + properties.testFramework = testFramework ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(new File('/'), secondFile)) JavaTestGenerator testGenerator = new JavaTestGenerator() when: @@ -548,7 +549,7 @@ class SingleTestGeneratorSpec extends Specification { }''') and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties() - properties.testFramework =testFramework + properties.testFramework = testFramework ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(new File('/'), secondFile)) JavaTestGenerator testGenerator = new JavaTestGenerator() when: @@ -602,7 +603,8 @@ class SingleTestGeneratorSpec extends Specification { ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( testFramework: testFramework, contractsDslDir: contractLocation.parentFile, basePackageForTests: 'a.b', - generatedTestSourcesDir: temp + generatedTestSourcesDir: temp, + generatedTestResourcesDir: tmpFolder.newFolder() ) TestGenerator testGenerator = new TestGenerator(properties) when: @@ -611,7 +613,7 @@ class SingleTestGeneratorSpec extends Specification { count == 1 and: String test = new File(temp, "a/b/ContractVerifier${getTestName(testFramework)}").text - test.contains('REQUEST') + test.contains('readFromFile_request_request.json') test.contains('RESPONSE') where: testFramework << [JUNIT, JUNIT5, SPOCK] @@ -626,7 +628,8 @@ class SingleTestGeneratorSpec extends Specification { and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( testFramework: testFramework, contractsDslDir: contractLocation.parentFile, - basePackageForTests: 'a.b', generatedTestSourcesDir: temp + basePackageForTests: 'a.b', generatedTestSourcesDir: temp, + generatedTestResourcesDir: tmpFolder.newFolder() ) TestGenerator testGenerator = new TestGenerator(properties) when: @@ -635,7 +638,7 @@ class SingleTestGeneratorSpec extends Specification { count == 1 and: String test = new File(temp, "a/b/ContractVerifier${getTestName(testFramework)}").text - test.contains('REQUEST') + test.contains('readFromFile_request_request.json') test.contains('RESPONSE') where: testFramework << [JUNIT, JUNIT5, SPOCK] @@ -650,7 +653,8 @@ class SingleTestGeneratorSpec extends Specification { and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( testFramework: testFramework, contractsDslDir: contractLocation.parentFile, - baseClassForTests: 'a.b.SomeClass', generatedTestSourcesDir: temp + baseClassForTests: 'a.b.SomeClass', generatedTestSourcesDir: temp, + generatedTestResourcesDir: tmpFolder.newFolder() ) TestGenerator testGenerator = new TestGenerator(properties) when: @@ -659,7 +663,7 @@ class SingleTestGeneratorSpec extends Specification { count == 1 and: String test = new File(temp, "a/b/ContractVerifier${getTestName(testFramework)}").text - test.contains('REQUEST') + test.contains('readFromFile_request_request.json') test.contains('RESPONSE') where: testFramework << [JUNIT, JUNIT5, SPOCK] @@ -674,7 +678,8 @@ class SingleTestGeneratorSpec extends Specification { and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( testFramework: testFramework, contractsDslDir: contractLocation.parentFile, - packageWithBaseClasses: 'a.b', generatedTestSourcesDir: temp + packageWithBaseClasses: 'a.b', generatedTestSourcesDir: temp, + generatedTestResourcesDir: tmpFolder.newFolder() ) TestGenerator testGenerator = new TestGenerator(properties) when: @@ -683,7 +688,7 @@ class SingleTestGeneratorSpec extends Specification { count == 1 and: String test = new File(temp, "a/b/ContractVerifier${getTestName(testFramework)}").text - test.contains('REQUEST') + test.contains('readFromFile_request_request.json') test.contains('RESPONSE') where: testFramework << [JUNIT, JUNIT5, SPOCK] @@ -698,7 +703,7 @@ class SingleTestGeneratorSpec extends Specification { and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( testFramework: testFramework, contractsDslDir: contractLocation.parentFile, - generatedTestSourcesDir: temp + generatedTestSourcesDir: temp, generatedTestResourcesDir: tmpFolder.newFolder() ) TestGenerator testGenerator = new TestGenerator(properties) when: @@ -707,7 +712,7 @@ class SingleTestGeneratorSpec extends Specification { count == 1 and: String test = new File(temp, "org/springframework/cloud/contract/verifier/tests/ContractVerifier${getTestName(testFramework)}").text - test.contains('REQUEST') + test.contains('readFromFile_request_request.json') test.contains('RESPONSE') where: testFramework << [JUNIT, JUNIT5, SPOCK] diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy index 4e7f4081f7..2ce72f8f5e 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/SpringTestMethodBodyBuildersSpec.groovy @@ -43,6 +43,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties( assertJsonSize: true ) + + @Shared GeneratedClassDataForMethod generatedClassDataForMethod = new GeneratedClassDataForMethod( + new SingleTestGenerator.GeneratedClassData("foo", "bar", new File(".").toPath()), "method") @Shared Contract contractDslWithCookiesValue = Contract.make { @@ -201,9 +204,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#187') @@ -237,9 +240,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#79') @@ -275,9 +278,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#79') @@ -316,9 +319,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#82') @@ -348,9 +351,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | """.body('''{\"items\":[\"HOP\"]}''')""" - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '.body("{\\"items\\":[\\"HOP\\"]}")' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '.body("{\\"items\\":[\\"HOP\\"]}")' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | """.body('''{\"items\":[\"HOP\"]}''')""" + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("{\\"items\\":[\\"HOP\\"]}")' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("{\\"items\\":[\\"HOP\\"]}")' } @Issue('#88') @@ -380,9 +383,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock stubMappingIsValidWireMockStub(contractDsl) where: methodBuilderName | methodBuilder | bodyString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | """.body('''property1=VAL1''')""" - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '.body("property1=VAL1")' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '.body("property1=VAL1")' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | """.body('''property1=VAL1''')""" + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("property1=VAL1")' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("property1=VAL1")' } @Issue('185') @@ -416,9 +419,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate assertions for array in response body with #methodBuilderName'() { @@ -452,9 +455,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate assertions for array inside response body element with #methodBuilderName'() { @@ -487,9 +490,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate assertions for nested objects in response body with #methodBuilderName'() { @@ -522,9 +525,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate regex assertions for map objects in response body with #methodBuilderName'() { @@ -561,9 +564,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate regex assertions for string objects in response body with #methodBuilderName'() { @@ -596,9 +599,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue(['#126', '#143']) @@ -631,9 +634,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate a call with an url path and query parameters with #methodBuilderName'() { @@ -689,9 +692,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#169') @@ -748,9 +751,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate test for empty body with #methodBuilderName'() { @@ -778,9 +781,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ".body('''''')" - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '.body("")' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '.body("")' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ".body('''''')" + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("")' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("")' } def 'should generate test for String in response body with #methodBuilderName'() { @@ -809,9 +812,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyDefinitionString | bodyEvaluationString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | 'def responseBody = (response.body.asString())' | 'responseBody == "test"' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'def responseBody = (response.body.asString())' | 'responseBody == "test"' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' } @Issue('113') @@ -851,9 +854,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | headerEvaluationString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '''response.header('Location') ==~ java.util.regex.Pattern.compile('http://localhost/partners/[0-9]+/users/[0-9]+')''' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''response.header('Location') ==~ java.util.regex.Pattern.compile('http://localhost/partners/[0-9]+/users/[0-9]+')''' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' } @Issue('115') @@ -893,9 +896,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | headerEvaluationString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '''response.header('Location') ==~ java.util.regex.Pattern.compile('^((http[s]?|ftp):/)/?([^:/s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+')''' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''response.header('Location') ==~ java.util.regex.Pattern.compile('^((http[s]?|ftp):/)/?([^:/s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+')''' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'assertThat(response.header("Location")).matches("^((http[s]?|ftp):/)/?([^:/s]+)(:[0-9]{1,5})?/partners/[0-9]+/users/[0-9]+");' } def 'should work with more complex stuff and jsonpaths with #methodBuilderName'() { @@ -937,9 +940,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should work properly with GString url with #methodBuilderName'() { @@ -973,9 +976,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should resolve properties in GString with regular expression with #methodBuilderName'() { @@ -1016,15 +1019,15 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('42') def 'should not omit the optional field in the test creation with MockMvcSpockMethodBodyBuilder'() { given: - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1044,7 +1047,7 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock @Issue('42') def "should not omit the optional field in the test creation with MockMvcJUnitMethodBodyBuilder"() { given: - MethodBodyBuilder builder = new MockMvcJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new MockMvcJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1110,9 +1113,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock } where: methodBuilderName | methodBuilder | assertionStrings - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ['''assertThatRejectionReasonIsNull(parsedJson.read(\'\'\'$.rejectionReason\'\'\'))''', '''assertThatLocationIsNull(response.header('Location'))'''] - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['''assertThatRejectionReasonIsNull(parsedJson.read(\'\'\'$.rejectionReason\'\'\'))''', '''assertThatLocationIsNull(response.header('Location'))'''] + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] } def 'should support inner map and list definitions with #methodBuilderName'() { @@ -1180,9 +1183,9 @@ class SpringTestMethodBodyBuildersSpec extends Specification implements WireMock SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '"street":"Light Street"' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '\\"street\\":\\"Light Street\\"' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '\\"street\\":\\"Light Street\\"' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '"street":"Light Street"' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\"street\\":\\"Light Street\\"' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\"street\\":\\"Light Street\\"' } @@ -1225,9 +1228,9 @@ DocumentContext parsedJson = JsonPath.parse(json); SyntaxChecker.tryToRun(methodBuilderName, lines.join("\n")) where: methodBuilderName | methodBuilder | bodyString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '"street":"Light Street"' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '\\"street\\":\\"Light Street\\"' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '\\"street\\":\\"Light Street\\"' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '"street":"Light Street"' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\"street\\":\\"Light Street\\"' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\"street\\":\\"Light Street\\"' } @@ -1267,9 +1270,9 @@ DocumentContext parsedJson = JsonPath.parse(json); SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('177') @@ -1297,10 +1300,10 @@ World.''') SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | """'''hello, + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | """'''hello, World.'''""" - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '"hello,\\nWorld."' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '"hello,\\nWorld."' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '"hello,\\nWorld."' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '"hello,\\nWorld."' } @Issue('180') @@ -1347,15 +1350,15 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | requestStrings - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', """.param('formParameter', '"formParameterValue"'""", """.param('someBooleanParameter', 'true')""", """.multiPart('file', 'filename.csv', 'file content'.bytes, 'application/json')"""] - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.param("formParameter", "\\"formParameterValue\\"")', '.param("someBooleanParameter", "true")', '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json");'] - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.param("formParameter", "\\"formParameterValue\\"")', '.param("someBooleanParameter", "true")', '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json");'] @@ -1402,15 +1405,15 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | requestStrings - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', """.param('formParameter', '"formParameterValue"'""", """.param('someBooleanParameter', 'true')""", """.multiPart('file', 'filename.csv', 'file content'.bytes)"""] - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.param("formParameter", "\\"formParameterValue\\"")', '.param("someBooleanParameter", "true")', '.multiPart("file", "filename.csv", "file content".getBytes());'] - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.param("formParameter", "\\"formParameterValue\\"")', '.param("someBooleanParameter", "true")', '.multiPart("file", "filename.csv", "file content".getBytes());'] @@ -1452,11 +1455,11 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | requestStrings - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', """.multiPart('file', 'file', [100, 117, 100, 97] as byte[])"""] - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.multiPart("file", "file", new byte[] {100, 117, 100, 97});'] - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.multiPart("file", "file", new byte[] {100, 117, 100, 97});'] } @@ -1496,15 +1499,15 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | requestStrings - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', """.param('formParameter', '"formParameterValue"'""", """.param('someBooleanParameter', 'true')""", """.multiPart('file', toString(), 'file content'.bytes)"""] - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.param("formParameter", "\\"formParameterValue\\"")', '.param("someBooleanParameter", "true")', '.multiPart("file", toString(), "file content".getBytes());'] - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.param("formParameter", "\\"formParameterValue\\"")', '.param("someBooleanParameter", "true")', '.multiPart("file", toString(), "file content".getBytes());'] @@ -1549,9 +1552,9 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#216') @@ -1578,7 +1581,7 @@ World.'''""" ) } } - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1613,7 +1616,7 @@ World.'''""" ) } } - MethodBodyBuilder builder = new MockMvcJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new MockMvcJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1650,9 +1653,9 @@ World.'''""" test.contains('''assertThatRejectionReasonIsNull(''') where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('262') @@ -1677,7 +1680,7 @@ World.'''""" } } } - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1719,9 +1722,9 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('266') @@ -1758,9 +1761,9 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('266') @@ -1793,9 +1796,9 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('47') @@ -1824,8 +1827,8 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyDefinitionString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '.when().async()' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '.when().async()' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.when().async()' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.when().async()' } @Issue('372') @@ -1859,8 +1862,8 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate proper test code with array of primitives using #methodBuilderName'() { @@ -1894,9 +1897,9 @@ World.'''""" SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#273') @@ -1912,7 +1915,7 @@ World.'''""" body(code: 9, message: $(consumer('Wrong credentials'), producer(regex('^(?!\\s*$).+')))) } } - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1998,7 +2001,7 @@ World.'''""" def 'should generate the regular expression for the other side of communication'() { given: MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder( - dslWithOnlyOneSideForDocs, properties) + dslWithOnlyOneSideForDocs, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -2033,7 +2036,7 @@ World.'''""" ]) } } - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.then(blockBuilder) @@ -2067,7 +2070,7 @@ World.'''""" ]) } } - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.then(blockBuilder) @@ -2097,7 +2100,7 @@ World.'''""" ]) } } - MethodBodyBuilder builder = new MockMvcJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new MockMvcJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.then(blockBuilder) @@ -2128,7 +2131,7 @@ World.'''""" ]) } } - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.given(blockBuilder) @@ -2155,7 +2158,7 @@ World.'''""" body(value(stub("HELLO FROM STUB"), server(regex(".*")))) } } - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -2179,7 +2182,7 @@ World.'''""" body(value(stub("HELLO FROM STUB"), server(execute('foo($it)')))) } } - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -2214,7 +2217,7 @@ World.'''""" ]) } } - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.given(blockBuilder) @@ -2330,9 +2333,9 @@ DocumentContext parsedJson = JsonPath.parse(json); SyntaxChecker.tryToRun(methodBuilderName, lines.join("\n")) where: methodBuilderName | methodBuilder | endOfLineRegExSymbol - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '\\$' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '$' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '$' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '\\$' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '$' } @Issue('#162') @@ -2364,9 +2367,9 @@ DocumentContext parsedJson = JsonPath.parse(json); SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#173') @@ -2402,9 +2405,9 @@ DocumentContext parsedJson = JsonPath.parse(json); SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#172') @@ -2436,9 +2439,9 @@ DocumentContext parsedJson = JsonPath.parse(json); where: //order is inverted cause Intellij didn't parse this properly methodBuilderName | methodBuilder | expectedAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"''' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"''' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' } @Issue('#443') @@ -2470,11 +2473,11 @@ DocumentContext parsedJson = JsonPath.parse(json); SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | testAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile('true|false')""") } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile('true|false')""") } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile('true|false')""") } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile('true|false')""") } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } } @Issue('#169') @@ -2509,9 +2512,9 @@ DocumentContext parsedJson = JsonPath.parse(json); where: //order is inverted cause Intellij didn't parse this properly methodBuilderName | methodBuilder | expectedAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"''' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"''' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' } @Issue('#169') @@ -2542,11 +2545,11 @@ DocumentContext parsedJson = JsonPath.parse(json); !test.contains("'executedMethod()'") where: methodBuilderName | methodBuilder | missingMethodAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Cannot find matching method Script1#executedMethod") } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("post(executedMethod())") } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Cannot find matching method Script1#executedMethod") } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("path(executedMethod())") } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("post(executedMethod())") } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { Throwable t, OutputCapture capture -> t.message.contains("Cannot find matching method Script1#executedMethod") } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("post(executedMethod())") } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { Throwable t, OutputCapture capture -> t.message.contains("Cannot find matching method Script1#executedMethod") } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("path(executedMethod())") } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("post(executedMethod())") } } @Issue('#203') @@ -2578,11 +2581,11 @@ DocumentContext parsedJson = JsonPath.parse(json); !test.contains('assertThatJson(parsedJson).array("[\'foo\']").isEmpty()') where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#226') @@ -2611,11 +2614,11 @@ DocumentContext parsedJson = JsonPath.parse(json); responseAssertion(test) where: methodBuilderName | methodBuilder | requestAssertion | responseAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String body -> body.contains("body('''12000''')") } | { String body -> body.contains('responseBody == "12000"') } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String body -> body.contains(""".method('GET', entity('12000', 'text/plain'))""") } | { String body -> body.contains('responseBody == "12000"') } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { String body -> body.contains(""".method("GET", entity("12000", "text/plain"))""") } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000")') } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains("body('''12000''')") } | { String body -> body.contains('responseBody == "12000"') } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains(""".method('GET', entity('12000', 'text/plain'))""") } | { String body -> body.contains('responseBody == "12000"') } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains(""".method("GET", entity("12000", "text/plain"))""") } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000")') } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } } @Issue('#230') @@ -2702,11 +2705,11 @@ DocumentContext parsedJson = JsonPath.parse(json); responseAssertion(test) where: methodBuilderName | methodBuilder | responseAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String body -> body.contains("response.header('Authorization') == 'foo secret bar'") } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { String body -> body.contains('assertThat(response.header("Authorization")).isEqualTo("foo secret bar");') } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String body -> body.contains("response.getHeaderString('Authorization') == 'foo secret bar'") } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { String body -> body.contains('assertThat(response.getHeaderString("Authorization")).isEqualTo("foo secret bar");') } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | { String body -> body.contains('assertThat(response.header("Authorization")).isEqualTo("foo secret bar");') } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains("response.header('Authorization') == 'foo secret bar'") } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains('assertThat(response.header("Authorization")).isEqualTo("foo secret bar");') } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains("response.getHeaderString('Authorization') == 'foo secret bar'") } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains('assertThat(response.getHeaderString("Authorization")).isEqualTo("foo secret bar");') } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains('assertThat(response.header("Authorization")).isEqualTo("foo secret bar");') } } @Issue('#230') @@ -2757,11 +2760,11 @@ DocumentContext parsedJson = JsonPath.parse(json); test.contains('''assertThatJson(parsedJson).field("['responseBaz2']").isEqualTo("Bla bla bar bla bla")''') where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate JUnit assertions with cookies [#methodBuilderName]'() { @@ -2779,8 +2782,8 @@ DocumentContext parsedJson = JsonPath.parse(json); SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate JUnit assertions with cookies pattern [#methodBuilderName]'() { @@ -2798,8 +2801,8 @@ DocumentContext parsedJson = JsonPath.parse(json); SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should not generate JUnit cookie assertion with absent cookie [#methodBuilderName]'() { @@ -2815,13 +2818,13 @@ DocumentContext parsedJson = JsonPath.parse(json); SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate spock assertions with cookies'() { given: - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDslWithCookiesValue, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDslWithCookiesValue, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -2836,7 +2839,7 @@ DocumentContext parsedJson = JsonPath.parse(json); def 'should generate spock assertions with cookies pattern'() { given: - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDslWithCookiesPattern, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDslWithCookiesPattern, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -2851,7 +2854,7 @@ DocumentContext parsedJson = JsonPath.parse(json); def 'should not generate spock cookie assertion with absent cookie'() { given: - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDslWithAbsentCookies, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDslWithAbsentCookies, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -2890,10 +2893,10 @@ DocumentContext parsedJson = JsonPath.parse(json); test.contains('''assertThatJson(parsedJson).field("['anEmptyMap']").isEmpty()''') where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy index 969392e85d..b01c2cf8ee 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/YamlMockMvcMethodBodyBuilderSpec.groovy @@ -43,6 +43,9 @@ class YamlMockMvcMethodBodyBuilderSpec extends Specification implements WireMock assertJsonSize: true ) + @Shared GeneratedClassDataForMethod generatedClassDataForMethod = new GeneratedClassDataForMethod( + new SingleTestGenerator.GeneratedClassData("foo", "bar", new File(".").toPath()), "method") + static File textToFile(String text) { File temp = File.createTempFile("yaml", ".yml") temp.text = text @@ -200,8 +203,8 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue("#187") @@ -234,8 +237,8 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#79') @@ -269,10 +272,10 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#79') @@ -309,9 +312,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#82') @@ -341,9 +344,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | """.body('''{\"items\":[\"HOP\"]}''')""" - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '.body("{\\"items\\":[\\"HOP\\"]}")' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '.body("{\\"items\\":[\\"HOP\\"]}")' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | """.body('''{\"items\":[\"HOP\"]}''')""" + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("{\\"items\\":[\\"HOP\\"]}")' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("{\\"items\\":[\\"HOP\\"]}")' } @Issue('#88') @@ -371,9 +374,9 @@ response: stubMappingIsValidWireMockStub(contractDsl) where: methodBuilderName | methodBuilder | bodyString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | """.body('''property1=VAL1''')""" - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '.body("property1=VAL1")' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '.body("property1=VAL1")' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | """.body('''property1=VAL1''')""" + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("property1=VAL1")' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("property1=VAL1")' } @Issue('185') @@ -406,9 +409,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate assertions for array in response body with #methodBuilderName'() { @@ -444,9 +447,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate assertions for array inside response body element with #methodBuilderName'() { @@ -481,9 +484,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate assertions for nested objects in response body with #methodBuilderName'() { @@ -515,9 +518,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate regex assertions for map objects in response body with #methodBuilderName'() { @@ -552,9 +555,9 @@ response: SyntaxChecker.tryToCompileWithoutCompileStatic(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def "should generate a call with an url path and query parameters with #methodBuilderName"() { @@ -625,9 +628,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#169') @@ -701,9 +704,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate test for empty body with #methodBuilderName'() { @@ -731,9 +734,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ".body('''''')" - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '.body("")' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '.body("")' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ".body('''''')" + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("")' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.body("")' } def 'should generate test for String in response body with #methodBuilderName'() { @@ -763,9 +766,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyDefinitionString | bodyEvaluationString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | 'def responseBody = (response.body.asString())' | 'responseBody == "test"' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'def responseBody = (response.body.asString())' | 'responseBody == "test"' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'String responseBody = response.getBody().asString();' | 'assertThat(responseBody).isEqualTo("test");' } @Issue('113') @@ -814,9 +817,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | headerEvaluationString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '''response.header('Location') ==~ java.util.regex.Pattern.compile('http://localhost/partners/[0-9]+/users/[0-9]+')''' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''response.header('Location') ==~ java.util.regex.Pattern.compile('http://localhost/partners/[0-9]+/users/[0-9]+')''' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | 'assertThat(response.header("Location")).matches("http://localhost/partners/[0-9]+/users/[0-9]+");' } def 'should work with more complex stuff and jsonpaths with #methodBuilderName'() { @@ -862,9 +865,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('72') @@ -903,9 +906,9 @@ response: } where: methodBuilderName | methodBuilder | assertionStrings - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("\\\$.rejectionReason"))''', '''assertThatLocationIsNull(response.header('Location'))'''] - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("\\\$.rejectionReason"))''', '''assertThatLocationIsNull(response.header('Location'))'''] + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['''assertThatRejectionReasonIsNull(parsedJson.read("$.rejectionReason"))''', '''assertThatLocationIsNull(response.header("Location"))'''] } def "shouldn't generate unicode escape characters with #methodBuilderName"() { @@ -952,9 +955,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('180') @@ -1015,15 +1018,15 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | requestStrings - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', """.param('formParameter', '"formParameterValue"'""", """.param('someBooleanParameter', 'true')""", """.multiPart('file', 'filename.csv', 'file content'.bytes, 'application/json')"""] - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.param("formParameter", "\\"formParameterValue\\"")', '.param("someBooleanParameter", "true")', '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json");'] - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.param("formParameter", "\\"formParameterValue\\"")', '.param("someBooleanParameter", "true")', '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json");'] @@ -1088,11 +1091,11 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | requestStrings - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', """.multiPart('file', 'filename.csv', 'file content'.bytes, 'application/json')"""] - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json");'] - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.multiPart("file", "filename.csv", "file content".getBytes(), "application/json");'] } @@ -1155,15 +1158,15 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | requestStrings - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', """.param('formParameter', '"formParameterValue"'""", """.param('someBooleanParameter', 'true')""", """.multiPart('file', toString(), 'file content'.bytes, 'application/json')"""] - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.param("formParameter", "\\"formParameterValue\\"")', '.param("someBooleanParameter", "true")', '.multiPart("file", toString(), "file content".getBytes(), "application/json");'] - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | ['"Content-Type", "multipart/form-data;boundary=AaB03x"', '.param("formParameter", "\\"formParameterValue\\"")', '.param("someBooleanParameter", "true")', '.multiPart("file", toString(), "file content".getBytes(), "application/json");'] @@ -1190,7 +1193,7 @@ response: value: '^[a-zA-Z0-9_\\- ]+$' ''' Contract contractDsl = fromYaml(contract) - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1221,7 +1224,7 @@ response: value: '^[a-zA-Z0-9_\\- ]+$' ''' Contract contractDsl = fromYaml(contract) - MethodBodyBuilder builder = new MockMvcJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new MockMvcJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1261,8 +1264,8 @@ response: test.contains('''assertThatRejectionReasonIsNull(''') where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('262') @@ -1290,7 +1293,7 @@ response: value: "[0-9]+" ''' Contract contractDsl = fromYaml(contract) - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1337,9 +1340,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('266') @@ -1375,9 +1378,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('266') @@ -1409,9 +1412,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('47') @@ -1440,8 +1443,8 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | bodyDefinitionString - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '.when().async()' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '.when().async()' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.when().async()' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '.when().async()' } @Issue('372') @@ -1473,8 +1476,8 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } def 'should generate proper test code with array of primitives using #methodBuilderName'() { @@ -1505,9 +1508,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#273') @@ -1530,7 +1533,7 @@ response: value: '^(?!\\s*$).+' ''' Contract contractDsl = fromYaml(contract) - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1563,7 +1566,7 @@ response: value: "assertThatRejectionReasonIsNull($it)" ''' Contract contractDsl = fromYaml(contract) - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.then(blockBuilder) @@ -1600,7 +1603,7 @@ response: value: "assertThatUserNameIsNotNull($it)" ''' Contract contractDsl = fromYaml(contract) - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.then(blockBuilder) @@ -1633,7 +1636,7 @@ response: value: "assertThatUserNameIsNotNull($it)" ''' Contract contractDsl = fromYaml(contract) - MethodBodyBuilder builder = new MockMvcJUnitMethodBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new MockMvcJUnitMethodBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.then(blockBuilder) @@ -1661,7 +1664,7 @@ response: status: 200 ''' Contract contractDsl = fromYaml(contract) - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.given(blockBuilder) @@ -1692,7 +1695,7 @@ response: value: ".*" ''' Contract contractDsl = fromYaml(contract) - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1720,7 +1723,7 @@ response: value: "foo($it)" ''' Contract contractDsl = fromYaml(contract) - MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties) + MethodBodyBuilder builder = new HttpSpockMethodRequestProcessingBodyBuilder(contractDsl, properties, generatedClassDataForMethod) BlockBuilder blockBuilder = new BlockBuilder(" ") when: builder.appendTo(blockBuilder) @@ -1769,9 +1772,9 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | matcher - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String s -> 'assertThat(response.header("Content-Type")).matches("application.vnd.fraud.v1.json.*")' } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { String s -> "response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application.vnd.fraud.v1.json.*')" } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | { String s -> "response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application.vnd.fraud.v1.json.*')" } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String s -> 'assertThat(response.header("Content-Type")).matches("application.vnd.fraud.v1.json.*")' } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String s -> "response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application.vnd.fraud.v1.json.*')" } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String s -> "response.header('Content-Type') ==~ java.util.regex.Pattern.compile('application.vnd.fraud.v1.json.*')" } } @Issue('#172') @@ -1808,9 +1811,9 @@ response: where: //order is inverted cause Intellij didn't parse this properly methodBuilderName | methodBuilder | expectedAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}''' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}''' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' } @Issue('#443') @@ -1846,10 +1849,10 @@ response: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) where: methodBuilderName | methodBuilder | testAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile('true|false')""") } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile('true|false')""") } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile('true|false')""") } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String testContents -> testContents.contains("""responseBody ==~ java.util.regex.Pattern.compile('true|false')""") } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String testContents -> testContents.contains("""assertThat(responseBody).matches("true|false");""") } } @Issue('#169') @@ -1888,8 +1891,8 @@ response: where: //order is inverted cause Intellij didn't parse this properly methodBuilderName | methodBuilder | expectedAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"''' - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''responseBody == "{\\"a\\":1}\\n{\\"a\\":2}"''' + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | '''assertThat(responseBody).isEqualTo("{\\"a\\":1}\\n{\\"a\\":2}''' } @Issue('#169') @@ -1920,10 +1923,10 @@ response: !test.contains("'executedMethod()'") where: methodBuilderName | methodBuilder | missingMethodAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Cannot find matching method Script1#executedMethod") } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("post(executedMethod())") } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Cannot find matching method Script1#executedMethod") } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("path(executedMethod())") } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { Throwable t, OutputCapture capture -> t.message.contains("Cannot find matching method Script1#executedMethod") } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("post(executedMethod())") } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { Throwable t, OutputCapture capture -> t.message.contains("Cannot find matching method Script1#executedMethod") } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { Throwable t, OutputCapture capture -> t.message.contains("Truncated class file") && capture.toString().contains("path(executedMethod())") } } @Issue('#203') @@ -1956,11 +1959,11 @@ response: !test.contains('assertThatJson(parsedJson).array("[\'foo\']").isEmpty()') where: methodBuilderName | methodBuilder - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } } @Issue('#226') @@ -1989,10 +1992,10 @@ response: responseAssertion(test) where: methodBuilderName | methodBuilder | requestAssertion | responseAssertion - HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String body -> body.contains("body('''12000''')") } | { String body -> body.contains('responseBody == "12000"') } - MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties) } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } - JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties) } | { String body -> body.contains(""".method('GET', entity('12000', 'text/plain'))""") } | { String body -> body.contains('responseBody == "12000"') } - JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties) } | { String body -> body.contains(""".method("GET", entity("12000", "text/plain"))""") } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000")') } - WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties) } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } + HttpSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new HttpSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains("body('''12000''')") } | { String body -> body.contains('responseBody == "12000"') } + MockMvcJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new MockMvcJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } + JaxRsClientSpockMethodRequestProcessingBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientSpockMethodRequestProcessingBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains(""".method('GET', entity('12000', 'text/plain'))""") } | { String body -> body.contains('responseBody == "12000"') } + JaxRsClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new JaxRsClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains(""".method("GET", entity("12000", "text/plain"))""") } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000")') } + WebTestClientJUnitMethodBodyBuilder.simpleName | { Contract dsl -> new WebTestClientJUnitMethodBodyBuilder(dsl, properties, generatedClassDataForMethod) } | { String body -> body.contains('body("12000")') } | { String body -> body.contains('assertThat(responseBody).isEqualTo("12000");') } } } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy index 5fa4734f89..a96636a88e 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverterSpec.groovy @@ -16,8 +16,15 @@ package org.springframework.cloud.contract.verifier.converter +import java.util.regex.Pattern + +import spock.lang.Issue +import spock.lang.Shared +import spock.lang.Specification + import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.spec.internal.ExecutionProperty +import org.springframework.cloud.contract.spec.internal.FromFileProperty import org.springframework.cloud.contract.spec.internal.MatchingStrategy import org.springframework.cloud.contract.spec.internal.MatchingType import org.springframework.cloud.contract.spec.internal.NamedProperty @@ -25,11 +32,7 @@ import org.springframework.cloud.contract.spec.internal.QueryParameters import org.springframework.cloud.contract.spec.internal.RegexPatterns import org.springframework.cloud.contract.spec.internal.Url import org.springframework.cloud.contract.verifier.util.MapConverter -import spock.lang.Issue -import spock.lang.Shared -import spock.lang.Specification -import java.util.regex.Pattern /** * @author Marcin Grzejszczak * @author Tim Ysewyn @@ -60,6 +63,10 @@ class YamlContractConverterSpec extends Specification { File ymlMessagingMatchers = new File(ymlMessagingMatchersFile.toURI()) URL ymlCookiesUrl = YamlContractConverterSpec.getResource("/yml/contract_cookies.yml") File ymlCookies = new File(ymlCookiesUrl.toURI()) + URL ymlBytesUrl = YamlContractConverterSpec.getResource("/yml/contract_pdf.yml") + File ymlBytes = new File(ymlBytesUrl.toURI()) + URL ymlMessagingBytesUrl = YamlContractConverterSpec.getResource("/yml/contract_messaging_pdf.yml") + File ymlMessagingBytes = new File(ymlMessagingBytesUrl.toURI()) YamlContractConverter converter = new YamlContractConverter() def "should convert YAML with Cookies to DSL"() { @@ -499,6 +506,36 @@ class YamlContractConverterSpec extends Specification { contract.outputMessage.body.clientValue == [bookName: "foo"] } + def "should convert YAML with HTTP binary body to DSL"() { + given: + assert converter.isAccepted(ymlBytes) + when: + Collection contracts = converter.convertFrom(ymlBytes) + then: + contracts.size() == 1 + Contract contract = contracts.first() + contract.request.body.clientValue instanceof FromFileProperty + ((FromFileProperty) contract.request.body.clientValue).type == byte[] + and: + contract.response.body.clientValue instanceof FromFileProperty + ((FromFileProperty) contract.response.body.clientValue).type == byte[] + } + + def "should convert YAML with messaging binary body to DSL"() { + given: + assert converter.isAccepted(ymlMessagingBytes) + when: + Collection contracts = converter.convertFrom(ymlMessagingBytes) + then: + contracts.size() == 1 + Contract contract = contracts.first() + contract.input.messageBody.clientValue instanceof FromFileProperty + ((FromFileProperty) contract.input.messageBody.clientValue).type == byte[] + and: + contract.outputMessage.body.clientValue instanceof FromFileProperty + ((FromFileProperty) contract.outputMessage.body.clientValue).type == byte[] + } + def "should assert request headers when converting YAML to DSL"() { given: File yml = new File(YamlContractConverterSpec.getResource("/yml/contract_broken_request_headers.yml").toURI()) @@ -548,6 +585,7 @@ request: cookies: {} body: null bodyFromFile: null + bodyFromFileAsBytes: null matchers: url: null body: [] @@ -562,6 +600,7 @@ response: cookies: {} body: null bodyFromFile: null + bodyFromFileAsBytes: null matchers: body: [] headers: [] @@ -587,6 +626,7 @@ request: cookies: {} body: null bodyFromFile: null + bodyFromFileAsBytes: null matchers: url: null body: [] @@ -601,6 +641,7 @@ response: cookies: {} body: null bodyFromFile: null + bodyFromFileAsBytes: null matchers: body: [] headers: [] diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy index 7c51905fd4..7bca59ba62 100755 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/dsl/WireMockGroovyDslSpec.groovy @@ -22,6 +22,9 @@ import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemp import groovy.json.JsonBuilder import groovy.json.JsonOutput import groovy.json.JsonSlurper +import spock.lang.Issue +import spock.lang.Specification + import org.springframework.boot.test.web.client.TestRestTemplate import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.verifier.builder.handlebars.HandlebarsEscapeHelper @@ -30,11 +33,10 @@ import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubMapp import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubStrategy import org.springframework.cloud.contract.verifier.file.ContractMetadata import org.springframework.cloud.contract.verifier.util.AssertionUtil +import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter import org.springframework.http.RequestEntity import org.springframework.http.ResponseEntity import org.springframework.util.SocketUtils -import spock.lang.Issue -import spock.lang.Specification class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifier { @@ -400,7 +402,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie header "Content-Type", "customtype/xml" } body """${value(consumer('Jozo'), producer('Denis'))}${ - value(consumer(""), producer('1234567890')) + value(consumer("<test>"), producer('1234567890')) }""" } response { @@ -443,7 +445,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie method 'GET' url "/users" body """${value(consumer('Jozo'), producer('Denis'))}${ - value(consumer(""), producer('1234567890')) + value(consumer("<test>"), producer('1234567890')) }""" } response { @@ -551,7 +553,7 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie method 'GET' url "/users" body equalToXml("""${value(consumer('Jozo'), producer('Denis'))}${ - value(consumer(""), producer('1234567890')) + value(consumer("<test>"), producer('1234567890')) }""") } response { @@ -1801,6 +1803,33 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie server?.shutdown() } + @Issue("#664") + def "should work with byte arrays"() { + given: + File request = new File(WireMockGroovyDslSpec.getResource("/body_builder/request.pdf").file) + File response = new File(WireMockGroovyDslSpec.getResource("/body_builder/response.pdf").file) + and: + File file = new File(WireMockGroovyDslSpec.getResource("/body_builder/worksWithPdf.groovy").file) + Contract contract = ContractVerifierDslConverter.convertAsCollection( + file.parentFile, file + ).first() + and: + def json = toWireMockClientJsonStub(contract) + and: + int port = SocketUtils.findAvailableTcpPort() + WireMockServer server = new WireMockServer(config().port(port)) + server.start() + and: + server.addStubMapping(WireMockStubMapping.buildFrom(json)) + when: + ResponseEntity entity = callBytes(port, request) + then: + entity.statusCodeValue == 200 + entity.body == response.bytes + cleanup: + server?.shutdown() + } + @Issue('#540') def "should generate a stub with standard WireMock request template"() { given: @@ -2418,6 +2447,13 @@ class WireMockGroovyDslSpec extends Specification implements WireMockStubVerifie .body("{\"foo\":\"bar\",\"baz\":5}"), String.class) } + ResponseEntity callBytes(int port, File request) { + return new TestRestTemplate().exchange( + RequestEntity.put(URI.create("http://localhost:" + port + "/1")) + .header("Content-Type", "application/octet-stream") + .body(request.bytes), byte[].class) + } + String callApiCategories(int port) { return new TestRestTemplate().exchange( RequestEntity.post(URI.create("http://localhost:" + port + "/api/categories")) diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapperSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapperSpec.groovy index 6ca12701d9..015c713efe 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapperSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/messaging/internal/ContractVerifierObjectMapperSpec.groovy @@ -1,5 +1,6 @@ package org.springframework.cloud.contract.verifier.messaging.internal + import spock.lang.Specification class ContractVerifierObjectMapperSpec extends Specification { @@ -24,7 +25,30 @@ class ContractVerifierObjectMapperSpec extends Specification { result == '''{"foo":"bar"}''' } - class MyClass { + def "should convert an object into a byte[] representation"() { + given: + MyClass input = new MyClass(foo: "bar") + when: + byte[] result = mapper.writeValueAsBytes(input) + then: + result == '''{"foo":"bar"}'''.bytes + } + + def "should convert a String into a byte[] representation"() { + when: + byte[] result = mapper.writeValueAsBytes('''{"foo":"bar"}''') + then: + result == '''{"foo":"bar"}'''.bytes + } + + def "should pass byte[] as a byte[] representation"() { + when: + byte[] result = mapper.writeValueAsBytes('''{"foo":"bar"}'''.bytes) + then: + result == '''{"foo":"bar"}'''.bytes + } + + static class MyClass { String foo } } diff --git a/spring-cloud-contract-verifier/src/test/resources/body_builder/request.pdf b/spring-cloud-contract-verifier/src/test/resources/body_builder/request.pdf new file mode 100644 index 0000000000000000000000000000000000000000..69503635d87cbdfa660d5cd8be66d3e74b3b20e8 GIT binary patch literal 14631 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-verifier/src/test/resources/body_builder/response.pdf b/spring-cloud-contract-verifier/src/test/resources/body_builder/response.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3b233056b758d1cc9bf3176e99a95add89ba607 GIT binary patch literal 15767 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-contract-verifier/src/test/resources/yml/response.pdf b/spring-cloud-contract-verifier/src/test/resources/yml/response.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3b233056b758d1cc9bf3176e99a95add89ba607 GIT binary patch literal 15767 zcmch;W0WS%+NND*m+iZ3+g)~5mu=g&ZQJUyZJS+Pw!3WC)bs59&f0tSJ8S00H{YF+ zh`1vo<2tT$<&Ri-lKv1DrDddJg(2;EEck$70x$q<4J=@IcmVX$<~GLq4(1-lMgYdI z8i0|NosAtpFAmTIuyL>h7@61r+5mbv02_c_|b4#{;n|s`1oLqZH)dJ z4)Fi?4~F?)0#S0eGX~JBDHxl4g<))C>SP9BWdP8Nnp-&;JA9q3^qq`_jSX#$zIy%R z{6pWt+7a*<1R+~1XKNcr01JTrhl8<^xuKJ-!&m5Eu>t5+zeq3wn7;Ne4iYv-#%^B? zUscwB)J<#wjErB?Pyo;?*xEXM4e|H2;ulc>;}^)U@m&7N?SI8XFCh%jOqhV8@>u4e~Vg%0z$TgVE8M2|GfGCMIvGTBJy8q z`=M`Y?D!Yizajl2WkUK+`c}54{~{#Tf4Sqo&7UHG`Ad)g%rXn-zlX1+E3o73^R75^-}9Q*`o11?0_(4t z{TJT<7S=y8F)?%e8>j5}ElDB9Z^M_bsBP#eq~;5a0G)5^)yV+}c{U7b+g`p5rKV@c zBG+=Dq*FET-Hpb8ShQCqg`guvHv~ly%ZC6xWy9cGOSg7^c2hG+^`8>_kKPBNSS4=j zeOXxu`d!2vUQRL<&}pQy4zIqdopm}yb;c+%IgYzIndnQJAhKyqFBG#6{;8SBjf!^J zXbq+Gc2Xpn+-4)aL8rgjd?TnSvz1sDq$SX6&+`Bkf7G6_gwtg(QIJqpl7F0$5Mrq= zfD6An>N3WD$Mx6OjTd_mN|n-mJa^p!D9BgYy}jV19@#}h#>xSiMl}A1!a4r$pfLiN z8Q9pr-gy6H$jHpd`R{5w_l9;-8oF_H-pV0;B{3p~9?OUlvINoxkw9D_{2n08 zBpqS|z)26n%oTJy)3-l@CITrS3WJZtv;(#mu8Am1kdgM zyve@JzKpwet!VG~+J3gT+X@mP0zvtC#O0-SO{%DO+MZ{%&X;|j!($-XX`SSJV znE_eXtRxQ^H)-cSf#-Qb`weSrX|S((pH^uDwS5B3daLc$qTx-ndSS#o@f7$%s{|zn zUwr>C6;_Z?zpol;Zm$F~0(^fuoQLUvquDA3QL`PqX=YlhO7^(~+l)NtAQ(MpW*U(y za)auP8UU&jNLG#+zjU2?1p&aVz1M*J&hCDU?V;iB@i7^V)4i+n*w)qTIa>`}Ftu5} zeMv5@LC1kO8PS_VI0#4VEwwS5;K0=Pqn2yAWBjJ@$6GhUrc-nQj$oh{9y?FZj|CIH z7sOr%x=iIx zGi4Za7-3j>7-o|VO@Bz*C}uAZU7+`pxoa<|S`X6NxmpXfIetnDfFJbrUcsGz1N(TAQZVvF`RG;8OEZ;oB@uz9WVj~$+f+2v-~M4ad+Fr@}F&EV5`|1}07 z+fLe6m>WfaRu(^+Il)76SiW)CFOJ_LHQBA!wVhD!T+l}rhujdaa-vbfJ&VMWZG0TQ z*e#ro-07NIV$j>G?$S4Wo%}JzDtmU8)WKC04G`xZ=#)ajc6gnL_9Y-| zIs^7x#EoHeVM>FlVO3#mVFF>MNE>!Gz3!w)HJHpiY$9HIR%S5;aPsU(4dd8s(7sfj zCXrm|xg%xX$cH}}ZWy0^b{Heu&mLl?9#Lbl=+UluQ%888<7*N}l45r^4Yvlws{@w< zF*S9@AMs8n9|yR&z*PVne)gSdBQ(Efq}sIIDxovCbAFt}v00vzK0qlz_ZAJm7|`FZ z_KQjB;l!wyWe0N_Gp~>S+z~yoNgJXQNLj>FVC|}f{~cIw^TI1VPY}X)JaMh2v*pj% zo6jw9Xa>K>(E zc_o7%p6I8rUd~9D-@PKs(RN%Tgi1Y1j+_MV;sQ#oGzKtRJG>+Ivh-Uw0KkN=cc^9&XDmSJ*HSJqHzo`4}at>up^5>I&w`8b@!7O zD85MhI8H9!u9HpZ)3-CsRJ?KyO@`3|2P0{56b&V(b*9MjGlJoC&CI48(q z#+d=z0Vii&@}I5H&ToPnuW6xkTMIn+)-gx+=X^6Rl#>nGnK5tVP|-*BT8~xT%&apD z1v#Y~U8dy<2*8_;N(+$Vi(bt#`6 zWnDAqHk8~jlV%xZ)Yf5=C%m2R0{H0$@{z*K9Gik^*zKPRN{o7^Ld1h+kJi-C@q z_`O+SHeyw|7|t}B<&1%3jP~?nY$GTQk7(ngA^zcG_-npDsZg^EU1eW8EB0g}$0b#z zX25F;#>GbRGQYsonxA9MpvR^wX3xYGH^>$}7q!#;Qluvk6y6gr_)%(iFzvidEyx~+ zqA&ldK4sCiy8y$(E>ag-*bN9;1zH$apkTN>Q!idYH$tbJt2i)b%iA~JUUdINnP8`K zb|;hkxc<$7t`{60ir`*pmv8t+(X|<=>g2~{ZT9c4S2kmRVh6x<(`aY=h zvZlaN8*vOTg|18+=6)~BHK6a2K)-$l?fnGk_B)wVT~ry5ejd6fOoVejxR==1;t-15 zS%T(QVBk5G6wcYO=gZ0KPPZ&zINzU~{JM6%L;176XTVQ4fDh(ndX*)ZhPKKSU+teA zHg(60Nf;f>RgZ@F+xVP3{`oq= z(VrQc@18^q=$E^*bU`QW&&NI0Y6P){E);t_Cudk`x27*|SflpGq*i6Ut1i(xzJTaA z1iPPb$(+hFA)oO+pLlt`7(_5Z-oAcNtRVqoVsT+kRP*HuaO>m#2dFehp63!*=c;<# z>(r;-ABv}pDp$$KHpgmPb?b9AzA7c2J9Euf!~XR67yhKUR+!_&Tq*aqy~yzA70VB& zO~wyTxq4i8acof8-v`w~>s@$q(xEbf+K0pVDmc9k_F7Ysv{dd80$6bkE{Tr$>>Qp} zU-dsk8|y56ZB(-q8$I9m?xn;&^L$hu;0?HP&@R8z7bV71HqU*er>XOFpUID8y=`-E#{BMJh9~KuXMGXSU3EMEyFg{ z_|P|PapJfKVJE>L{ZD7yH$I0c&*M+7_xH!x&!pY#p%@Rct4nvnuC6`qL0{>vk2jRn zYwdwQpZtZ^-KMktR4%=)CG=ODM>ek)w_=wZIuRdM=CEu-j%b%j{%`nGm-TNSG#9Z{ zXqUFT_>s3DL7tR7+_$gPe;?*)#Z}E%1#>Cicys@N?}{UZq2PeLk?BKoe)8z~ygxtc zJ+}zx184xSW7+%o^}(%Ul)L%QcNE@%K6FSD32!8cjo&TeRHQVET-5+LGbXj^XF3n; z4~U*Y=f*R2aw{zvpc$#GTjoAX5Eh0_(5nKg602>iOy@l3Am>cypsUua!kb!Yf3j<6ZlFHvsoA9;N97>iyswwrBfiiNfLKF-&u57LBO#VXZyd z;n(Oj6!QW$MiNFEMj}QsM#4Hz1Bcz{@MhuA@QiO{g;NG+$VQ5_@tR~iNS+<0I znU9gX7CXY(#$?_zLs;Of$F0UKu(y)7oWvG>mb_;2Of^))cf2S{HI%OG?QG?TO!Yft zjxFq4JAl(ZVryKWKzpTV2Bc_G^Y%l*nxL%Ep3ybOSnFx7C|1UM_jk{=vd)-q{?byQ zHC@zb3huFNle)gY&OG?umWWF_Vb+Fk*5<@1)U=Mk#Ob;;44$B@}cpO1dOG>%f}Eg(=STrhWC{ zWEQitDT2?+?b#~x+Ds*P*Tvn^LIsd4|L|*0I2Z3Fi^<_am#n7TBWJb~)sfOeIbkW2 z>^=XlBc&R}4LQ=B2wpUwh^)7r{YUa1&gWla^lmkYHQ78)H$#aW6Jx4!d>%I^i7Vux zxsyEUPE6ND*G68GJ89I6N8jjoWiCZF4BJDUaGViN*^Za~;LmpDuNAKqcw)}f*ft5V zKDkh>Ja3Y|uYG0(d}s@F+>lbvYo*xeJxaXpl>g5eau_*4D{eD-|T{QJDe2_X+BL2^!< zi)2SpY4OH9^E~hg_zCHW@(J9D^?Jpn1bLBM@l3Jfyy|?*Jorh$9r1hohw!I_Z%NPW z#GUF3{R>W)V5V8aK0Ua&zgs(^)*{;jg=ZA+baMmwGJJC)@0iO@`3;L>!-f??&gAPd zvlYK5`b;|L86an2rU7F)@(huCQpZ4SdEyN1fyy%)&$y<6eVOrr%rmlUYEyq?rQ?kE zf$!DNdsMbIc6r22(tDiGkbH&mfs=b`y0+mA_cg$KY`URld28kO8O{UkYmE2IM;~1+ z!Lo=;`1`1j!KV>_gYIbRK2OJ_kMXBLPaSn7w95eg>i3s^=2`-s;g-U#S_B>co_?uX zT*o;#^8^-w3<{a}63K-k9`pJn*q*qW6a8kOoX~qaVAsP!I|M8U*92*%-1X?Ap{^oy z?6LEGkZ1oXLuD%@M~UZorxO$N5T)LfT5Oexl=^2YtO~=46`1A()>>sN){f+jk)_(E zGg+SaOLWtlKr7-+bGDtSL*V9|jXr#n%oTK=a)S65iT7e($u~TC*zI=##{8!|ym@#w zN$J90C+}~dAb|lw-}3dd`-zDP3%ExHhn>Ua;-bS#NE(VQTP}DLJWGm7?oYEfOKp2T zKp{-NVe{;VdA`poHK(5tswJx3(NRjAacdmd@KZaH3h zKi0gif&O9VX}!*uL9pGdzmK<$<$HK~Aa^-S%2~f(T)5cqe7Nv5`D}=Wgy(yFgQdsk zdYg|=)pfsbDy-?TKbvaV^f`L!xY~Rr@N(NNjOBm6Ye+2R#RSgTtnSK0?4(Fz{MCou*PQq>}Ei37xZ#fMfu~DI;zsHC`~$40|!qDYRTyf zfVnbB6`zDbTxf4xQjSBjgiBAhaRScRUAX&b%^1_c#06{s0rgV{7(r0yTo~T|*>M8R ziVVzwmFx6dLdaP^4X%x=-zU@pRH(0{-10erpB0e91%={)4KiyIREVfC!m5k_L6Bsd zp|twS#dHZxwZA5l=~~1(3fZBt=@54GGbQhaQP2j<1YF6^MVt{K2=O3`%{f$ytTZwA zvxQ!AXUEY_$ggOKH03m0H6yC}sZmF%W-mT5Gp6axgP8VnFDFYRNCcetmQHKS%EdUm z^Cb7WeEqhwO&-P?>xy{(+gtl@XHrv~!El@$_ZBR>$74*>qN#^RZDR^q3WwA?6$(p7 z492$^{hak{Gc4;$^9-ek+9(U#Arj8Ryo`)Xpg9eQiL~tdhv`ul`gJ8UJSKsW{Fw8Lo#X}~15fhxc&ua&rSxcQ1upofwb)TJHRU;|w>8z#1q+c}L@||^A?aL%0OtVt zB&@r?jmhw5BT-o-wzEf+q`c5RZcF}^=t26WEz3t}Ha2gn8@+%=N4Z5iBxwshf{m(8 zsg7P?5DYUcUN(1EeqWC^PDlpR4n?xwppZ?DJpN7yWh?X4lWyVB)%Tb;wH7oPwg6bY zH%euTx@^75@uNMA*y*Gk&a`7}YzJuvSt0$vsyRje2@)J>ILKopkD`30j#(Uz=$ya` zgALA#+c_0dqaTtb(1Jx2tzlOH67gPBYy%zxvR&E10jR3DJyx`^;4q;use&OYk@L3F z*e0YgDuIV-N*N51Ooc3YK!j)M0kzYaaIi_V!XN~tLDwtQukr!3)uvLxfytBmtQW{) zg6XKiiq{S(nB*stJ2WUlFl4<3RA3vh0BMIN9xIv&AP~<*K^MIpT;Rmqb z64Mt&gf1xkxbMDs7)j_J`nGmvF9Yf9bM)KhgM>lCJ-suW9`NY%4XvPpSDfFj8FmqO zId+KzrDk@IzWK;5EKuBY77>OJnh@cO;tFaBA0Hn*vCJxZ@rRQig%VQm2Fro+hEH&X z&mg{FIpogG{AfaW_%o;!(s%M4=WQki+_b`i_OEg$1q^-kDfKijjf##TRy_vr5zNTh1D04{(gMY z;c1s4>fse@>?UYJ;vI?~Ou=%xcIPaxRZs){LguYJ%N{pO%qyz9hLQ`E4!jJ%JmRfp%0xi`NIQhD$#F-WsqUeZBTkJ8;X`!808U_G-wAf)5pl0w~zm%GCQJI zfnVu}T$zG|X~^WO2C?CX%ZHyr(EOvqc*BF{Ce-+xcl0{cc+6t|X~1EP=y zJjk5{#MX=FxxYk0njgm%xAj*ZPRj`h*dzbYP%+Zcw{*u#L zzD#QrTWs1dfIR7WF84%x;nm+_AC0l|(A0Ayg6{a3PA-&xSk1AQyeL*?2EVqL`Gl4;*uOP;A z-#mwSYLIw?GkZ5Auw}&L@MT3i5Z3hXXjZ)4>&xSx_JDsf!jWIp&M|PgwtDK_9E)a~ zCU}0oF>A5upK|YjR?m!WvS}}f-#+;*&eLgOPSf)fA4pIzwL1Kuac!RU`56(9(^u`T zwl+T>i&MSlmO?3atV(z8{E629F@!+m1Im5)-c{hP0wr4`PwNG-*SC8L&(V!y8>^| znV&qr=TolvQ#jRR=pvt2=aNozoIjt!1{B++bOkA94rJRp7`2_3(6~QtWA!ZX1hONr z8J~w>t+cs!n5yBadqQYJnr2$5KYNPF9&_hyXiRceUZp(N!QPI&*1)u!B)~T>!=(yvt!4BOI1?ED)Yk>t z><7J$ri1FsRA5qMa!0wK+(ez!eON3x1`mv`gB){d8uR;=U$PUYrM>sl|JcejBd_TnillfK!txX-uU8 zznh$}kFxJ9}&CTv$ z4@8?Jy|vR2s!3qSzvg%3DR#2r`Hw1vVhk61_oh=|xP+;GzNVKzXP`cNV*$~2-0P4N*Ql8>tkn9* zJ}hd!1Se-Jkmj}EGj+6AY~!+l;C6^a5{*ZiYEV+e2(`ZzpaO(PgP?x^TaIGN!A<%x zTQPp~WBdW1T(p^Zr2eOEqyY{;7=v`$ zkou|o4PjXToB}X$j=>DtVlPxv8E9bL6&t5?qP-KOmrTLf`8*Wv0aEPREsW%l0B}+- z1c&%beEecr`VQ6~cN`-77)|@d`&!6{y;39{zZvno!vxdJBV?zL90r)*4G5crp~Wc` zks2ZPLWRlgLJ-YLy^(gPo1|nn$W^mo7W1qsQ`R{Mgt#69sEZHwXV0!T)Y^Wz!Sj|h zBh0t~b9AnbmID=bF@td|OgYlU8|L5}B+CByrf1Q)M0N#T1if=|hKpyV{&%f+P-|lu zjoKR19szU2=x&Jk0jc7M)kx*C&j~Sk%qM|&uqS*EV4k|B1Ik+<#L$2(<5n@Xcj8xeHIda-$+h) z()M`F^G@gy4G$14e)ud0QF8;0>?pov`O}AmfW_&(U0uG&68iSdfYgUrp=||jhBkCc zbpy6`q3>YL3*2fIXrm9djE7>wRd#}J_}b&~M`k+i2=3S^B_)#*ihbr0DRqB-uS$_} z-8sTK!Hv`(Nrybos#Y&`S8LF2P;?CXPvNC~;B0aKreFvFyVJw2gk{r%6Hc8+#!f!*PZ40sj#KLUk63rAQ z^O0f59|5q*on(vOkL|ed`CEQKW{0}gcpme;AaxO)6ai5RN5pxE6BmPw5h_bL&vT8@ zc9DA1c@t`JHGgk1UNv47J&$z@$NHI> zmsv(VyHUPY^ZG+~v?mf~rnkY`cTr$kGP20(1WQfowRZYx_y&IXR+=JVSRqQOJ-af` zHO`ww!m+}I0Z)3kkJPKFC$?LZpd|G~&zuHJhHL=$BlG8*6wdUMtq+1e{Q&p_PxUz- z?z4(DK>a(t1*kp(QV+X~PO?Xx(TU8HG?$Q*6>OH#2T6ohUaS-f1B{NI5Uaah5?jCG zJdXn;k5B{fTjpH_W6VfAUK)mj1lM!wexK$gM^pjud}=M`;k?{7$i*Jo6}!SQ!)wR`Je%01%UOePEoEP9IokyorVW; z6TfV3!f?G*hC~sVYcF2yw?lVyfo!taF1ZK+BE`PRX#lAn)e6)MVHgYja z;eU8RQFvoLk;C|t+$8mRco1SwS@af2D^QX?_+uuj02SQZNgyvMenCmJig|d`pUr*F zS|k74^2QG@If$Ue@}_(LNAHPGa@x{4+NrAv#cbIf`px-_$A8+R>X0Wnr?jgtwvxOY zG25z@Xa6+LJ|s6Zs*4LOgwWP(SnN_~_=jN`76BM0%f$SS3H7Jg0~7b8?@|w%-*s*x zc<bHe0!dNX8&OGhE~~!)ONRPosg~Q!WVon3QWq8F+I>h;d(hb zF-@!YlH-}SYB4+<-HsVJ#MDML5<*l9=Ke4Yk{?n@S?rXMwBaM9ox@%K#dJ27lBcbe zXx(}$oG&p34An2u;SzB?QRK$|IrVY*qUZ}(4D8V*O8>`cHQ)t+EDVZD+8TgF5xF`l zAPk>@sD!D6H3)GeMvgJbtR+jgT|&`1$to}v0yjn>j^aW%<}E1C7zCZW7BfpN7Nhmc z0$#^EO139K=urnRGO$MI_3nEW%j^iYIK^opaMvW1Wl^kVptF(!Ts|I8py&6=`$v!= z5U&ldgFi8|kF1b2Z;lu+HiOD!+ipHr8yB@e)gJsx+H#~4OD6-)T)e*|5;kMyPfHh= zC6+8$!5x6&LCL^SA(S8%AhWnZvcx7(~|@)4!Lw z|K4};ta00RCgUa&@&_wyZY%jfMw61xVpVYT|!t(xarJ;z}9UuFT)# zj*hJ#-Z#H_E5RxWnm%LUwJ^C`Of#>mC|FVyI&zbMiA1=HtR3Ylh%CPpY!6avt>PM4 zF{MD_e(2|jf+1lz>#v11%M5V;@#6$~&(!CoRs^Tk@nmicoUKC$tBJ~3@<4%b5cbNcVGI}A-9Yfjmh zgyk-h?ah>$r%QvIEzb6c4}<`-G?ViqsB9crF&xp*Evr_}EO4;lP%ua#C6+CpJcNd0 z!+p$v&mm#Ra{Hw=*6CraLo}_!Q_q$Rs8bM%-ZZJ$h|*S&LPpf*kM|dib`9xanZ{RM zL#fNL&-{bv6tsQ%8CxpM1y6|y$*I0=hLMl@BaLbuZv~ zEJHYGSST|6_q`JG$)!}%+FH>W49@|B7ox64_BzY0A37KFO*I0=gj7Qhat|(b6z3GS zKPYWm+T$1@w@_UZc{ue%wbZqex2pP_38mgugWhP5!{dhIYy*1W8NnbS#`6hx^79Gv z3H^Qa>lQIlPHNy_S;4?93f|v{3JthM#6#C`n>B7Cg8C?-7~IE2HP%wBv&v&l1S%%7x?(;xQ(nCffKv408QuTZ z6k-zm7AQCXas5PgJJ=HmHEfN%z)6hCu7F9jjGd}4{!NSo;Kfax+d8&7$#pb%9!6HhDkJNk8vn6`@ra->J6 z<+_mWu*ja3_E!9ov;q?1xOz$48)7kr8SK;5_>*!9Jqj(`1B&qJ{i-@&MWrRl2`sVWnx4Z&>1eZhxGZO;>L0E=c>8|TM zvQs3Kq$VZ8)j~%kt;Vx4hcJi;hrSyz`J*OCI$+Eti0(FLDDLhNlgfBS=vI;*lJUbj zk#88zN2f3tKu@4~Hn(W=8V~36=(Pf3(qZ|jUzhBfwt04semG&j&?K4i7Ip{dZRYDG?6$rseLV*ZuKB!@JpKZ!Bs^=#YPy(_v2`+pQm8WKumeP$3);Il22l; zD{#%JcW#%y;y+ubAL@-(ldo$sK_tlCp4w_I-ObLW_*Rn>;Eey4#<>_Dr(+XYNr2?p zEpsa$eO@ZqR<^|0;OUmjZQFq0XYM&{t$5MonRP6(&wDGz@k76NeP}Ix8~c%5ide}B zx7ics7NN68(gy;eFo6+la)eV~qm1qT)q zt>8{OzNVxD+0ZYkq=S&na8A`pU?fIX-pSt-+*x`9Jj*>_e&at&?hrT*DX}mRQ|`r3 zB-%ao8GxAhqosG0tS_=B3Lg#NMq3jbfz~Oz=!({Q!`A z86EY{tB6=so$L61YCZ+GAu*Vmr+?`-=>Ey}2M*B^i}IuYfcj8j_-tO3EFUhHWd9Pw3!#sn=n1v&^02cz`s0Po z5xlt^;jWq#<1`N$mjTC0PmF2+B}|I~=}oQ7&q26}igW;qMwxIXm#xwj1{%v!vd)*v zLA_w}fghK0sxX387c#<(b6H(x#j&O6kGEA-5?vFaG(0qkPa zbjC)uS2E7~9x-mt%HlG=!Xn?7+ZB{C=%05dH=#DMeCM^s-!x;hHBZY zq0c6HGncfg(!r(tN2QF~9_ATa-s1kJl(1F#?8T#De}|)1chglf6Qj-_Ol6K4EoIG2 z3*U|~bMt>S7XfSw_lN+OLO6lv3ta_C1rPF6aMoMHHTTN5B65|H`5`x{_4jW;;V7oNPeGw zRFK=UaVVEx%7{%`V%kB%Stom;*0{AlFKA+&Pg;o#YN8sVE5EJk=VrgurCzn}M^-+? z^+KRjsYHM8!uAxaL1k1Tb0|}7S+u-4&2!P&d#+X+awqZwd z5lB@>kmSACHKk_ASgk1~7tT?m@aUb6>0LcD^0|>!^Hi)h6$H=P({xB_yh!PWKgu9* zm)b{kh!Z(;&GBf3)TR@8z3c>SnOas@+|Q9TF|ww2<;7z4(LfmF{n>)T%| zZs_SXhiB^DigM`~d|n-MCoE`ETE_A>-JdV$kyBin zIjerIuD5!;6jiJaTK~b@iKQKCqDI;C-1}Lu;nvju=@`tuW`bgiZ{GA2PhOxz=%300XPf1oj4Q8)b%$Gv6rr{Bax(7?%qprQ{hN=8bu;gD9kCGi% z7VeM)O3t;ee@4B$(THv_%H5s2TLXUyu4%64dTw#&)RW_#Y8SqTpW$6<@KY^WbYZOx zrTxAztQoPwv*La2DYC9euF1}S?<(jLg}-msiY6~|1@jpUXtN@-67kPmk&PAUnx@amG4^F z_UxS#-M)7?1~{r4xGufy3UY#HTQnbV$sl8Ca0-o-KUTurL(DvuIwYusqnBRw8hJJ6 z;PCu>%0%lSfBStWi*oZuk5#fnagDD4E`CKvt^Jlwu+*rY?#VjSVY-aB)Mu;U7k)gWmWNjMziT$E@=Kq z?`A(@9$RNGK`hy@XA=vnOW`U$hsrc1Wjrx!i1Zhod&0m$S;i#=w!FN~ImKR}(yuW( z9G8BNBdf0kcL(&;$0X*8tY(Fk7zH+RwiIP0&i#Z8Ce5}5W!g0(D@eg)DE2`^OqzA)Y^I#>=Vi^0 zN>L#jky+K_3YvJi0grU9i|tg_$z|9PsQD4UWHAWRB2`tCla#~e6uRoT#MM_x#O!6t zt1M=f&PEE^c%Ajy*R3lTbd>wN7q!Ksr_hW#vNVIc=^K=%4yZp0M@O1a4H3B*Hif10 zkCVo3z%-kz;vGlE_e^JG(IPk{wPRM1QKj(M`COHz%aGFB3WsA8M~+4fMWaXY**P_* zaXBfuJ*^&E*8!h^&vj&{;NSD>v|f5zxYg|%ZhfT)7o8EiRGP*T*=eDW{4EQWTy50_ zA&-r>P$K6RDY0 zLvhWnz+Yrjg?3>Z8nUf+E7M;*L>Po3BI)n^3B4E$%T-p47Anj@YlU5-DXW;MK!xa; zLG7OA5j=Qqp2uFJiIU8OE&OSHspKx%7Iw>ZNo6PV)6q_9*+{i`;3Dh1QMbbZt4fWI zDCw~Y4UMxcmeJv-@b2kYMMaRci0E;iQhCGV7)DScRNHFA&o(;JT9I#&;}IHB=^5(9 zvZ~OzkRu9{+97?>FNGCUe~d`Cm0_E5#h1U97MF&uqu6VPcaRtKsvEg~j{ibaD))fZ zSCtTvF-ICc^(rk?k+A{o~DR`(O`tf?PQo^MZ- z50=0O>91eOf%EegmX?YWoiQz{NlhCl@SGLnDihZJnuy8$@np)A{dipPjw;|}PdQ$R zDxBxCnLI0G4#{R3X`DLrVaz_zbO_UikpL_X$}32fpW#TZ3GVW9H@ zCu3}eD}zJ5ntbHLE{&NJb2coD_>rbvD`sp78-6q2lA6O+2Z`>v6a?3eBEfbeMtYzX zNvlo0zWIHES{KQ?{D;kl^Z(A~17KqNcW;z-{De&~05Rl|XNX1)gWSz}x<4&zHD^$S zzWf{%5S3B{BB1s3AX3Xl2^|-k{uzp8w!qgc$(3iTatn|5O#wQxL5D`{*gh$u2n%X# zLstI)g*nK>zGWJ|R0S?W2@S~mac*S=O;$DEvy=Gl7fho+SB1e)LN(r$Q4#E1G=@JJ-~rnKDgN1XcE7m;Zs3@h{)ofBDV+VMvoRuuyce z{+}i(mM@t9z3o!=FBhq(xr3tg){LTG*O_b1Oovx9br*Ye+XE6ziH zKe>QER=k`L()Ua|``{4DRk1W{OzZdJ>wo;1h1mYy)9&Dx8%K1`+zGNlz#X|!Qa@1a z(gyx={5rh&9X3!V)s=a;XGmn}ZwV751hX^rzZYBNMQS)iO32j!!d~Lhm z{sG9z)eW}L2-U>x`Lb$25cYZ5jg95>P505KVHGb_FH`1qLWt&NDYZG)A~A9m^|+yG z9r1-&8ok)JVS!@HxyiZ~H@_3tgtZH5 zA8+p=M_F4Wc2t0A1XQ+oc(u%r0HwKif#4M?lU5ci1h`7@96sb=P z@0oce source) { + return contract + } + } + when: + def result = streamTransformer.transform(message) + then: + result.payload == StubRunnerStreamTransformerSpec.getResource("/response.pdf").bytes + } + } diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/request.pdf b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/request.pdf new file mode 100644 index 0000000000000000000000000000000000000000..69503635d87cbdfa660d5cd8be66d3e74b3b20e8 GIT binary patch literal 14631 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 literal 0 HcmV?d00001 diff --git a/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/response.pdf b/tests/spring-cloud-contract-stub-runner-stream/src/test/resources/response.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c3b233056b758d1cc9bf3176e99a95add89ba607 GIT binary patch literal 15767 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