1/* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @summary Tests for exceptions 27 * @build KullaTesting TestingInputStream 28 * @run testng ExceptionsTest 29 */ 30 31import jdk.jshell.SnippetEvent; 32import jdk.jshell.EvalException; 33import java.io.PrintWriter; 34import java.io.StringWriter; 35 36import jdk.jshell.Snippet; 37import org.testng.annotations.Test; 38 39import static org.testng.Assert.*; 40 41@Test 42public class ExceptionsTest extends KullaTesting { 43 44 public void throwUncheckedException() { 45 String message = "error_message"; 46 SnippetEvent cr = assertEvalException("throw new RuntimeException(\"" + message + "\");"); 47 assertExceptionMatch(cr, 48 new ExceptionInfo(RuntimeException.class, message, 49 newStackTraceElement("", "", cr.snippet(), 1))); 50 } 51 52 public void throwCheckedException() { 53 String message = "error_message"; 54 SnippetEvent cr = assertEvalException("throw new Exception(\"" + message + "\");"); 55 assertExceptionMatch(cr, 56 new ExceptionInfo(Exception.class, message, 57 newStackTraceElement("", "", cr.snippet(), 1))); 58 } 59 60 public void throwFromStaticMethodOfClass() { 61 String message = "error_message"; 62 Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); 63 Snippet s2 = classKey(assertEval("class A { static void g() { f(); } }")); 64 SnippetEvent cr3 = assertEvalException("A.g();"); 65 assertExceptionMatch(cr3, 66 new ExceptionInfo(RuntimeException.class, message, 67 newStackTraceElement("", "f", s1, 1), 68 newStackTraceElement("A", "g", s2, 1), 69 newStackTraceElement("", "", cr3.snippet(), 1))); 70 } 71 72 public void throwFromStaticMethodOfInterface() { 73 String message = "error_message"; 74 Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); 75 Snippet s2 = classKey(assertEval("interface A { static void g() { f(); } }")); 76 SnippetEvent cr3 = assertEvalException("A.g();"); 77 assertExceptionMatch(cr3, 78 new ExceptionInfo(RuntimeException.class, message, 79 newStackTraceElement("", "f", s1, 1), 80 newStackTraceElement("A", "g", s2, 1), 81 newStackTraceElement("", "", cr3.snippet(), 1))); 82 } 83 84 public void throwFromConstructor() { 85 String message = "error_message"; 86 Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); 87 Snippet s2 = classKey(assertEval("class A { A() { f(); } }")); 88 SnippetEvent cr3 = assertEvalException("new A();"); 89 assertExceptionMatch(cr3, 90 new ExceptionInfo(RuntimeException.class, message, 91 newStackTraceElement("", "f", s1, 1), 92 newStackTraceElement("A", "<init>", s2, 1), 93 newStackTraceElement("", "", cr3.snippet(), 1))); 94 } 95 96 public void throwFromDefaultMethodOfInterface() { 97 String message = "error_message"; 98 Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }")); 99 Snippet s2 = classKey(assertEval("interface A { default void g() { f(); } }")); 100 SnippetEvent cr3 = assertEvalException("new A() { }.g();"); 101 assertExceptionMatch(cr3, 102 new ExceptionInfo(RuntimeException.class, message, 103 newStackTraceElement("", "f", s1, 1), 104 newStackTraceElement("A", "g", s2, 1), 105 newStackTraceElement("", "", cr3.snippet(), 1))); 106 } 107 108 public void throwFromLambda() { 109 String message = "lambda"; 110 Snippet s1 = varKey(assertEval( 111 "Runnable run = () -> {\n" + 112 " throw new RuntimeException(\"" + message + "\");\n" + 113 "};" 114 )); 115 SnippetEvent cr2 = assertEvalException("run.run();"); 116 assertExceptionMatch(cr2, 117 new ExceptionInfo(RuntimeException.class, message, 118 newStackTraceElement("", "lambda$", s1, 2), 119 newStackTraceElement("", "", cr2.snippet(), 1))); 120 } 121 122 public void throwFromAnonymousClass() { 123 String message = "anonymous"; 124 Snippet s1 = varKey(assertEval( 125 "Runnable run = new Runnable() {\n" + 126 " public void run() {\n"+ 127 " throw new RuntimeException(\"" + message + "\");\n" + 128 " }\n" + 129 "};" 130 )); 131 SnippetEvent cr2 = assertEvalException("run.run();"); 132 assertExceptionMatch(cr2, 133 new ExceptionInfo(RuntimeException.class, message, 134 newStackTraceElement("1", "run", s1, 3), 135 newStackTraceElement("", "", cr2.snippet(), 1))); 136 } 137 138 public void throwFromLocalClass() { 139 String message = "local"; 140 Snippet s1 = methodKey(assertEval( 141 "void f() {\n" + 142 " class A {\n" + 143 " void f() {\n"+ 144 " throw new RuntimeException(\"" + message + "\");\n" + 145 " }\n" + 146 " }\n" + 147 " new A().f();\n" + 148 "}" 149 )); 150 SnippetEvent cr2 = assertEvalException("f();"); 151 assertExceptionMatch(cr2, 152 new ExceptionInfo(RuntimeException.class, message, 153 newStackTraceElement("1A", "f", s1, 4), 154 newStackTraceElement("", "f", s1, 7), 155 newStackTraceElement("", "", cr2.snippet(), 1))); 156 } 157 158 @Test(enabled = false) // TODO 8129427 159 public void outOfMemory() { 160 assertEval("import java.util.*;"); 161 assertEval("List<byte[]> list = new ArrayList<>();"); 162 assertExecuteException("while (true) { list.add(new byte[10000]); }", OutOfMemoryError.class); 163 } 164 165 public void stackOverflow() { 166 assertEval("void f() { f(); }"); 167 assertExecuteException("f();", StackOverflowError.class); 168 } 169 170 private StackTraceElement newStackTraceElement(String className, String methodName, Snippet key, int lineNumber) { 171 return new StackTraceElement(className, methodName, "#" + key.id(), lineNumber); 172 } 173 174 private static class ExceptionInfo { 175 public final Class<? extends Throwable> exception; 176 public final String message; 177 public final StackTraceElement[] stackTraceElements; 178 179 public ExceptionInfo(Class<? extends Throwable> exception, String message, StackTraceElement...stackTraceElements) { 180 this.exception = exception; 181 this.message = message; 182 this.stackTraceElements = stackTraceElements.length == 0 ? null : stackTraceElements; 183 } 184 } 185 186 private void assertExecuteException(String input, Class<? extends Throwable> exception) { 187 assertExceptionMatch(assertEvalException(input), new ExceptionInfo(exception, null)); 188 } 189 190 private void assertExceptionMatch(SnippetEvent cr, ExceptionInfo exceptionInfo) { 191 assertNotNull(cr.exception(), "Expected exception was not thrown: " + exceptionInfo.exception); 192 if (cr.exception() instanceof EvalException) { 193 EvalException ex = (EvalException) cr.exception(); 194 String actualException = ex.getExceptionClassName(); 195 String expectedException = exceptionInfo.exception.getCanonicalName(); 196 String stackTrace = getStackTrace(ex); 197 String source = cr.snippet().source(); 198 assertEquals(actualException, expectedException, 199 String.format("Given \"%s\" expected exception: %s, got: %s%nStack trace:%n%s", 200 source, expectedException, actualException, stackTrace)); 201 if (exceptionInfo.message != null) { 202 assertEquals(ex.getMessage(), exceptionInfo.message, 203 String.format("Given \"%s\" expected message: %s, got: %s", 204 source, exceptionInfo.message, ex.getMessage())); 205 } 206 if (exceptionInfo.stackTraceElements != null) { 207 assertStackTrace(ex.getStackTrace(), exceptionInfo.stackTraceElements, 208 String.format("Given \"%s\"%nStack trace:%n%s%n", 209 source, stackTrace)); 210 } 211 } else { 212 fail("Unexpected execution exceptionInfo: " + cr.exception()); 213 } 214 } 215 216 private void assertStackTrace(StackTraceElement[] actual, StackTraceElement[] expected, String message) { 217 if (actual != expected) { 218 if (actual == null || expected == null) { 219 fail(message); 220 } else { 221 assertEquals(actual.length, expected.length, message + " : arrays do not have the same size"); 222 for (int i = 0; i < actual.length; ++i) { 223 StackTraceElement actualElement = actual[i]; 224 StackTraceElement expectedElement = expected[i]; 225 assertEquals(actualElement.getClassName(), expectedElement.getClassName(), message + " : class names"); 226 String expectedMethodName = expectedElement.getMethodName(); 227 if (expectedMethodName.startsWith("lambda$")) { 228 assertTrue(actualElement.getMethodName().startsWith("lambda$"), message + " : method names"); 229 } else { 230 assertEquals(actualElement.getMethodName(), expectedElement.getMethodName(), message + " : method names"); 231 } 232 assertEquals(actualElement.getFileName(), expectedElement.getFileName(), message + " : file names"); 233 assertEquals(actualElement.getLineNumber(), expectedElement.getLineNumber(), message + " : line numbers"); 234 } 235 } 236 } 237 } 238 239 private String getStackTrace(EvalException ex) { 240 StringWriter st = new StringWriter(); 241 ex.printStackTrace(new PrintWriter(st)); 242 return st.toString(); 243 } 244} 245