From 2810b0bb8ec58701f0e93268d45142a1846c467c Mon Sep 17 00:00:00 2001 From: anto Date: Fri, 19 Jun 2020 12:55:24 +0100 Subject: [PATCH] fix: backward compatibily with legacy date formats #1007 --- .../pact/core/matchers/MatcherExecutor.kt | 27 +++++++++++----- .../core/matchers/MatcherExecutorSpec.groovy | 32 +++++++++++-------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/core/matchers/src/main/kotlin/au/com/dius/pact/core/matchers/MatcherExecutor.kt b/core/matchers/src/main/kotlin/au/com/dius/pact/core/matchers/MatcherExecutor.kt index 8dbec61e5f..5b1b51a3f4 100755 --- a/core/matchers/src/main/kotlin/au/com/dius/pact/core/matchers/MatcherExecutor.kt +++ b/core/matchers/src/main/kotlin/au/com/dius/pact/core/matchers/MatcherExecutor.kt @@ -341,20 +341,31 @@ fun matchDateTime( } else { var newPattern = pattern try { - /** - Replacing 'Z' with 'X' in order to offer backward compatibility for consumers who might be - using ISO 8601 the UTC designator 'Z' - **/ if (pattern.endsWith('Z')) { newPattern = pattern.replace('Z', 'X') - logger.warn { "Found unsupported UTC designator in pattern '$pattern'. Replacing non quote 'Z's with 'X's" } + logger.warn { + """Found unsupported UTC designator in pattern '$pattern'. Replacing non quote 'Z's with 'X's + This is in order to offer backwards compatibility for consumers using the ISO 8601 UTC designator 'Z' + Please update your patterns in your pact tests as this may not be supported in future versions.""" + } } DateTimeFormatter.ofPattern(newPattern).parse(safeToString(actual)) emptyList() } catch (e: DateTimeParseException) { - listOf(mismatchFactory.create(expected, actual, - "Expected ${valueOf(actual)} to match a datetime of '$newPattern': " + - "${e.message}", path)) + try { + logger.warn { + """Unable to parse ${valueOf(actual)} with $pattern using java.time.format.DateTimeFormatter. + Attempting to parse using org.apache.commons.lang3.time.DateUtils + to guarantee backwards compatibility with versions < 4.1.1. + Please update your patterns in your pact tests as this may not be supported in future versions.""" + } + DateUtils.parseDate(safeToString(actual), pattern) + emptyList() + } catch (e: ParseException) { + listOf(mismatchFactory.create(expected, actual, + "Expected ${valueOf(actual)} to match a datetime of '$pattern': " + + "${e.message}", path)) + } } } } diff --git a/core/matchers/src/test/groovy/au/com/dius/pact/core/matchers/MatcherExecutorSpec.groovy b/core/matchers/src/test/groovy/au/com/dius/pact/core/matchers/MatcherExecutorSpec.groovy index fa9b0965e0..b8e75ccc77 100755 --- a/core/matchers/src/test/groovy/au/com/dius/pact/core/matchers/MatcherExecutorSpec.groovy +++ b/core/matchers/src/test/groovy/au/com/dius/pact/core/matchers/MatcherExecutorSpec.groovy @@ -143,20 +143,24 @@ class MatcherExecutorSpec extends Specification { MatcherExecutorKt.domatch(matcher, path, expected, actual, mismatchFactory).empty == mustBeEmpty where: - expected | actual | pattern || mustBeEmpty - '2014-01-01 14:00:00+10:00' | '2013-12-01 14:00:00+10:00' | null || true - '2014-01-01 14:00:00+10:00' | 'I\'m a timestamp!' | null || false - '2014-01-01 14:00:00+10:00' | '2013#12#01#14#00#00' | "yyyy'#'MM'#'dd'#'HH'#'mm'#'ss" || true - '2014-01-01 14:00:00+10:00' | null | null || false - '2014-01-01T10:00+10:00[Australia/Melbourne]' | '2020-01-01T10:00+01:00[Europe/Warsaw]' | "yyyy-MM-dd'T'HH:mmXXX'['zzz']'" || true - '2019-11-25T13:45:00+02:00' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ssX" || true - '2019-11-25T13:45:00+02:00' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ssZZ" || true - '2019-11-25T13:45:00+02:00' | '2019-11-25T11:45Z' | "yyyy-MM-dd'T'HH:mmZZ" || true - '2019-11-25T13:45:00+02:00' | '2019-11-25T11Z' | "yyyy-MM-dd'T'HHZZ" || true - '2019-11-25T13:45:00+0200' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ssZ" || true - '2019-11-25T13:45:00+0200' | '2019-11-25T11:45Z' | "yyyy-MM-dd'T'HH:mmZ" || true - '2019-11-25T13:45:00+0200' | '2019-11-25T11Z' | "yyyy-MM-dd'T'HHZ" || true - '2019-11-25T13:45:00+0200' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ss'Z'" || true + expected | actual | pattern || mustBeEmpty + '2014-01-01 14:00:00+10:00' | '2013-12-01 14:00:00+10:00' | null || true + '2014-01-01 14:00:00+10:00' | 'I\'m a timestamp!' | null || false + '2014-01-01 14:00:00+10:00' | '2013#12#01#14#00#00' | "yyyy'#'MM'#'dd'#'HH'#'mm'#'ss" || true + '2014-01-01 14:00:00+10:00' | null | null || false + '2014-01-01T10:00+10:00[Australia/Melbourne]' | '2020-01-01T10:00+01:00[Europe/Warsaw]' | "yyyy-MM-dd'T'HH:mmXXX'['zzz']'" || true + '2019-11-25T13:45:00+02:00' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ssX" || true + '2019-11-25T13:45:00+02:00' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ssZZ" || true + '2019-11-25T13:45:00+02:00' | '2019-11-25T11:45Z' | "yyyy-MM-dd'T'HH:mmZZ" || true + '2019-11-25T13:45:00+02:00' | '2019-11-25T11Z' | "yyyy-MM-dd'T'HHZZ" || true + '2019-11-25T13:45:00+0200' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ssZ" || true + '2019-11-25T13:45:00+0200' | '2019-11-25T11:45Z' | "yyyy-MM-dd'T'HH:mmZ" || true + '2019-11-25T13:45:00+0200' | '2019-11-25T11Z' | "yyyy-MM-dd'T'HHZ" || true + '2019-11-25T13:45:00+0200' | '2019-11-25T11:45:00Z' | "yyyy-MM-dd'T'HH:mm:ss'Z'" || true + '2019-11-25T13:45:00:000000+0200' | '2019-11-25T11:19:00.000000Z' | "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'" || true + '2019-11-25T13:45:00:000+0200' | '2019-11-25T11:19:00.000Z' | "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" || true +// This is in order to keep backwards compatibility with version < 4.1.1 + '2019-11-25T13:45:00:000000+0200' | '2019-11-25T11:19:00.000000Z' | "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" || true matcher = pattern ? new TimestampMatcher(pattern) : new TimestampMatcher() }