diff --git a/eo-runtime/src/main/java/org/eolang/Expect.java b/eo-runtime/src/main/java/org/eolang/Expect.java index 9fd311f68d..98e5213399 100644 --- a/eo-runtime/src/main/java/org/eolang/Expect.java +++ b/eo-runtime/src/main/java/org/eolang/Expect.java @@ -81,7 +81,13 @@ public static Expect at(final Phi phi, final String attr) { public Expect that(final Function fun) { return new Expect<>( this.subject, - () -> fun.apply(this.sup.get()) + () -> { + try { + return fun.apply(this.sup.get()); + } catch (final ExFailure ex) { + throw new ExThat(ex.getMessage(), ex); + } + } ); } @@ -96,9 +102,19 @@ public Expect otherwise(final String message) { () -> { try { return this.sup.get(); - } catch (final ExFailure ex) { + } catch (final ExMust ex) { + throw new ExFailure( + String.format( + "%s %s %s", + this.subject, + ex.getMessage(), + message + ), + ex + ); + } catch (final ExThat ex) { throw new ExFailure( - String.format("%s %s %s", this.subject, ex.getMessage(), message), + message, ex ); } @@ -117,7 +133,7 @@ public Expect must(final Function fun) { () -> { final T ret = this.sup.get(); if (!fun.apply(ret)) { - throw new ExFailure( + throw new ExMust( String.format("(%s)", ret) ); } @@ -135,4 +151,38 @@ public T it() { return this.sup.get(); } + /** + * This exception is used to enhance the error message + * in the {@link Expect#otherwise(String)} method. + * + * @since 0.51 + */ + private static class ExMust extends ExFailure { + /** + * Ctor. + * @param cause Exception cause + * @param args Arguments for {@link String#format(String, Object...)} + */ + ExMust(final String cause, final Object... args) { + super(String.format(cause, args)); + } + } + + /** + * This exception is used to enhance the error message + * in the {@link Expect#otherwise(String)} method. + * + * @since 0.51 + */ + private static class ExThat extends ExFailure { + /** + * Ctor. + * @param cause Exception cause + * @param args Arguments for {@link String#format(String, Object...)} + */ + ExThat(final String cause, final Object... args) { + super(String.format(cause, args)); + } + } + } diff --git a/eo-runtime/src/test/java/org/eolang/ExpectTest.java b/eo-runtime/src/test/java/org/eolang/ExpectTest.java index 6793e27c66..b369d01dbe 100644 --- a/eo-runtime/src/test/java/org/eolang/ExpectTest.java +++ b/eo-runtime/src/test/java/org/eolang/ExpectTest.java @@ -36,9 +36,9 @@ final class ExpectTest { @Test - void buildsAndChecks() { + void buildsAndChecksWithoutErrors() { MatcherAssert.assertThat( - "passes through and throws correctly", + "Passes checks", new Expect<>("something", () -> 42) .must(i -> i > 0) .otherwise("must be positive") @@ -50,9 +50,9 @@ void buildsAndChecks() { } @Test - void failsWithCorrectTrace() { + void failsWithCorrectTraceWithOneError() { MatcherAssert.assertThat( - "error message is correct", + "Throw error in first 'must'. Error message is correct", Assertions.assertThrows( ExFailure.class, () -> new Expect<>("a number", () -> 42) @@ -61,7 +61,65 @@ void failsWithCorrectTrace() { .it(), "fails on check" ).getMessage(), - Matchers.containsString("negative") + Matchers.equalTo("a number (42) must be negative") + ); + } + + @Test + void failsWithCorrectTraceWithTwoErrors() { + MatcherAssert.assertThat( + "Throw error in first 'must'. Not add error about second 'must'", + Assertions.assertThrows( + ExFailure.class, + () -> new Expect<>("a number", () -> 42.2) + .must(i -> i < 0) + .otherwise("must be negative") + .must(i -> i % 1 == 0) + .otherwise("must be an integer") + .it(), + "fails only for first 'must'" + ).getMessage(), + Matchers.equalTo("a number (42.2) must be negative") + ); + } + + @Test + void failsWithCorrectTraceWithOneOkAndOneError() { + MatcherAssert.assertThat( + "Throw error in second 'must'. First 'must' passes check", + Assertions.assertThrows( + ExFailure.class, + () -> new Expect<>("a number", () -> 42.2) + .must(i -> i > 0) + .otherwise("must be positive") + .must(i -> i % 1 == 0) + .otherwise("must be an integer") + .it(), + "fails on checking integer" + ).getMessage(), + Matchers.equalTo("a number (42.2) must be an integer") + ); + } + + @Test + void failsWithCorrectTraceWithExFailureInThat() { + MatcherAssert.assertThat( + "Take error message from 'otherwise', not from original error", + Assertions.assertThrows( + ExFailure.class, + () -> new Expect<>("something", () -> 42.2) + .must(i -> i > 0) + .otherwise("must be positive") + .that( + i -> { + throw new ExFailure("some error"); + } + ) + .otherwise("something went wrong") + .it(), + "fails on 'that'" + ).getMessage(), + Matchers.equalTo("something went wrong") ); } }