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