diff --git a/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/chronoLocalDateTimeAssertions.kt b/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/chronoLocalDateTimeAssertions.kt index 9114a80310..3441bccce9 100644 --- a/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/chronoLocalDateTimeAssertions.kt +++ b/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/fluent/en_GB/chronoLocalDateTimeAssertions.kt @@ -7,6 +7,7 @@ package ch.tutteli.atrium.api.fluent.en_GB import ch.tutteli.atrium.creating.Expect import ch.tutteli.atrium.logic.* +import java.time.LocalDateTime import java.time.chrono.ChronoLocalDate import java.time.chrono.ChronoLocalDateTime @@ -74,3 +75,103 @@ fun > Expect.isAfterOrEqual( fun > Expect.isEqual( expected: ChronoLocalDateTime<*> ): Expect = _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 > Expect.isBefore( + expected: String +): Expect = _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 > Expect.isBeforeOrEqual( + expected: String +): Expect = _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 > Expect.isAfter( + expected: String +): Expect = _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 > Expect.isAfterOrEqual( + expected: String +): Expect = _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 > Expect.isEqual( + expected: String +): Expect = _logicAppend { isEqual(expected) } diff --git a/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/ChronoLocalDateTimeAssertionSpec.kt b/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/ChronoLocalDateTimeAssertionSpec.kt index 7c03d78b2d..c4e3318a69 100644 --- a/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/ChronoLocalDateTimeAssertionSpec.kt +++ b/apis/fluent-en_GB/atrium-api-fluent-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/fluent/en_GB/ChronoLocalDateTimeAssertionSpec.kt @@ -11,24 +11,24 @@ import java.time.chrono.ChronoLocalDateTime class ChronoLocalDateTimeAssertionSpec : Spek({ include(ChronoLocalDateTimeSpec) + include(ChronoLocalDateTimeAsStringSpec) }) { object ChronoLocalDateTimeSpec : ch.tutteli.atrium.specs.integration.ChronoLocalDateTimeAssertionSpec( - fun1(Expect>::isBefore), - fun1(Expect>::isBeforeOrEqual), - fun1(Expect>::isAfter), - fun1(Expect>::isAfterOrEqual), - fun1(Expect>::isEqual) + fun1, ChronoLocalDateTime<*>>(Expect>::isBefore), + fun1, ChronoLocalDateTime<*>>(Expect>::isBeforeOrEqual), + fun1, ChronoLocalDateTime<*>>(Expect>::isAfter), + fun1, ChronoLocalDateTime<*>>(Expect>::isAfterOrEqual), + fun1, ChronoLocalDateTime<*>>(Expect>::isEqual) ) - companion object { - fun isBefore( - expect: Expect>, - expected: ChronoLocalDateTime<*> - ): Expect> = - //TODO #481 turn into string in ISO format - expect.isBefore(expected) - } - + object ChronoLocalDateTimeAsStringSpec : + ch.tutteli.atrium.specs.integration.ChronoLocalDateTimeAsStringAssertionSpec( + fun1, String>(Expect>::isBefore), + fun1, String>(Expect>::isBeforeOrEqual), + fun1, String>(Expect>::isAfter), + fun1, String>(Expect>::isAfterOrEqual), + fun1, String>(Expect>::isEqual) + ) @Suppress("unused", "UNUSED_VALUE") private fun ambiguityTest() { @@ -85,5 +85,29 @@ class ChronoLocalDateTimeAssertionSpec : Spek({ a4 = a4.isAfter(chronoLocalDateTime) a4 = a4.isAfterOrEqual(chronoLocalDateTime) a4 = a4.isEqual(chronoLocalDateTime) + + a1 = a1.isBefore("also not ambiguous if string is passed") + a1 = a1.isBeforeOrEqual("also not ambiguous if string is passed") + a1 = a1.isAfter("also not ambiguous if string is passed") + a1 = a1.isAfterOrEqual("also not ambiguous if string is passed") + a1 = a1.isEqual("also not ambiguous if string is passed") + + a2 = a2.isBefore("also not ambiguous if string is passed") + a2 = a2.isBeforeOrEqual("also not ambiguous if string is passed") + a2 = a2.isAfter("also not ambiguous if string is passed") + a2 = a2.isAfterOrEqual("also not ambiguous if string is passed") + a2 = a2.isEqual("also not ambiguous if string is passed") + + a3 = a3.isBefore("also not ambiguous if string is passed") + a3 = a3.isBeforeOrEqual("also not ambiguous if string is passed") + a3 = a3.isAfter("also not ambiguous if string is passed") + a3 = a3.isAfterOrEqual("also not ambiguous if string is passed") + a3 = a3.isEqual("also not ambiguous if string is passed") + + a4 = a4.isBefore("also not ambiguous if string is passed") + a4 = a4.isBeforeOrEqual("also not ambiguous if string is passed") + a4 = a4.isAfter("also not ambiguous if string is passed") + a4 = a4.isAfterOrEqual("also not ambiguous if string is passed") + a4 = a4.isEqual("also not ambiguous if string is passed") } } diff --git a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/chronoLocalDateTimeAssertions.kt b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/chronoLocalDateTimeAssertions.kt index cf686330aa..37b1983643 100644 --- a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/chronoLocalDateTimeAssertions.kt +++ b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/main/kotlin/ch/tutteli/atrium/api/infix/en_GB/chronoLocalDateTimeAssertions.kt @@ -7,6 +7,7 @@ package ch.tutteli.atrium.api.infix.en_GB import ch.tutteli.atrium.creating.Expect import ch.tutteli.atrium.logic.* +import java.time.LocalDateTime import java.time.chrono.ChronoLocalDate import java.time.chrono.ChronoLocalDateTime @@ -74,3 +75,103 @@ infix fun > Expect.isAfterOrEqua infix fun > Expect.isEqual( expected: ChronoLocalDateTime<*> ): Expect = _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 + */ +infix fun > Expect.isBefore( + expected: String +): Expect = _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 + */ +infix fun > Expect.isBeforeOrEqual( + expected: String +): Expect = _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 + */ +infix fun > Expect.isAfter( + expected: String +): Expect = _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 + */ +infix fun > Expect.isAfterOrEqual( + expected: String +): Expect = _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 + */ +infix fun > Expect.isEqual( + expected: String +): Expect = _logicAppend { isEqual(expected) } diff --git a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/infix/en_GB/ChronoLocalDateTimeAssertionSpec.kt b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/infix/en_GB/ChronoLocalDateTimeAssertionSpec.kt index 21e5a4b0d3..cfc90494c6 100644 --- a/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/infix/en_GB/ChronoLocalDateTimeAssertionSpec.kt +++ b/apis/infix-en_GB/atrium-api-infix-en_GB-jvm/src/test/kotlin/ch/tutteli/atrium/api/infix/en_GB/ChronoLocalDateTimeAssertionSpec.kt @@ -4,18 +4,33 @@ import ch.tutteli.atrium.creating.Expect import ch.tutteli.atrium.specs.fun1 import ch.tutteli.atrium.specs.notImplemented import ch.tutteli.atrium.specs.testutils.WithAsciiReporter +import org.spekframework.spek2.Spek import java.time.LocalDate import java.time.LocalDateTime import java.time.chrono.ChronoLocalDate import java.time.chrono.ChronoLocalDateTime -class ChronoLocalDateTimeAssertionSpec : ch.tutteli.atrium.specs.integration.ChronoLocalDateTimeAssertionSpec( - fun1(Expect>::isBefore), - fun1(Expect>::isBeforeOrEqual), - fun1(Expect>::isAfter), - fun1(Expect>::isAfterOrEqual), - fun1(Expect>::isEqual) -) { +class ChronoLocalDateTimeAssertionSpec : Spek({ + include(ChronoLocalDateTimeSpec) + include(ChronoLocalDateTimeAsStringSpec) +}) { + object ChronoLocalDateTimeSpec : ch.tutteli.atrium.specs.integration.ChronoLocalDateTimeAssertionSpec( + fun1, ChronoLocalDateTime<*>>(Expect>::isBefore), + fun1, ChronoLocalDateTime<*>>(Expect>::isBeforeOrEqual), + fun1, ChronoLocalDateTime<*>>(Expect>::isAfter), + fun1, ChronoLocalDateTime<*>>(Expect>::isAfterOrEqual), + fun1, ChronoLocalDateTime<*>>(Expect>::isEqual) + ) + + object ChronoLocalDateTimeAsStringSpec : + ch.tutteli.atrium.specs.integration.ChronoLocalDateTimeAsStringAssertionSpec( + fun1, String>(Expect>::isBefore), + fun1, String>(Expect>::isBeforeOrEqual), + fun1, String>(Expect>::isAfter), + fun1, String>(Expect>::isAfterOrEqual), + fun1, String>(Expect>::isEqual) + ) + companion object : WithAsciiReporter() @Suppress("unused", "UNUSED_VALUE") diff --git a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDateTime.kt b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDateTime.kt index d9a21e83b2..9661d71bc0 100644 --- a/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDateTime.kt +++ b/logic/atrium-logic-jvm/src/generated/kotlin/ch/tutteli/atrium/logic/chronoLocalDateTime.kt @@ -25,3 +25,14 @@ fun > AssertionContainer.isAfter fun > AssertionContainer.isAfterOrEqual(expected: ChronoLocalDateTime<*>): Assertion = _chronoLocalDateTimeImpl.isAfterOrEqual(this, expected) fun > AssertionContainer.isEqual(expected: ChronoLocalDateTime<*>): Assertion = _chronoLocalDateTimeImpl.isEqual(this, expected) + +fun > AssertionContainer.isBefore(expected: String): Assertion = _chronoLocalDateTimeImpl.isBefore(this, expected) + +fun > AssertionContainer.isBeforeOrEqual(expected: String): Assertion = _chronoLocalDateTimeImpl.isBeforeOrEqual(this, expected) + +fun > AssertionContainer.isAfter(expected: String): Assertion = _chronoLocalDateTimeImpl.isAfter(this, expected) + +fun > AssertionContainer.isAfterOrEqual(expected: String): Assertion = _chronoLocalDateTimeImpl.isAfterOrEqual(this, expected) + +fun > AssertionContainer.isEqual(expected: String): Assertion = _chronoLocalDateTimeImpl.isEqual(this, expected) + diff --git a/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/ChronoLocalDateTimeAssertions.kt b/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/ChronoLocalDateTimeAssertions.kt index bfb72b7ca9..9b6c86fd0c 100644 --- a/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/ChronoLocalDateTimeAssertions.kt +++ b/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/ChronoLocalDateTimeAssertions.kt @@ -38,4 +38,30 @@ interface ChronoLocalDateTimeAssertions { container: AssertionContainer, expected: ChronoLocalDateTime<*> ): Assertion + + fun > isBefore( + container: AssertionContainer, + expected: String + ): Assertion + + fun > isBeforeOrEqual( + container: AssertionContainer, + expected: String + ): Assertion + + fun > isAfter( + container: AssertionContainer, + expected: String + ): Assertion + + fun > isAfterOrEqual( + container: AssertionContainer, + expected: String + ): Assertion + + fun > isEqual( + container: AssertionContainer, + expected: String + ): Assertion + } diff --git a/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/impl/DefaultChronoLocalDateTimeAssertions.kt b/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/impl/DefaultChronoLocalDateTimeAssertions.kt index a0139ae675..66350bd63c 100644 --- a/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/impl/DefaultChronoLocalDateTimeAssertions.kt +++ b/logic/atrium-logic-jvm/src/main/kotlin/ch/tutteli/atrium/logic/impl/DefaultChronoLocalDateTimeAssertions.kt @@ -7,9 +7,10 @@ package ch.tutteli.atrium.logic.impl import ch.tutteli.atrium.assertions.Assertion import ch.tutteli.atrium.creating.AssertionContainer -import ch.tutteli.atrium.logic.ChronoLocalDateTimeAssertions -import ch.tutteli.atrium.logic.createDescriptiveAssertion +import ch.tutteli.atrium.logic.* import ch.tutteli.atrium.translations.DescriptionDateTimeLikeAssertion.* +import java.time.LocalDate +import java.time.LocalDateTime import java.time.chrono.ChronoLocalDate import java.time.chrono.ChronoLocalDateTime @@ -19,6 +20,11 @@ class DefaultChronoLocalDateTimeAssertions : ChronoLocalDateTimeAssertions { expected: ChronoLocalDateTime<*> ): Assertion = container.createDescriptiveAssertion(IS_BEFORE, expected) { it.isBefore(expected) } + override fun > isBefore( + container: AssertionContainer, + expected: String + ): Assertion = container.isBefore(stringToLocalDateTime(expected)) + override fun > isBeforeOrEqual( container: AssertionContainer, expected: ChronoLocalDateTime<*> @@ -26,11 +32,21 @@ class DefaultChronoLocalDateTimeAssertions : ChronoLocalDateTimeAssertions { it.isBefore(expected) || it.isEqual(expected) } + override fun > isBeforeOrEqual( + container: AssertionContainer, + expected: String + ): Assertion = container.isBeforeOrEqual(stringToLocalDateTime(expected)) + override fun > isAfter( container: AssertionContainer, expected: ChronoLocalDateTime<*> ): Assertion = container.createDescriptiveAssertion(IS_AFTER, expected) { it.isAfter(expected) } + override fun > isAfter( + container: AssertionContainer, + expected: String + ): Assertion = container.isAfter(stringToLocalDateTime(expected)) + override fun > isAfterOrEqual( container: AssertionContainer, expected: ChronoLocalDateTime<*> @@ -38,10 +54,28 @@ class DefaultChronoLocalDateTimeAssertions : ChronoLocalDateTimeAssertions { it.isAfter(expected) || it.isEqual(expected) } + override fun > isAfterOrEqual( + container: AssertionContainer, + expected: String + ): Assertion = container.isAfterOrEqual(stringToLocalDateTime(expected)) + override fun > isEqual( container: AssertionContainer, expected: ChronoLocalDateTime<*> ): Assertion = container.createDescriptiveAssertion(IS_EQUAL_TO, expected) { it.isEqual(expected) } + + override fun > isEqual( + container: AssertionContainer, + expected: String + ): Assertion = container.isEqual(stringToLocalDateTime(expected)) + + private fun stringToLocalDateTime(data: String): LocalDateTime { + return if (data.contains("T")) { + LocalDateTime.parse(data) + } else { + LocalDate.parse(data).atStartOfDay() + } + } } diff --git a/misc/deprecated/domain/robstoll-lib/atrium-domain-robstoll-lib-jvm/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/lib/creating/chronoLocalDateTimeAssertions.kt b/misc/deprecated/domain/robstoll-lib/atrium-domain-robstoll-lib-jvm/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/lib/creating/chronoLocalDateTimeAssertions.kt index ae533e377f..c22ae18038 100644 --- a/misc/deprecated/domain/robstoll-lib/atrium-domain-robstoll-lib-jvm/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/lib/creating/chronoLocalDateTimeAssertions.kt +++ b/misc/deprecated/domain/robstoll-lib/atrium-domain-robstoll-lib-jvm/src/main/kotlin/ch/tutteli/atrium/domain/robstoll/lib/creating/chronoLocalDateTimeAssertions.kt @@ -11,6 +11,8 @@ import ch.tutteli.atrium.assertions.Assertion import ch.tutteli.atrium.assertions.builders.assertionBuilder import ch.tutteli.atrium.creating.Expect import ch.tutteli.atrium.translations.DescriptionDateTimeLikeAssertion.* +import java.time.LocalDate +import java.time.LocalDateTime import java.time.chrono.ChronoLocalDate import java.time.chrono.ChronoLocalDateTime @@ -19,6 +21,9 @@ import java.time.chrono.ChronoLocalDateTime fun > _isBefore(expect: Expect, expected: ChronoLocalDateTime<*>): Assertion = assertionBuilder.createDescriptive(expect, IS_BEFORE, expected) { it.isBefore(expected) } +fun > _isBefore(expect: Expect, expected: String): Assertion = + assertionBuilder.createDescriptive(expect, IS_BEFORE, expected) { it.isBefore(stringToLocalDateTime(expected)) } + @Suppress("DeprecatedCallableAddReplaceWith") @Deprecated("use the function from atrium-logic instead, will be removed with 1.0.0") fun > _isBeforeOrEquals( @@ -29,6 +34,13 @@ fun > _isBeforeOrEquals( it.isBefore(expected) || it.isEqual(expected) } +fun > _isBeforeOrEquals( + expect: Expect, + expected: String +): Assertion = assertionBuilder.createDescriptive(expect, IS_BEFORE_OR_EQUAL, expected) { + it.isBefore(stringToLocalDateTime(expected)) || it.isEqual(stringToLocalDateTime(expected)) + } + @Suppress("DeprecatedCallableAddReplaceWith") @Deprecated("use the function from atrium-logic instead, will be removed with 1.0.0") fun > _isAfter( @@ -38,6 +50,13 @@ fun > _isAfter( @Suppress("DeprecatedCallableAddReplaceWith") @Deprecated("use the function from atrium-logic instead, will be removed with 1.0.0") +fun > _isAfter( + expect: Expect, + expected: String +): Assertion = assertionBuilder.createDescriptive(expect, IS_AFTER, expected) { + it.isAfter(stringToLocalDateTime(expected)) +} + fun > _isAfterOrEquals( expect: Expect, expected: ChronoLocalDateTime<*> @@ -47,9 +66,31 @@ fun > _isAfterOrEquals( @Suppress("DeprecatedCallableAddReplaceWith") @Deprecated("use the function from atrium-logic instead, will be removed with 1.0.0") +fun > _isAfterOrEquals( + expect: Expect, + expected: String +): Assertion = assertionBuilder.createDescriptive(expect, IS_AFTER_OR_EQUAL, expected) { + it.isAfter(stringToLocalDateTime(expected)) || it.isEqual(stringToLocalDateTime(expected)) +} + fun > _isEqual( expect: Expect, expected: ChronoLocalDateTime<*> ): Assertion = assertionBuilder.createDescriptive(expect, IS_EQUAL_TO, expected) { it.isEqual(expected) } + +fun > _isEqual( + expect: Expect, + expected: String +): Assertion = assertionBuilder.createDescriptive(expect, IS_EQUAL_TO, expected) { + it.isEqual(stringToLocalDateTime(expected)) +} + +private fun stringToLocalDateTime(data: String): LocalDateTime { + return if (data.contains("T")) { + LocalDateTime.parse(data) + } else { + LocalDate.parse(data).atStartOfDay() + } +} diff --git a/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/ChronoLocalDateTimeAsStringAssertionSpec.kt b/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/ChronoLocalDateTimeAsStringAssertionSpec.kt new file mode 100644 index 0000000000..f272b5b0e0 --- /dev/null +++ b/misc/specs/atrium-specs-jvm/src/main/kotlin/ch/tutteli/atrium/specs/integration/ChronoLocalDateTimeAsStringAssertionSpec.kt @@ -0,0 +1,202 @@ +package ch.tutteli.atrium.specs.integration + +import ch.tutteli.atrium.api.fluent.en_GB.messageContains +import ch.tutteli.atrium.api.fluent.en_GB.toThrow +import ch.tutteli.atrium.api.verbs.internal.expect +import ch.tutteli.atrium.creating.Expect +import ch.tutteli.atrium.specs.Fun1 +import ch.tutteli.atrium.specs.fun1 +import ch.tutteli.atrium.specs.lambda +import ch.tutteli.atrium.specs.name +import ch.tutteli.atrium.translations.DescriptionDateTimeLikeAssertion.* +import org.spekframework.spek2.Spek +import org.spekframework.spek2.style.specification.describe +import java.time.Duration +import java.time.LocalDateTime +import java.time.chrono.ChronoLocalDateTime +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeParseException + +abstract class ChronoLocalDateTimeAsStringAssertionSpec( + isBefore: Fun1, String>, + isBeforeOrEqual: Fun1, String>, + isAfter: Fun1, String>, + isAfterOrEqual: Fun1, String>, + isEqual: Fun1, String>, + describePrefix: String = "[Atrium] " +) : Spek({ + + fun isBefore( + expect: Expect>, + expected: ChronoLocalDateTime<*> + ): Expect> = + expect.(isBefore.lambda)(expected.format(DateTimeFormatter.ISO_DATE_TIME)) + + fun isBeforeOrEqual( + expect: Expect>, + expected: ChronoLocalDateTime<*> + ): Expect> = + expect.(isBeforeOrEqual.lambda)(expected.format(DateTimeFormatter.ISO_DATE_TIME)) + + fun isAfter( + expect: Expect>, + expected: ChronoLocalDateTime<*> + ): Expect> = + expect.(isAfter.lambda)(expected.format(DateTimeFormatter.ISO_DATE_TIME)) + + fun isAfterOrEqual( + expect: Expect>, + expected: ChronoLocalDateTime<*> + ): Expect> = + expect.(isAfterOrEqual.lambda)(expected.format(DateTimeFormatter.ISO_DATE_TIME)) + + fun isEqual( + expect: Expect>, + expected: ChronoLocalDateTime<*> + ): Expect> = + expect.(isEqual.lambda)(expected.format(DateTimeFormatter.ISO_DATE_TIME)) + + include(object : ChronoLocalDateTimeAssertionSpec( + fun1(::isBefore), + fun1(::isBeforeOrEqual), + fun1(::isAfter), + fun1(::isAfterOrEqual), + fun1(::isEqual), + describePrefix + ) {}) + + val isBeforeFun = isBefore.lambda + val isBeforeOrEqualFun = isBeforeOrEqual.lambda + val isAfterFun = isAfter.lambda + val isAfterOrEqualFun = isAfterOrEqual.lambda + val isEqualFun = isEqual.lambda + + val subject = LocalDateTime.now() as ChronoLocalDateTime<*> + val now = expect(subject) + + describe("wrong format") { + listOf( + "20200101010101111", + "20200101010101", + "202001010101", + "2020010101", + "20-01-01T01:01", + "2020-1-01T01:01", + "2020-01-1T01:01", + "2020-01-01T01", + "2020-01-01T1:01", + "2020-01-01T01:1", + "2020-01-01T01:01:1", + "2020-01-01t01:01:01" + ).forEach { value -> + context(value) { + it("${isBefore.name} throws a DateTimeParseException") { + expect { + now.isBeforeFun(value) + }.toThrow { messageContains("could not be parsed") } + } + it("${isBeforeOrEqual.name} throws a DateTimeParseException") { + expect { + now.isBeforeOrEqualFun(value) + }.toThrow { messageContains("could not be parsed") } + } + it("${isAfter.name} throws a DateTimeParseException") { + expect { + now.isAfterFun(value) + }.toThrow { messageContains("could not be parsed") } + } + it("isAfterOrEqual throws a DateTimeParseException") { + expect { + now.isAfterOrEqualFun(value) + }.toThrow { messageContains("could not be parsed") } + } + it("${isEqual.name} throws a DateTimeParseException") { + expect { + now.isEqualFun(value) + }.toThrow { messageContains("could not be parsed") } + } + } + } + } + + describe("allowed shortcuts") { + mapOf( + "2020-01-02T03:04:05" to LocalDateTime.of(2020, 1, 2, 3, 4, 5) as ChronoLocalDateTime<*>, + "2020-01-02T03:04" to LocalDateTime.of(2020, 1, 2, 3, 4, 0), + "2020-01-02" to LocalDateTime.of(2020, 1, 2, 0, 0, 0) + ).forEach { (localDateTimeAsString, chronoLocalDateTime) -> + val before = chronoLocalDateTime.minus(Duration.ofSeconds(1)) + val after = chronoLocalDateTime.plus(Duration.ofSeconds(1)) + context("passing $localDateTimeAsString") { + + it("$before ${isBefore.name} $localDateTimeAsString does not throw") { + expect(before).isBeforeFun(localDateTimeAsString) + } + it("$chronoLocalDateTime ${isBefore.name} $localDateTimeAsString throws an AssertionError") { + expect { + expect(chronoLocalDateTime).isBeforeFun(localDateTimeAsString) + }.toThrow { messageContains("${IS_BEFORE.getDefault()}: $localDateTimeAsString") } + } + it("$after ${isBefore.name} $localDateTimeAsString throws an AssertionError") { + expect { + expect(after).isBeforeFun(localDateTimeAsString) + }.toThrow { messageContains("${IS_BEFORE.getDefault()}: $localDateTimeAsString") } + } + + it("$before ${isBeforeOrEqual.name} $localDateTimeAsString does not throw") { + expect(before).isBeforeOrEqualFun(localDateTimeAsString) + } + it("$chronoLocalDateTime ${isBeforeOrEqual.name} $localDateTimeAsString does not throw") { + expect(chronoLocalDateTime).isBeforeOrEqualFun(localDateTimeAsString) + } + it("$after ${isBeforeOrEqual.name} $localDateTimeAsString throws an AssertionError") { + expect { + expect(after).isBeforeOrEqualFun(localDateTimeAsString) + }.toThrow { + messageContains("${IS_BEFORE_OR_EQUAL.getDefault()}: $localDateTimeAsString") + } + } + + it("$before ${isAfter.name} $localDateTimeAsString throws an AssertionError") { + expect { + expect(before).isAfterFun(localDateTimeAsString) + }.toThrow { messageContains("${IS_AFTER.getDefault()}: $localDateTimeAsString") } + } + it("$chronoLocalDateTime ${isAfter.name} $localDateTimeAsString throws an AssertionError") { + expect { + expect(chronoLocalDateTime).isAfterFun(localDateTimeAsString) + }.toThrow { messageContains("${IS_AFTER.getDefault()}: $localDateTimeAsString") } + } + it("$after ${isAfter.name} $localDateTimeAsString does not throw") { + expect(after).isAfterFun(localDateTimeAsString) + } + + it("$before ${isAfterOrEqual.name} $localDateTimeAsString throws an AssertionError") { + expect { + expect(before).isAfterOrEqualFun(localDateTimeAsString) + }.toThrow { messageContains("${IS_AFTER_OR_EQUAL.getDefault()}: $localDateTimeAsString") } + } + it("$chronoLocalDateTime ${isAfterOrEqual.name} $localDateTimeAsString does not throw") { + expect(chronoLocalDateTime).isAfterOrEqualFun(localDateTimeAsString) + } + it("$after ${isAfterOrEqual.name} $localDateTimeAsString does not throw") { + expect(after).isAfterOrEqualFun(localDateTimeAsString) + } + + it("$before ${isEqual.name} $localDateTimeAsString throws an AssertionError") { + expect { + expect(before).isEqualFun(localDateTimeAsString) + }.toThrow { messageContains("${IS_EQUAL_TO.getDefault()}: $localDateTimeAsString") } + } + it("$chronoLocalDateTime ${isEqual.name} $localDateTimeAsString does not throw") { + expect(chronoLocalDateTime).isEqualFun(localDateTimeAsString) + } + it("$after ${isEqual.name} $localDateTimeAsString throws an AssertionError") { + expect { + expect(after).isEqualFun(localDateTimeAsString) + }.toThrow { messageContains("${IS_EQUAL_TO.getDefault()}: $localDateTimeAsString") } + } + } + } + } +}) diff --git a/misc/tools/atrium-bc-test/build.gradle b/misc/tools/atrium-bc-test/build.gradle index 4ffbf8c68a..0e108a6e42 100644 --- a/misc/tools/atrium-bc-test/build.gradle +++ b/misc/tools/atrium-bc-test/build.gradle @@ -396,8 +396,8 @@ createBcAndBbcTasksForApis('0.12.0', ) //@formatter:on -def apis = ['cc-de_CH', 'cc-en_GB', 'cc-infix-en_GB'] -apis.each { apiName -> + +['cc-de_CH', 'cc-en_GB', 'cc-infix-en_GB'].each { apiName -> createFixSrcTask(apiName, '0.7.0', 'ArrayAsIterableAssertionsSpec.kt') { String content -> return content.replaceAll(/Assert>::asIterable.name/, '"asIterable"') } @@ -414,8 +414,8 @@ createFixSrcTask('cc-infix-en_GB', '0.7.0', 'CharSequenceAssertionsSpec.kt') { S createFixSrcTask('cc-infix-en_GB', '0.7.0', 'IterableContainsInOrderOnlyValuesAssertionsSpec.kt') { String content -> return content.replaceAll(/NullableValues/, 'NullableValues') } -//def apis = ['fluent-en_GB', 'cc-en_GB', 'cc-infix-en_GB'] -//apis.each { -//createFixSrcTask('cc-infix-en_GB', '0.12.0', 'PathAssertionsSpec.kt') { String content -> -// return content.replaceAll(/val expectedMessage = "${"\$"}{TO_BE.getDefault()}:/, 'val expectedMessage = "$isDescr:') -//} +['fluent-en_GB', 'infix-en_GB'].each { apiName -> + createFixSrcTask(apiName, '0.12.0', 'ChronoLocalDateTimeAssertionSpec.kt') { String content -> + return content.replaceAll(/ fun1/, ' fun1, ChronoLocalDateTime<*>>') + } +}