Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

481 accept date and time as string in ISO 8601 format for ChronoLocalDateTime 2 #552

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
e78f254
#481 added String parameter instead of a ChronoLocalDateTime
rkiselev Jul 5, 2020
dc044f5
#481 moved implementation after review.
rkiselev Jul 12, 2020
902194e
Merge branch 'master' into #481-chrono-local-date-time
rkiselev Jul 12, 2020
c43e808
#481 fixed error on MR
rkiselev Jul 12, 2020
b0fd9df
Update logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic…
robstoll Jul 13, 2020
5571d9a
Update logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic…
robstoll Jul 13, 2020
2db85bd
Update logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic…
robstoll Jul 13, 2020
b1b7580
Update logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic…
robstoll Jul 13, 2020
5e646ee
Update logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic…
robstoll Jul 13, 2020
0a743da
#481 added Companion implementation
rkiselev Jul 26, 2020
5b0a2d1
Merge branch '#481-ChronoLocalDateTime-as-string' into #481-chrono-lo…
rkiselev Jul 26, 2020
19e5e32
#481 added Companion implementation
rkiselev Jul 26, 2020
054f718
#481 added Companion implementation
rkiselev Jul 26, 2020
ef88590
#481 fixed types problem, extended KDoc
rkiselev Aug 8, 2020
71bf82a
#481 tests
rkiselev Aug 8, 2020
5baf43a
Merge branch '#481-ChronoLocalDateTime-as-string-v2' into #481-chrono…
rkiselev Aug 8, 2020
f9821be
#481 removed run, replaced map by list, clarified comments.
Aug 19, 2020
19ba491
481 removed run, replaced map by list, clarified comments.
rkiselev Aug 19, 2020
2506df6
Merge remote-tracking branch 'origin/#481-chrono-local-date-time' int…
Aug 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,103 @@ fun <T : ChronoLocalDateTime<out ChronoLocalDate>> Expect<T>.isAfterOrEqual(
fun <T : ChronoLocalDateTime<out ChronoLocalDate>> Expect<T>.isEqual(
expected: ChronoLocalDateTime<*>
): Expect<T> = _logicAppend { isEqual(expected) }

/**
* Expects that the subject of the assertion (a [ChronoLocalDateTime])
* is before the [expected] [LocalDateTime] given as [String] in (modified) ISO 8601 format.
* The string will be converted to a LocalDateTime according to ISO 8601 but with a slight deviation.
* The alternative notation (e.g. 20200401120001 instead of 2020-04-01T12:00:01) is not supported and we accept a
* date without time in which case 00:00:00 is used. Following the supported formats from the longest to the shortest:
* yyyy-mm-ddThh:mm:ss.sss (up to 9 digits for nanoseconds)
* yyyy-mm-ddThh:mm:ss
* yyyy-mm-ddThh:mm
* yyyy-mm-dd
*
* @return An [Expect] for the current subject of the assertion.
* @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct.
*
* @since 0.13.0
*/
fun <T : ChronoLocalDateTime<out ChronoLocalDate>> Expect<T>.isBefore(
expected: String
): Expect<T> = _logicAppend { isBefore(expected) }

/**
* Expects that the subject of the assertion (a [ChronoLocalDateTime])
* is before the [expected] [LocalDateTime] given as [String] in (modified) ISO 8601 format.
* The string will be converted to a LocalDateTime according to ISO 8601 but with a slight deviation.
* The alternative notation (e.g. 20200401120001 instead of 2020-04-01T12:00:01) is not supported and we accept a
* date without time in which case 00:00:00 is used. Following the supported formats from the longest to the shortest:
* yyyy-mm-ddThh:mm:ss.sss (up to 9 digits for nanoseconds)
* yyyy-mm-ddThh:mm:ss
* yyyy-mm-ddThh:mm
* yyyy-mm-dd
*
* @return An [Expect] for the current subject of the assertion.
* @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct.
*
* @since 0.13.0
*/
fun <T : ChronoLocalDateTime<out ChronoLocalDate>> Expect<T>.isBeforeOrEqual(
expected: String
): Expect<T> = _logicAppend { isBeforeOrEqual(expected) }

/**
* Expects that the subject of the assertion (a [ChronoLocalDateTime])
* is before the [expected] [LocalDateTime] given as [String] in (modified) ISO 8601 format.
* The string will be converted to a LocalDateTime according to ISO 8601 but with a slight deviation.
* The alternative notation (e.g. 20200401120001 instead of 2020-04-01T12:00:01) is not supported and we accept a date
* without time in which case 00:00:00 is used. Following the supported formats from the longest to the shortest:
* yyyy-mm-ddThh:mm:ss.sss (up to 9 digits for nanoseconds)
* yyyy-mm-ddThh:mm:ss
* yyyy-mm-ddThh:mm
* yyyy-mm-dd
*
* @return An [Expect] for the current subject of the assertion.
* @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct.
*
* @since 0.13.0
*/
fun <T : ChronoLocalDateTime<out ChronoLocalDate>> Expect<T>.isAfter(
expected: String
): Expect<T> = _logicAppend { isAfter(expected) }

/**
* Expects that the subject of the assertion (a [ChronoLocalDateTime])
* is before the [expected] [LocalDateTime] given as [String] in (modified) ISO 8601 format.
* The string will be converted to a LocalDateTime according to ISO 8601 but with a slight deviation.
* The alternative notation (e.g. 20200401120001 instead of 2020-04-01T12:00:01) is not supported and we accept a date
* without time in which case 00:00:00 is used. Following the supported formats from the longest to the shortest:
* yyyy-mm-ddThh:mm:ss.sss (up to 9 digits for nanoseconds)
* yyyy-mm-ddThh:mm:ss
* yyyy-mm-ddThh:mm
* yyyy-mm-dd
*
* @return An [Expect] for the current subject of the assertion.
* @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct.
*
* @since 0.13.0
*/
fun <T : ChronoLocalDateTime<out ChronoLocalDate>> Expect<T>.isAfterOrEqual(
expected: String
): Expect<T> = _logicAppend { isAfterOrEqual(expected) }

/**
* Expects that the subject of the assertion (a [ChronoLocalDateTime])
* is before the [expected] [LocalDateTime] given as [String] in (modified) ISO 8601 format.
* The string will be converted to a LocalDateTime according to ISO 8601 but with a slight deviation.
* The alternative notation (e.g. 20200401120001 instead of 2020-04-01T12:00:01) is not supported and we accept a date
* without time in which case 00:00:00 is used. Following the supported formats from the longest to the shortest:
* yyyy-mm-ddThh:mm:ss.sss (up to 9 digits for nanoseconds)
* yyyy-mm-ddThh:mm:ss
* yyyy-mm-ddThh:mm
* yyyy-mm-dd
*
* @return An [Expect] for the current subject of the assertion.
* @throws AssertionError Might throw an [AssertionError] if the assertion made is not correct.
*
* @since 0.13.0
*/
fun <T : ChronoLocalDateTime<out ChronoLocalDate>> Expect<T>.isEqual(
expected: String
): Expect<T> = _logicAppend { isEqual(expected) }
Original file line number Diff line number Diff line change
@@ -1,46 +1,179 @@
package ch.tutteli.atrium.api.fluent.en_GB

import ch.tutteli.atrium.api.verbs.internal.expect
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.reporting.AtriumError
import ch.tutteli.atrium.specs.fun1
import ch.tutteli.atrium.specs.notImplemented
import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.chrono.ChronoLocalDate
import java.time.chrono.ChronoLocalDateTime
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeFormatter.ISO_DATE_TIME
import java.time.format.DateTimeParseException

class ChronoLocalDateTimeAssertionSpec : Spek({
include(ChronoLocalDateTimeSpec)
include(StringSpec)
listOf(
"20200101010101111",
"20200101010101",
"202001010101",
"2020010101",
"2020-1-01T01:01",
"2020-01-1T01:01",
"20-01-01T01:01" ,
"2020-01-01T1:01",
"2020-01-01T01:1",
"2020-01-01T01:01:1",
"2020-01-01t01:01:01"
).forEach{ value ->
val now = expect(LocalDateTime.now())
describe("wrong string format") {
it("isBefore throws an DateTimeParseException") {
expect {
now.isBefore(value)
}.toThrow<DateTimeParseException> { messageContains("could not be parsed") }
}
it("isBeforeOrEqual throws an DateTimeParseException") {
expect {
now.isBeforeOrEqual(value)
}.toThrow<DateTimeParseException> { messageContains("could not be parsed") }
}
it("isAfter throws an DateTimeParseException") {
expect {
now.isAfter(value)
}.toThrow<DateTimeParseException> { messageContains("could not be parsed") }
}
it("isAfterOrEqual throws an DateTimeParseException") {
expect {
now.isAfterOrEqual(value)
}.toThrow<DateTimeParseException> { messageContains("could not be parsed") }
}
it("isEqual throws an DateTimeParseException") {
expect {
now.isEqual(value)
}.toThrow<DateTimeParseException> { messageContains("could not be parsed") }
}
}
}

listOf(
"2020-01-01T01:01:01",
"2020-01-01T01:01",
"2020-01-01"
).forEach{value ->
val nowLocalDateTime = LocalDateTime.now()
val now = expect(nowLocalDateTime)
val before = LocalDateTime.now()
describe("allowed shortcuts") {
it("isBefore throws an AtriumError") {
expect {
now.isBefore(value)
}.toThrow<AtriumError> { messageContains("is before: $value") }
}
it("isBefore doesn't throw any Error") {
expect {
now.isBefore(before.format(ISO_DATE_TIME))
}.notToThrow()
}
it("isBeforeOrEqual doesn't throw any Error") {
expect {
now.isBeforeOrEqual(nowLocalDateTime.format(ISO_DATE_TIME))
}.notToThrow()
}
it("isBeforeOrEqual throws an AtriumError") {
expect {
now.isBeforeOrEqual(value)
}.toThrow<AtriumError> { messageContains("is before or equal: $value") }
}
it("isAfter doesn't throw any Error") {
expect {
now.isAfter(value)
}.notToThrow()
}
it("isAfter throws an AtriumError") {
expect {
now.isAfter(before.format(ISO_DATE_TIME))
}.toThrow<AtriumError> { messageContains("is after: ${before.format(ISO_DATE_TIME)}") }
}
it("isAfterOrEqual doesn't throw any Error") {
expect {
now.isAfterOrEqual(nowLocalDateTime.format(ISO_DATE_TIME))
}.notToThrow()
}
it("isAfterOrEqual doesn't throw any Error") {
expect {
now.isAfterOrEqual(value)
}.notToThrow()
}
it("isAfterOrEqual throws an AtriumError") {
expect {
now.isAfterOrEqual(before.format(ISO_DATE_TIME))
}.toThrow<AtriumError> { messageContains("is after or equal: ${before.format(ISO_DATE_TIME)}") }
}
it("isEqual throws an AtriumError") {
expect {
now.isEqual(value)
}.toThrow<AtriumError> { messageContains("is equal to: $value") }
}
it("isEqual doesn't throw any error") {
expect {
now.isEqual(nowLocalDateTime.format(ISO_DATE_TIME))
}.notToThrow()
}
}
}
}) {
object ChronoLocalDateTimeSpec : ch.tutteli.atrium.specs.integration.ChronoLocalDateTimeAssertionSpec(
fun1(Expect<ChronoLocalDateTime<*>>::isBefore),
fun1(Expect<ChronoLocalDateTime<*>>::isBeforeOrEqual),
fun1(Expect<ChronoLocalDateTime<*>>::isAfter),
fun1(Expect<ChronoLocalDateTime<*>>::isAfterOrEqual),
fun1(Expect<ChronoLocalDateTime<*>>::isEqual)
fun1<ChronoLocalDateTime<*>, ChronoLocalDateTime<*>>(Expect<ChronoLocalDateTime<*>>::isBefore),
fun1<ChronoLocalDateTime<*>, ChronoLocalDateTime<*>>(Expect<ChronoLocalDateTime<*>>::isBeforeOrEqual),
fun1<ChronoLocalDateTime<*>, ChronoLocalDateTime<*>>(Expect<ChronoLocalDateTime<*>>::isAfter),
fun1<ChronoLocalDateTime<*>, ChronoLocalDateTime<*>>(Expect<ChronoLocalDateTime<*>>::isAfterOrEqual),
fun1<ChronoLocalDateTime<*>, ChronoLocalDateTime<*>>(Expect<ChronoLocalDateTime<*>>::isEqual)
)

object StringSpec : ch.tutteli.atrium.specs.integration.ChronoLocalDateTimeAssertionSpec(
fun1(Companion::isBefore),
//TODO #481 introduce more companions
fun1(Expect<ChronoLocalDateTime<*>>::isBeforeOrEqual),
fun1(Expect<ChronoLocalDateTime<*>>::isAfter),
fun1(Expect<ChronoLocalDateTime<*>>::isAfterOrEqual),
fun1(Expect<ChronoLocalDateTime<*>>::isEqual)
fun1(Companion::isBeforeOrEqual),
fun1(Companion::isAfter),
fun1(Companion::isAfterOrEqual),
fun1(Companion::isEqual)
)

companion object {
fun isBefore(
expect: Expect<ChronoLocalDateTime<*>>,
expected: ChronoLocalDateTime<*>
): Expect<ChronoLocalDateTime<*>> =
//TODO #481 turn into string in ISO format
//expect.isBefore(expected.format(DateTimeFormatter.ISO_DATE_TIME))
expect.isBefore(expected)
}
expect.isBefore(expected.format(ISO_DATE_TIME))

fun isBeforeOrEqual(
expect: Expect<ChronoLocalDateTime<*>>,
expected: ChronoLocalDateTime<*>
): Expect<ChronoLocalDateTime<*>> =
expect.isBeforeOrEqual(expected.format(ISO_DATE_TIME))

fun isAfter(
expect: Expect<ChronoLocalDateTime<*>>,
expected: ChronoLocalDateTime<*>
): Expect<ChronoLocalDateTime<*>> =
expect.isAfter(expected.format(ISO_DATE_TIME))

fun isAfterOrEqual(
expect: Expect<ChronoLocalDateTime<*>>,
expected: ChronoLocalDateTime<*>
): Expect<ChronoLocalDateTime<*>> =
expect.isAfterOrEqual(expected.format(ISO_DATE_TIME))

fun isEqual(
expect: Expect<ChronoLocalDateTime<*>>,
expected: ChronoLocalDateTime<*>
): Expect<ChronoLocalDateTime<*>> =
expect.isEqual(expected.format(ISO_DATE_TIME))
}

@Suppress("unused", "UNUSED_VALUE")
private fun ambiguityTest() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.creating.ChronoLocalDateTimeAssertions
import ch.tutteli.atrium.domain.robstoll.lib.creating.*
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.chrono.ChronoLocalDate
import java.time.chrono.ChronoLocalDateTime

Expand Down