From 150f7fdc43786fe898f89051be66f20ec22a6065 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 3 Jan 2017 18:13:06 +0100 Subject: [PATCH 1/2] Added isoDate, isoTime, isoDateTime fixes #183 --- .../internal/PatternValueDslProperty.groovy | 17 +++- .../spec/internal/RegexPatterns.groovy | 20 ++++- .../spec/internal/RegexPatternsSpec.groovy | 85 ++++++++++++++++--- .../JaxRsClientMethodBuilderSpec.groovy | 13 ++- .../MockMvcMethodBodyBuilderSpec.groovy | 15 +++- 5 files changed, 129 insertions(+), 21 deletions(-) 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..f00d27f6da 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 @@ -64,10 +64,25 @@ abstract class PatternValueDslProperty { return createAndValidateProperty(RegexPatterns.URL, "http://foo" + this.random.nextInt() + ".com") } - T anyUuid(){ + T anyUuid() { return createAndValidateProperty(RegexPatterns.UUID, UUID.randomUUID().toString()) } + T anyDate() { + int d = this.random.nextInt(8) + 1 + return createAndValidateProperty(RegexPatterns.ANY_DATE, "201$d-0$d-1$d") + } + + T anyDateTime() { + int d = this.random.nextInt(8) + 1 + return createAndValidateProperty(RegexPatterns.ANY_DATE_TIME, "201$d-0$d-1${d}T12:23:34") + } + + T anyTime() { + int d = this.random.nextInt(9) + return createAndValidateProperty(RegexPatterns.ANY_TIME, "12:2$d:3$d") + } + private static String randomString(int length) { char[] characterSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray() Random random = new Random() diff --git a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/RegexPatterns.groovy b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/RegexPatterns.groovy index 1cf37a9d7b..8af7f580e8 100644 --- a/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/RegexPatterns.groovy +++ b/spring-cloud-contract-spec/src/main/groovy/org/springframework/cloud/contract/spec/internal/RegexPatterns.groovy @@ -31,11 +31,14 @@ class RegexPatterns { protected static final Pattern TRUE_OR_FALSE = Pattern.compile(/(true|false)/) protected static final Pattern ONLY_ALPHA_UNICODE = Pattern.compile(/[\p{L}]*/) protected static final Pattern NUMBER = Pattern.compile('-?\\d*(\\.\\d+)?') - protected static final Pattern IP_ADDRESS = Pattern.compile('([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])'); - protected static final Pattern HOSTNAME_PATTERN = Pattern.compile('((http[s]?|ftp):\\/)\\/?([^:\\/\\s]+)(:[0-9]{1,5})?'); + protected static final Pattern IP_ADDRESS = Pattern.compile('([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])') + protected static final Pattern HOSTNAME_PATTERN = Pattern.compile('((http[s]?|ftp):\\/)\\/?([^:\\/\\s]+)(:[0-9]{1,5})?') protected static final Pattern EMAIL = Pattern.compile('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}'); protected static final Pattern URL = Pattern.compile('((www\\.|(http|https|ftp|news|file)+\\:\\/\\/)[_.a-z0-9-]+\\.[a-z0-9\\/_:@=.+?,##%&~-]*[^.|\\\'|\\# |!|\\(|?|,| |>|<|;|\\)])') protected static final Pattern UUID = Pattern.compile('[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}') + protected static final Pattern ANY_DATE = Pattern.compile('(\\d\\d\\d\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])') + protected static final Pattern ANY_DATE_TIME = Pattern.compile('([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])') + protected static final Pattern ANY_TIME = Pattern.compile('(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])') String onlyAlphaUnicode() { return ONLY_ALPHA_UNICODE.pattern() @@ -68,6 +71,19 @@ class RegexPatterns { String uuid(){ return UUID.pattern() } + + String isoDate() { + return ANY_DATE.pattern() + } + + String isoDateTime() { + return ANY_DATE_TIME.pattern() + } + + String isoTime() { + return ANY_TIME.pattern() + } + // end::regexps[] static String multipartParam(Object name, Object value) { diff --git a/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPatternsSpec.groovy b/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPatternsSpec.groovy index 43660fa89c..b9f0a21c28 100644 --- a/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPatternsSpec.groovy +++ b/spring-cloud-contract-spec/src/test/groovy/org/springframework/cloud/contract/spec/internal/RegexPatternsSpec.groovy @@ -66,25 +66,84 @@ class RegexPatternsSpec extends Specification { def "should generate a regex for a number [#textToMatch] that is a match [#shouldMatch]"() { expect: - shouldMatch == Pattern.compile(regexPatterns.number()).matcher(textToMatch).matches() + shouldMatch == Pattern.compile(regexPatterns.number()).matcher(textToMatch).matches() where: - textToMatch || shouldMatch - '1' || true - '1.0' || true - '0.1' || true - '.1' || true - '1.' || false + textToMatch || shouldMatch + '1' || true + '1.0' || true + '0.1' || true + '.1' || true + '1.' || false } def "should generate a regex for a uuid [#textToMatch] that is a match [#shouldMatch]"() { expect: - shouldMatch == Pattern.compile(regexPatterns.uuid()).matcher(textToMatch).matches() + shouldMatch == Pattern.compile(regexPatterns.uuid()).matcher(textToMatch).matches() where: textToMatch || shouldMatch - UUID.randomUUID().toString() || true - UUID.randomUUID().toString() || true - UUID.randomUUID().toString() + "!" || false - 'dog' || false - '5' || false + UUID.randomUUID().toString() || true + UUID.randomUUID().toString() || true + UUID.randomUUID().toString() + "!" || false + 'dog' || false + '5' || false + } + + def "should generate a regex with date [#textToMatch] in YYYY-MM-DD format that should match [#shouldMatch]"() { + expect: + shouldMatch == Pattern.compile(regexPatterns.isoDate()).matcher(textToMatch).matches() + where: + textToMatch || shouldMatch + "2014-03-01" || true + "1014-03-01" || true + "1014-3-01" || false + "14-03-01" || false + "1014-12-01" || true + "1014-12-31" || true + "1014-12-1" || false + "1014-12-32" || false + "1014-13-31" || false + "1014-20-30" || false + '5' || false + } + + def "should generate a regex with datetime [#textToMatch] in YYYY-MM-DDTHH:mm:ss format that should match [#shouldMatch]"() { + expect: + shouldMatch == Pattern.compile(regexPatterns.isoDateTime()).matcher(textToMatch).matches() + where: + textToMatch || shouldMatch + "2014-03-01T12:23:45" || true + "1014-03-01T23:59:59" || true + "1014-3-01T01:01:01" || false + "1014-03-01T00:00:00" || true + "1014-03-01T00:00:0" || false + "1014-03-01T00:0:01" || false + "1014-03-01T0:01:01" || false + "1014-03-0100:01:01" || false + "14-03-01T12:23:45" || false + "1014-12-01T12:23:45" || true + "1014-12-31T12:23:45" || true + "1014-12-1T12:23:45" || false + "1014-12-32T12:23:45" || false + "1014-13-31T12:23:45" || false + "1014-20-30T12:23:45" || false + "1014-20-30T24:23:45" || false + "1014-20-30T23:60:45" || false + "1014-20-30T23:59:60" || false + } + + def "should generate a regex with time [#textToMatch] in HH:mm:ss format that should match [#shouldMatch]"() { + expect: + shouldMatch == Pattern.compile(regexPatterns.isoTime()).matcher(textToMatch).matches() + where: + textToMatch || shouldMatch + "12:23:45" || true + "23:59:59" || true + "00:00:00" || true + "00:00:0" || false + "00:0:01" || false + "0:01:01" || false + "24:23:45" || false + "23:60:45" || false + "23:59:60" || false } } 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 4d391393d0..d47984bf41 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 @@ -993,7 +993,10 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub hostname: $(anyHostname()), email: $(anyEmail()), url: $(anyUrl()), - uuid: $(anyUuid()) + uuid: $(anyUuid()), + date: $(anyDate()), + dateTime: $(anyDateTime()), + time: $(anyTime()) ]) headers { contentType(applicationJson()) @@ -1009,7 +1012,10 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub hostname: $(anyHostname()), email: $(anyEmail()), url: $(anyUrl()), - uuid: $(anyUuid()) + uuid: $(anyUuid()), + date: $(anyDate()), + dateTime: $(anyDateTime()), + time: $(anyTime()) ]) headers { contentType(applicationJson()) @@ -1030,6 +1036,9 @@ class JaxRsClientMethodBuilderSpec extends Specification implements WireMockStub test.contains('assertThatJson(parsedJson).field("email").matches("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,4}")') test.contains('assertThatJson(parsedJson).field("ip").matches("([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])")') test.contains('assertThatJson(parsedJson).field("uuid").matches("[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}")') + test.contains('assertThatJson(parsedJson).field("date").matches("(\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])")') + test.contains('assertThatJson(parsedJson).field("dateTime").matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') + test.contains('assertThatJson(parsedJson).field("time").matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') !test.contains('cursor') and: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) 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 5de43ecaa9..38bc4a7b83 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 @@ -1897,7 +1897,7 @@ World.'''""" @Issue('#149') @Unroll - def "should allow easier way of providing dynamic values"() { + def "should allow easier way of providing dynamic values for [#methodBuilderName]"() { given: Contract contractDsl = Contract.make { request { @@ -1912,7 +1912,10 @@ World.'''""" hostname: $(anyHostname()), email: $(anyEmail()), url: $(anyUrl()), - uuid: $(anyUuid()) + uuid: $(anyUuid()), + date: $(anyDate()), + dateTime: $(anyDateTime()), + time: $(anyTime()) ]) headers { contentType(applicationJson()) @@ -1928,7 +1931,10 @@ World.'''""" hostname: $(anyHostname()), email: $(anyEmail()), url: $(anyUrl()), - uuid: $(anyUuid()) + uuid: $(anyUuid()), + date: $(anyDate()), + dateTime: $(anyDateTime()), + time: $(anyTime()) ]) headers { contentType(applicationJson()) @@ -1949,6 +1955,9 @@ World.'''""" test.contains('assertThatJson(parsedJson).field("email").matches("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\\\.[a-zA-Z]{2,4}")') test.contains('assertThatJson(parsedJson).field("ip").matches("([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])")') test.contains('assertThatJson(parsedJson).field("uuid").matches("[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}")') + test.contains('assertThatJson(parsedJson).field("date").matches("(\\\\d\\\\d\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])') + test.contains('assertThatJson(parsedJson).field("dateTime").matches("([0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])') + test.contains('assertThatJson(parsedJson).field("time").matches("(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])")') !test.contains('cursor') and: SyntaxChecker.tryToCompile(methodBuilderName, blockBuilder.toString()) From 2d0d06b6f6dcbd5b0cf61777610b86fb0c023c7f Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Mon, 9 Jan 2017 10:48:59 +0100 Subject: [PATCH 2/2] Added snapshot repos --- .../pom.xml | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml index 5950f8971a..4abd92dbf9 100644 --- a/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml +++ b/spring-cloud-contract-tools/spring-cloud-contract-maven-plugin/pom.xml @@ -372,4 +372,63 @@ + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/libs-snapshot-local + + true + + + false + + + + spring-milestones + Spring Milestones + https://repo.spring.io/libs-milestone-local + + false + + + + spring-releases + Spring Releases + https://repo.spring.io/release + + false + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/libs-snapshot-local + + true + + + false + + + + spring-milestones + Spring Milestones + https://repo.spring.io/libs-milestone-local + + false + + + + spring-releases + Spring Releases + https://repo.spring.io/libs-release-local + + false + + + +