1 /*
   2  * Copyright (c) 2010, 2011, 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 import java.io.*;
  25 import java.util.*;
  26 
  27 /*
  28  * @test
  29  * @bug     6911258 6962571 6963622 6991528 7005628 8012044
  30  * @summary Basic tests of suppressed exceptions
  31  * @author  Joseph D. Darcy
  32  */
  33 
  34 public class SuppressedExceptions {
  35     private static String message = "Bad suppressed exception information";
  36 
  37     public static void main(String... args) throws Exception {
  38         noSelfSuppression();
  39         basicSupressionTest();
  40         serializationTest();
  41         selfReference();
  42         noModification();
  43         initCausePlumbing();
  44     }
  45 
  46     private static void noSelfSuppression() {
  47         Throwable throwable = new Throwable();
  48         try {
  49             throwable.addSuppressed(throwable);
  50             throw new RuntimeException("IllegalArgumentException for self-suppresion not thrown.");
  51         } catch (IllegalArgumentException iae) {
  52             // Expected to be here
  53             if (iae.getCause() != throwable)
  54                 throw new RuntimeException("Bad cause after self-suppresion.");
  55         }
  56     }
  57 
  58     private static void basicSupressionTest() {
  59         Throwable throwable = new Throwable();
  60         RuntimeException suppressed = new RuntimeException("A suppressed exception.");
  61         AssertionError repressed  = new AssertionError("A repressed error.");
  62 
  63         Throwable[] t0 = throwable.getSuppressed();
  64         if (t0.length != 0) {
  65             throw new RuntimeException(message);
  66         }
  67         throwable.printStackTrace();
  68 
  69         throwable.addSuppressed(suppressed);
  70         Throwable[] t1 = throwable.getSuppressed();
  71         if (t1.length != 1 ||
  72             t1[0] != suppressed) {throw new RuntimeException(message);
  73         }
  74         throwable.printStackTrace();
  75 
  76         throwable.addSuppressed(repressed);
  77         Throwable[] t2 = throwable.getSuppressed();
  78         if (t2.length != 2 ||
  79             t2[0] != suppressed ||
  80             t2[1] != repressed) {
  81             throw new RuntimeException(message);
  82         }
  83         throwable.printStackTrace();
  84     }
  85 
  86     private static void serializationTest() throws Exception {
  87         /*
  88          * Bytes of the serial form of
  89          *
  90          * (new Throwable())setStackTrace(new StackTraceElement[0])
  91          *
  92          * from JDK 6; suppressedException field will be missing and
  93          * thus default to null upon deserialization.
  94          */
  95         byte[] bytes = {
  96             (byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x13,
  97             (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
  98             (byte)0x67, (byte)0x2e, (byte)0x54, (byte)0x68, (byte)0x72, (byte)0x6f, (byte)0x77, (byte)0x61,
  99             (byte)0x62, (byte)0x6c, (byte)0x65, (byte)0xd5, (byte)0xc6, (byte)0x35, (byte)0x27, (byte)0x39,
 100             (byte)0x77, (byte)0xb8, (byte)0xcb, (byte)0x03, (byte)0x00, (byte)0x03, (byte)0x4c, (byte)0x00,
 101             (byte)0x05, (byte)0x63, (byte)0x61, (byte)0x75, (byte)0x73, (byte)0x65, (byte)0x74, (byte)0x00,
 102             (byte)0x15, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c,
 103             (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x54, (byte)0x68, (byte)0x72, (byte)0x6f,
 104             (byte)0x77, (byte)0x61, (byte)0x62, (byte)0x6c, (byte)0x65, (byte)0x3b, (byte)0x4c, (byte)0x00,
 105             (byte)0x0d, (byte)0x64, (byte)0x65, (byte)0x74, (byte)0x61, (byte)0x69, (byte)0x6c, (byte)0x4d,
 106             (byte)0x65, (byte)0x73, (byte)0x73, (byte)0x61, (byte)0x67, (byte)0x65, (byte)0x74, (byte)0x00,
 107             (byte)0x12, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c,
 108             (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, (byte)0x74, (byte)0x72, (byte)0x69,
 109             (byte)0x6e, (byte)0x67, (byte)0x3b, (byte)0x5b, (byte)0x00, (byte)0x0a, (byte)0x73, (byte)0x74,
 110             (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65,
 111             (byte)0x74, (byte)0x00, (byte)0x1e, (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76,
 112             (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53,
 113             (byte)0x74, (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63,
 114             (byte)0x65, (byte)0x45, (byte)0x6c, (byte)0x65, (byte)0x6d, (byte)0x65, (byte)0x6e, (byte)0x74,
 115             (byte)0x3b, (byte)0x78, (byte)0x70, (byte)0x71, (byte)0x00, (byte)0x7e, (byte)0x00, (byte)0x04,
 116             (byte)0x70, (byte)0x75, (byte)0x72, (byte)0x00, (byte)0x1e, (byte)0x5b, (byte)0x4c, (byte)0x6a,
 117             (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67,
 118             (byte)0x2e, (byte)0x53, (byte)0x74, (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72,
 119             (byte)0x61, (byte)0x63, (byte)0x65, (byte)0x45, (byte)0x6c, (byte)0x65, (byte)0x6d, (byte)0x65,
 120             (byte)0x6e, (byte)0x74, (byte)0x3b, (byte)0x02, (byte)0x46, (byte)0x2a, (byte)0x3c, (byte)0x3c,
 121             (byte)0xfd, (byte)0x22, (byte)0x39, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
 122             (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0xac, (byte)0xed, (byte)0x00,
 123             (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x13, (byte)0x6a, (byte)0x61, (byte)0x76,
 124             (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x54,
 125             (byte)0x68, (byte)0x72, (byte)0x6f, (byte)0x77, (byte)0x61, (byte)0x62, (byte)0x6c, (byte)0x65,
 126             (byte)0xd5, (byte)0xc6, (byte)0x35, (byte)0x27, (byte)0x39, (byte)0x77, (byte)0xb8, (byte)0xcb,
 127             (byte)0x03, (byte)0x00, (byte)0x03, (byte)0x4c, (byte)0x00, (byte)0x05, (byte)0x63, (byte)0x61,
 128             (byte)0x75, (byte)0x73, (byte)0x65, (byte)0x74, (byte)0x00, (byte)0x15, (byte)0x4c, (byte)0x6a,
 129             (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67,
 130             (byte)0x2f, (byte)0x54, (byte)0x68, (byte)0x72, (byte)0x6f, (byte)0x77, (byte)0x61, (byte)0x62,
 131             (byte)0x6c, (byte)0x65, (byte)0x3b, (byte)0x4c, (byte)0x00, (byte)0x0d, (byte)0x64, (byte)0x65,
 132             (byte)0x74, (byte)0x61, (byte)0x69, (byte)0x6c, (byte)0x4d, (byte)0x65, (byte)0x73, (byte)0x73,
 133             (byte)0x61, (byte)0x67, (byte)0x65, (byte)0x74, (byte)0x00, (byte)0x12, (byte)0x4c, (byte)0x6a,
 134             (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x6e, (byte)0x67, (byte)0x3b,
 135             (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, (byte)0x74, (byte)0x72, (byte)0x69,
 136             (byte)0x5b, (byte)0x00, (byte)0x0a, (byte)0x73, (byte)0x74, (byte)0x61, (byte)0x63, (byte)0x6b,
 137             (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65, (byte)0x74, (byte)0x00, (byte)0x1e,
 138             (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c,
 139             (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, (byte)0x74, (byte)0x61, (byte)0x63,
 140             (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65, (byte)0x45, (byte)0x6c,
 141             (byte)0x65, (byte)0x6d, (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x3b, (byte)0x78, (byte)0x70,
 142             (byte)0x71, (byte)0x00, (byte)0x7e, (byte)0x00, (byte)0x04, (byte)0x70, (byte)0x75, (byte)0x72,
 143             (byte)0x00, (byte)0x1e, (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61,
 144             (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x53, (byte)0x74,
 145             (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65,
 146             (byte)0x45, (byte)0x6c, (byte)0x65, (byte)0x6d, (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x3b,
 147             (byte)0x02, (byte)0x46, (byte)0x2a, (byte)0x3c, (byte)0x3c, (byte)0xfd, (byte)0x22, (byte)0x39,
 148             (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
 149         };
 150 
 151         try(ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
 152             ObjectInputStream ois = new ObjectInputStream(bais)) {
 153             Object o = ois.readObject();
 154             Throwable throwable = (Throwable) o;
 155 
 156             System.err.println("TESTING SERIALIZED EXCEPTION");
 157 
 158             Throwable[] t0 = throwable.getSuppressed();
 159             if (t0.length != 0) { // Will fail if t0 is null.
 160                 throw new RuntimeException(message);
 161             }
 162             throwable.printStackTrace();
 163         }
 164     }
 165 
 166     private static void selfReference() {
 167         Throwable throwable1 = new RuntimeException();
 168         Throwable throwable2 = new AssertionError();
 169         throwable1.initCause(throwable2);
 170         throwable2.initCause(throwable1);
 171 
 172         throwable1.printStackTrace();
 173 
 174         throwable1.addSuppressed(throwable2);
 175         throwable2.addSuppressed(throwable1);
 176 
 177         throwable1.printStackTrace();
 178     }
 179 
 180     private static void noModification() {
 181         Throwable t = new NoSuppression(false);
 182 
 183         Throwable[] t0 = t.getSuppressed();
 184         if (t0.length != 0)
 185             throw new RuntimeException("Bad nonzero length of suppressed exceptions.");
 186 
 187         t.addSuppressed(new ArithmeticException());
 188 
 189         // Make sure a suppressed exception did *not* get added.
 190         t0 = t.getSuppressed();
 191         if (t0.length != 0)
 192             throw new RuntimeException("Bad nonzero length of suppressed exceptions.");
 193 
 194         Throwable suppressed = new ArithmeticException();
 195         t = new NoSuppression(true); // Suppression enabled
 196         // Make sure addSuppressed(null) throws an NPE
 197         try {
 198             t.addSuppressed(null);
 199             throw new RuntimeException("NPE not thrown!");
 200         } catch(NullPointerException e) {
 201             ; // Expected
 202         }
 203         t.addSuppressed(suppressed);
 204         t0 = t.getSuppressed();
 205         if (t0.length != 1 || t0[0] != suppressed)
 206             throw new RuntimeException("Expected suppression did not occur.");
 207     }
 208 
 209     private static class NoSuppression extends Throwable {
 210         public NoSuppression(boolean enableSuppression) {
 211             super("The medium.", null, enableSuppression, true);
 212         }
 213     }
 214 
 215     private static void initCausePlumbing() {
 216         Throwable t1 = new Throwable();
 217         Throwable t2 = new Throwable("message", t1);
 218         Throwable t3 = new Throwable();
 219 
 220         try {
 221             t2.initCause(t3);
 222             throw new RuntimeException("Shouldn't reach.");
 223         } catch (IllegalStateException ise) {
 224             if (ise.getCause() != null)
 225                 throw new RuntimeException("Unexpected cause in ISE", ise);
 226             Throwable[] suppressed = ise.getSuppressed();
 227             if (suppressed.length != 2 || suppressed[0] != t2 || suppressed[1] != t3)
 228                 throw new RuntimeException("Bad suppression in ISE", ise);
 229         }
 230 
 231         try {
 232             t2.initCause(null);
 233             throw new RuntimeException("Shouldn't reach.");
 234         } catch (IllegalStateException ise) {
 235             ; // Expected; don't want an NPE.
 236         }
 237 
 238         try {
 239             t3.initCause(t3);
 240             throw new RuntimeException("Shouldn't reach.");
 241         } catch (IllegalArgumentException iae) {
 242             if (iae.getCause() != t3)
 243                 throw new RuntimeException("Unexpected cause in ISE", iae);
 244         }
 245     }
 246 }