ExceptionsTest.java revision 3062:15bdc18525ff
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