diff --git a/eo-runtime/src/main/java/org/eolang/Expect.java b/eo-runtime/src/main/java/org/eolang/Expect.java index e412b8c263..dc266506e0 100644 --- a/eo-runtime/src/main/java/org/eolang/Expect.java +++ b/eo-runtime/src/main/java/org/eolang/Expect.java @@ -165,7 +165,7 @@ public T it() { * * @since 0.51 */ - private static class ExMust extends RuntimeException { + private static final class ExMust extends RuntimeException { /** * Ctor. * @param cause Exception cause @@ -182,7 +182,7 @@ private static class ExMust extends RuntimeException { * * @since 0.51 */ - private static class ExThat extends RuntimeException { + private static final class ExThat extends RuntimeException { /** * Ctor. * @param cause Exception cause @@ -199,7 +199,7 @@ private static class ExThat extends RuntimeException { * * @since 0.51 */ - private static class ExOtherwise extends RuntimeException { + private static final class ExOtherwise extends RuntimeException { /** * Ctor. * @param cause Exception cause @@ -210,4 +210,112 @@ private static class ExOtherwise extends RuntimeException { } } + /** + * Transform Expect to Number. + * + * @since 0.51 + */ + public static final class Number { + + /** + * Expect. + */ + private final Expect expect; + + /** + * Ctor. + * @param expect Expect + */ + public Number(final Expect expect) { + this.expect = expect; + } + + /** + * Return it. + * @return The token + * @checkstyle MethodNameCheck (5 lines) + */ + public Double it() { + return this.expect + .that(phi -> new Dataized(phi).asNumber()) + .otherwise("must be a number") + .it(); + } + } + + /** + * Transform Expect to Integer. + * + * @since 0.51 + */ + public static final class Int { + + /** + * Expect. + */ + private final Expect expect; + + /** + * Ctor. + * @param expect Expect + */ + public Int(final Expect expect) { + this.expect = expect; + } + + /** + * Return it. + * @return The token + * @checkstyle MethodNameCheck (5 lines) + */ + public Integer it() { + return this.expect + .that(phi -> new Dataized(phi).asNumber()) + .otherwise("must be a number") + .must(number -> number % 1 == 0) + .otherwise("must be an integer") + .that(Double::intValue) + .it(); + } + } + + /** + * Transform Expect to Natural number. + * Natural number is integer greater or equal to zero. + * + * @since 0.51 + */ + public static final class Natural { + + /** + * Expect. + */ + private final Expect expect; + + /** + * Ctor. + * @param expect Expect + */ + public Natural(final Expect expect) { + this.expect = expect; + } + + /** + * Return it. + * @return The token + * @checkstyle MethodNameCheck (5 lines) + */ + public Integer it() { + return this.expect + .that(phi -> new Dataized(phi).asNumber()) + .otherwise("must be a number") + .must(number -> number % 1 == 0) + .otherwise("must be an integer") + .that(Double::intValue) + .must(integer -> integer >= 0) + .otherwise("must be greater or equal to zero") + .it(); + } + } + } diff --git a/eo-runtime/src/test/java/org/eolang/ExpectTest.java b/eo-runtime/src/test/java/org/eolang/ExpectTest.java index 9c08dc78b5..6b1fa81880 100644 --- a/eo-runtime/src/test/java/org/eolang/ExpectTest.java +++ b/eo-runtime/src/test/java/org/eolang/ExpectTest.java @@ -33,6 +33,7 @@ * * @since 0.1.0 */ +@SuppressWarnings("PMD.TooManyMethods") final class ExpectTest { @Test @@ -163,4 +164,136 @@ void failsWithCorrectTraceForMustAndThat() { ); } + @Test + void failsInTransformingToNumberForNotNumber() { + MatcherAssert.assertThat( + "inner class Number working throws error if attr is not a number", + Assertions.assertThrows( + ExFailure.class, + () -> new Expect.Number( + Expect.at( + new PhWith( + new PhDefault(), + Attr.RHO, + new Data.ToPhi(true) + ), + Attr.RHO + ) + ).it(), + "fails with correct error message while transform Phi to Number" + ).getMessage(), + Matchers.equalTo("the 'ρ' attribute must be a number") + ); + } + + @Test + void failsInTransformingToIntegerForNotNumber() { + MatcherAssert.assertThat( + "inner class Integer throws error for not a number", + Assertions.assertThrows( + ExFailure.class, + () -> new Expect.Int( + Expect.at( + new PhWith( + new PhDefault(), + Attr.RHO, + new Data.ToPhi(true) + ), + Attr.RHO + ) + ).it(), + "fails with correct error message while transform Phi to Integer" + ).getMessage(), + Matchers.equalTo("the 'ρ' attribute must be a number") + ); + } + + @Test + void failsInTransformingToIntegerForNotInteger() { + MatcherAssert.assertThat( + "inner class Integer throws error for not an integer number", + Assertions.assertThrows( + ExFailure.class, + () -> new Expect.Int( + Expect.at( + new PhWith( + new PhDefault(), + Attr.RHO, + new Data.ToPhi(42.23) + ), + Attr.RHO + ) + ).it(), + "fails with correct error message while transform Phi to Integer" + ).getMessage(), + Matchers.equalTo("the 'ρ' attribute (42.23) must be an integer") + ); + } + + @Test + void failsInTransformingToNonNegativeIntegerForNotNumber() { + MatcherAssert.assertThat( + "inner class NonNegativeInteger throws error for not a number", + Assertions.assertThrows( + ExFailure.class, + () -> new Expect.Natural( + Expect.at( + new PhWith( + new PhDefault(), + Attr.RHO, + new Data.ToPhi(true) + ), + Attr.RHO + ) + ).it(), + "fails with correct error message while transform Phi to NonNegativeInteger" + ).getMessage(), + Matchers.equalTo("the 'ρ' attribute must be a number") + ); + } + + @Test + void failsInTransformingToNonNegativeIntegerForNotInteger() { + MatcherAssert.assertThat( + "inner class NonNegativeInteger throws error for not an integer number", + Assertions.assertThrows( + ExFailure.class, + () -> new Expect.Natural( + Expect.at( + new PhWith( + new PhDefault(), + Attr.RHO, + new Data.ToPhi(42.23) + ), + Attr.RHO + ) + ).it(), + "fails with correct error message while transform Phi to NonNegativeInteger" + ).getMessage(), + Matchers.equalTo("the 'ρ' attribute (42.23) must be an integer") + ); + } + + @Test + void failsInTransformingToNonNegativeIntegerForNegative() { + MatcherAssert.assertThat( + "inner class NonNegativeInteger throws error for a negative integer", + Assertions.assertThrows( + ExFailure.class, + () -> new Expect.Natural( + Expect.at( + new PhWith( + new PhDefault(), + Attr.RHO, + new Data.ToPhi(-42) + ), + Attr.RHO + ) + ).it(), + "fails with correct error message while transform Phi to NonNegativeInteger" + ).getMessage(), + Matchers.equalTo("the 'ρ' attribute (-42) must be greater or equal to zero") + ); + } + }