Home | History | Annotate | Download | only in runner
      1 package junit.runner;
      2 
      3 import junit.framework.*;
      4 import java.lang.reflect.*;
      5 import java.text.NumberFormat;
      6 import java.io.*;
      7 import java.util.*;
      8 
      9 /**
     10  * Base class for all test runners.
     11  * This class was born live on stage in Sardinia during XP2000.
     12  */
     13 public abstract class BaseTestRunner implements TestListener {
     14 	public static final String SUITE_METHODNAME= "suite";
     15 
     16 	private static Properties fPreferences;
     17 	static int fgMaxMessageLength= 500;
     18 	static boolean fgFilterStack= true;
     19 	boolean fLoading= true;
     20 
     21     /*
     22     * Implementation of TestListener
     23     */
     24 	public synchronized void startTest(Test test) {
     25 		testStarted(test.toString());
     26 	}
     27 
     28 	protected static void setPreferences(Properties preferences) {
     29 		fPreferences= preferences;
     30 	}
     31 
     32 	protected static Properties getPreferences() {
     33 		if (fPreferences == null) {
     34 			fPreferences= new Properties();
     35 	 		fPreferences.put("loading", "true");
     36  			fPreferences.put("filterstack", "true");
     37   			readPreferences();
     38 		}
     39 		return fPreferences;
     40 	}
     41 
     42 	public static void savePreferences() throws IOException {
     43 		FileOutputStream fos= new FileOutputStream(getPreferencesFile());
     44 		try {
     45 			getPreferences().store(fos, "");
     46 		} finally {
     47 			fos.close();
     48 		}
     49 	}
     50 
     51 	public void setPreference(String key, String value) {
     52 		getPreferences().setProperty(key, value);
     53 	}
     54 
     55 	public synchronized void endTest(Test test) {
     56 		testEnded(test.toString());
     57 	}
     58 
     59 	public synchronized void addError(final Test test, final Throwable t) {
     60 		testFailed(TestRunListener.STATUS_ERROR, test, t);
     61 	}
     62 
     63 	public synchronized void addFailure(final Test test, final AssertionFailedError t) {
     64 		testFailed(TestRunListener.STATUS_FAILURE, test, t);
     65 	}
     66 
     67 	// TestRunListener implementation
     68 
     69 	public abstract void testStarted(String testName);
     70 
     71 	public abstract void testEnded(String testName);
     72 
     73 	public abstract void testFailed(int status, Test test, Throwable t);
     74 
     75 	/**
     76 	 * Returns the Test corresponding to the given suite. This is
     77 	 * a template method, subclasses override runFailed(), clearStatus().
     78 	 */
     79 	public Test getTest(String suiteClassName) {
     80 		if (suiteClassName.length() <= 0) {
     81 			clearStatus();
     82 			return null;
     83 		}
     84 		Class testClass= null;
     85 		try {
     86 			testClass= loadSuiteClass(suiteClassName);
     87 		} catch (ClassNotFoundException e) {
     88 			String clazz= e.getMessage();
     89 			if (clazz == null)
     90 				clazz= suiteClassName;
     91 			runFailed("Class not found \""+clazz+"\"");
     92 			return null;
     93 		} catch(Exception e) {
     94 			runFailed("Error: "+e.toString());
     95 			return null;
     96 		}
     97 		Method suiteMethod= null;
     98 		try {
     99 			suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]);
    100 	 	} catch(Exception e) {
    101 	 		// try to extract a test suite automatically
    102 			clearStatus();
    103 			return new TestSuite(testClass);
    104 		}
    105 		if (! Modifier.isStatic(suiteMethod.getModifiers())) {
    106 			runFailed("Suite() method must be static");
    107 			return null;
    108 		}
    109 		Test test= null;
    110 		try {
    111 			test= (Test)suiteMethod.invoke(null, (Object[]) new Class[0]); // static method
    112 			if (test == null)
    113 				return test;
    114 		}
    115 		catch (InvocationTargetException e) {
    116 			runFailed("Failed to invoke suite():" + e.getTargetException().toString());
    117 			return null;
    118 		}
    119 		catch (IllegalAccessException e) {
    120 			runFailed("Failed to invoke suite():" + e.toString());
    121 			return null;
    122 		}
    123 
    124 		clearStatus();
    125 		return test;
    126 	}
    127 
    128 	/**
    129 	 * Returns the formatted string of the elapsed time.
    130 	 */
    131 	public String elapsedTimeAsString(long runTime) {
    132 		return NumberFormat.getInstance().format((double)runTime/1000);
    133 	}
    134 
    135 	/**
    136 	 * Processes the command line arguments and
    137 	 * returns the name of the suite class to run or null
    138 	 */
    139 	protected String processArguments(String[] args) {
    140 		String suiteName= null;
    141 		for (int i= 0; i < args.length; i++) {
    142 			if (args[i].equals("-noloading")) {
    143 				setLoading(false);
    144 			} else if (args[i].equals("-nofilterstack")) {
    145 				fgFilterStack= false;
    146 			} else if (args[i].equals("-c")) {
    147 				if (args.length > i+1)
    148 					suiteName= extractClassName(args[i+1]);
    149 				else
    150 					System.out.println("Missing Test class name");
    151 				i++;
    152 			} else {
    153 				suiteName= args[i];
    154 			}
    155 		}
    156 		return suiteName;
    157 	}
    158 
    159 	/**
    160 	 * Sets the loading behaviour of the test runner
    161 	 */
    162 	public void setLoading(boolean enable) {
    163 		fLoading= enable;
    164 	}
    165 	/**
    166 	 * Extract the class name from a String in VA/Java style
    167 	 */
    168 	public String extractClassName(String className) {
    169 		if(className.startsWith("Default package for"))
    170 			return className.substring(className.lastIndexOf(".")+1);
    171 		return className;
    172 	}
    173 
    174 	/**
    175 	 * Truncates a String to the maximum length.
    176 	 */
    177 	public static String truncate(String s) {
    178 		if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength)
    179 			s= s.substring(0, fgMaxMessageLength)+"...";
    180 		return s;
    181 	}
    182 
    183 	/**
    184 	 * Override to define how to handle a failed loading of
    185 	 * a test suite.
    186 	 */
    187 	protected abstract void runFailed(String message);
    188 
    189 	/**
    190 	 * Returns the loaded Class for a suite name.
    191 	 */
    192 	protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
    193 		return getLoader().load(suiteClassName);
    194 	}
    195 
    196 	/**
    197 	 * Clears the status message.
    198 	 */
    199 	protected void clearStatus() { // Belongs in the GUI TestRunner class
    200 	}
    201 
    202 	/**
    203 	 * Returns the loader to be used.
    204 	 */
    205 	public TestSuiteLoader getLoader() {
    206 		if (useReloadingTestSuiteLoader())
    207 			return new ReloadingTestSuiteLoader();
    208 		return new StandardTestSuiteLoader();
    209 	}
    210 
    211 	protected boolean useReloadingTestSuiteLoader() {
    212 		return getPreference("loading").equals("true") && !inVAJava() && fLoading;
    213 	}
    214 
    215 	private static File getPreferencesFile() {
    216 	 	String home= System.getProperty("user.home");
    217  		return new File(home, "junit.properties");
    218  	}
    219 
    220  	private static void readPreferences() {
    221  		InputStream is= null;
    222  		try {
    223  			is= new FileInputStream(getPreferencesFile());
    224  			setPreferences(new Properties(getPreferences()));
    225 			getPreferences().load(is);
    226 		} catch (IOException e) {
    227 			try {
    228 				if (is != null)
    229 					is.close();
    230 			} catch (IOException e1) {
    231 			}
    232 		}
    233  	}
    234 
    235  	public static String getPreference(String key) {
    236  		return getPreferences().getProperty(key);
    237  	}
    238 
    239  	public static int getPreference(String key, int dflt) {
    240  		String value= getPreference(key);
    241  		int intValue= dflt;
    242  		if (value == null)
    243  			return intValue;
    244  		try {
    245  			intValue= Integer.parseInt(value);
    246  	 	} catch (NumberFormatException ne) {
    247  		}
    248  		return intValue;
    249  	}
    250 
    251  	public static boolean inVAJava() {
    252 		try {
    253 			Class.forName("com.ibm.uvm.tools.DebugSupport");
    254 		}
    255 		catch (Exception e) {
    256 			return false;
    257 		}
    258 		return true;
    259 	}
    260 
    261 	/**
    262 	 * Returns a filtered stack trace
    263 	 */
    264 	public static String getFilteredTrace(Throwable t) {
    265 		StringWriter stringWriter= new StringWriter();
    266 		PrintWriter writer= new PrintWriter(stringWriter);
    267 		t.printStackTrace(writer);
    268 		StringBuffer buffer= stringWriter.getBuffer();
    269 		String trace= buffer.toString();
    270 		return BaseTestRunner.getFilteredTrace(trace);
    271 	}
    272 
    273 	/**
    274 	 * Filters stack frames from internal JUnit classes
    275 	 */
    276 	public static String getFilteredTrace(String stack) {
    277 		if (showStackRaw())
    278 			return stack;
    279 
    280 		StringWriter sw= new StringWriter();
    281 		PrintWriter pw= new PrintWriter(sw);
    282 		StringReader sr= new StringReader(stack);
    283 		BufferedReader br= new BufferedReader(sr);
    284 
    285 		String line;
    286 		try {
    287 			while ((line= br.readLine()) != null) {
    288 				if (!filterLine(line))
    289 					pw.println(line);
    290 			}
    291 		} catch (Exception IOException) {
    292 			return stack; // return the stack unfiltered
    293 		}
    294 		return sw.toString();
    295 	}
    296 
    297 	protected static boolean showStackRaw() {
    298 		return !getPreference("filterstack").equals("true") || fgFilterStack == false;
    299 	}
    300 
    301 	static boolean filterLine(String line) {
    302 		String[] patterns= new String[] {
    303 			"junit.framework.TestCase",
    304 			"junit.framework.TestResult",
    305 			"junit.framework.TestSuite",
    306 			"junit.framework.Assert.", // don't filter AssertionFailure
    307 			"junit.swingui.TestRunner",
    308 			"junit.awtui.TestRunner",
    309 			"junit.textui.TestRunner",
    310 			"java.lang.reflect.Method.invoke("
    311 		};
    312 		for (int i= 0; i < patterns.length; i++) {
    313 			if (line.indexOf(patterns[i]) > 0)
    314 				return true;
    315 		}
    316 		return false;
    317 	}
    318 
    319  	static {
    320  		fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength);
    321  	}
    322 
    323 }
    324