/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.tools.ant.taskdefs.optional.junit; import java.io.OutputStream; import java.lang.reflect.Method; import junit.framework.AssertionFailedError; import junit.framework.Test; /** * Formatter that doesn't create any output but tries to invoke the * tearDown method on a testcase if that test was forked and caused a * timeout or VM crash. * * <p>This formatter has some limitations, for details see the * <junit> task's manual.</p> * * @since Ant 1.8.0 */ public class TearDownOnVmCrash implements JUnitResultFormatter { private String suiteName; /** * Records the suite's name to later determine the class to invoke * tearDown on. */ @Override public void startTestSuite(final JUnitTest suite) { suiteName = suite.getName(); if (suiteName != null && suiteName.endsWith(JUnitTask.NAME_OF_DUMMY_TEST)) { // no way to know which class caused the timeout suiteName = null; } } /** * Only invoke tearDown if the suite is known and not the dummy * test we get when a Batch fails and the error is an actual * error generated by Ant. */ @Override public void addError(final Test fakeTest, final Throwable t) { if (suiteName != null && fakeTest instanceof JUnitTaskMirrorImpl.VmExitErrorTest) { tearDown(); } } // no need to implement the rest public void addFailure(Test test, Throwable t) {} @Override public void addFailure(Test test, AssertionFailedError t) {} @Override public void startTest(Test test) {} @Override public void endTest(Test test) {} @Override public void endTestSuite(JUnitTest suite) {} @Override public void setOutput(OutputStream out) {} @Override public void setSystemOutput(String out) {} @Override public void setSystemError(String err) {} private void tearDown() { try { // first try to load the class and let's hope it is on our // classpath Class<?> testClass = null; if (Thread.currentThread().getContextClassLoader() != null) { try { testClass = Thread.currentThread().getContextClassLoader() .loadClass(suiteName); } catch (ClassNotFoundException cnfe) { // ignore } } if (testClass == null && getClass().getClassLoader() != null) { try { testClass = getClass().getClassLoader().loadClass(suiteName); } catch (ClassNotFoundException cnfe) { // ignore } } if (testClass == null) { // fall back to system classloader testClass = Class.forName(suiteName); } // if the test has a suite method, then we can't know // which test of the executed suite timed out, ignore it try { // check if there is a suite method testClass.getMethod("suite"); return; } catch (NoSuchMethodException e) { // no suite method } // a loadable class and no suite method // no reason to check for JUnit 4 since JUnit4TestAdapter // doesn't have any tearDown method. try { Method td = testClass.getMethod("tearDown"); if (td.getReturnType() == Void.TYPE) { td.invoke(testClass.newInstance()); } } catch (NoSuchMethodException nsme) { // no tearDown, fine } } catch (ClassNotFoundException cnfe) { // class probably is not in our classpath, there is // nothing we can do } catch (Throwable t) { System.err.println("Caught an exception while trying to invoke" + " tearDown: " + t.getMessage()); } } }