package org.threadly.util; import static org.junit.Assert.*; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.util.Collections; import java.util.StringTokenizer; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.threadly.concurrent.TestRuntimeFailureRunnable; import org.threadly.test.concurrent.TestRunnable; import org.threadly.util.ExceptionUtils.TransformedException; import org.threadly.util.ExceptionUtils.TransformedSuppressedStackException; @SuppressWarnings("javadoc") public class ExceptionUtilsTest { @Before @After public void cleanup() { ExceptionUtils.setDefaultExceptionHandler(null); ExceptionUtils.setInheritableExceptionHandler(null); ExceptionUtils.setThreadExceptionHandler(null); Thread.setDefaultUncaughtExceptionHandler(null); Thread.currentThread().setUncaughtExceptionHandler(null); } @Test public void runRunnableTest() { TestRunnable tr = new TestRunnable(); ExceptionUtils.runRunnable(tr); assertTrue(tr.ranOnce()); } @Test public void runRunnableThrownTest() { TestExceptionHandler exceptionHandler = new TestExceptionHandler(); ExceptionUtils.setThreadExceptionHandler(exceptionHandler); RuntimeException failure = new SuppressedStackRuntimeException(); TestRuntimeFailureRunnable runnable = new TestRuntimeFailureRunnable(failure); ExceptionUtils.runRunnable(runnable); assertTrue(exceptionHandler.getLastThrowable() == failure); } @Test public void getThreadLocalExceptionHandlerTest() { ExceptionUtils.setDefaultExceptionHandler(new TestExceptionHandler()); ExceptionUtils.setInheritableExceptionHandler(new TestExceptionHandler()); assertNull(ExceptionUtils.getThreadLocalExceptionHandler()); TestExceptionHandler exceptionHandler = new TestExceptionHandler(); ExceptionUtils.setThreadExceptionHandler(exceptionHandler); assertTrue(exceptionHandler == ExceptionUtils.getThreadLocalExceptionHandler()); } @Test public void getThreadExceptionHandlerTest() { TestExceptionHandler defaultExceptionHandler = new TestExceptionHandler(); TestExceptionHandler inheritableExceptionHandler = new TestExceptionHandler(); TestExceptionHandler threadExceptionHandler = new TestExceptionHandler(); assertNull(ExceptionUtils.getExceptionHandler()); ExceptionUtils.setDefaultExceptionHandler(defaultExceptionHandler); assertTrue(defaultExceptionHandler == ExceptionUtils.getExceptionHandler()); ExceptionUtils.setInheritableExceptionHandler(inheritableExceptionHandler); assertTrue(inheritableExceptionHandler == ExceptionUtils.getExceptionHandler()); ExceptionUtils.setThreadExceptionHandler(threadExceptionHandler); assertTrue(threadExceptionHandler == ExceptionUtils.getExceptionHandler()); } @Test @SuppressWarnings("resource") public void handleExceptionWithoutUncaughtExceptionHandler() { // make sure no uncaughtExceptionHandler is set Thread.setDefaultUncaughtExceptionHandler(null); Thread.currentThread().setUncaughtExceptionHandler(null); PrintStream originalSystemErr = System.err; try { // set it up so System.err goes to a StringBuffer final StringBuilder sb = new StringBuilder(); System.setErr(new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { sb.append((char)b); } })); // make call Exception e = new Exception(); ExceptionUtils.handleException(e); assertTrue(sb.length() > 0); assertTrue(sb.toString().contains(ExceptionUtils.stackToString(e))); } finally { System.setErr(originalSystemErr); } } @Test @SuppressWarnings("resource") public void handleExceptionThrowExceptionTest() { final RuntimeException thrownException = new SuppressedStackRuntimeException(); // set handler that will throw exception ExceptionUtils.setThreadExceptionHandler(new ExceptionHandler() { @Override public void handleException(Throwable thrown) { throw thrownException; } }); PrintStream originalSystemErr = System.err; try { // set it up so System.err goes to a StringBuffer final StringBuilder sb = new StringBuilder(); System.setErr(new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { sb.append((char)b); } })); // make call Exception e = new Exception(); ExceptionUtils.handleException(e); assertTrue(sb.length() > 0); String resultStr = sb.toString(); assertTrue(resultStr.contains(ExceptionUtils.stackToString(e))); assertTrue(resultStr.contains(ExceptionUtils.stackToString(thrownException))); } finally { System.setErr(originalSystemErr); } } @Test @SuppressWarnings("resource") public void handleExceptionWithThreadExceptionHandler() { PrintStream originalSystemErr = System.err; try { // set it up so System.err goes to a StringBuffer final StringBuilder sb = new StringBuilder(); System.setErr(new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { sb.append((char)b); } })); TestExceptionHandler teh = new TestExceptionHandler(); ExceptionUtils.setThreadExceptionHandler(teh); TestExceptionHandler uncalledHandler = new TestExceptionHandler(); ExceptionUtils.setInheritableExceptionHandler(uncalledHandler); ExceptionUtils.setDefaultExceptionHandler(uncalledHandler); // make call Exception e = new Exception(); ExceptionUtils.handleException(e); assertEquals(0, sb.length()); // should not have gone to std err assertEquals(0, uncalledHandler.getCallCount()); assertEquals(1, teh.getCallCount()); assertTrue(teh.getLastThrowable() == e); } finally { System.setErr(originalSystemErr); } } @Test @SuppressWarnings("resource") public void handleExceptionWithInheritableThreadExceptionHandler() { PrintStream originalSystemErr = System.err; try { // set it up so System.err goes to a StringBuffer final StringBuilder sb = new StringBuilder(); System.setErr(new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { sb.append((char)b); } })); TestExceptionHandler teh = new TestExceptionHandler(); ExceptionUtils.setInheritableExceptionHandler(teh); TestExceptionHandler uncalledHandler = new TestExceptionHandler(); ExceptionUtils.setDefaultExceptionHandler(uncalledHandler); // make call Exception e = new Exception(); ExceptionUtils.handleException(e); assertEquals(0, sb.length()); // should not have gone to std err assertEquals(0, uncalledHandler.getCallCount()); assertEquals(1, teh.getCallCount()); assertTrue(teh.getLastThrowable() == e); } finally { System.setErr(originalSystemErr); } } @Test @SuppressWarnings("resource") public void handleExceptionWithDefaultThreadExceptionHandler() { PrintStream originalSystemErr = System.err; try { // set it up so System.err goes to a StringBuffer final StringBuilder sb = new StringBuilder(); System.setErr(new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { sb.append((char)b); } })); TestExceptionHandler teh = new TestExceptionHandler(); ExceptionUtils.setDefaultExceptionHandler(teh); // make call Exception e = new Exception(); ExceptionUtils.handleException(e); assertEquals(0, sb.length()); // should not have gone to std err assertEquals(1, teh.getCallCount()); assertTrue(teh.getLastThrowable() == e); } finally { System.setErr(originalSystemErr); } } @Test @SuppressWarnings("resource") public void handleExceptionWithDefaultUncaughtExceptionHandler() { PrintStream originalSystemErr = System.err; try { // set it up so System.err goes to a StringBuffer final StringBuilder sb = new StringBuilder(); System.setErr(new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { sb.append((char)b); } })); TestUncaughtExceptionHandler ueh = new TestUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(ueh); // make call Exception e = new Exception(); ExceptionUtils.handleException(e); assertEquals(0, sb.length()); // should not have gone to std err assertEquals(1, ueh.getCallCount()); assertTrue(ueh.getCalledWithThread() == Thread.currentThread()); assertTrue(ueh.getCalledWithThrowable() == e); } finally { System.setErr(originalSystemErr); } } @Test @SuppressWarnings("resource") public void handleExceptionWithUncaughtExceptionHandler() { PrintStream originalSystemErr = System.err; try { // set it up so System.err goes to a StringBuffer final StringBuilder sb = new StringBuilder(); System.setErr(new PrintStream(new OutputStream() { @Override public void write(int b) throws IOException { sb.append((char)b); } })); TestUncaughtExceptionHandler ueh = new TestUncaughtExceptionHandler(); Thread.currentThread().setUncaughtExceptionHandler(ueh); // make call Exception e = new Exception(); ExceptionUtils.handleException(e); assertEquals(0, sb.length()); // should not have gone to std err assertEquals(1, ueh.getCallCount()); assertTrue(ueh.getCalledWithThread() == Thread.currentThread()); assertTrue(ueh.getCalledWithThrowable() == e); } finally { System.setErr(originalSystemErr); } } @Test public void handleExceptionWithNullException() { TestExceptionHandler teh = new TestExceptionHandler(); ExceptionUtils.setDefaultExceptionHandler(teh); ExceptionUtils.handleException(null); // no exception should be thrown or called assertEquals(0, teh.getCallCount()); } @Test (expected = IllegalArgumentException.class) public void getRootCauseFail() { ExceptionUtils.getRootCause(null); fail("Exception should have thrown"); } @Test public void getRootCauseNoCauseTest() { Exception e = new Exception(); assertTrue(e == ExceptionUtils.getRootCause(e)); } @Test public void getRootCauseTest() { Exception rootCause = new Exception(); Exception e1 = new Exception(rootCause); Exception e2 = new Exception(e1); Exception e3 = new Exception(e2); assertTrue(ExceptionUtils.getRootCause(e3) == rootCause); assertTrue(ExceptionUtils.getRootCause(e2) == rootCause); assertTrue(ExceptionUtils.getRootCause(e1) == rootCause); } @Test public void getCauseOfTypeNoInputTest() { assertNull(ExceptionUtils.getCauseOfType(null, Exception.class)); } @Test public void getCauseOfTypeMissingTest() { Exception e = new Exception(new SuppressedStackRuntimeException(new SuppressedStackRuntimeException())); assertNull(ExceptionUtils.getCauseOfType(e, IllegalArgumentException.class)); } @Test public void getCauseOfTypeTest() { IllegalArgumentException expected = new IllegalArgumentException(new Exception()); Exception e = new Exception(expected); assertTrue(expected == ExceptionUtils.getCauseOfType(e, IllegalArgumentException.class)); } @Test public void hasCauseOfTypeNoInputTest() { assertFalse(ExceptionUtils.hasCauseOfType(null, Exception.class)); } @Test public void hasCauseOfTypeMissingTest() { Exception e = new Exception(new SuppressedStackRuntimeException(new SuppressedStackRuntimeException())); assertFalse(ExceptionUtils.hasCauseOfType(e, IllegalArgumentException.class)); } @Test public void hasCauseOfTypeTest() { Exception e = new Exception(new IllegalArgumentException(new Exception())); assertTrue(ExceptionUtils.hasCauseOfType(e, IllegalArgumentException.class)); } @Test public void getCauseOfTypesNoInputTest() { assertNull(ExceptionUtils.getCauseOfTypes(null, Collections.singletonList(Exception.class))); } @Test public void getCauseOfTypesMissingTest() { Exception e = new Exception(new SuppressedStackRuntimeException(new SuppressedStackRuntimeException())); assertNull(ExceptionUtils.getCauseOfTypes(e, Collections.singletonList(IllegalArgumentException.class))); } @Test public void getCauseOfTypesTest() { IllegalArgumentException expected = new IllegalArgumentException(new Exception()); Exception e = new Exception(expected); assertTrue(expected == ExceptionUtils.getCauseOfTypes(e, Collections.singletonList(IllegalArgumentException.class))); } @Test public void hasCauseOfTypesNoInputTest() { assertFalse(ExceptionUtils.hasCauseOfTypes(null, Collections.singletonList(Exception.class))); } @Test public void hasCauseOfTypesMissingTest() { Exception e = new Exception(new SuppressedStackRuntimeException(new SuppressedStackRuntimeException())); assertFalse(ExceptionUtils.hasCauseOfTypes(e, Collections.singletonList(IllegalArgumentException.class))); } @Test public void hasCauseOfTypesTest() { Exception e = new Exception(new IllegalArgumentException(new Exception())); assertTrue(ExceptionUtils.hasCauseOfTypes(e, Collections.singletonList(IllegalArgumentException.class))); } @Test public void makeRuntimeWithRuntimeTest() { RuntimeException testException = new SuppressedStackRuntimeException(); RuntimeException resultException = ExceptionUtils.makeRuntime(testException); assertNotNull(resultException); // we expect the exact same reference to come out assertTrue(testException == resultException); } @Test public void makeRuntimeWithNonRuntimeTest() { Exception testException = new Exception(); RuntimeException resultException = ExceptionUtils.makeRuntime(testException); assertNotNull(resultException); assertTrue(resultException instanceof TransformedException); // verify stack trace does not contain Util.makeRuntime inside it for when it created a new exception StackTraceElement[] stack = resultException.getStackTrace(); for (StackTraceElement ste : stack) { assertFalse(ste.getClassName().equals(ExceptionUtils.class.getName())); } // verify the cause was our original exception assertTrue(testException == resultException.getCause()); } @Test public void makeRuntimeWithNullTest() { RuntimeException resultException = ExceptionUtils.makeRuntime(null); assertNotNull(resultException); // verify stack trace does not contain Util.makeRuntime inside it for when it created a new exception StackTraceElement[] stack = resultException.getStackTrace(); for (StackTraceElement ste : stack) { assertFalse(ste.getClass().getName().equals(ExceptionUtils.class.getName())); } // verify that no cause is provided assertNull(resultException.getCause()); } @Test public void makeRuntimeBooleanWithRuntimeTest() { RuntimeException testException = new SuppressedStackRuntimeException(); RuntimeException resultException = ExceptionUtils.makeRuntime(testException, false); assertNotNull(resultException); // we expect the exact same reference to come out assertTrue(testException == resultException); } @Test public void makeRuntimeBooleanWithNonRuntimeTest() { Exception testException = new Exception(); RuntimeException resultException = ExceptionUtils.makeRuntime(testException, false); assertNotNull(resultException); assertTrue(resultException instanceof TransformedException); // verify stack trace does not contain Util.makeRuntime inside it for when it created a new exception StackTraceElement[] stack = resultException.getStackTrace(); for (StackTraceElement ste : stack) { assertFalse(ste.getClassName().equals(ExceptionUtils.class.getName())); } // verify the cause was our original exception assertTrue(testException == resultException.getCause()); } @Test public void makeRuntimeStackSuppressedWithNonRuntimeTest() { Exception testException = new Exception(); RuntimeException resultException = ExceptionUtils.makeRuntime(testException, true); assertNotNull(resultException); assertTrue(resultException instanceof TransformedSuppressedStackException); // verify stack trace does not contain Util.makeRuntime inside it for when it created a new exception StackTraceElement[] stack = resultException.getStackTrace(); for (StackTraceElement ste : stack) { assertFalse(ste.getClassName().equals(ExceptionUtils.class.getName())); assertFalse(ste.getClassName().equals(ExceptionUtilsTest.class.getName())); } // verify the cause was our original exception assertTrue(testException == resultException.getCause()); } @Test public void makeRuntimeBooleanWithNullTest() { RuntimeException resultException = ExceptionUtils.makeRuntime(null, false); assertNotNull(resultException); // verify stack trace does not contain Util.makeRuntime inside it for when it created a new exception StackTraceElement[] stack = resultException.getStackTrace(); for (StackTraceElement ste : stack) { assertFalse(ste.getClass().getName().equals(ExceptionUtils.class.getName())); } // verify that no cause is provided assertNull(resultException.getCause()); } @Test public void stackToStringTest() { String message = "TestMessage"; Exception testException = new Exception(message); String result = ExceptionUtils.stackToString(testException); assertNotNull(result); StringTokenizer st = new StringTokenizer(result, "\n"); assertEquals(testException.getStackTrace().length + 1, st.countTokens()); assertTrue(result.contains(message)); } @Test public void stackToStringNullTest() { String result = ExceptionUtils.stackToString((Throwable)null); assertNotNull(result); assertEquals(0, result.length()); } @Test public void writeStackToBuilderTest() { String message = "TestMessage"; Exception testException = new Exception(message); StringBuilder sb = new StringBuilder(); ExceptionUtils.writeStackTo(testException, sb); String result = sb.toString(); assertNotNull(result); StringTokenizer st = new StringTokenizer(result, "\n"); assertEquals(testException.getStackTrace().length + 1, st.countTokens()); assertTrue(result.contains(message)); } @Test public void writeStackToBuilderNullTest() { StringBuilder sb = new StringBuilder(); ExceptionUtils.writeStackTo((Throwable)null, sb); assertEquals(0, sb.length()); } @Test (expected = IllegalArgumentException.class) public void writeStackToBuilderFail() { ExceptionUtils.writeStackTo(new Exception(), (StringBuilder)null); } @Test public void writeStackToBufferTest() { String message = "TestMessage"; Exception testException = new Exception(message); StringBuffer sb = new StringBuffer(); ExceptionUtils.writeStackTo(testException, sb); String result = sb.toString(); assertNotNull(result); StringTokenizer st = new StringTokenizer(result, "\n"); assertEquals(testException.getStackTrace().length + 1, st.countTokens()); assertTrue(result.contains(message)); } @Test public void writeStackToBufferNullTest() { StringBuffer sb = new StringBuffer(); ExceptionUtils.writeStackTo(null, sb); assertEquals(0, sb.length()); } @Test (expected = IllegalArgumentException.class) public void writeStackToBufferFail() { ExceptionUtils.writeStackTo(new Exception(), (StringBuffer)null); } @Test public void stackToStringArrayTest() { Exception testException = new Exception(); String result = ExceptionUtils.stackToString(testException.getStackTrace()); assertNotNull(result); StringTokenizer st = new StringTokenizer(result, "\n"); assertEquals(testException.getStackTrace().length, st.countTokens()); } @Test public void stackToStringArrayNullStackTest() { String result = ExceptionUtils.stackToString((StackTraceElement[])null); assertNotNull(result); assertEquals(0, result.length()); } @Test public void writeArrayStackToBuilderTest() { Exception testException = new Exception(); StringBuilder sb = new StringBuilder(); ExceptionUtils.writeStackTo(testException.getStackTrace(), sb); String result = sb.toString(); assertNotNull(result); StringTokenizer st = new StringTokenizer(result, "\n"); assertEquals(testException.getStackTrace().length, st.countTokens()); } @Test public void writeArrayStackToBuilderNullTest() { StringBuilder sb = new StringBuilder(); ExceptionUtils.writeStackTo((StackTraceElement[])null, sb); assertEquals(0, sb.length()); } @Test (expected = IllegalArgumentException.class) public void writeArrayStackFail() { ExceptionUtils.writeStackTo(new Exception().getStackTrace(), null); } }