Skip to content

Commit

Permalink
fix: generalize function calculating normalized distance between date…
Browse files Browse the repository at this point in the history
…/time values (#2543)
  • Loading branch information
papiomytoglou authored Feb 9, 2024
1 parent c01ef7d commit db70771
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2022 Thomas Akehurst
* Copyright (C) 2021-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,6 +22,8 @@

public abstract class AbstractDateTimeMatchResult extends MatchResult {

private static final long ONE_YEAR_IN_MILLIS = 365 * 24 * 60 * 60 * 1000L;

private final boolean isZoned;
private final boolean isLocal;

Expand Down Expand Up @@ -83,8 +85,7 @@ public double getDistance() {
}

private double calculateDistance(Temporal start, Temporal end) {
double distance = ((double) ChronoUnit.YEARS.between(start, end)) / 100;
distance = Math.abs(distance);
return Math.min(distance, 1.0);
long absoluteTimeDifference = Math.abs((ChronoUnit.MILLIS.between(start, end)));
return (double) absoluteTimeDifference / (absoluteTimeDifference + 2 * ONE_YEAR_IN_MILLIS);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2023 Thomas Akehurst
* Copyright (C) 2021-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,7 +17,10 @@

import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.jupiter.api.Assertions.*;

import com.github.tomakehurst.wiremock.client.WireMock;
Expand Down Expand Up @@ -97,10 +100,14 @@ public void doesNotMatchWhenActualValueIsNull() {
@Test
public void returnsAReasonableDistanceWhenNoMatchForLocalExpectedZonedActual() {
StringValuePattern matcher = WireMock.after("2021-01-01T00:00:00Z");
assertThat(matcher.match("1971-01-01T00:00:00Z").getDistance(), is(0.5));
assertThat(matcher.match("1921-01-01T00:00:00Z").getDistance(), is(1.0));
assertThat(matcher.match("2023-01-01T00:00:00Z").getDistance(), is(0.5));
assertThat(
matcher.match("1921-01-01T00:00:00Z").getDistance(),
allOf(greaterThan(0.5), lessThan(1.0)));
assertThat(matcher.match(null).getDistance(), is(1.0));
assertThat(matcher.match("2020-01-01T00:00:00Z").getDistance(), is(0.01));
assertThat(
matcher.match("2020-01-01T00:00:00Z").getDistance(),
allOf(greaterThan(0.0), lessThan(0.5)));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2023 Thomas Akehurst
* Copyright (C) 2021-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,7 +18,10 @@
import static com.github.tomakehurst.wiremock.common.DateTimeTruncation.*;
import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.*;

Expand Down Expand Up @@ -87,28 +90,38 @@ public void doesNotMatchWhenExpectedValueUnparseable() {
@Test
public void returnsAReasonableDistanceWhenNoMatchForZonedExpectedZonedActual() {
StringValuePattern matcher = WireMock.before("2021-01-01T00:00:00Z");
assertThat(matcher.match("2071-01-01T00:00:00Z").getDistance(), is(0.5));
assertThat(matcher.match("2121-01-01T00:00:00Z").getDistance(), is(1.0));
assertThat(matcher.match("2023-01-01T00:00:00Z").getDistance(), is(0.5));
assertThat(
matcher.match("2121-01-01T00:00:00Z").getDistance(),
allOf(greaterThan(0.5), lessThan(1.0)));
assertThat(matcher.match(null).getDistance(), is(1.0));
assertThat(matcher.match("2022-01-01T00:00:00Z").getDistance(), is(0.01));
assertThat(
matcher.match("2022-01-01T00:00:00Z").getDistance(),
allOf(greaterThan(0.0), lessThan(0.5)));
}

@Test
public void returnsAReasonableDistanceWhenNoMatchForLocalExpectedZonedActual() {
StringValuePattern matcher = WireMock.before("2021-01-01T00:00:00");
assertThat(matcher.match("2071-01-01T00:00:00Z").getDistance(), is(0.5));
assertThat(matcher.match("2121-01-01T00:00:00Z").getDistance(), is(1.0));
assertThat(matcher.match("2023-01-01T00:00:00Z").getDistance(), is(0.5));
assertThat(
matcher.match("2121-01-01T00:00:00Z").getDistance(),
allOf(greaterThan(0.5), lessThan(1.0)));
assertThat(matcher.match(null).getDistance(), is(1.0));
assertThat(matcher.match("2022-01-01T00:00:00Z").getDistance(), is(0.01));
assertThat(
matcher.match("2022-01-01T00:00:00Z").getDistance(),
allOf(greaterThan(0.0), lessThan(0.5)));
}

@Test
public void returnsAReasonableDistanceWhenNoMatchForLocalExpectedLocalActual() {
StringValuePattern matcher = WireMock.before("2021-01-01T00:00:00");
assertThat(matcher.match("2071-01-01T00:00:00").getDistance(), is(0.5));
assertThat(matcher.match("2121-01-01T00:00:00").getDistance(), is(1.0));
assertThat(matcher.match("2023-01-01T00:00:00").getDistance(), is(0.5));
assertThat(
matcher.match("2121-01-01T00:00:00").getDistance(), allOf(greaterThan(0.5), lessThan(1.0)));
assertThat(matcher.match(null).getDistance(), is(1.0));
assertThat(matcher.match("2022-01-01T00:00:00").getDistance(), is(0.01));
assertThat(
matcher.match("2022-01-01T00:00:00").getDistance(), allOf(greaterThan(0.0), lessThan(0.5)));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021-2023 Thomas Akehurst
* Copyright (C) 2021-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,7 +19,10 @@
import static java.time.temporal.ChronoUnit.HOURS;
import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.jupiter.api.Assertions.*;

import com.github.tomakehurst.wiremock.client.WireMock;
Expand Down Expand Up @@ -113,10 +116,14 @@ public void doesNotMatchWhenActualValueIsNull() {
@Test
public void returnsAReasonableDistanceWhenNoMatchForLocalExpectedZonedActual() {
StringValuePattern matcher = WireMock.equalToDateTime("2021-01-01T00:00:00Z");
assertThat(matcher.match("2071-01-01T00:00:00Z").getDistance(), is(0.5));
assertThat(matcher.match("2121-01-01T00:00:00Z").getDistance(), is(1.0));
assertThat(matcher.match("2023-01-01T00:00:00Z").getDistance(), is(0.5));
assertThat(
matcher.match("2121-01-01T00:00:00Z").getDistance(),
allOf(greaterThan(0.5), lessThan(1.0)));
assertThat(matcher.match(null).getDistance(), is(1.0));
assertThat(matcher.match("2022-01-01T00:00:00Z").getDistance(), is(0.01));
assertThat(
matcher.match("2022-01-01T00:00:00Z").getDistance(),
allOf(greaterThan(0.0), lessThan(0.5)));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2023 Thomas Akehurst
* Copyright (C) 2016-2024 Thomas Akehurst
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,6 +21,7 @@
import static com.github.tomakehurst.wiremock.http.QueryParameter.queryParam;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.jupiter.api.Assertions.*;

import com.github.tomakehurst.wiremock.common.Json;
Expand All @@ -30,6 +31,20 @@

public class MultiValuePatternTest {

public static final String EXPECTED_DATE_TIME = "2024-01-01T00:00:00.000Z";
public static final String ACTUAL_DATE_TIME_ONE_MILLI_EARLIER = "2023-12-31T23:59:59.999Z";
public static final String ACTUAL_DATE_TIME_ONE_MILLI_LATER = "2024-01-01T00:00:00.001Z";
public static final String ACTUAL_DATE_TIME_TWO_MILLIS_EARLIER = "2023-12-31T23:59:59.998Z";
public static final String ACTUAL_DATE_TIME_TWO_MILLIS_LATER = "2024-01-01T00:00:00.002Z";
public static final String ACTUAL_DATE_TIME_ONE_DAY_EARLIER = "2023-12-31T00:00:00.000Z";
public static final String ACTUAL_DATE_TIME_ONE_DAY_LATER = "2024-01-02T00:00:00.000Z";
public static final String ACTUAL_DATE_TIME_ONE_YEAR_EARLIER = "2023-01-01T00:00:00.000Z";
public static final String ACTUAL_DATE_TIME_ONE_YEAR_LATER = "2025-01-01T00:00:00.000Z";
public static final String ACTUAL_DATE_TIME_ONE_CENTURY_EARLIER = "1924-01-01T00:00:00.000Z";
public static final String ACTUAL_DATE_TIME_ONE_CENTURY_LATER = "2124-01-01T00:00:00.000Z";
public static final String ACTUAL_DATE_TIME_ONE_MILLENIUM_EARLIER = "1024-01-01T00:00:00.000Z";
public static final String ACTUAL_DATE_TIME_ONE_MILLENIUM_LATER = "3024-01-01T00:00:00.000Z";

@Test
public void returnsExactMatchForAbsentHeaderWhenRequiredAbsent() {
assertTrue(MultiValuePattern.absent().match(HttpHeader.absent("any-key")).isExactMatch());
Expand Down Expand Up @@ -74,14 +89,43 @@ public void returnsNonZeroDistanceWhenHeaderValuesAreSimilar() {
}

@Test
public void returnsTheBestMatchWhenSeveralValuesAreAvailableAndNoneAreExact() {
public void returnsTheBestMatchWhenSeveralHeaderValuesAreAvailableAndNoneAreExact() {
assertThat(
MultiValuePattern.of(equalTo("required-value"))
.match(httpHeader("any-key", "require1234567", "requi12345", "1234567rrrr"))
.getDistance(),
is(0.5));
}

@Test
public void returnsTheBestMatchWhenSeveralHeaderDateTimeValuesAreAvailableAndNoneAreExact() {
double distanceOfOneMilliDifference =
MultiValuePattern.of(equalToDateTime(EXPECTED_DATE_TIME))
.match(
httpHeader(
"any-key",
ACTUAL_DATE_TIME_ONE_MILLI_EARLIER,
ACTUAL_DATE_TIME_ONE_MILLI_LATER))
.getDistance();
double distanceOfGreaterThanOneMilliDifference =
MultiValuePattern.of(equalToDateTime(EXPECTED_DATE_TIME))
.match(
httpHeader(
"any-key",
ACTUAL_DATE_TIME_TWO_MILLIS_EARLIER,
ACTUAL_DATE_TIME_TWO_MILLIS_LATER,
ACTUAL_DATE_TIME_ONE_DAY_EARLIER,
ACTUAL_DATE_TIME_ONE_DAY_LATER,
ACTUAL_DATE_TIME_ONE_YEAR_EARLIER,
ACTUAL_DATE_TIME_ONE_YEAR_LATER,
ACTUAL_DATE_TIME_ONE_CENTURY_EARLIER,
ACTUAL_DATE_TIME_ONE_CENTURY_LATER,
ACTUAL_DATE_TIME_ONE_MILLENIUM_EARLIER,
ACTUAL_DATE_TIME_ONE_MILLENIUM_LATER))
.getDistance();
assertThat(distanceOfOneMilliDifference, lessThan(distanceOfGreaterThanOneMilliDifference));
}

@Test
public void returnsTheBestMatchWhenSeveralHeaderValuesAreAvailableAndOneIsExact() {
assertTrue(
Expand All @@ -90,6 +134,29 @@ public void returnsTheBestMatchWhenSeveralHeaderValuesAreAvailableAndOneIsExact(
.isExactMatch());
}

@Test
public void returnsTheBestMatchWhenSeveralHeaderDateTimeValuesAreAvailableAndOneIsExact() {
assertTrue(
MultiValuePattern.of(equalToDateTime(EXPECTED_DATE_TIME))
.match(
httpHeader(
"any-key",
ACTUAL_DATE_TIME_ONE_MILLI_EARLIER,
ACTUAL_DATE_TIME_ONE_MILLI_LATER,
ACTUAL_DATE_TIME_TWO_MILLIS_EARLIER,
ACTUAL_DATE_TIME_TWO_MILLIS_LATER,
ACTUAL_DATE_TIME_ONE_DAY_EARLIER,
ACTUAL_DATE_TIME_ONE_DAY_LATER,
ACTUAL_DATE_TIME_ONE_YEAR_EARLIER,
ACTUAL_DATE_TIME_ONE_YEAR_LATER,
ACTUAL_DATE_TIME_ONE_CENTURY_EARLIER,
ACTUAL_DATE_TIME_ONE_CENTURY_LATER,
ACTUAL_DATE_TIME_ONE_MILLENIUM_EARLIER,
ACTUAL_DATE_TIME_ONE_MILLENIUM_LATER,
EXPECTED_DATE_TIME))
.isExactMatch());
}

@Test
public void returnsTheBestMatchWhenSeveralQueryParamValuesAreAvailableAndOneIsExact() {
assertTrue(
Expand All @@ -101,7 +168,6 @@ public void returnsTheBestMatchWhenSeveralQueryParamValuesAreAvailableAndOneIsEx
@Test
public void correctlyRendersEqualToAsJson() throws Exception {
String actual = Json.write(MultiValuePattern.of(equalTo("something")));
System.out.println(actual);
JSONAssert.assertEquals(
"{ \n" + " \"equalTo\": \"something\" \n" + "}",
actual,
Expand All @@ -111,7 +177,6 @@ public void correctlyRendersEqualToAsJson() throws Exception {
@Test
public void correctlyRendersAbsentAsJson() throws Exception {
String actual = Json.write(MultiValuePattern.absent());
System.out.println(actual);
JSONAssert.assertEquals(
"{ \n" + " \"absent\": true \n" + "}", actual, true);
}
Expand Down

0 comments on commit db70771

Please sign in to comment.