Skip to content

Commit

Permalink
Plus or minus for zoned date time draft (#8) (#3785)
Browse files Browse the repository at this point in the history
complete implementation of #3747

Co-authored-by: Sam <sam@sksamuel.com>
  • Loading branch information
AlexCue987 and sksamuel committed Nov 18, 2023
1 parent 23c09ac commit 99061c1
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1087,9 +1087,21 @@ public final class io/kotest/matchers/date/TimestampKt {
public static final fun shouldNotBeBetween (Ljava/sql/Timestamp;Ljava/sql/Timestamp;Ljava/sql/Timestamp;)V
}

public final class io/kotest/matchers/date/ZonedDateTimeToleranceMatcher : io/kotest/matchers/Matcher {
public synthetic fun <init> (Ljava/time/ZonedDateTime;JLkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun compose (Lkotlin/jvm/functions/Function1;)Lio/kotest/matchers/Matcher;
public fun contramap (Lkotlin/jvm/functions/Function1;)Lio/kotest/matchers/Matcher;
public fun invert ()Lio/kotest/matchers/Matcher;
public fun invertIf (Lio/kotest/matchers/Matcher;Z)Lio/kotest/matchers/Matcher;
public final fun plusOrMinus-LRDsOJo (J)Lio/kotest/matchers/date/ZonedDateTimeToleranceMatcher;
public synthetic fun test (Ljava/lang/Object;)Lio/kotest/matchers/MatcherResult;
public fun test (Ljava/time/ZonedDateTime;)Lio/kotest/matchers/MatcherResult;
}

public final class io/kotest/matchers/date/ZoneddatetimeKt {
public static final fun atSameZone (Ljava/time/ZonedDateTime;)Lio/kotest/matchers/Matcher;
public static final fun beInTodayZDT ()Lio/kotest/matchers/Matcher;
public static final fun plusOrMinus-HG0u8IE (Ljava/time/ZonedDateTime;J)Lio/kotest/matchers/date/ZonedDateTimeToleranceMatcher;
public static final fun shouldBeToday (Ljava/time/ZonedDateTime;)V
public static final fun shouldNotBeToday (Ljava/time/ZonedDateTime;)V
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import io.kotest.matchers.MatcherResult
import io.kotest.matchers.equalityMatcher
import io.kotest.matchers.should
import io.kotest.matchers.shouldNot
import java.time.OffsetDateTime
import java.time.ZonedDateTime
import kotlin.time.Duration

fun beInTodayZDT() = object : Matcher<ZonedDateTime> {
override fun test(value: ZonedDateTime): MatcherResult {
Expand Down Expand Up @@ -49,3 +51,29 @@ fun ZonedDateTime.shouldBeToday() = this should beInTodayZDT()
fun ZonedDateTime.atSameZone() = object : Matcher<ZonedDateTime> {
override fun test(value: ZonedDateTime): MatcherResult = equalityMatcher(withZoneSameInstant(value.zone)).test(value)
}


infix fun ZonedDateTime.plusOrMinus(tolerance: Duration): ZonedDateTimeToleranceMatcher =
ZonedDateTimeToleranceMatcher(this, tolerance)

class ZonedDateTimeToleranceMatcher(
private val expected: ZonedDateTime,
private val tolerance: Duration
): Matcher<ZonedDateTime> {
override fun test(value: ZonedDateTime): MatcherResult {
val positiveTolerance = tolerance.absoluteValue
val lowerBound = expected.minusNanos(positiveTolerance.inWholeNanoseconds)
val upperBound = expected.plusNanos(positiveTolerance.inWholeNanoseconds)
val valueAsInstant = value.toInstant()
val insideToleranceInterval = (lowerBound.toInstant() <= valueAsInstant) && (valueAsInstant <= upperBound.toInstant())
return MatcherResult(
insideToleranceInterval,
{ "$value should be equal to $expected with tolerance $tolerance (between $lowerBound and $upperBound)" },
{ "$value should not be equal to $expected with tolerance $tolerance (not between $lowerBound and $upperBound)" }
)
}

infix fun plusOrMinus(tolerance: Duration): ZonedDateTimeToleranceMatcher =
ZonedDateTimeToleranceMatcher(expected, tolerance)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package com.sksamuel.kotest.matchers.date

import io.kotest.assertions.throwables.shouldThrowAny
import io.kotest.core.spec.style.WordSpec
import io.kotest.matchers.date.and
import io.kotest.matchers.date.plusOrMinus
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import java.time.ZoneId
import java.time.ZonedDateTime
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds

class ZonedDateTimeToleranceMatcherTest : WordSpec() {
private val chicagoTimeZone = ZoneId.of("America/Chicago")
private val newYorkTimeZone = ZoneId.of("America/New_York")

init {
"shouldBe" should {
"mismatch below lower bound, same offset" {
shouldThrowAny {
ZonedDateTime.of(2023, 11, 14, 0, 59, 0, 0, chicagoTimeZone) shouldBe
(ZonedDateTime.of(2023, 11, 14, 1, 30, 0, 0, chicagoTimeZone) plusOrMinus 30.minutes)
}.message shouldBe "2023-11-14T00:59-06:00[America/Chicago] should be equal to 2023-11-14T01:30-06:00[America/Chicago] with tolerance 30m (between 2023-11-14T01:00-06:00[America/Chicago] and 2023-11-14T02:00-06:00[America/Chicago])"
}

"mismatch below lower bound, another offset" {
shouldThrowAny {
ZonedDateTime.of(2023, 11, 14, 0, 59, 0, 0, chicagoTimeZone) shouldBe
(ZonedDateTime.of(2023, 11, 14, 0, 30, 0, 0, newYorkTimeZone) plusOrMinus 30.minutes)
}.message shouldBe "2023-11-14T00:59-06:00[America/Chicago] should be equal to 2023-11-14T00:30-05:00[America/New_York] with tolerance 30m (between 2023-11-14T00:00-05:00[America/New_York] and 2023-11-14T01:00-05:00[America/New_York])"
}

"match exactly on lower bound" {
ZonedDateTime.of(2023, 11, 14, 1, 1, 0, 0, chicagoTimeZone) shouldBe
(ZonedDateTime.of(2023, 11, 14, 1, 31, 0, 0, chicagoTimeZone) plusOrMinus 30.minutes)
}

"match inside tolerance interval, same offset" {
ZonedDateTime.of(2023, 11, 14, 1, 2, 0, 0, chicagoTimeZone) shouldBe
(ZonedDateTime.of(2023, 11, 14, 1, 30, 0, 0, chicagoTimeZone) plusOrMinus (30.minutes and 30.seconds))
}

"match inside tolerance interval, another offset" {
ZonedDateTime.of(2023, 11, 14, 1, 2, 0, 0, chicagoTimeZone) shouldBe
(ZonedDateTime.of(2023, 11, 14, 2, 30, 0, 0, newYorkTimeZone) plusOrMinus (30.minutes and 30.seconds))
}

"match exactly on upper bound" {
ZonedDateTime.of(2023, 11, 14, 2, 1, 0, 0, chicagoTimeZone) shouldBe
(ZonedDateTime.of(2023, 11, 14, 1, 31, 0, 0, chicagoTimeZone) plusOrMinus 30.minutes)
}

"mismatch above upper bound, same offset" {
shouldThrowAny {
ZonedDateTime.of(2023, 11, 14, 2, 1, 0, 0, chicagoTimeZone) shouldBe
(ZonedDateTime.of(2023, 11, 14, 1, 30, 0, 0, chicagoTimeZone) plusOrMinus 30.minutes)
}.message shouldBe "2023-11-14T02:01-06:00[America/Chicago] should be equal to 2023-11-14T01:30-06:00[America/Chicago] with tolerance 30m (between 2023-11-14T01:00-06:00[America/Chicago] and 2023-11-14T02:00-06:00[America/Chicago])"
}

"mismatch above upper bound, another offset" {
shouldThrowAny {
ZonedDateTime.of(2023, 11, 14, 2, 1, 0, 0, chicagoTimeZone) shouldBe
(ZonedDateTime.of(2023, 11, 14, 0, 30, 0, 0, newYorkTimeZone) plusOrMinus 30.minutes)
}.message shouldBe "2023-11-14T02:01-06:00[America/Chicago] should be equal to 2023-11-14T00:30-05:00[America/New_York] with tolerance 30m (between 2023-11-14T00:00-05:00[America/New_York] and 2023-11-14T01:00-05:00[America/New_York])"
}

"handle negative duration" {
ZonedDateTime.of(2023, 11, 14, 2, 1, 0, 0, chicagoTimeZone) shouldBe
(ZonedDateTime.of(2023, 11, 14, 1, 31, 0, 0, chicagoTimeZone) plusOrMinus (-30.minutes))
}

"handle duration with multiple components" {
ZonedDateTime.of(2023, 11, 14, 1, 29, 30, 0, chicagoTimeZone) shouldBe
(ZonedDateTime.of(2023, 11, 14, 1, 31, 0, 0, chicagoTimeZone) plusOrMinus (1.minutes and 30.seconds))
}
}

"shouldNot" should {
"match below lower bound, same offset" {
ZonedDateTime.of(2023, 11, 14, 0, 59, 0, 0, chicagoTimeZone) shouldNotBe
(ZonedDateTime.of(2023, 11, 14, 1, 30, 0, 0, chicagoTimeZone) plusOrMinus 30.minutes)
}

"match below lower bound, another offset" {
ZonedDateTime.of(2023, 11, 14, 0, 59, 0, 0, chicagoTimeZone) shouldNotBe
(ZonedDateTime.of(2023, 11, 14, 2, 30, 0, 0, newYorkTimeZone) plusOrMinus 30.minutes)
}

"mismatch exactly on lower bound" {
shouldThrowAny {
ZonedDateTime.of(2023, 11, 14, 1, 1, 0, 0, chicagoTimeZone) shouldNotBe
(ZonedDateTime.of(2023, 11, 14, 1, 31, 0, 0, chicagoTimeZone) plusOrMinus 30.minutes)
}.message shouldBe "2023-11-14T01:01-06:00[America/Chicago] should not be equal to 2023-11-14T01:31-06:00[America/Chicago] with tolerance 30m (not between 2023-11-14T01:01-06:00[America/Chicago] and 2023-11-14T02:01-06:00[America/Chicago])"
}

"mismatch inside tolerance interval, same offset" {
shouldThrowAny {
ZonedDateTime.of(2023, 11, 14, 1, 2, 0, 0, chicagoTimeZone) shouldNotBe
(ZonedDateTime.of(2023, 11, 14, 1, 30, 0, 0, chicagoTimeZone) plusOrMinus 30.minutes)
}.message shouldBe "2023-11-14T01:02-06:00[America/Chicago] should not be equal to 2023-11-14T01:30-06:00[America/Chicago] with tolerance 30m (not between 2023-11-14T01:00-06:00[America/Chicago] and 2023-11-14T02:00-06:00[America/Chicago])"
}

"mismatch inside tolerance interval, another offset" {
shouldThrowAny {
ZonedDateTime.of(2023, 11, 14, 1, 31, 0, 0, chicagoTimeZone) shouldNotBe
(ZonedDateTime.of(2023, 11, 14, 2, 30, 0, 0, newYorkTimeZone) plusOrMinus 2.minutes)
}.message shouldBe "2023-11-14T01:31-06:00[America/Chicago] should not be equal to 2023-11-14T02:30-05:00[America/New_York] with tolerance 2m (not between 2023-11-14T02:28-05:00[America/New_York] and 2023-11-14T02:32-05:00[America/New_York])"
}

"mismatch exactly on upper bound" {
shouldThrowAny {
ZonedDateTime.of(2023, 11, 14, 2, 1, 0, 0, chicagoTimeZone) shouldNotBe
(ZonedDateTime.of(2023, 11, 14, 1, 31, 0, 0, chicagoTimeZone) plusOrMinus 30.minutes)
}.message shouldBe "2023-11-14T02:01-06:00[America/Chicago] should not be equal to 2023-11-14T01:31-06:00[America/Chicago] with tolerance 30m (not between 2023-11-14T01:01-06:00[America/Chicago] and 2023-11-14T02:01-06:00[America/Chicago])"
}

"match above upper bound" {
ZonedDateTime.of(2023, 11, 14, 2, 1, 0, 0, chicagoTimeZone) shouldNotBe
(ZonedDateTime.of(2023, 11, 14, 1, 30, 0, 0, chicagoTimeZone) plusOrMinus 30.minutes)
}
}
}
}

0 comments on commit 99061c1

Please sign in to comment.