/** * This file Copyright (c) 2009-2012 Magnolia International * Ltd. (http://www.magnolia-cms.com). All rights reserved. * * * This file is dual-licensed under both the Magnolia * Network Agreement and the GNU General Public License. * You may elect to use one or the other of these licenses. * * This file is distributed in the hope that it will be * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT. * Redistribution, except as permitted by whichever of the GPL * or MNA you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or * modify this file under the terms of the GNU General * Public License, Version 3, as published by the Free Software * Foundation. You should have received a copy of the GNU * General Public License, Version 3 along with this program; * if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * 2. For the Magnolia Network Agreement (MNA), this file * and the accompanying materials are made available under the * terms of the MNA which accompanies this distribution, and * is available at http://www.magnolia-cms.com/mna.html * * Any modifications to this file must keep this entire header * intact. * */ package info.magnolia.cms.util; import info.magnolia.content2bean.Content2BeanException; import info.magnolia.exception.MgnlException; import info.magnolia.test.hamcrest.UtilMatchers; import java.io.FileNotFoundException; import java.io.IOException; import javax.jcr.PathNotFoundException; import javax.jcr.RepositoryException; import org.junit.Test; import static info.magnolia.cms.util.ExceptionUtil.wasCausedBy; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.*; /** * @version $Id$ */ public class ExceptionUtilTest { @Test public void testUnwrapIfShouldThrowWrappedExceptionIfItMatchesThe2ndParameter() { doTestUnwrapIf(new FileNotFoundException("HOP"), IOException.class); } @Test public void testUnwrapIfShouldThrowWrappedExceptionIfItIsARuntimeExceptionEvenIfItDoesntMatch2ndParameter() { doTestUnwrapIf(new ArrayIndexOutOfBoundsException("HELLO"), IOException.class); } private void doTestUnwrapIf(Throwable wrapped, final Class<? extends Exception> unwrapIf) { // wrapping the test exception - as client code would do final RuntimeException runtimeWrapping = new RuntimeException(wrapped); try { ExceptionUtil.unwrapIf(runtimeWrapping, unwrapIf); fail(); } catch (Throwable t) { assertSame(wrapped, t); assertNull(t.getCause()); } } @Test public void testUnwrapIfShouldThrowPassedExceptionIfItDoesNotMatchAndIsntARuntimeException() { // wrapping the test exception - as client code would do final IOException originalException = new IOException("AIE"); final RuntimeException runtimeWrapping = new RuntimeException(originalException); try { ExceptionUtil.unwrapIf(runtimeWrapping, RepositoryException.class); fail(); } catch (Throwable t) { assertSame(runtimeWrapping, t); assertSame(originalException, t.getCause()); assertNull(t.getCause().getCause()); } } @Test public void testUnwrapIfWithCauseBeingNull() { final RuntimeException runtimeWrapping = new RuntimeException((Throwable) null); try { ExceptionUtil.unwrapIf(runtimeWrapping, IOException.class); fail(); } catch (Throwable t) { assertSame(runtimeWrapping, t); assertNull(t.getCause()); } } @Test public void testUnwrapIfWithUnwrapIfBeingNull() { final IOException originalException = new IOException("AIE"); final RuntimeException runtimeWrapping = new RuntimeException(originalException); try { ExceptionUtil.unwrapIf(runtimeWrapping, null); fail(); } catch (Throwable t) { assertSame(runtimeWrapping, t); assertSame(originalException, t.getCause()); } } @Test public void canSneakilyRethrowGivenExceptions() { final IOException e = new IOException("The exception we'll throw without catching explicitly"); try { someMethodThatWillCatchThrowableAndSneakilyRethrow(e, IOException.class, Error.class); fail("Should not be here"); } catch (Throwable caught) { assertSame(e, caught); } } @Test public void willThrowGivenRuntimeEvenIfNotExplicitlyAllowed() { final IndexOutOfBoundsException e = new IndexOutOfBoundsException("The exception we'll throw without catching explicitly"); try { someMethodThatWillCatchThrowableAndSneakilyRethrow(e, IOException.class, Error.class); fail("Should not be here"); } catch (Throwable caught) { assertSame(e, caught); } } @Test public void whatHappensWithACheckedExceptionWeDontExplicitlyAllow() { final ClassNotFoundException e = new ClassNotFoundException("What happens to this exception ?"); try { someMethodThatWillCatchThrowableAndSneakilyRethrow(e, IOException.class, Error.class); fail("Should not be here"); } catch (Throwable caught) { assertThat(caught, UtilMatchers.isExceptionWithMessage(Error.class, "Caught the following exception, which was not allowed: ")); assertSame(e, caught.getCause()); } } @Test public void exampleOfAbuse() { try { ExceptionUtil.rethrow(new IOException(), IOException.class); fail("should have thrown an undeclared IOException"); } catch (Throwable e) { if (e.getClass().equals(IOException.class)) { // well ok then ... } else { fail("should have thrown an undeclared IOException"); } } } protected void someMethodThatWillCatchThrowableAndSneakilyRethrow(Throwable e, Class<? extends Throwable>... allowedExceptions) { try { throw e; } catch (Throwable t) { ExceptionUtil.rethrow(t, allowedExceptions); } } @Test public void translatesSimpleExceptionNameProperly() { assertEquals("Path not found", ExceptionUtil.classNameToWords(new PathNotFoundException())); } @Test public void translatesSimpleExceptionWithMessage() { assertEquals("Path not found: /foo/bar", ExceptionUtil.exceptionToWords(new PathNotFoundException("/foo/bar"))); } @Test public void ignoresExceptionSuffixIfNotPresent() { assertEquals("Dummy problem: lol", ExceptionUtil.exceptionToWords(new DummyProblem("lol"))); } @Test public void wasCausedByReturnsTrueIfGivenExceptionMatches() { assertTrue(wasCausedBy(new MgnlException(), MgnlException.class)); } @Test public void wasCausedByReturnsTrueIfCauseExceptionMatches() { assertTrue(wasCausedBy(new RuntimeException(new MgnlException()), MgnlException.class)); } @Test public void wasCausedByReturnsTrueIfDeeperExceptionMatches() { assertTrue(wasCausedBy(new IOException(new RuntimeException(new UnsupportedOperationException(new MgnlException()))), MgnlException.class)); } @Test public void wasCausedByReturnsFalseIfNoCauseInGivenException() { assertFalse(wasCausedBy(new IOException("no cause here"), MgnlException.class)); } @Test public void wasCausedByReturnsFalseIfNoCauseMatches() { assertFalse(wasCausedBy(new IOException(new RuntimeException(new UnsupportedOperationException("no cause here"))), MgnlException.class)); } @Test public void wasCausedByReturnsTrueIfMatchIsASubClass() { assertTrue("preventive check - if this fails, the test has become invalid. The rest of this test class relies on the fact that Content2BeanException is a subclass of MgnlException", MgnlException.class.isAssignableFrom(Content2BeanException.class)); assertTrue(wasCausedBy(new IOException(new Content2BeanException("this is the cause")), MgnlException.class)); } @Test public void wasCausedByReturnsFalseIfMatchIsAParentClass() { assertFalse(wasCausedBy(new IOException(new MgnlException("this is the cause")), Content2BeanException.class)); } private static class DummyProblem extends Exception { public DummyProblem(String message) { super(message); } } }