/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary Tests for exceptions
* @build KullaTesting TestingInputStream
* @run testng ExceptionsTest
*/
import jdk.jshell.SnippetEvent;
import jdk.jshell.EvalException;
import java.io.PrintWriter;
import java.io.StringWriter;
import jdk.jshell.Snippet;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@Test
public class ExceptionsTest extends KullaTesting {
public void throwUncheckedException() {
String message = "error_message";
SnippetEvent cr = assertEvalException("throw new RuntimeException(\"" + message + "\");");
assertExceptionMatch(cr,
new ExceptionInfo(RuntimeException.class, message,
newStackTraceElement("", "", cr.snippet(), 1)));
}
public void throwCheckedException() {
String message = "error_message";
SnippetEvent cr = assertEvalException("throw new Exception(\"" + message + "\");");
assertExceptionMatch(cr,
new ExceptionInfo(Exception.class, message,
newStackTraceElement("", "", cr.snippet(), 1)));
}
public void throwFromStaticMethodOfClass() {
String message = "error_message";
Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }"));
Snippet s2 = classKey(assertEval("class A { static void g() { f(); } }"));
SnippetEvent cr3 = assertEvalException("A.g();");
assertExceptionMatch(cr3,
new ExceptionInfo(RuntimeException.class, message,
newStackTraceElement("", "f", s1, 1),
newStackTraceElement("A", "g", s2, 1),
newStackTraceElement("", "", cr3.snippet(), 1)));
}
public void throwFromStaticMethodOfInterface() {
String message = "error_message";
Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }"));
Snippet s2 = classKey(assertEval("interface A { static void g() { f(); } }"));
SnippetEvent cr3 = assertEvalException("A.g();");
assertExceptionMatch(cr3,
new ExceptionInfo(RuntimeException.class, message,
newStackTraceElement("", "f", s1, 1),
newStackTraceElement("A", "g", s2, 1),
newStackTraceElement("", "", cr3.snippet(), 1)));
}
public void throwFromConstructor() {
String message = "error_message";
Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }"));
Snippet s2 = classKey(assertEval("class A { A() { f(); } }"));
SnippetEvent cr3 = assertEvalException("new A();");
assertExceptionMatch(cr3,
new ExceptionInfo(RuntimeException.class, message,
newStackTraceElement("", "f", s1, 1),
newStackTraceElement("A", "<init>", s2, 1),
newStackTraceElement("", "", cr3.snippet(), 1)));
}
public void throwFromDefaultMethodOfInterface() {
String message = "error_message";
Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }"));
Snippet s2 = classKey(assertEval("interface A { default void g() { f(); } }"));
SnippetEvent cr3 = assertEvalException("new A() { }.g();");
assertExceptionMatch(cr3,
new ExceptionInfo(RuntimeException.class, message,
newStackTraceElement("", "f", s1, 1),
newStackTraceElement("A", "g", s2, 1),
newStackTraceElement("", "", cr3.snippet(), 1)));
}
public void throwFromLambda() {
String message = "lambda";
Snippet s1 = varKey(assertEval(
"Runnable run = () -> {\n" +
" throw new RuntimeException(\"" + message + "\");\n" +
"};"
));
SnippetEvent cr2 = assertEvalException("run.run();");
assertExceptionMatch(cr2,
new ExceptionInfo(RuntimeException.class, message,
newStackTraceElement("", "lambda$", s1, 2),
newStackTraceElement("", "", cr2.snippet(), 1)));
}
public void throwFromAnonymousClass() {
String message = "anonymous";
Snippet s1 = varKey(assertEval(
"Runnable run = new Runnable() {\n" +
" public void run() {\n"+
" throw new RuntimeException(\"" + message + "\");\n" +
" }\n" +
"};"
));
SnippetEvent cr2 = assertEvalException("run.run();");
assertExceptionMatch(cr2,
new ExceptionInfo(RuntimeException.class, message,
newStackTraceElement("1", "run", s1, 3),
newStackTraceElement("", "", cr2.snippet(), 1)));
}
public void throwFromLocalClass() {
String message = "local";
Snippet s1 = methodKey(assertEval(
"void f() {\n" +
" class A {\n" +
" void f() {\n"+
" throw new RuntimeException(\"" + message + "\");\n" +
" }\n" +
" }\n" +
" new A().f();\n" +
"}"
));
SnippetEvent cr2 = assertEvalException("f();");
assertExceptionMatch(cr2,
new ExceptionInfo(RuntimeException.class, message,
newStackTraceElement("1A", "f", s1, 4),
newStackTraceElement("", "f", s1, 7),
newStackTraceElement("", "", cr2.snippet(), 1)));
}
@Test(enabled = false) // TODO 8129427
public void outOfMemory() {
assertEval("import java.util.*;");
assertEval("List<byte[]> list = new ArrayList<>();");
assertExecuteException("while (true) { list.add(new byte[10000]); }", OutOfMemoryError.class);
}
public void stackOverflow() {
assertEval("void f() { f(); }");
assertExecuteException("f();", StackOverflowError.class);
}
private StackTraceElement newStackTraceElement(String className, String methodName, Snippet key, int lineNumber) {
return new StackTraceElement(className, methodName, "#" + key.id(), lineNumber);
}
private static class ExceptionInfo {
public final Class<? extends Throwable> exception;
public final String message;
public final StackTraceElement[] stackTraceElements;
public ExceptionInfo(Class<? extends Throwable> exception, String message, StackTraceElement...stackTraceElements) {
this.exception = exception;
this.message = message;
this.stackTraceElements = stackTraceElements.length == 0 ? null : stackTraceElements;
}
}
private void assertExecuteException(String input, Class<? extends Throwable> exception) {
assertExceptionMatch(assertEvalException(input), new ExceptionInfo(exception, null));
}
private void assertExceptionMatch(SnippetEvent cr, ExceptionInfo exceptionInfo) {
assertNotNull(cr.exception(), "Expected exception was not thrown: " + exceptionInfo.exception);
if (cr.exception() instanceof EvalException) {
EvalException ex = (EvalException) cr.exception();
String actualException = ex.getExceptionClassName();
String expectedException = exceptionInfo.exception.getCanonicalName();
String stackTrace = getStackTrace(ex);
String source = cr.snippet().source();
assertEquals(actualException, expectedException,
String.format("Given \"%s\" expected exception: %s, got: %s%nStack trace:%n%s",
source, expectedException, actualException, stackTrace));
if (exceptionInfo.message != null) {
assertEquals(ex.getMessage(), exceptionInfo.message,
String.format("Given \"%s\" expected message: %s, got: %s",
source, exceptionInfo.message, ex.getMessage()));
}
if (exceptionInfo.stackTraceElements != null) {
assertStackTrace(ex.getStackTrace(), exceptionInfo.stackTraceElements,
String.format("Given \"%s\"%nStack trace:%n%s%n",
source, stackTrace));
}
} else {
fail("Unexpected execution exceptionInfo: " + cr.exception());
}
}
private void assertStackTrace(StackTraceElement[] actual, StackTraceElement[] expected, String message) {
if (actual != expected) {
if (actual == null || expected == null) {
fail(message);
} else {
assertEquals(actual.length, expected.length, message + " : arrays do not have the same size");
for (int i = 0; i < actual.length; ++i) {
StackTraceElement actualElement = actual[i];
StackTraceElement expectedElement = expected[i];
assertEquals(actualElement.getClassName(), expectedElement.getClassName(), message + " : class names");
String expectedMethodName = expectedElement.getMethodName();
if (expectedMethodName.startsWith("lambda$")) {
assertTrue(actualElement.getMethodName().startsWith("lambda$"), message + " : method names");
} else {
assertEquals(actualElement.getMethodName(), expectedElement.getMethodName(), message + " : method names");
}
assertEquals(actualElement.getFileName(), expectedElement.getFileName(), message + " : file names");
assertEquals(actualElement.getLineNumber(), expectedElement.getLineNumber(), message + " : line numbers");
}
}
}
}
private String getStackTrace(EvalException ex) {
StringWriter st = new StringWriter();
ex.printStackTrace(new PrintWriter(st));
return st.toString();
}
}