1e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes/*
2e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes * Copyright (C) 2010 The Android Open Source Project
3e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes *
4e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
5e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes * you may not use this file except in compliance with the License.
6e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes * You may obtain a copy of the License at
7e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes *
8e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
9e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes *
10e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes * Unless required by applicable law or agreed to in writing, software
11e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
12e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes * See the License for the specific language governing permissions and
14e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes * limitations under the License.
15e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes */
16e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes
174557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonpackage libcore.java.lang;
18e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes
19e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughesimport java.io.PrintWriter;
20e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughesimport java.io.StringWriter;
218033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilsonimport java.util.Arrays;
22e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughesimport junit.framework.TestCase;
23b416ef5dc224630af2b9393a15ae120b27e4864aJesse Wilsonimport libcore.util.SerializationTester;
24e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes
25e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughespublic class ThrowableTest extends TestCase {
26e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes    private static class NoStackTraceException extends Exception {
27e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes        @Override
28e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes        public synchronized Throwable fillInStackTrace() {
29e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes            return null;
30e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes        }
31e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes    }
32e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes    public void testNullStackTrace() {
33e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes        try {
34e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes            throw new NoStackTraceException();
35e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes        } catch (NoStackTraceException ex) {
36e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes            // We used to throw NullPointerException when printing an exception with no stack trace.
37e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes            ex.printStackTrace(new PrintWriter(new StringWriter()));
38e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes        }
39e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes    }
408033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
41c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes    public void testNonWritableStackTrace() {
42c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes        try {
43c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            // The 4th argument, writableStackTrace, is false...
44c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            throw new SuppressionsThrowable("hi", null, true, false);
45c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes        } catch (Throwable th) {
46c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            assertEquals("hi", th.getMessage());
47c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes
48c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            // We see an empty stack trace.
49c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            assertEquals(0, th.getStackTrace().length);
50c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes
51c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            // setStackTrace is a no-op.
52c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            th.setStackTrace(new StackTraceElement[] { new StackTraceElement("c", "m", "f", -2) });
53c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            assertEquals(0, th.getStackTrace().length);
54c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes
55c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            // fillInStackTrace is a no-op.
56c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            th.fillInStackTrace();
57c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            assertEquals(0, th.getStackTrace().length);
58c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes
59c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            // It's still possible to print an exception with writableStackTrace == false.
60c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            th.printStackTrace(new PrintWriter(new StringWriter()));
61c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes        }
62c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes    }
63c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes
648033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    private static class SuppressionsThrowable extends Throwable {
65c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes        private static final long serialVersionUID = 202649043897209143L;
66c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes
678033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        public SuppressionsThrowable(String detailMessage, Throwable throwable,
68c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes                boolean enableSuppression, boolean writableStackTrace) {
69c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes            super(detailMessage, throwable, enableSuppression, writableStackTrace);
708033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        }
718033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
728033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
738033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testAddSuppressed() {
748033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = new Throwable();
758033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertSuppressed(throwable);
768033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable suppressedA = new Throwable();
778033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(suppressedA);
788033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertSuppressed(throwable, suppressedA);
798033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable suppressedB = new Throwable();
808033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(suppressedB);
818033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertSuppressed(throwable, suppressedA, suppressedB);
828033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
838033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
848033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testAddDuplicateSuppressed() {
858033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = new Throwable();
868033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable suppressedA = new Throwable();
878033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(suppressedA);
888033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(suppressedA);
898033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(suppressedA);
908033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertSuppressed(throwable, suppressedA, suppressedA, suppressedA);
918033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
928033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
938033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testGetSuppressedReturnsCopy() {
948033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = new Throwable();
958033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable suppressedA = new Throwable();
968033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable suppressedB = new Throwable();
978033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(suppressedA);
988033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(suppressedB);
998033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable[] mutable = throwable.getSuppressed();
1008033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        mutable[0] = null;
1018033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        mutable[1] = null;
1028033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertSuppressed(throwable, suppressedA, suppressedB);
1038033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
1048033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1058033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testAddSuppressedWithSuppressionDisabled() {
106c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes        Throwable throwable = new SuppressionsThrowable("foo", null, false, true);
1078033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertSuppressed(throwable);
1088033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(new Throwable());
1098033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertSuppressed(throwable);
1108033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(new Throwable());
1118033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertSuppressed(throwable);
1128033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
1138033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1148033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testAddSuppressedSelf() {
1158033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = new Throwable();
1168033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        try {
1178033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            throwable.addSuppressed(throwable);
1188033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            fail();
1198033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        } catch (IllegalArgumentException expected) {
1208033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        }
1218033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
1228033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1238033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testAddSuppressedNull() {
1248033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = new Throwable();
1258033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        try {
1268033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            throwable.addSuppressed(null);
1278033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            fail();
1288033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        } catch (NullPointerException expected) {
1298033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        }
1308033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
1318033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1328033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testPrintStackTraceWithCause() {
1338033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = newThrowable("Throwable", "A", "B");
1348033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.initCause(newThrowable("Cause", "A", "B", "C", "D"));
1358033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1368033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertEquals("java.lang.Throwable: Throwable\n"
1378033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassB.doB(ClassB.java:1)\n"
1388033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassA.doA(ClassA.java:0)\n"
1398033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "Caused by: java.lang.Throwable: Cause\n"
1408033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassD.doD(ClassD.java:3)\n"
1418033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassC.doC(ClassC.java:2)\n"
1428033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t... 2 more\n", printStackTraceToString(throwable));
1438033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
1448033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1458033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testPrintStackTraceWithCauseAndSuppressed() {
1468033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = newThrowable("Throwable", "A", "B");
1478033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.initCause(newThrowable("Cause", "A", "B", "C", "D"));
1488033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(newThrowable("Suppressed", "A", "B", "E", "F"));
1498033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(newThrowable("Suppressed", "A", "B", "G", "H"));
1508033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1518033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertEquals("java.lang.Throwable: Throwable\n"
1528033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassB.doB(ClassB.java:1)\n"
1538033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassA.doA(ClassA.java:0)\n"
1548033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tSuppressed: java.lang.Throwable: Suppressed\n"
1558033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\tat ClassF.doF(ClassF.java:3)\n"
1568033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\tat ClassE.doE(ClassE.java:2)\n"
1578033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\t... 2 more\n"
1588033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tSuppressed: java.lang.Throwable: Suppressed\n"
1598033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\tat ClassH.doH(ClassH.java:3)\n"
1608033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\tat ClassG.doG(ClassG.java:2)\n"
1618033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\t... 2 more\n"
1628033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "Caused by: java.lang.Throwable: Cause\n"
1638033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassD.doD(ClassD.java:3)\n"
1648033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassC.doC(ClassC.java:2)\n"
1658033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t... 2 more\n", printStackTraceToString(throwable));
1668033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
1678033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1688033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testPrintStackTraceWithEverything() {
1698033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = newThrowable("Throwable", "A", "B");
1708033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable cause = newThrowable("Cause", "A", "B", "C", "D");
1718033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable suppressed = newThrowable("Suppressed", "A", "B", "E", "F");
1728033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1738033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(suppressed);
1748033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        suppressed.addSuppressed(newThrowable("Suppressed/Suppressed", "A", "B", "E", "G"));
1758033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        suppressed.initCause(newThrowable("Suppressed/Cause", "A", "B", "E", "H"));
1768033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1778033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.initCause(cause);
1788033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        cause.addSuppressed(newThrowable("Cause/Suppressed", "A", "B", "C", "I"));
1798033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        cause.initCause(newThrowable("Cause/Cause", "A", "B", "C", "J"));
1808033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
1818033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertEquals("java.lang.Throwable: Throwable\n"
1828033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassB.doB(ClassB.java:1)\n"
1838033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassA.doA(ClassA.java:0)\n"
1848033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tSuppressed: java.lang.Throwable: Suppressed\n"
1858033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\tat ClassF.doF(ClassF.java:3)\n"
1868033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\tat ClassE.doE(ClassE.java:2)\n"
1878033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\t... 2 more\n"
1888033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\tSuppressed: java.lang.Throwable: Suppressed/Suppressed\n"
1898033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\t\tat ClassG.doG(ClassG.java:3)\n"
1908033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\t\t... 3 more\n"
1918033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tCaused by: java.lang.Throwable: Suppressed/Cause\n"
1928033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\tat ClassH.doH(ClassH.java:3)\n"
1938033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\t... 3 more\n"
1948033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "Caused by: java.lang.Throwable: Cause\n"
1958033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassD.doD(ClassD.java:3)\n"
1968033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassC.doC(ClassC.java:2)\n"
1978033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t... 2 more\n"
1988033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tSuppressed: java.lang.Throwable: Cause/Suppressed\n"
1998033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\tat ClassI.doI(ClassI.java:3)\n"
2008033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t\t... 3 more\n"
2018033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "Caused by: java.lang.Throwable: Cause/Cause\n"
2028033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\tat ClassJ.doJ(ClassJ.java:3)\n"
2038033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "\t... 3 more\n", printStackTraceToString(throwable));
2048033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
2058033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
2068033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testSetStackTraceWithNullElement() {
2078033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = new Throwable();
2088033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        try {
2098033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            throwable.setStackTrace(new StackTraceElement[]{ null });
2108033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            fail();
2118033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        } catch (NullPointerException expected) {
2128033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        }
2138033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
2148033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
2158033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testCauseSerialization() {
2168033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        String s = "aced0005737200136a6176612e6c616e672e5468726f7761626c65d5c635273977b8cb0300034c0"
2178033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "00563617573657400154c6a6176612f6c616e672f5468726f7761626c653b4c000d64657461696c4"
2188033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "d6573736167657400124c6a6176612f6c616e672f537472696e673b5b000a737461636b547261636"
2198033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "574001e5b4c6a6176612f6c616e672f537461636b5472616365456c656d656e743b78707371007e0"
2208033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "00071007e000574000543617573657572001e5b4c6a6176612e6c616e672e537461636b547261636"
2218033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "5456c656d656e743b02462a3c3cfd22390200007870000000047372001b6a6176612e6c616e672e5"
2228033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "37461636b5472616365456c656d656e746109c59a2636dd8502000449000a6c696e654e756d62657"
2238033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "24c000e6465636c6172696e67436c61737371007e00024c000866696c654e616d6571007e00024c0"
2248033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "00a6d6574686f644e616d6571007e0002787000000003740006436c6173734474000b436c6173734"
2258033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "42e6a617661740003646f447371007e000900000002740006436c6173734374000b436c617373432"
2268033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "e6a617661740003646f437371007e000900000001740006436c6173734274000b436c617373422e6"
2278033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "a617661740003646f427371007e000900000000740006436c6173734174000b436c617373412e6a6"
2288033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "17661740003646f41787400095468726f7761626c657571007e0007000000027371007e000900000"
2298033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "001740006436c6173734274000b436c617373422e6a617661740003646f427371007e00090000000"
2308033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "0740006436c6173734174000b436c617373412e6a617661740003646f4178";
2318033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = newThrowable("Throwable", "A", "B");
2328033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.initCause(newThrowable("Cause", "A", "B", "C", "D"));
2338033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertSerialized(throwable, s);
2348033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
2358033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
2368033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testSuppressedSerialization() {
2378033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        String s = "aced0005737200136a6176612e6c616e672e5468726f7761626c65d5c635273977b8cb0300044c0"
2388033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "00563617573657400154c6a6176612f6c616e672f5468726f7761626c653b4c000d64657461696c4"
2398033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "d6573736167657400124c6a6176612f6c616e672f537472696e673b5b000a737461636b547261636"
2408033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "574001e5b4c6a6176612f6c616e672f537461636b5472616365456c656d656e743b4c00147375707"
2418033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "0726573736564457863657074696f6e737400104c6a6176612f7574696c2f4c6973743b787071007"
2428033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "e000574000a53657269616c697a65647572001e5b4c6a6176612e6c616e672e537461636b5472616"
2438033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "365456c656d656e743b02462a3c3cfd22390200007870000000027372001b6a6176612e6c616e672"
2448033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "e537461636b5472616365456c656d656e746109c59a2636dd8502000449000a6c696e654e756d626"
2458033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "5724c000e6465636c6172696e67436c61737371007e00024c000866696c654e616d6571007e00024"
2468033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "c000a6d6574686f644e616d6571007e0002787000000001740006436c6173734274000b436c61737"
2478033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "3422e6a617661740003646f427371007e000900000000740006436c6173734174000b436c6173734"
2488033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "12e6a617661740003646f41737200136a6176612e7574696c2e41727261794c6973747881d21d99c"
2498033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "7619d03000149000473697a657870000000017704000000017371007e000071007e001474000a537"
2508033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "570707265737365647571007e0007000000047371007e000900000003740006436c6173734474000"
2518033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "b436c617373442e6a617661740003646f447371007e000900000002740006436c6173734374000b4"
2528033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "36c617373432e6a617661740003646f437371007e000900000001740006436c6173734274000b436"
2538033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "c617373422e6a617661740003646f427371007e000900000000740006436c6173734174000b436c6"
2548033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "17373412e6a617661740003646f41737200266a6176612e7574696c2e436f6c6c656374696f6e732"
2558033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "4556e6d6f6469666961626c654c697374fc0f2531b5ec8e100200014c00046c69737471007e00047"
2568033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "872002c6a6176612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c65436f6"
2578033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "c6c656374696f6e19420080cb5ef71e0200014c0001637400164c6a6176612f7574696c2f436f6c6"
2588033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "c656374696f6e3b78707371007e0012000000007704000000007871007e002b787878";
2598033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable throwable = newThrowable("Serialized", "A", "B");
2608033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.addSuppressed(newThrowable("Suppressed", "A", "B", "C", "D"));
2618033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertSerialized(throwable, s);
2628033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
2638033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
2648033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testDisableSuppressionSerialization() {
2658033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        String s = "aced0005737200356c6962636f72652e6a6176612e6c616e672e5468726f7761626c65546573742"
2668033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "45375707072657373696f6e735468726f7761626c6502cff43b5390d137020000787200136a61766"
2678033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "12e6c616e672e5468726f7761626c65d5c635273977b8cb0300044c000563617573657400154c6a6"
2688033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "176612f6c616e672f5468726f7761626c653b4c000d64657461696c4d6573736167657400124c6a6"
2698033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "176612f6c616e672f537472696e673b5b000a737461636b547261636574001e5b4c6a6176612f6c6"
2708033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "16e672f537461636b5472616365456c656d656e743b4c00147375707072657373656445786365707"
2718033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "4696f6e737400104c6a6176612f7574696c2f4c6973743b787070740003666f6f7572001e5b4c6a6"
2728033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "176612e6c616e672e537461636b5472616365456c656d656e743b02462a3c3cfd223902000078700"
2738033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "00000007078";
274c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes        Throwable throwable = new SuppressionsThrowable("foo", null, false, true);
2758033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.setStackTrace(new StackTraceElement[0]);
276b416ef5dc224630af2b9393a15ae120b27e4864aJesse Wilson        new SerializationTester<Throwable>(throwable, s) {
2778033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            @Override protected boolean equals(Throwable a, Throwable b) {
2788033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                return printStackTraceToString(a).equals(printStackTraceToString(b));
2798033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            }
2808033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            @Override protected void verify(Throwable deserialized) {
2818033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                // the suppressed exception is silently discarded
2828033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                deserialized.addSuppressed(newThrowable("Suppressed"));
2838033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                assertSuppressed(deserialized);
2848033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            }
2858033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        }.test();
2868033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
2878033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
2888033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    public void testEnableSuppressionSerialization() {
2898033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        String s = "aced0005737200356c6962636f72652e6a6176612e6c616e672e5468726f7761626c65546573742"
2908033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "45375707072657373696f6e735468726f7761626c6502cff43b5390d137020000787200136a61766"
2918033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "12e6c616e672e5468726f7761626c65d5c635273977b8cb0300044c000563617573657400154c6a6"
2928033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "176612f6c616e672f5468726f7761626c653b4c000d64657461696c4d6573736167657400124c6a6"
2938033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "176612f6c616e672f537472696e673b5b000a737461636b547261636574001e5b4c6a6176612f6c6"
2948033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "16e672f537461636b5472616365456c656d656e743b4c00147375707072657373656445786365707"
2958033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "4696f6e737400104c6a6176612f7574696c2f4c6973743b787070740003666f6f7572001e5b4c6a6"
2968033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "176612e6c616e672e537461636b5472616365456c656d656e743b02462a3c3cfd223902000078700"
2978033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "0000000737200266a6176612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626"
2988033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "c654c697374fc0f2531b5ec8e100200014c00046c69737471007e00057872002c6a6176612e75746"
2998033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "96c2e436f6c6c656374696f6e7324556e6d6f6469666961626c65436f6c6c656374696f6e1942008"
3008033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "0cb5ef71e0200014c0001637400164c6a6176612f7574696c2f436f6c6c656374696f6e3b7870737"
3018033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657"
3028033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                + "870000000007704000000007871007e000f78";
303c2f2aaaae219c69d50eee6549d507c91e9a08519Elliott Hughes        Throwable throwable = new SuppressionsThrowable("foo", null, true, true);
3048033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.setStackTrace(new StackTraceElement[0]);
305b416ef5dc224630af2b9393a15ae120b27e4864aJesse Wilson        new SerializationTester<Throwable>(throwable, s) {
3068033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            @Override protected boolean equals(Throwable a, Throwable b) {
3078033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                return printStackTraceToString(a).equals(printStackTraceToString(b));
3088033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            }
3098033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            @Override protected void verify(Throwable deserialized) {
3108033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                // the suppressed exception is permitted
3118033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                Throwable suppressed = newThrowable("Suppressed");
3128033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                deserialized.addSuppressed(suppressed);
3138033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                assertSuppressed(deserialized, suppressed);
3148033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            }
3158033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        }.test();
3168033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
3178033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
3188033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    private void assertSerialized(final Throwable throwable, String golden) {
319b416ef5dc224630af2b9393a15ae120b27e4864aJesse Wilson        new SerializationTester<Throwable>(throwable, golden) {
3208033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            @Override protected boolean equals(Throwable a, Throwable b) {
3218033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                return printStackTraceToString(a).equals(printStackTraceToString(b));
3228033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            }
3238033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        }.test();
3248033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
3258033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
3268033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    private Throwable newThrowable(String message, String... stackTraceElements) {
3278033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        StackTraceElement[] array = new StackTraceElement[stackTraceElements.length];
3288033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        for (int i = 0; i < stackTraceElements.length; i++) {
3298033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            String s = stackTraceElements[i];
3308033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            array[stackTraceElements.length - 1 - i]
3318033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson                    = new StackTraceElement("Class" + s, "do" + s, "Class" + s + ".java", i);
3328033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        }
3338033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        Throwable result = new Throwable(message);
3348033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        result.setStackTrace(array);
3358033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        return result;
3368033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
3378033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
3388033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    private String printStackTraceToString(Throwable throwable) {
3398033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        StringWriter writer = new StringWriter();
3408033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        throwable.printStackTrace(new PrintWriter(writer));
3418033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        return writer.toString();
3428033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
3438033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
3448033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    private void assertSuppressed(Throwable throwable, Throwable... expectedSuppressed) {
3458033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson        assertEquals(Arrays.asList(throwable.getSuppressed()), Arrays.asList(expectedSuppressed));
3468033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    }
347e8ca15fac603d1adb0fd9007ea6343584a15db67Elliott Hughes}
348