From 39bef2ce08c8a5aaa4abd295fdf345ab2f5f42c5 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 6 Dec 2016 17:22:52 +0100 Subject: [PATCH] Fixed equals and hashcode --- .../cloud/contract/spec/Contract.groovy | 34 +++- .../cloud/contract/spec/internal/Body.groovy | 4 +- .../spec/internal/ClientDslProperty.groovy | 4 + .../contract/spec/internal/Common.groovy | 1 - .../contract/spec/internal/DslProperty.groovy | 3 +- .../spec/internal/ExecutionProperty.groovy | 2 + .../contract/spec/internal/Header.groovy | 4 +- .../contract/spec/internal/HttpMethods.groovy | 2 +- .../cloud/contract/spec/internal/Input.groovy | 2 + .../spec/internal/MatchingStrategy.groovy | 4 +- .../contract/spec/internal/Multipart.groovy | 4 +- .../internal/PatternValueDslProperty.groovy | 1 - .../spec/internal/QueryParameter.groovy | 4 +- .../contract/spec/internal/Request.groovy | 8 +- .../contract/spec/internal/Response.groovy | 10 +- .../spec/internal/ServerDslProperty.groovy | 4 +- .../cloud/contract/spec/internal/Url.groovy | 4 +- .../contract/spec/internal/UrlPath.groovy | 4 +- .../spec/internal/ContractSpec.groovy | 150 ++++++++++++++++++ .../contract/stubrunner/StubRepository.java | 2 +- .../converter/SingleFileConverter.groovy | 5 +- .../DslToWireMockClientConverter.groovy | 3 +- .../wiremock/DslToWireMockConverter.groovy | 2 +- .../wiremock/RecursiveFilesConverter.groovy | 22 ++- .../RecursiveFilesConverterSpec.groovy | 3 +- .../WireMockToDslConverterSpec.groovy | 124 ++++++++------- .../converter/source/dir1/dsl1_list2.groovy | 33 ++++ .../verifier/builder/JavaTestGenerator.groovy | 5 +- .../verifier/builder/MethodBuilder.groovy | 16 +- .../verifier/file/ContractMetadata.groovy | 2 + .../util/ContractVerifierDslConverter.groovy | 2 +- .../contract/verifier/util/NamesUtil.groovy | 2 +- .../MockMvcMethodBodyBuilderSpec.groovy | 4 +- .../builder/SingleTestGeneratorSpec.groovy | 105 +++++++++++- .../verifier/util/NamesUtilSpec.groovy | 99 ++++++++++++ 35 files changed, 567 insertions(+), 111 deletions(-) create mode 100644 spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list2.groovy create mode 100644 spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/NamesUtilSpec.groovy diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/Contract.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/Contract.groovy index 5e34b90bb3..bf4717d451 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/Contract.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/Contract.groovy @@ -40,15 +40,43 @@ class Contract { * take precedence */ Integer priority + /** + * The HTTP request part of the contract + */ Request request + /** + * The HTTP response part of the contract + */ Response response + /** + * The label by which you'll reference the contract on the message consumer side + */ String label + /** + * Description of a contract. May be used in the documentation generation. + */ String description + /** + * Name of the generated test / stub. If not provided then the file name will be used. + * If you have multiple contracts in a single file and you don't provide this value + * then a prefix will be added to the file with the index number while iterating + * over the collection of contracts. + * + * Remember to have a unique name for every single contract. Otherwise you might + * generate tests that have two identical methods or you will override the stubs. + */ + String name + /** + * The input side of a messaging contract. + */ Input input + /** + * The output side of a messaging contract. + */ OutputMessage outputMessage /** - * Whether the contract should be ignored or not + * Whether the contract should be ignored or not. */ boolean ignored @@ -68,6 +96,10 @@ class Contract { this.priority = priority } + void name(String name) { + this.name = name + } + void label(String label) { this.label = label } diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Body.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Body.groovy index 38e42ad8ba..cba1c3d72f 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Body.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Body.groovy @@ -25,8 +25,8 @@ import groovy.transform.ToString * * @since 1.0.0 */ -@ToString(includePackage = false, includeFields = true, includeNames = true) -@EqualsAndHashCode(includeFields = true) +@ToString(includePackage = false, includeFields = true, includeNames = true, includeSuper = true) +@EqualsAndHashCode(callSuper = true) @CompileStatic class Body extends DslProperty { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ClientDslProperty.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ClientDslProperty.groovy index b9f1906ab9..15910c7c00 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ClientDslProperty.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ClientDslProperty.groovy @@ -17,6 +17,8 @@ package org.springframework.cloud.contract.spec.internal import groovy.transform.CompileStatic +import groovy.transform.EqualsAndHashCode +import groovy.transform.ToString /** * Represents a client side {@link DslProperty} @@ -24,6 +26,8 @@ import groovy.transform.CompileStatic * @since 1.0.0 */ @CompileStatic +@EqualsAndHashCode(callSuper = true) +@ToString(includeSuper = true) class ClientDslProperty extends DslProperty { ClientDslProperty(Object singleValue) { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Common.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Common.groovy index 398fb4c8e2..0491a5cfcf 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Common.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Common.groovy @@ -20,7 +20,6 @@ import groovy.transform.PackageScope import groovy.transform.TypeChecked import java.util.regex.Pattern - /** * Contains useful common methods for the DSL. * diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/DslProperty.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/DslProperty.groovy index ef3b9758fa..39bdbd733b 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/DslProperty.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/DslProperty.groovy @@ -19,14 +19,13 @@ package org.springframework.cloud.contract.spec.internal import groovy.transform.CompileStatic import groovy.transform.EqualsAndHashCode import groovy.transform.ToString - /** * Represents an element of a DSL that can contain client or sever side values * * @since 1.0.0 */ @CompileStatic -@EqualsAndHashCode(includeFields = true) +@EqualsAndHashCode @ToString(includePackage = false, includeNames = true) class DslProperty { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ExecutionProperty.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ExecutionProperty.groovy index f9f10d07d5..4321568131 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ExecutionProperty.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ExecutionProperty.groovy @@ -17,6 +17,7 @@ package org.springframework.cloud.contract.spec.internal import groovy.transform.CompileStatic +import groovy.transform.EqualsAndHashCode /** * Represents a property that will become an executable method in the @@ -25,6 +26,7 @@ import groovy.transform.CompileStatic * @since 1.0.0 */ @CompileStatic +@EqualsAndHashCode class ExecutionProperty { private static final String PLACEHOLDER_VALUE = '\\$it' diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Header.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Header.groovy index 9989d875b4..d26f0b3ab7 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Header.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Header.groovy @@ -24,8 +24,8 @@ import groovy.transform.ToString * * @since 1.0.0 */ -@EqualsAndHashCode(includeFields = true) -@ToString(includePackage = false, includeFields = true, ignoreNulls = true, includeNames = true) +@EqualsAndHashCode(includeFields = true, callSuper = true) +@ToString(includePackage = false, includeFields = true, ignoreNulls = true, includeNames = true, includeSuper = true) @CompileStatic class Header extends DslProperty { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/HttpMethods.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/HttpMethods.groovy index c2316c4bdc..29ec3c7fe3 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/HttpMethods.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/HttpMethods.groovy @@ -11,7 +11,7 @@ import groovy.transform.ToString * @since 1.0.2 */ @CompileStatic -@EqualsAndHashCode +@EqualsAndHashCode(includeFields = true) @ToString(includePackage = false) class HttpMethods { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Input.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Input.groovy index 8aa7800e99..c536e8c64c 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Input.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Input.groovy @@ -88,6 +88,8 @@ class Input extends Common { return new DslProperty(client.clientValue, clientValue) } + @EqualsAndHashCode(includeFields = true, callSuper = true) + @ToString(includeSuper = true) static class BodyType extends DslProperty { BodyType(Object clientValue, Object serverValue) { 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 4d4a366f9f..09dc3ec6ee 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 @@ -25,8 +25,8 @@ import groovy.transform.ToString; * * @since 1.0.0 */ -@EqualsAndHashCode(includeFields = true) -@ToString(includePackage = false, includeFields = true, ignoreNulls = true, includeNames = true) +@EqualsAndHashCode(includeFields = true, callSuper = true) +@ToString(includePackage = false, includeFields = true, ignoreNulls = true, includeNames = true, includeSuper = true) @CompileStatic class MatchingStrategy extends DslProperty { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Multipart.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Multipart.groovy index 59efa9fe77..da6da2ce98 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Multipart.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Multipart.groovy @@ -20,8 +20,8 @@ import groovy.transform.CompileStatic import groovy.transform.EqualsAndHashCode import groovy.transform.ToString -@ToString(includePackage = false, includeFields = true, includeNames = true) -@EqualsAndHashCode(includeFields = true) +@ToString(includePackage = false, includeFields = true, includeNames = true, includeSuper = true) +@EqualsAndHashCode(callSuper = true) @CompileStatic class Multipart extends DslProperty { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/PatternValueDslProperty.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/PatternValueDslProperty.groovy index 1338b2f69a..fdbe142940 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/PatternValueDslProperty.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/PatternValueDslProperty.groovy @@ -4,7 +4,6 @@ import groovy.transform.CompileStatic import groovy.transform.PackageScope import java.util.regex.Pattern - /** * @author Marcin Grzejszczak */ diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/QueryParameter.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/QueryParameter.groovy index d34ea61383..069d535b90 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/QueryParameter.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/QueryParameter.groovy @@ -27,8 +27,8 @@ import static org.springframework.cloud.contract.spec.util.ValidateUtils.validat * * @since 1.0.0 */ -@EqualsAndHashCode(includeFields = true) -@ToString(includePackage = false, includeFields = true, ignoreNulls = true, includeNames = true) +@EqualsAndHashCode(includeFields = true, callSuper = true) +@ToString(includePackage = false, includeFields = true, ignoreNulls = true, includeNames = true, includeSuper = true) @CompileStatic class QueryParameter extends DslProperty { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Request.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Request.groovy index 372728945e..542083d0b1 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Request.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Request.groovy @@ -213,7 +213,7 @@ class Request extends Common { } @CompileStatic - @EqualsAndHashCode + @EqualsAndHashCode(includeFields = true) @ToString(includePackage = false) private class ServerRequest extends Request { ServerRequest(Request request) { @@ -222,7 +222,7 @@ class Request extends Common { } @CompileStatic - @EqualsAndHashCode + @EqualsAndHashCode(includeFields = true) @ToString(includePackage = false) private class ClientRequest extends Request { ClientRequest(Request request) { @@ -231,7 +231,7 @@ class Request extends Common { } @CompileStatic - @EqualsAndHashCode + @EqualsAndHashCode(includeFields = true) @ToString(includePackage = false) private class RequestHeaders extends Headers { @@ -243,7 +243,7 @@ class Request extends Common { } @CompileStatic - @EqualsAndHashCode + @EqualsAndHashCode(includeFields = true) @ToString(includePackage = false) private class ClientPatternValueDslProperty extends PatternValueDslProperty { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Response.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Response.groovy index 8e9acdd792..cb9941f427 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Response.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Response.groovy @@ -30,7 +30,7 @@ import java.util.regex.Pattern * @since 1.0.0 */ @TypeChecked -@EqualsAndHashCode +@EqualsAndHashCode(includeFields = true) @ToString(includePackage = false, includeFields = true) class Response extends Common { @@ -120,7 +120,7 @@ class Response extends Common { } @CompileStatic - @EqualsAndHashCode + @EqualsAndHashCode(callSuper = true) @ToString(includePackage = false) private class ServerResponse extends Response { ServerResponse(Response request) { @@ -129,7 +129,7 @@ class Response extends Common { } @CompileStatic - @EqualsAndHashCode + @EqualsAndHashCode(callSuper = true) @ToString(includePackage = false) private class ClientResponse extends Response { ClientResponse(Response request) { @@ -138,7 +138,7 @@ class Response extends Common { } @CompileStatic - @EqualsAndHashCode + @EqualsAndHashCode(includeFields = true) @ToString(includePackage = false) private class ResponseHeaders extends Headers { @@ -150,7 +150,7 @@ class Response extends Common { } @CompileStatic - @EqualsAndHashCode + @EqualsAndHashCode(includeFields = true) @ToString(includePackage = false) private class ServerPatternValueDslProperty extends PatternValueDslProperty { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ServerDslProperty.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ServerDslProperty.groovy index 5efbe09f8b..e91d04b588 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ServerDslProperty.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/ServerDslProperty.groovy @@ -26,8 +26,8 @@ import groovy.transform.ToString * @since 1.0.0 */ @CompileStatic -@EqualsAndHashCode(includeFields = true) -@ToString(includePackage = false) +@EqualsAndHashCode(callSuper = true) +@ToString(includePackage = false, includeSuper = true) class ServerDslProperty extends DslProperty { ServerDslProperty(Object singleValue) { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Url.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Url.groovy index 1abee32aa5..b7ebf2c2f5 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Url.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/Url.groovy @@ -27,8 +27,8 @@ import static org.springframework.cloud.contract.spec.util.ValidateUtils.validat * * @since 1.0.0 */ -@ToString(includePackage = false, includeFields = true, includeNames = true) -@EqualsAndHashCode(includeFields = true) +@ToString(includePackage = false, includeFields = true, includeNames = true, includeSuper = true) +@EqualsAndHashCode(includeFields = true, callSuper = true) @CompileStatic class Url extends DslProperty { diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/UrlPath.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/UrlPath.groovy index df4f277459..6fa2525fca 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/UrlPath.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/UrlPath.groovy @@ -25,8 +25,8 @@ import groovy.transform.ToString * * @since 1.0.0 */ -@ToString(includePackage = false, includeFields = true, includeNames = true) -@EqualsAndHashCode(includeFields = true) +@ToString(includePackage = false, includeFields = true, includeNames = true, includeSuper = true) +@EqualsAndHashCode(includeFields = true, callSuper = true) @CompileStatic class UrlPath extends Url { diff --git a/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy b/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy index a5207545a0..397d1d93ae 100644 --- a/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy +++ b/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/ContractSpec.groovy @@ -102,4 +102,154 @@ then: } // end::ignored[] } + + def 'should make equals and hashcode work properly for URL'() { + expect: + def a = Contract.make { + request { + url("/1") + } + } + def b = Contract.make { + request { + url("/1") + } + } + a == b + } + + def 'should make equals and hashcode work properly for URL with consumer producer'() { + expect: + Contract.make { + request { + url($(c("/1"), p("/1"))) + } + } == Contract.make { + request { + url($(c("/1"), p("/1"))) + } + } + } + + def 'should return true when comparing two equal contracts with gstring'() { + expect: + int index = 1 + def a = Contract.make { + request { + method(PUT()) + headers { + contentType(applicationJson()) + } + url "/${index}" + } + response { + status 200 + } + } + def b = Contract.make { + request { + method(PUT()) + headers { + contentType(applicationJson()) + } + url "/${index}" + } + response { + status 200 + } + } + a == b + } + + def 'should return false when comparing two unequal contracts with gstring'() { + expect: + int index = 1 + def a = Contract.make { + request { + method(PUT()) + headers { + contentType(applicationJson()) + } + url "/${index}" + } + response { + status 200 + } + } + int index2 = 2 + def b = Contract.make { + request { + method(PUT()) + headers { + contentType(applicationJson()) + } + url "/${index2}" + } + response { + status 200 + } + } + a != b + } + + def 'should return true when comparing two equal complex contracts'() { + expect: + def a = Contract.make { + request { + method 'GET' + url '/path' + headers { + header('Accept': $( + consumer(regex('text/.*')), + producer('text/plain') + )) + header('X-Custom-Header': $( + consumer(regex('^.*2134.*$')), + producer('121345') + )) + } + } + response { + status 200 + body( + id: [value: '132'], + surname: 'Kowalsky', + name: 'Jan', + created: '2014-02-02 12:23:43' + ) + headers { + header 'Content-Type': 'text/plain' + } + } + } + def b = Contract.make { + request { + method 'GET' + url '/path' + headers { + header('Accept': $( + consumer(regex('text/.*')), + producer('text/plain') + )) + header('X-Custom-Header': $( + consumer(regex('^.*2134.*$')), + producer('121345') + )) + } + } + response { + status 200 + body( + id: [value: '132'], + surname: 'Kowalsky', + name: 'Jan', + created: '2014-02-02 12:23:43' + ) + headers { + header 'Content-Type': 'text/plain' + } + } + } + a == b + } } diff --git a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRepository.java b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRepository.java index e010c61ab2..7f0d234c1c 100644 --- a/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRepository.java +++ b/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/StubRepository.java @@ -131,7 +131,7 @@ class StubRepository { File file = path.toFile(); if (isContractDescriptor(file)) { mappingDescriptors - .add(ContractVerifierDslConverter.convert(file)); + .addAll(ContractVerifierDslConverter.convertAsCollection(file)); } return super.visitFile(path, attrs); } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/converter/SingleFileConverter.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/converter/SingleFileConverter.groovy index 348408bd48..99f5e8b042 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/converter/SingleFileConverter.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/converter/SingleFileConverter.groovy @@ -17,6 +17,7 @@ package org.springframework.cloud.contract.verifier.converter import groovy.transform.CompileStatic +import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.verifier.file.ContractMetadata /** @@ -46,7 +47,9 @@ interface SingleFileConverter { /** * Returns the name of the converted stub file. If you have multiple contracts - * in a single file then a prefix will be added to the generated file. + * in a single file then a prefix will be added to the generated file. If you + * provide the {@link Contract#name} field then that field will override the + * generated file name. * * Example: name of file with 2 contracts is {@code foo.groovy}, it will be * converted by the implementation to {@code foo.json}. The recursive file diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.groovy index 62f8df0137..678a1a56fd 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockClientConverter.groovy @@ -20,6 +20,7 @@ import groovy.transform.CompileStatic import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.verifier.dsl.wiremock.WireMockStubStrategy import org.springframework.cloud.contract.verifier.file.ContractMetadata +import org.springframework.cloud.contract.verifier.util.NamesUtil import java.nio.charset.StandardCharsets @@ -49,7 +50,7 @@ class DslToWireMockClientConverter extends DslToWireMockConverter { } List convertedContracts = [] contract.convertedContract.eachWithIndex { Contract dsl, int index -> - String name = "${rootName}_${index}" + String name = dsl.name ? NamesUtil.convertIllegalPackageChars(dsl.name) : "${rootName}_${index}" convertedContracts << convertASingleContract(name, contract, dsl) } return convertedContracts diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.groovy index bdecb3c386..6298f85938 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/DslToWireMockConverter.groovy @@ -47,7 +47,7 @@ abstract class DslToWireMockConverter implements SingleFileConverter { return "" } - protected List createGroovyDSLFromStringContent(String groovyDslAsString) { + protected Collection createGroovyDSLFromStringContent(String groovyDslAsString) { return ContractVerifierDslConverter.convertAsCollection(groovyDslAsString) } } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/RecursiveFilesConverter.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/RecursiveFilesConverter.groovy index 4a7373bb78..feb391b509 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/RecursiveFilesConverter.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/main/groovy/org/springframework/cloud/contract/verifier/wiremock/RecursiveFilesConverter.groovy @@ -25,6 +25,7 @@ import org.springframework.cloud.contract.verifier.converter.SingleFileConverter import org.springframework.cloud.contract.verifier.converter.SingleFileConvertersHolder import org.springframework.cloud.contract.verifier.file.ContractFileScanner import org.springframework.cloud.contract.verifier.file.ContractMetadata +import org.springframework.cloud.contract.verifier.util.NamesUtil import java.nio.charset.StandardCharsets import java.nio.file.Files @@ -94,7 +95,7 @@ class RecursiveFilesConverter { } Path absoluteTargetPath = createAndReturnTargetDirectory(sourceFile) File newJsonFile = createTargetFileWithProperName(singleFileConverter, absoluteTargetPath, - sourceFile, contractsSize, index) + sourceFile, contractsSize, index, dsl) newJsonFile.setText(convertedContent, StandardCharsets.UTF_8.toString()) } } catch (Exception e) { @@ -112,11 +113,22 @@ class RecursiveFilesConverter { } private File createTargetFileWithProperName(SingleFileConverter singleFileConverter, Path absoluteTargetPath, - File sourceFile, int contractsSize, int index) { - String generatedName = singleFileConverter.generateOutputFileNameForInput(sourceFile.name) - String name = contractsSize == 1 ? generatedName : "${index}_${generatedName}" + File sourceFile, int contractsSize, int index, Contract dsl) { + String name = generateName(dsl, contractsSize, singleFileConverter, sourceFile, index) File newJsonFile = new File(absoluteTargetPath.toFile(), name) - log.info("Creating new json [$newJsonFile.path]") + log.info("Creating new stub [$newJsonFile.path]") return newJsonFile } + + private String generateName(Contract dsl, int contractsSize, SingleFileConverter converter, + File sourceFile, int index) { + String generatedName = converter.generateOutputFileNameForInput(sourceFile.name) + String extension = NamesUtil.afterLastDot(generatedName) + if (dsl.name) { + return "${dsl.name}.${extension}" + } else if (contractsSize == 1) { + return generatedName + } + return "${index}_${generatedName}" + } } diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/RecursiveFilesConverterSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/RecursiveFilesConverterSpec.groovy index a5137f21b6..7407181f4c 100755 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/RecursiveFilesConverterSpec.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/RecursiveFilesConverterSpec.groovy @@ -35,7 +35,8 @@ class RecursiveFilesConverterSpec extends Specification { private static final Set EXPECTED_TARGET_FILES = [Paths.get("dslRoot.json"), Paths.get("dir1/dsl1.json"), Paths.get("dir1/dsl1b.json"), Paths.get("dir2/dsl2.json"), - Paths.get("dir1/0_dsl1_list.json"), Paths.get("dir1/1_dsl1_list.json")] + Paths.get("dir1/0_dsl1_list.json"), Paths.get("dir1/1_dsl1_list.json"), + Paths.get("dir1/shouldHaveIndex1.json"), Paths.get("dir1/shouldHaveIndex2.json")] @Rule public TemporaryFolder tmpFolder = new TemporaryFolder(); diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverterSpec.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverterSpec.groovy index 32d39a2874..24481580b1 100755 --- a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverterSpec.groovy +++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/groovy/org/springframework/cloud/contract/verifier/wiremock/WireMockToDslConverterSpec.groovy @@ -17,10 +17,12 @@ package org.springframework.cloud.contract.verifier.wiremock import com.github.tomakehurst.wiremock.stubbing.StubMapping -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter import org.springframework.cloud.contract.spec.Contract +import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter import spock.lang.Specification +import java.util.regex.Pattern + class WireMockToDslConverterSpec extends Specification { def 'should produce a Groovy DSL from WireMock stub'() { @@ -69,12 +71,14 @@ class WireMockToDslConverterSpec extends Specification { } response { status 200 - body( - id: [value: '132'], - surname: 'Kowalsky', - name: 'Jan', - created: '2014-02-02 12:23:43' - ) + body("""{ + "id": { + "value": "132" + }, + "surname": "Kowalsky", + "name": "Jan", + "created": "2014-02-02 12:23:43" +}""") headers { header 'Content-Type': 'text/plain' @@ -84,10 +88,12 @@ class WireMockToDslConverterSpec extends Specification { when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - ContractVerifierDslConverter.convert( + def a = ContractVerifierDslConverter.convert( """org.springframework.cloud.contract.spec.Contract.make { $groovyDsl - }""") == expectedGroovyDsl + }""") + def b = expectedGroovyDsl + a == b } @@ -97,7 +103,7 @@ class WireMockToDslConverterSpec extends Specification { { "request": { "method": "DELETE", - "urlPattern": "/credit-card-verification-data/[0-9]+", + "urlPattern": "1", "headers": { "Content-Type": { "equalTo": "application/vnd.mymoid-adapter.v2+json; charset=UTF-8" @@ -119,29 +125,30 @@ class WireMockToDslConverterSpec extends Specification { Contract expectedGroovyDsl = Contract.make { request { method 'DELETE' - url $(consumer(~/\/credit-card-verification-data\/[0-9]+/), producer('/credit-card-verification-data/1')) + url $(consumer(~/1/), producer('1')) headers { header('Content-Type': 'application/vnd.mymoid-adapter.v2+json; charset=UTF-8') } } response { status 200 - body("""{ - "status": "OK" + body( """{ + "status": "OK" }""") headers { header 'Content-Type': 'application/json' - } } } when: String groovyDsl = WireMockToDslConverter.fromWireMockStub(wireMockStub) then: - ContractVerifierDslConverter.convert( + def a = ContractVerifierDslConverter.convert( """org.springframework.cloud.contract.spec.Contract.make { - $groovyDsl - }""") == expectedGroovyDsl + $groovyDsl + }""") + def b = expectedGroovyDsl + (a.request.url.clientValue as Pattern).pattern() == (b.request.url.clientValue as Pattern).pattern() } def 'should convert WireMock stub with response body containing integer'() { @@ -230,11 +237,14 @@ class WireMockToDslConverterSpec extends Specification { } response { status 200 - body([ - [a: 1, c: '3'], - 'b', - 'a' - ]) + body( """[ + { + "a": 1, + "c": "3" + }, + "b", + "a" +]""") headers { header 'Content-Type': 'application/json' } @@ -282,26 +292,26 @@ class WireMockToDslConverterSpec extends Specification { response { status 200 body("""[ - { - "amount": 1.01, - "name": "Name", - "info": { - "title": "title1", - "payload": null - }, - "booleanvalue": true, - "user": null - }, - { - "amount": 2.01, - "name": "Name2", - "info": { - "title": "title2", - "payload": null - }, - "booleanvalue": true, - "user": null - } + { + "amount": 1.01, + "name": "Name", + "info": { + "title": "title1", + "payload": null + }, + "booleanvalue": true, + "user": null + }, + { + "amount": 2.01, + "name": "Name2", + "info": { + "title": "title2", + "payload": null + }, + "booleanvalue": true, + "user": null + } ]""") } } @@ -337,7 +347,7 @@ class WireMockToDslConverterSpec extends Specification { request { method 'POST' url '/test' - body ('''{"property1":"abc","property2":"2017-01","property3":"666","property4":1428566412}''') + body ('''{"property1":"abc", "property2":"2017-01", "property3":"666", "property4":1428566412}''') } response { status 200 @@ -359,15 +369,15 @@ class WireMockToDslConverterSpec extends Specification { String wireMockStub = '''\ { "request": { - "method": "POST", - "url": "/test", - "bodyPatterns": [{ - "matches": "[0-9]{5}" - }] + "method": "POST", + "url": "/test", + "bodyPatterns": [{ + "matches": "1" + }] }, "response": { - "status": 200 - } + "status": 200 + } } ''' and: @@ -377,7 +387,7 @@ class WireMockToDslConverterSpec extends Specification { request { method 'POST' url '/test' - body $(consumer(~/[0-9]{5}/), producer('12345')) + body $(consumer(~/1/), producer('1')) } response { status 200 @@ -391,7 +401,7 @@ class WireMockToDslConverterSpec extends Specification { $groovyDsl }""") and: - evaluatedGroovyDsl == expectedGroovyDsl + (evaluatedGroovyDsl.request.body.clientValue as Pattern).pattern() == (expectedGroovyDsl.request.body.clientValue as Pattern).pattern() } def 'should convert WireMock stub with request body with equalToJson'() { @@ -418,7 +428,7 @@ class WireMockToDslConverterSpec extends Specification { request { method 'POST' url '/test' - body '''{"pan":"4855141150107894","expirationDate":"2017-01","dcvx":"178"}''' + body '''{"pan":"4855141150107894", "expirationDate":"2017-01", "dcvx":"178"}''' } response { status 200 @@ -458,7 +468,7 @@ class WireMockToDslConverterSpec extends Specification { request { method 'POST' url '/test' - body '''{"pan":"4855141150107894","expirationDate":"2017-01","dcvx":"178"}''' + body '''{"pan":"4855141150107894", "expirationDate":"2017-01", "dcvx":"178"}''' } response { status 200 @@ -483,7 +493,7 @@ class WireMockToDslConverterSpec extends Specification { "url" : "/test", "method" : "POST", "bodyPatterns" : [ { - "matches" : "[0-9]{2}" + "matches" : "1" } ] }, "response" : { @@ -498,7 +508,7 @@ class WireMockToDslConverterSpec extends Specification { request { method 'POST' url '/test' - body $(consumer(~/[0-9]{2}/), producer('12')) + body $(consumer(~/1/), producer('1')) } response { status 200 @@ -512,7 +522,7 @@ class WireMockToDslConverterSpec extends Specification { $groovyDsl }""") and: - evaluatedGroovyDsl == expectedGroovyDsl + (evaluatedGroovyDsl.request.body.clientValue as Pattern).pattern() == (expectedGroovyDsl.request.body.clientValue as Pattern).pattern() } def 'should convert WireMock stub with priorities'() { diff --git a/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list2.groovy b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list2.groovy new file mode 100644 index 0000000000..8a397c5cfb --- /dev/null +++ b/spring-cloud-contract-tools/spring-cloud-contract-converters/src/test/resources/converter/source/dir1/dsl1_list2.groovy @@ -0,0 +1,33 @@ +import org.springframework.cloud.contract.spec.Contract + +/* + * Copyright 2013-2016 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. + */ + +(1..2).collect { int index -> + Contract.make { + name("shouldHaveIndex${index}") + request { + method(PUT()) + headers { + contentType(applicationJson()) + } + url "/${index}" + } + response { + status 200 + } + } +} \ No newline at end of file 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 b8c8bfe1ee..135c42eeb0 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 @@ -113,16 +113,17 @@ class JavaTestGenerator implements SingleTestGenerator { log.debug("Stub content from file [${stubsFile.text}]") } List stubContents = metadata.convertedContract - dsls << stubContents.collectEntries { Contract stubContent -> + Map entries = stubContents.collectEntries { Contract stubContent -> TestType testType = (stubContent.input || stubContent.outputMessage) ? TestType.MESSAGING : TestType.HTTP return [(new ParsedDsl(metadata, stubContent, stubsFile)): testType] } + dsls.putAll(entries) } return dsls } @Canonical - @EqualsAndHashCode + @EqualsAndHashCode(includeFields = true) private static class ParsedDsl { ContractMetadata contract Contract groovyDsl 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 60927dde38..b86797c08f 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 @@ -57,10 +57,24 @@ class MethodBuilder { if (log.isDebugEnabled()) { log.debug("Stub content Groovy DSL [$stubContent]") } - String methodName = NamesUtil.camelCase(NamesUtil.toLastDot(NamesUtil.afterLast(stubsFile.path, File.separator))) + String methodName = methodName(contract, stubsFile, stubContent) return new MethodBuilder(methodName, stubContent, configProperties, contract.ignored || stubContent.ignored) } + private static String methodName(ContractMetadata contract, File stubsFile, Contract stubContent) { + if (stubContent.name) { + return NamesUtil.camelCase(stubContent.name) + } else if (contract.convertedContract.size() > 1) { + int index = contract.convertedContract.findIndexOf { it == stubContent} + return "${camelCasedMethodFromFileName(stubsFile)}_${index}" + } + return camelCasedMethodFromFileName(stubsFile) + } + + private static String camelCasedMethodFromFileName(File stubsFile) { + return NamesUtil.camelCase(NamesUtil.toLastDot(NamesUtil.afterLast(stubsFile.path, File.separator))) + } + /** * Appends to the {@link BlockBuilder} the contents of the test */ diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractMetadata.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractMetadata.groovy index 1246cb282c..95ebe9963b 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractMetadata.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/file/ContractMetadata.groovy @@ -17,6 +17,7 @@ package org.springframework.cloud.contract.verifier.file import groovy.transform.CompileStatic +import groovy.transform.EqualsAndHashCode import groovy.transform.ToString import org.springframework.cloud.contract.spec.Contract import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter @@ -30,6 +31,7 @@ import java.nio.file.Path * @since 1.0.0 */ @CompileStatic +@EqualsAndHashCode @ToString class ContractMetadata { /** diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.groovy index b2031b659e..403286f508 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/ContractVerifierDslConverter.groovy @@ -80,7 +80,7 @@ class ContractVerifierDslConverter { return new GroovyShell(ContractVerifierDslConverter.classLoader, new Binding(), new CompilerConfiguration(sourceEncoding: 'UTF-8')) } - private static List listOfContracts(object) { + private static Collection listOfContracts(object) { if (object instanceof Collection) { return object as Collection } else if (!object instanceof Contract) { diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/NamesUtil.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/NamesUtil.groovy index 6957ed3d8d..10317e1c11 100644 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/NamesUtil.groovy +++ b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/NamesUtil.groovy @@ -106,6 +106,6 @@ class NamesUtil { * Converts illegal package characters to underscores */ static String convertIllegalPackageChars(String packageName) { - return packageName.replace('-', '_') + return packageName.replace('-', '_').replace(" ", "_") } } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy index 430d6986c7..665dc38d7c 100644 --- a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/builder/MockMvcMethodBodyBuilderSpec.groovy @@ -38,7 +38,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub Contract dslWithOptionalsInString = Contract.make { priority 1 request { - method 'POST' + method POST() url '/users/password' headers { contentType(applicationJson()) @@ -65,7 +65,7 @@ class MockMvcMethodBodyBuilderSpec extends Specification implements WireMockStub Contract dslWithOptionals = Contract.make { priority 1 request { - method 'POST' + method POST() url '/users/password' headers { contentType(applicationJson()) 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 b0b3a0dd8a..8c731b53da 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 @@ -26,7 +26,7 @@ import spock.lang.Specification import static org.springframework.cloud.contract.verifier.config.TestFramework.JUNIT import static org.springframework.cloud.contract.verifier.config.TestFramework.SPOCK -import static org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter.convert +import static org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter.convertAsCollection class SingleTestGeneratorSpec extends Specification { @@ -64,7 +64,7 @@ class SingleTestGeneratorSpec extends Specification { given: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convert(file)) + ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convertAsCollection(file)) contract.ignored >> true contract.order >> 2 JavaTestGenerator testGenerator = new JavaTestGenerator() @@ -86,7 +86,7 @@ class SingleTestGeneratorSpec extends Specification { ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.testMode = TestMode.JAXRSCLIENT properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convert(file)) + ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convertAsCollection(file)) contract.ignored >> true contract.order >> 2 JavaTestGenerator testGenerator = new JavaTestGenerator() @@ -124,11 +124,11 @@ class SingleTestGeneratorSpec extends Specification { and: ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.targetFramework = testFramework - ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convert(file)) + ContractMetadata contract = new ContractMetadata(file.toPath(), true, 1, 2, convertAsCollection(file)) contract.ignored >> true contract.order >> 2 and: - ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convert(secondFile)) + ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convertAsCollection(secondFile)) contract2.ignored >> true contract2.order >> 2 and: @@ -167,7 +167,7 @@ class SingleTestGeneratorSpec extends Specification { ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); properties.targetFramework = testFramework and: - ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convert(file)) + ContractMetadata contract2 = new ContractMetadata(secondFile.toPath(), true, 1, 2, convertAsCollection(file)) contract2.ignored >> false contract2.order >> 2 and: @@ -186,5 +186,98 @@ class SingleTestGeneratorSpec extends Specification { SPOCK | spockClassStrings } + def "should pick the contract's name as the test method"() { + given: + File secondFile = tmpFolder.newFile() + secondFile.write(""" + org.springframework.cloud.contract.spec.Contract.make { + name("MySuperMethod") + request { + method 'PUT' + url 'url' + } + response { + status 200 + } + } + """) + and: + ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); + properties.targetFramework = testFramework + ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(secondFile)) + JavaTestGenerator testGenerator = new JavaTestGenerator() + when: + String clazz = testGenerator.buildClass(properties, [contract], "test", "test", 'com/foo') + then: + clazz.contains("validate_mySuperMethod()") + where: + testFramework << [JUNIT, SPOCK] + } + + def "should pick the contract's name as the test method when there are multiple contracts"() { + given: + File secondFile = tmpFolder.newFile() + secondFile.write(''' + (1..2).collect { int index -> + org.springframework.cloud.contract.spec.Contract.make { + name("shouldHaveIndex${index}") + request { + method(PUT()) + headers { + contentType(applicationJson()) + } + url "/${index}" + } + response { + status 200 + } + } +}''') + and: + ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); + properties.targetFramework = testFramework + ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(secondFile)) + JavaTestGenerator testGenerator = new JavaTestGenerator() + when: + String clazz = testGenerator.buildClass(properties, [contract], "test", "test", 'com/foo') + then: + clazz.contains("validate_shouldHaveIndex1()") + clazz.contains("validate_shouldHaveIndex2()") + where: + testFramework << [JUNIT, SPOCK] + } + + def "should generate the test method when there are multiple contracts without name field"() { + given: + File secondFile = tmpFolder.newFile() + secondFile.write(''' + (1..2).collect { int index -> + org.springframework.cloud.contract.spec.Contract.make { + request { + method(PUT()) + headers { + contentType(applicationJson()) + } + url "/${index}" + } + response { + status 200 + } + } +}''') + and: + ContractVerifierConfigProperties properties = new ContractVerifierConfigProperties(); + properties.targetFramework = testFramework + ContractMetadata contract = new ContractMetadata(secondFile.toPath(), false, 1, null, convertAsCollection(secondFile)) + JavaTestGenerator testGenerator = new JavaTestGenerator() + when: + String clazz = testGenerator.buildClass(properties, [contract], "test", "test", 'com/foo') + then: + clazz.contains("_0() throws Exception") + clazz.contains("_1() throws Exception") + where: + testFramework << [JUNIT, SPOCK] + } + } diff --git a/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/NamesUtilSpec.groovy b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/NamesUtilSpec.groovy new file mode 100644 index 0000000000..dbf23ce4b8 --- /dev/null +++ b/spring-cloud-contract-verifier/src/test/groovy/org/springframework/cloud/contract/verifier/util/NamesUtilSpec.groovy @@ -0,0 +1,99 @@ +package org.springframework.cloud.contract.verifier.util + +import spock.lang.Specification +/** + * @author Marcin Grzejszczak + */ +class NamesUtilSpec extends Specification { + def "should return the whole string before the last one"() { + given: + String string = "a.b.c.d.e" + expect: + "a.b.c.d" == NamesUtil.beforeLast(string, ".") + } + + def "should return empty string when no token was found for before last"() { + given: + String string = "a.b.c.d.e" + expect: + "" == NamesUtil.beforeLast(string, "/") + } + + def "should return first token after the last one"() { + given: + String string = "a.b.c.d.e" + expect: + "e" == NamesUtil.afterLast(string, ".") + } + + def "should return the input string when no token was found for after last"() { + given: + String string = "a.b.c.d.e" + expect: + string == NamesUtil.afterLast(string, "/") + } + + def "should return first token after the last dot"() { + given: + String string = "a.b.c.d.e" + expect: + "e" == NamesUtil.afterLastDot(string) + } + + def "should return the input string when no token was found for after last dot"() { + given: + String string = "abcde" + expect: + string == NamesUtil.afterLastDot(string) + } + + def "should return camel case version of a string"() { + given: + String string = "BlaBlaBla" + expect: + "blaBlaBla" == NamesUtil.camelCase(string) + } + + def "should return capitalized version of a string"() { + given: + String string = "blaBlaBla" + expect: + "BlaBlaBla" == NamesUtil.capitalize(string) + } + + def "should return all text to last dot"() { + given: + String string = "a.b.c.d.e" + expect: + "a.b.c.d" == NamesUtil.toLastDot(string) + } + + def "should return the input string when no token was found for to last dot"() { + given: + String string = "abcde" + expect: + string == NamesUtil.toLastDot(string) + } + + def "should convert a package notation to directory"() { + given: + String string = "a.b.c.d.e" + expect: + "a/b/c/d/e".replace("/", File.separator) == NamesUtil.packageToDirectory(string) + } + + def "should convert a directory notation to package"() { + given: + String string = "a/b/c/d/e".replace("/", File.separator) + expect: + "a.b.c.d.e" == NamesUtil.directoryToPackage(string) + } + + def "should convert all illegal package chars to legal ones"() { + given: + String string = "a-b c" + expect: + "a_b_c" == NamesUtil.convertIllegalPackageChars(string) + } + +}