All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kiwiproject.test.mockito.JavaTimeArgumentMatchers Maven / Gradle / Ivy

package org.kiwiproject.test.mockito;

import static org.assertj.core.api.Assertions.assertThat;
import static org.kiwiproject.base.KiwiPreconditions.checkArgumentNotNull;
import static org.kiwiproject.base.KiwiPreconditions.checkPositive;
import static org.kiwiproject.logging.LazyLogParameterSupplier.lazy;

import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.mockito.ArgumentMatcher;

import java.time.Duration;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

/**
 * Static utility methods to create {@link ArgumentMatcher} instances for types in the {@code java.time} package.
 */
@UtilityClass
@Slf4j
public class JavaTimeArgumentMatchers {

    private static final int DEFAULT_SLACK_MILLIS = 500;
    private static final String EXPECTED_TIME_CANNOT_BE_NULL = "expectedTime cannot be null";
    private static final String SLACK_CANNOT_BE_NULL = "slack cannot be null";

    /**
     * Matches an {@link ZonedDateTime} near the given expected time within +/- 500 milliseconds.
     * 

* In other words, the actual time must be in the range {@code [ expectedTime - 500ms , expectedTime + 500ms ]}. *

* Example usage: *

     * // Assume a Timekeeper class contains an announceTime(ZonedDateTime time) method
     * var expectedTime = determineExpectedZonedDateTime();
     * verify(timekeeper).announceTime(argThat(isNear(expectedTime));
     * 
* * @param expectedTime the expected time * @return a new {@link ArgumentMatcher} instance */ public static ArgumentMatcher isNear(ZonedDateTime expectedTime) { return isNear(expectedTime, DEFAULT_SLACK_MILLIS); } /** * Matches an {@link ZonedDateTime} near the given expected time within +/- {@code slack} duration. *

* In other words, the actual time must be in the range {@code [ expectedTime - slack , expectedTime + slack ]}. *

* Example usage: *

     * // Assume a Timekeeper class contains an announceTime(ZonedDateTime time) method
     * var expectedTime = determineExpectedZonedDateTime();
     * var slack = Duration.ofMillis(250)
     * verify(timekeeper).announceTime(argThat(isNear(expectedTime, slack));
     * 
* * @param expectedTime the expected time * @param slack the amount of time the actual time can differ before or after the expected time * @return a new {@link ArgumentMatcher} instance */ public static ArgumentMatcher isNear(ZonedDateTime expectedTime, Duration slack) { checkArgumentNotNull(slack, SLACK_CANNOT_BE_NULL); return isNear(expectedTime, slack.toMillis()); } /** * Matches an {@link ZonedDateTime} near the given expected time within +/- {@code slack} milliseconds. *

* In other words, the actual time must be in the range {@code [ expectedTime - slackMillis , expectedTime + slackMillis ]}. *

     * // Assume a Timekeeper class contains an announceTime(ZonedDateTime time) method
     * var expectedTime = determineExpectedZonedDateTime();
     * var slackMillis = 300;
     * verify(timekeeper).announceTime(argThat(isNear(expectedTime, slackMillis));
     * 
* * @param expectedTime the expected time * @param slackMillis the number of milliseconds the actual time can differ before or after the expected time * @return a new {@link ArgumentMatcher} instance */ public static ArgumentMatcher isNear(ZonedDateTime expectedTime, long slackMillis) { checkArgumentNotNull(expectedTime, EXPECTED_TIME_CANNOT_BE_NULL); checkPositive(slackMillis); return actualTime -> { LOG.trace("expectedTime: {} ; actualTime: {} ; Duration.between(expectedTimeTime, actualTime): {}", expectedTime, actualTime, lazy(() -> Duration.between(expectedTime, actualTime))); var lowerBound = expectedTime.minus(slackMillis, ChronoUnit.MILLIS); var upperBound = expectedTime.plus(slackMillis, ChronoUnit.MILLIS); assertThat(actualTime) .describedAs("actual time %s not between [ %s, %s ]", actualTime, lowerBound, upperBound) .isBetween(lowerBound, upperBound); return true; }; } /** * Matches an {@link Instant} near the given expected time within +/- 500 milliseconds. *

* In other words, the actual time must be in the range {@code [ expectedTime - 500ms , expectedTime + 500ms ]}. *

* Example usage: *

     * // Assume a Timekeeper class contains an announceTime(Instant time) method
     * var expectedInstant = determineExpectedInstant();
     * verify(timekeeper).announceTime(argThat(isNear(expectedInstant));
     * 
* * @param expectedTime the expected time * @return a new {@link ArgumentMatcher} instance */ public static ArgumentMatcher isNear(Instant expectedTime) { return isNear(expectedTime, DEFAULT_SLACK_MILLIS); } /** * Matches an {@link Instant} near the given expected time within +/- {@code slack} duration. *

* In other words, the actual time must be in the range {@code [ expectedTime - slack , expectedTime + slack ]}. *

* Example usage: *

     * // Assume a Timekeeper class contains an announceTime(Instant time) method
     * var expectedInstant = determineExpectedInstant();
     * var slack = Duration.ofMillis(250)
     * verify(timekeeper).announceTime(argThat(isNear(expectedInstant, slack));
     * 
* * @param expectedTime the expected time * @param slack the amount of time the actual time can differ before or after the expected time * @return a new {@link ArgumentMatcher} instance */ public static ArgumentMatcher isNear(Instant expectedTime, Duration slack) { checkArgumentNotNull(slack, SLACK_CANNOT_BE_NULL); return isNear(expectedTime, slack.toMillis()); } /** * Matches an {@link Instant} near the given expected time within +/- {@code slack} milliseconds. *

* In other words, the actual time must be in the range {@code [ expectedTime - slackMillis , expectedTime + slackMillis ]}. *

     * // Assume a Timekeeper class contains an announceTime(Instant time) method
     * var expectedInstant = determineExpectedInstant();
     * var slackMillis = 300;
     * verify(timekeeper).announceTime(argThat(isNear(expectedInstant, slackMillis));
     * 
* * @param expectedTime the expected time * @param slackMillis the number of milliseconds the actual time can differ before or after the expected time * @return a new {@link ArgumentMatcher} instance */ public static ArgumentMatcher isNear(Instant expectedTime, long slackMillis) { checkArgumentNotNull(expectedTime, EXPECTED_TIME_CANNOT_BE_NULL); checkPositive(slackMillis); return actualTime -> { LOG.trace("expectedTime: {} ; actualTime: {} ; Duration.between(expectedTimeTime, actualTime): {}", expectedTime, actualTime, lazy(() -> Duration.between(expectedTime, actualTime))); var lowerBound = expectedTime.minusMillis(slackMillis); var upperBound = expectedTime.plusMillis(slackMillis); assertThat(actualTime) .describedAs("actual time %s not between [ %s, %s ]", actualTime, lowerBound, upperBound) .isBetween(lowerBound, upperBound); return true; }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy