diff --git a/eo-maven-plugin/pom.xml b/eo-maven-plugin/pom.xml index 6509e8fd76..af4ba0e8e5 100644 --- a/eo-maven-plugin/pom.xml +++ b/eo-maven-plugin/pom.xml @@ -301,7 +301,9 @@ SOFTWARE. ${skipITs} ${skipITs} - + + fibonacci/pom.xml + diff --git a/eo-maven-plugin/src/main/resources/org/eolang/maven/pre/to-java.xsl b/eo-maven-plugin/src/main/resources/org/eolang/maven/pre/to-java.xsl index ff60feea01..f8930869c1 100644 --- a/eo-maven-plugin/src/main/resources/org/eolang/maven/pre/to-java.xsl +++ b/eo-maven-plugin/src/main/resources/org/eolang/maven/pre/to-java.xsl @@ -404,7 +404,7 @@ SOFTWARE. - = new PhLocated( + = new PhSafe( , " @@ -538,9 +538,9 @@ SOFTWARE. new Dataized( - new PhSafe(new + new - ()) + () ).asBool() diff --git a/eo-maven-plugin/src/test/resources/org/eolang/maven/packs/locators-to-java.yaml b/eo-maven-plugin/src/test/resources/org/eolang/maven/packs/locators-to-java.yaml index c191579e9b..dacf24e743 100644 --- a/eo-maven-plugin/src/test/resources/org/eolang/maven/packs/locators-to-java.yaml +++ b/eo-maven-plugin/src/test/resources/org/eolang/maven/packs/locators-to-java.yaml @@ -32,14 +32,14 @@ sheets: - /org/eolang/parser/blank-xsd-schema.xsl asserts: - /program[not(errors)] - - //java[contains(text(), 'new PhLocated(ret, "scenario", 3, 2, "Φ.foo.φ")')] - - //java[contains(text(), 'new PhLocated(ret_base, "scenario", 6, 4, "Φ.foo.other.φ.ρ")')] - - //java[contains(text(), 'new PhLocated(ret, "scenario", 6, 6, "Φ.foo.other.φ")')] - - //java[contains(text(), 'new PhLocated(ret_1, "scenario", 6, 12, "Φ.foo.other.φ.α0")')] - - //java[contains(text(), 'new PhLocated(ret_base, "scenario", 10, 2, "Φ.bar.φ.ρ")')] - - //java[contains(text(), 'new PhLocated(ret, "scenario", 10, 4, "Φ.bar.φ")')] - - //java[contains(text(), 'new PhLocated(ret_1, "scenario", 10, 10, "Φ.bar.φ.α0")')] - - //java[contains(text(), 'new PhLocated(ret, "scenario", 11, 2, "Φ.bar.five")')] + - //java[contains(text(), 'new PhSafe(ret, "scenario", 3, 2, "Φ.foo.φ")')] + - //java[contains(text(), 'new PhSafe(ret_base, "scenario", 6, 4, "Φ.foo.other.φ.ρ")')] + - //java[contains(text(), 'new PhSafe(ret, "scenario", 6, 6, "Φ.foo.other.φ")')] + - //java[contains(text(), 'new PhSafe(ret_1, "scenario", 6, 12, "Φ.foo.other.φ.α0")')] + - //java[contains(text(), 'new PhSafe(ret_base, "scenario", 10, 2, "Φ.bar.φ.ρ")')] + - //java[contains(text(), 'new PhSafe(ret, "scenario", 10, 4, "Φ.bar.φ")')] + - //java[contains(text(), 'new PhSafe(ret_1, "scenario", 10, 10, "Φ.bar.φ.α0")')] + - //java[contains(text(), 'new PhSafe(ret, "scenario", 11, 2, "Φ.bar.five")')] input: | # No comments. [] > foo diff --git a/eo-runtime/src/main/java/EOorg/EOeolang/EObytes$EOslice.java b/eo-runtime/src/main/java/EOorg/EOeolang/EObytes$EOslice.java index cf99e58841..57376d0bbb 100644 --- a/eo-runtime/src/main/java/EOorg/EOeolang/EObytes$EOslice.java +++ b/eo-runtime/src/main/java/EOorg/EOeolang/EObytes$EOslice.java @@ -77,9 +77,11 @@ public Phi lambda() { .must(integer -> integer >= 0) .otherwise("must be a positive integer") .it(); - final byte[] array = new Dataized(this.take(Attr.RHO)).take(); return new Data.ToPhi( - Arrays.copyOfRange(array, start, start + length) + Arrays.copyOfRange( + new Dataized(this.take(Attr.RHO)).take(), + start, start + length + ) ); } } diff --git a/eo-runtime/src/main/java/EOorg/EOeolang/EOerror.java b/eo-runtime/src/main/java/EOorg/EOeolang/EOerror.java index c1dcf96226..aaf712f165 100644 --- a/eo-runtime/src/main/java/EOorg/EOeolang/EOerror.java +++ b/eo-runtime/src/main/java/EOorg/EOeolang/EOerror.java @@ -99,6 +99,15 @@ public ExError(final Phi enclosure) { this(enclosure, Collections.emptyList()); } + /** + * Ctor. + * @param cause Previous error + * @param message New message + */ + public ExError(final Phi cause, final String message) { + this(cause, Collections.singletonList(message)); + } + /** * Ctor. * @param cause Previous error @@ -119,6 +128,15 @@ public ExError(final Phi enclosure, final Collection before) { this.trace = before; } + @Override + public String toString() { + return String.format( + "%s +%s", + super.toString(), + this.trace.size() + ); + } + /** * Take it. * @return The enclosed object diff --git a/eo-runtime/src/main/java/EOorg/EOeolang/EOtry.java b/eo-runtime/src/main/java/EOorg/EOeolang/EOtry.java index 536592bbfa..654e723948 100644 --- a/eo-runtime/src/main/java/EOorg/EOeolang/EOtry.java +++ b/eo-runtime/src/main/java/EOorg/EOeolang/EOtry.java @@ -33,7 +33,6 @@ import org.eolang.Data; import org.eolang.Dataized; import org.eolang.PhDefault; -import org.eolang.PhSafe; import org.eolang.Phi; import org.eolang.XmirObject; @@ -59,11 +58,11 @@ public EOtry() { public Phi lambda() { byte[] result; try { - result = new Dataized(new PhSafe(this.take("main"))).take(); + result = new Dataized(this.take("main")).take(); } catch (final EOerror.ExError ex) { - final Phi caught = this.take("catch").copy(); - caught.put(0, ex.enclosure()); - result = new Dataized(caught).take(); + final Phi catcher = this.take("catch").copy(); + catcher.put(0, ex.enclosure()); + result = new Dataized(catcher).take(); } finally { new Dataized(this.take("finally")).take(); } diff --git a/eo-runtime/src/main/java/org/eolang/Expect.java b/eo-runtime/src/main/java/org/eolang/Expect.java index 2424138e1c..de9ff53bd1 100644 --- a/eo-runtime/src/main/java/org/eolang/Expect.java +++ b/eo-runtime/src/main/java/org/eolang/Expect.java @@ -98,7 +98,7 @@ public Expect otherwise(final String message) { return this.sup.get(); } catch (final ExFailure ex) { throw new ExFailure( - String.format("%s %s", this.subject, message), + String.format("%s %s %s", this.subject, ex.getMessage(), message), ex ); } @@ -118,7 +118,7 @@ public Expect must(final Function fun) { final T ret = this.sup.get(); if (!fun.apply(ret)) { throw new ExFailure( - String.format("%s (%s)", this.subject, ret) + String.format("(%s)", ret) ); } return ret; diff --git a/eo-runtime/src/main/java/org/eolang/PhLocated.java b/eo-runtime/src/main/java/org/eolang/PhLocated.java deleted file mode 100644 index fff7d22012..0000000000 --- a/eo-runtime/src/main/java/org/eolang/PhLocated.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2016-2024 Objectionary.com - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.eolang; - -import EOorg.EOeolang.EOerror; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -/** - * An object with coordinates (line and position). - * - * @since 0.21 - */ -@SuppressWarnings("PMD.TooManyMethods") -public final class PhLocated implements Phi, Atom { - - /** - * The original. - */ - private final Phi origin; - - /** - * EO program name (the name of the {@code .eo} file). - */ - private final String program; - - /** - * The line number. - */ - private final int line; - - /** - * The position in the line. - */ - private final int position; - - /** - * The location. - */ - private final String location; - - /** - * Ctor. - * - * @param phi The object - * @param prg Name of the program - * @param lne Line - * @param pos Position - * @checkstyle ParameterNumberCheck (5 lines) - */ - public PhLocated(final Phi phi, final String prg, final int lne, final int pos) { - this(phi, prg, lne, pos, "?"); - } - - /** - * Ctor. - * - * @param phi The object - * @param prg Name of the program - * @param lne Line - * @param pos Position - * @param loc Location - * @checkstyle ParameterNumberCheck (5 lines) - */ - public PhLocated(final Phi phi, final String prg, final int lne, - final int pos, final String loc) { - this.origin = phi; - this.program = prg; - this.line = lne; - this.position = pos; - this.location = loc; - } - - @Override - public boolean equals(final Object obj) { - return this.origin.equals(obj); - } - - @Override - public int hashCode() { - return this.origin.hashCode(); - } - - @Override - public Phi copy() { - return new PhLocated( - this.origin.copy(), this.program, - this.line, this.position, this.location - ); - } - - @Override - public Phi take(final String name) { - return this.through(() -> this.origin.take(name)); - } - - @Override - public boolean put(final int pos, final Phi object) { - return this.through(() -> this.origin.put(pos, object)); - } - - @Override - public boolean put(final String nme, final Phi object) { - return this.through(() -> this.origin.put(nme, object)); - } - - @Override - public String locator() { - return String.format("%s:%d:%d", this.location, this.line, this.position); - } - - @Override - public String forma() { - return this.through(this.origin::forma); - } - - @Override - public byte[] delta() { - return this.through(this.origin::delta, ".Δ"); - } - - @Override - public Phi lambda() { - return this.through(() -> new AtomSafe((Atom) this.origin).lambda(), ".λ"); - } - - /** - * Helper, for other methods. - * @param action The action - * @param Type of result - * @return Result - */ - private T through(final Action action) { - return this.through(action, ""); - } - - /** - * Helper, for other methods. - * @param action The action - * @param suffix The suffix to add to the label - * @param Type of result - * @return Result - * @checkstyle IllegalCatchCheck (20 lines) - */ - @SuppressWarnings("PMD.AvoidCatchingGenericException") - private T through(final Action action, final String suffix) { - try { - return action.act(); - } catch (final ExUnset ex) { - throw new ExUnset(this.label(suffix), ex); - } catch (final ExReadOnly ex) { - throw new ExReadOnly(this.label(suffix), ex); - } catch (final EOerror.ExError ex) { - throw new EOerror.ExError(ex, this.label(suffix)); - } catch (final ExAbstract | Error ex) { - throw new ExFailure(this.label(suffix), ex); - } catch (final RuntimeException ex) { - throw this.wrap(ex, suffix); - } - } - - /** - * Wrap the exception into a new one. - * @param cause Original - * @param suffix Te suffix - * @return New exception - */ - private RuntimeException wrap(final RuntimeException cause, - final String suffix) { - final String label = this.label(suffix); - RuntimeException ret; - try { - final Constructor ctor = - cause.getClass().getConstructor(String.class, Throwable.class); - ret = ctor.newInstance(label, cause); - } catch (final NoSuchMethodException | InstantiationException - | IllegalAccessException | InvocationTargetException ex) { - ret = new ExFailure(label, cause); - } - return ret; - } - - /** - * The label of the exception. - * @param suffix The suffix to add to the label - * @return Label - */ - private String label(final String suffix) { - return String.format( - "Error in \"%s%s\" at %s:%d:%d", - this.location, suffix, this.program, this.line, this.position - ); - } -} diff --git a/eo-runtime/src/main/java/org/eolang/PhSafe.java b/eo-runtime/src/main/java/org/eolang/PhSafe.java index bff4897426..c15c363160 100644 --- a/eo-runtime/src/main/java/org/eolang/PhSafe.java +++ b/eo-runtime/src/main/java/org/eolang/PhSafe.java @@ -25,75 +25,141 @@ package org.eolang; import EOorg.EOeolang.EOerror; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; /** - * It catches {@link ExFailure} and - * throws {@link EOerror.ExError}. + * An object with coordinates (line and position) and a safe + * processing of any runtime errors. * - * @since 0.26 + *

It is used to wrap any object and provide a safe processing + * of any runtime errors. It is used in the EO runtime to provide + * a safe processing of any runtime errors in the EO code. If, in any + * method invocation, a runtime error occurs, it is caught and wrapped + * into {@link EOerror.ExError} with the location of the error in the + * EO code.

+ * + * @since 0.21 */ @SuppressWarnings("PMD.TooManyMethods") -public final class PhSafe implements Phi { +public final class PhSafe implements Phi, Atom { /** * The original. */ private final Phi origin; + /** + * EO program name (the name of the {@code .eo} file). + */ + private final String program; + + /** + * The line number. + */ + private final int line; + + /** + * The position in the line. + */ + private final int position; + + /** + * The location. + */ + private final String location; + /** * Ctor. + * * @param phi The object + * @checkstyle ParameterNumberCheck (5 lines) */ public PhSafe(final Phi phi) { + this(phi, "unknown", 0, 0); + } + + /** + * Ctor. + * + * @param phi The object + * @param prg Name of the program + * @param lne Line + * @param pos Position + * @checkstyle ParameterNumberCheck (5 lines) + */ + public PhSafe(final Phi phi, final String prg, final int lne, final int pos) { + this(phi, prg, lne, pos, "?"); + } + + /** + * Ctor. + * + * @param phi The object + * @param prg Name of the program + * @param lne Line + * @param pos Position + * @param loc Location + * @checkstyle ParameterNumberCheck (5 lines) + */ + public PhSafe(final Phi phi, final String prg, final int lne, + final int pos, final String loc) { this.origin = phi; + this.program = prg; + this.line = lne; + this.position = pos; + this.location = loc; } @Override public boolean equals(final Object obj) { - return PhSafe.through(() -> this.origin.equals(obj)); + return this.origin.equals(obj); } @Override public int hashCode() { - return PhSafe.through(this.origin::hashCode); + return this.origin.hashCode(); } @Override public Phi copy() { - return PhSafe.through(() -> new PhSafe(this.origin.copy())); + return new PhSafe( + this.origin.copy(), this.program, + this.line, this.position, this.location + ); } @Override public Phi take(final String name) { - return PhSafe.through(() -> new PhSafe(this.origin.take(name))); + return this.through(() -> this.origin.take(name)); } @Override public boolean put(final int pos, final Phi object) { - return PhSafe.through(() -> this.origin.put(pos, object)); + return this.through(() -> this.origin.put(pos, object)); } @Override - public boolean put(final String name, final Phi object) { - return PhSafe.through(() -> this.origin.put(name, object)); + public boolean put(final String nme, final Phi object) { + return this.through(() -> this.origin.put(nme, object)); } @Override public String locator() { - return PhSafe.through(this.origin::locator); + return String.format("%s:%d:%d", this.location, this.line, this.position); } @Override public String forma() { - return PhSafe.through(this.origin::forma); + return this.through(this.origin::forma); } @Override public byte[] delta() { - return PhSafe.through(this.origin::delta); + return this.through(this.origin::delta, ".Δ"); + } + + @Override + public Phi lambda() { + return this.through(() -> new AtomSafe((Atom) this.origin).lambda(), ".λ"); } /** @@ -102,53 +168,63 @@ public byte[] delta() { * @param Type of result * @return Result */ - private static T through(final Action action) { - try { - return action.act(); - } catch (final ExFailure ex) { - throw new EOerror.ExError( - new Data.ToPhi(PhSafe.message(ex)), - PhSafe.messages(ex) - ); - } + private T through(final Action action) { + return this.through(action, ""); } /** - * Make a message from an exception. - * @param exp The exception. - * @return Message. + * Helper, for other methods. + * + *

No matter what happens inside the {@code action}, only + * an instance of {@link EOerror.ExError} may be thrown out + * of this method.

+ * + * @param action The action + * @param suffix The suffix to add to the label + * @param Type of result + * @return Result + * @checkstyle IllegalCatchCheck (20 lines) */ - private static String message(final Throwable exp) { - final StringBuilder ret = new StringBuilder(0); - if (!(exp instanceof ExFailure)) { - ret.append(exp.getClass().getSimpleName()); - } - if (exp.getMessage() != null) { - if (ret.length() > 0) { - ret.append(": "); + @SuppressWarnings({"PMD.AvoidCatchingThrowable", "PMD.PreserveStackTrace"}) + private T through(final Action action, final String suffix) { + try { + return action.act(); + } catch (final EOerror.ExError ex) { + throw new EOerror.ExError(ex, this.label(suffix)); + } catch (final ExAbstract ex) { + throw new EOerror.ExError( + new Data.ToPhi(ex.getMessage()), + this.label(suffix) + ); + } catch (final Throwable ex) { + final StringBuilder msg = new StringBuilder(0); + final StackTraceElement[] stack = ex.getStackTrace(); + if (stack != null && stack.length > 0) { + final StackTraceElement last = stack[0]; + msg.append(last.getFileName()) + .append(':') + .append(last.getLineNumber()) + .append(": "); } - ret.append(exp.getMessage().replace("%", "%%")); - } - if (exp.getCause() != null) { - ret.setLength(0); - ret.append(PhSafe.message(exp.getCause())); + msg.append(ex.getClass().getSimpleName()) + .append(": ") + .append(ex.getMessage()); + throw new EOerror.ExError( + new Data.ToPhi(msg.toString()), + this.label(suffix) + ); } - return ret.toString(); } /** - * Make a chain of messages from an exception and its causes. - * @param exp The exception - * @return Messages + * The label of the exception. + * @param suffix The suffix to add to the label + * @return Label */ - private static List messages(final Throwable exp) { - final List msgs = new LinkedList<>(); - if (exp != null) { - msgs.add(exp.getMessage()); - msgs.addAll(PhSafe.messages(exp.getCause())); - Collections.reverse(msgs); - } - return msgs; + private String label(final String suffix) { + return String.format( + "Error in \"%s%s\" at %s:%d:%d", + this.location, suffix, this.program, this.line, this.position + ); } - } diff --git a/eo-runtime/src/test/java/EOorg/EOeolang/EObytesEOsliceTest.java b/eo-runtime/src/test/java/EOorg/EOeolang/EObytesEOsliceTest.java index 3e1d6a9731..2def3adcf0 100644 --- a/eo-runtime/src/test/java/EOorg/EOeolang/EObytesEOsliceTest.java +++ b/eo-runtime/src/test/java/EOorg/EOeolang/EObytesEOsliceTest.java @@ -32,7 +32,6 @@ import java.io.PrintWriter; import org.eolang.Data; import org.eolang.Dataized; -import org.eolang.ExFailure; import org.eolang.PhWith; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; @@ -71,8 +70,8 @@ void takesLegalSlice() { @Test void takesWrongSlice() { - final ExFailure exp = Assertions.assertThrows( - ExFailure.class, + final EOerror.ExError exp = Assertions.assertThrows( + EOerror.ExError.class, () -> new Dataized( new PhWith( new PhWith( @@ -96,10 +95,7 @@ void takesWrongSlice() { MatcherAssert.assertThat( "error message is correct", baos.toString(), - Matchers.allOf( - Matchers.containsString("the 'len' attribute must be a positive integer"), - Matchers.containsString("the 'len' attribute (-5)") - ) + Matchers.containsString("the 'len' attribute (-5) must be a positive integer") ); } diff --git a/eo-runtime/src/test/java/EOorg/EOeolang/EOtryTest.java b/eo-runtime/src/test/java/EOorg/EOeolang/EOtryTest.java index 6625acbe7d..02fc3562a7 100644 --- a/eo-runtime/src/test/java/EOorg/EOeolang/EOtryTest.java +++ b/eo-runtime/src/test/java/EOorg/EOeolang/EOtryTest.java @@ -53,7 +53,7 @@ final class EOtryTest { @Test void catchesException() { MatcherAssert.assertThat( - AtCompositeTest.TO_ADD_MESSAGE, + "catches exception", new Dataized( new PhWith( new PhWith( @@ -73,20 +73,21 @@ void catchesException() { @Test void usesCatcherOutput() { - final Phi body = new PhWith( - new PhWith( - new PhWith( - new EOtry(), - 0, new PhSafe(new Broken()) - ), - 1, new Catcher() - ), - 2, - new Data.ToPhi(true) - ); MatcherAssert.assertThat( - AtCompositeTest.TO_ADD_MESSAGE, - new Dataized(body).asString(), + "uses catcher's output", + new Dataized( + new PhWith( + new PhWith( + new PhWith( + new EOtry(), + 0, new PhSafe(new Broken()) + ), + 1, new Catcher() + ), + 2, + new Data.ToPhi(true) + ) + ).asString(), Matchers.containsString("it is broken") ); } diff --git a/eo-runtime/src/test/java/org/eolang/DataizedTest.java b/eo-runtime/src/test/java/org/eolang/DataizedTest.java index 827d7339a5..a6e4a101df 100644 --- a/eo-runtime/src/test/java/org/eolang/DataizedTest.java +++ b/eo-runtime/src/test/java/org/eolang/DataizedTest.java @@ -56,11 +56,20 @@ void logsAllLocationsWithPhSafe() { EOerror.ExError.class, () -> new Dataized( new PhSafe( - new PhLocated(new PhIncorrect(), "foo.bar", 0, 0) + new PhMethod( + new PhDefault() { + @Override + public Phi take(final String name) { + throw new IllegalStateException("intentional error"); + } + }, + "xyz" + ), + "foo.bar", 0, 0 ), log ).take(), - "it is expected to fail with ExFailure exception" + "it is expected to fail with and exception" ); log.setLevel(before); log.removeHandler(hnd); @@ -69,10 +78,8 @@ void logsAllLocationsWithPhSafe() { logs.get(0).getMessage(), Matchers.allOf( Matchers.containsString("1) Error in"), - Matchers.containsString("2) There's no"), - Matchers.containsString("3)"), Matchers.containsString("at foo.bar:0:0"), - Matchers.containsString("no \"Δ\" in the object of") + Matchers.containsString("intentional error") ) ); } @@ -92,55 +99,6 @@ void failsWhenError() { ); } - /** - * Fake Phi failing when dataized. - * @since 0.1.0 - */ - private static class PhIncorrect extends PhDefault { - - /** - * Ctor. - */ - @SuppressWarnings("PMD.ConstructorOnlyInitializesOrCallOtherConstructors") - PhIncorrect() { - this.add( - "Δ", - new AtComposite( - this, - rho -> Phi.Φ - ) - ); - } - } - - /** - * Fake Phi with decoration. - * - * @since 0.1.0 - */ - public static class PhiDec extends PhDefault { - - /** - * Ctor. - */ - @SuppressWarnings("PMD.ConstructorOnlyInitializesOrCallOtherConstructors") - PhiDec() { - this.add( - "φ", - new AtOnce( - new AtComposite( - this, - rho -> new PhWith( - new PhCopy(new PhMethod(new Data.ToPhi(2L), "plus")), - 0, - new Data.ToPhi(2L) - ) - ) - ) - ); - } - } - /** * Handler implementation for tests. * diff --git a/eo-runtime/src/test/java/org/eolang/PhLocatedTest.java b/eo-runtime/src/test/java/org/eolang/PhLocatedTest.java deleted file mode 100644 index 3db7275b4b..0000000000 --- a/eo-runtime/src/test/java/org/eolang/PhLocatedTest.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2016-2024 Objectionary.com - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package org.eolang; - -import org.hamcrest.MatcherAssert; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * Test case for {@link PhLocatedTest}. - * - * @since 0.36.0 - */ -final class PhLocatedTest { - - @Test - void savesLocationAfterCopying() { - final Phi located = new PhLocated(new Data.ToPhi(0L), "foo", 123, 124, "qwerty"); - MatcherAssert.assertThat( - "saves location", - located.copy().locator(), - Matchers.equalTo(located.locator()) - ); - } - - @Test - void catchesRuntimeException() { - MatcherAssert.assertThat( - "rethrows correctly", - Assertions.assertThrows( - IllegalArgumentException.class, - () -> new PhLocated( - new PhDefault() { - @Override - public byte[] delta() { - throw new IllegalArgumentException("oops"); - } - }, - "foobar", 10, 20 - ).delta(), - "throws correct class" - ), - Matchers.hasToString( - Matchers.containsString("Error in \"?.Δ\" at foobar:10:20") - ) - ); - } -} diff --git a/eo-runtime/src/test/java/org/eolang/PhSafeTest.java b/eo-runtime/src/test/java/org/eolang/PhSafeTest.java index 903ae44d34..e8360630c4 100644 --- a/eo-runtime/src/test/java/org/eolang/PhSafeTest.java +++ b/eo-runtime/src/test/java/org/eolang/PhSafeTest.java @@ -30,12 +30,44 @@ import org.junit.jupiter.api.Test; /** - * Test case for {@link PhSafe}. + * Test case for {@link PhSafeTest}. * - * @since 0.42 + * @since 0.36.0 */ final class PhSafeTest { + @Test + void savesLocationAfterCopying() { + final Phi located = new PhSafe(new Data.ToPhi(0L), "foo", 123, 124, "qwerty"); + MatcherAssert.assertThat( + "saves location", + located.copy().locator(), + Matchers.equalTo(located.locator()) + ); + } + + @Test + void catchesRuntimeException() { + MatcherAssert.assertThat( + "rethrows correctly", + Assertions.assertThrows( + EOerror.ExError.class, + () -> new PhSafe( + new PhDefault() { + @Override + public byte[] delta() { + throw new IllegalArgumentException("oops"); + } + } + ).delta(), + "throws correct class" + ).messages(), + Matchers.hasItem( + Matchers.containsString("Error in \"?.Δ\" at unknown:0:0") + ) + ); + } + @Test void rendersMultiLayeredErrorMessageCorrectly() { MatcherAssert.assertThat( @@ -57,4 +89,30 @@ void rendersMultiLayeredErrorMessageCorrectly() { ); } + @Test + void showsFileNameAndLineNumber() { + MatcherAssert.assertThat( + "shows file name and line number", + new Dataized( + Assertions.assertThrows( + EOerror.ExError.class, + () -> new PhSafe( + new PhDefault() { + @Override + public Phi take(final String name) { + throw new IllegalArgumentException("intentional error"); + } + } + ).take("foo"), + "throws correct class" + ).enclosure() + ).take(String.class), + Matchers.allOf( + Matchers.startsWith("PhSafeTest.java:"), + Matchers.containsString("IllegalArgumentException"), + Matchers.containsString("intentional error") + ) + ); + } + } diff --git a/eo-runtime/src/test/java/org/eolang/PhiTest.java b/eo-runtime/src/test/java/org/eolang/PhiTest.java index 6761f4dbc7..ca5aa723f9 100644 --- a/eo-runtime/src/test/java/org/eolang/PhiTest.java +++ b/eo-runtime/src/test/java/org/eolang/PhiTest.java @@ -99,7 +99,7 @@ void takesDirectly() { void getsLocation() { MatcherAssert.assertThat( AtCompositeTest.TO_ADD_MESSAGE, - new PhLocated( + new PhSafe( Phi.Φ, "foobar", 123,