package junit.runner;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.NumberFormat;
import java.util.Properties;

import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestListener;
import junit.framework.TestSuite;

import org.junit.internal.Throwables;

Base class for all test runners. This class was born live on stage in Sardinia during XP2000.
/** * Base class for all test runners. * This class was born live on stage in Sardinia during XP2000. */
public abstract class BaseTestRunner implements TestListener { public static final String SUITE_METHODNAME = "suite"; private static Properties fPreferences; static int fgMaxMessageLength = 500; static boolean fgFilterStack = true; boolean fLoading = true; /* * Implementation of TestListener */ public synchronized void startTest(Test test) { testStarted(test.toString()); } protected static void setPreferences(Properties preferences) { fPreferences = preferences; } protected static Properties getPreferences() { if (fPreferences == null) { fPreferences = new Properties(); fPreferences.put("loading", "true"); fPreferences.put("filterstack", "true"); readPreferences(); } return fPreferences; } public static void savePreferences() throws IOException { FileOutputStream fos = new FileOutputStream(getPreferencesFile()); try { getPreferences().store(fos, ""); } finally { fos.close(); } } public static void setPreference(String key, String value) { getPreferences().put(key, value); } public synchronized void endTest(Test test) { testEnded(test.toString()); } public synchronized void addError(final Test test, final Throwable e) { testFailed(TestRunListener.STATUS_ERROR, test, e); } public synchronized void addFailure(final Test test, final AssertionFailedError e) { testFailed(TestRunListener.STATUS_FAILURE, test, e); } // TestRunListener implementation public abstract void testStarted(String testName); public abstract void testEnded(String testName); public abstract void testFailed(int status, Test test, Throwable e);
Returns the Test corresponding to the given suite. This is a template method, subclasses override runFailed(), clearStatus().
/** * Returns the Test corresponding to the given suite. This is * a template method, subclasses override runFailed(), clearStatus(). */
public Test getTest(String suiteClassName) { if (suiteClassName.length() <= 0) { clearStatus(); return null; } Class<?> testClass = null; try { testClass = loadSuiteClass(suiteClassName); } catch (ClassNotFoundException e) { String clazz = e.getMessage(); if (clazz == null) { clazz = suiteClassName; } runFailed("Class not found \"" + clazz + "\""); return null; } catch (Exception e) { runFailed("Error: " + e.toString()); return null; } Method suiteMethod = null; try { suiteMethod = testClass.getMethod(SUITE_METHODNAME); } catch (Exception e) { // try to extract a test suite automatically clearStatus(); return new TestSuite(testClass); } if (!Modifier.isStatic(suiteMethod.getModifiers())) { runFailed("Suite() method must be static"); return null; } Test test = null; try { test = (Test) suiteMethod.invoke(null); // static method if (test == null) { return test; } } catch (InvocationTargetException e) { runFailed("Failed to invoke suite():" + e.getTargetException().toString()); return null; } catch (IllegalAccessException e) { runFailed("Failed to invoke suite():" + e.toString()); return null; } clearStatus(); return test; }
Returns the formatted string of the elapsed time.
/** * Returns the formatted string of the elapsed time. */
public String elapsedTimeAsString(long runTime) { return NumberFormat.getInstance().format((double) runTime / 1000); }
Processes the command line arguments and returns the name of the suite class to run or null
/** * Processes the command line arguments and * returns the name of the suite class to run or null */
protected String processArguments(String[] args) { String suiteName = null; for (int i = 0; i < args.length; i++) { if (args[i].equals("-noloading")) { setLoading(false); } else if (args[i].equals("-nofilterstack")) { fgFilterStack = false; } else if (args[i].equals("-c")) { if (args.length > i + 1) { suiteName = extractClassName(args[i + 1]); } else { System.out.println("Missing Test class name"); } i++; } else { suiteName = args[i]; } } return suiteName; }
Sets the loading behaviour of the test runner
/** * Sets the loading behaviour of the test runner */
public void setLoading(boolean enable) { fLoading = enable; }
Extract the class name from a String in VA/Java style
/** * Extract the class name from a String in VA/Java style */
public String extractClassName(String className) { if (className.startsWith("Default package for")) { return className.substring(className.lastIndexOf(".") + 1); } return className; }
Truncates a String to the maximum length.
/** * Truncates a String to the maximum length. */
public static String truncate(String s) { if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength) { s = s.substring(0, fgMaxMessageLength) + "..."; } return s; }
Override to define how to handle a failed loading of a test suite.
/** * Override to define how to handle a failed loading of * a test suite. */
protected abstract void runFailed(String message);
Returns the loaded Class for a suite name.
/** * Returns the loaded Class for a suite name. */
protected Class<?> loadSuiteClass(String suiteClassName) throws ClassNotFoundException { return Class.forName(suiteClassName); }
Clears the status message.
/** * Clears the status message. */
protected void clearStatus() { // Belongs in the GUI TestRunner class } protected boolean useReloadingTestSuiteLoader() { return getPreference("loading").equals("true") && fLoading; } private static File getPreferencesFile() { String home = System.getProperty("user.home"); return new File(home, "junit.properties"); } private static void readPreferences() { InputStream is = null; try { is = new FileInputStream(getPreferencesFile()); setPreferences(new Properties(getPreferences())); getPreferences().load(is); } catch (IOException ignored) { } catch (SecurityException ignored) { } finally { try { if (is != null) { is.close(); } } catch (IOException e1) { } } } public static String getPreference(String key) { return getPreferences().getProperty(key); } public static int getPreference(String key, int dflt) { String value = getPreference(key); int intValue = dflt; if (value == null) { return intValue; } try { intValue = Integer.parseInt(value); } catch (NumberFormatException ne) { } return intValue; }
Returns a filtered stack trace
/** * Returns a filtered stack trace */
public static String getFilteredTrace(Throwable e) { return BaseTestRunner.getFilteredTrace(Throwables.getStacktrace(e)); }
Filters stack frames from internal JUnit classes
/** * Filters stack frames from internal JUnit classes */
public static String getFilteredTrace(String stack) { if (showStackRaw()) { return stack; } StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); StringReader sr = new StringReader(stack); BufferedReader br = new BufferedReader(sr); String line; try { while ((line = br.readLine()) != null) { if (!filterLine(line)) { pw.println(line); } } } catch (Exception IOException) { return stack; // return the stack unfiltered } return sw.toString(); } protected static boolean showStackRaw() { return !getPreference("filterstack").equals("true") || fgFilterStack == false; } static boolean filterLine(String line) { String[] patterns = new String[]{ "junit.framework.TestCase", "junit.framework.TestResult", "junit.framework.TestSuite", "junit.framework.Assert.", // don't filter AssertionFailure "junit.swingui.TestRunner", "junit.awtui.TestRunner", "junit.textui.TestRunner", "java.lang.reflect.Method.invoke(" }; for (int i = 0; i < patterns.length; i++) { if (line.indexOf(patterns[i]) > 0) { return true; } } return false; } static { fgMaxMessageLength = getPreference("maxmessage", fgMaxMessageLength); } }