diff --git a/eo-runtime/src/main/java/EOorg/EOeolang/EOerror.java b/eo-runtime/src/main/java/EOorg/EOeolang/EOerror.java index c8cb3cbda7..1275cc9cd6 100644 --- a/eo-runtime/src/main/java/EOorg/EOeolang/EOerror.java +++ b/eo-runtime/src/main/java/EOorg/EOeolang/EOerror.java @@ -27,9 +27,13 @@ */ package EOorg.EOeolang; +import java.nio.charset.StandardCharsets; import org.eolang.AtFree; import org.eolang.AtLambda; import org.eolang.Attr; +import org.eolang.Bytes; +import org.eolang.BytesOf; +import org.eolang.Dataized; import org.eolang.ExAbstract; import org.eolang.ExFailure; import org.eolang.PhDefault; @@ -115,7 +119,7 @@ public static final class ExError extends ExAbstract { * @param enclosure Enclosure inside the error */ public ExError(final Phi enclosure) { - super(enclosure.toString()); + super(EOerror.ExError.safeMessage(enclosure)); this.enc = enclosure; } @@ -126,5 +130,62 @@ public ExError(final Phi enclosure) { public Phi enclosure() { return this.enc; } + + /** + * Retrieve message from enclosure safely. + * @param enclosure Enclosure. + * @return String message. + * @checkstyle IllegalCatchCheck (45 lines) + */ + private static String safeMessage(final Phi enclosure) { + String result; + if (enclosure == null) { + result = "null Phi"; + } else { + try { + final byte[] data = new Dataized(enclosure).take(); + switch (data.length) { + case 0: + result = String.format( + "%s(Δ = --)", + enclosure + ); + break; + case 1: + result = String.format( + "%s(Δ = %s)", + enclosure, + data[0] > 0 + ); + break; + case 8: + final Bytes bytes = new BytesOf(data); + result = String.format( + "%s(Δ = %s = %s, or %s, or %s)", + enclosure, + bytes, + bytes.asNumber(Long.class), + bytes.asNumber(Double.class), + new String(data, StandardCharsets.UTF_8) + ); + break; + default: + result = String.format( + "%s(Δ = %s or %s)", + enclosure, + new BytesOf(data), + new String(data, StandardCharsets.UTF_8) + ); + } + } catch (final Throwable first) { + try { + result = enclosure.toString(); + } catch (final Throwable second) { + result = enclosure.getClass().toString(); + } + } + } + return result; + } } } diff --git a/eo-runtime/src/test/java/EOorg/EOeolang/EOerrorTest.java b/eo-runtime/src/test/java/EOorg/EOeolang/EOerrorTest.java index 31981ec984..f96655725e 100644 --- a/eo-runtime/src/test/java/EOorg/EOeolang/EOerrorTest.java +++ b/eo-runtime/src/test/java/EOorg/EOeolang/EOerrorTest.java @@ -27,12 +27,22 @@ */ package EOorg.EOeolang; +import java.util.stream.Stream; +import org.eolang.AtComposite; +import org.eolang.AtOnce; import org.eolang.Data; import org.eolang.Dataized; +import org.eolang.ExAbstract; +import org.eolang.PhCopy; +import org.eolang.PhDefault; import org.eolang.PhWith; import org.eolang.Phi; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Test case for {@link EOerror}. @@ -55,4 +65,67 @@ void makesToxicObject() { ); } + @ParameterizedTest + @MethodSource("getTestSources") + void getsReadableError(final Object cnst) { + ExAbstract error = null; + try { + new Dataized(new MyError(cnst)).take(); + } catch (final ExAbstract exc) { + error = exc; + } + assert error != null; + MatcherAssert.assertThat( + error.toString(), + Matchers.containsString(cnst.toString()) + ); + } + + /** + * Input arguments for getsReadableError unit test. + * @return Stream of arguments. + */ + private static Stream getTestSources() { + return Stream.of( + 12345L, + "qwerty", + 12.34567D, + true, + false + ); + } + + /** + * The object below. + * [] > my-error + * error > @ + * "qwerty" + * @since 0.35 + * @checkstyle JavadocStyleCheck + */ + private static final class MyError extends PhDefault { + + /** + * Ctor. + * @param data Data inside error. + */ + MyError(final Object data) { + this.add( + "φ", + new AtOnce( + new AtComposite( + this, + rho -> new PhWith( + new PhCopy( + Phi.Φ.attr("org").get().attr("eolang").get().attr("error").get() + ), + "α", + new Data.ToPhi(data) + ) + ) + ) + ); + } + } + }