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