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); // 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 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 // BEGIN android-changed 284 // Use a sensible default buffer size 285 BufferedReader br= new BufferedReader(sr, 1000); 286 // END android-changed 287 288 String line; 289 try { 290 while ((line= br.readLine()) != null) { 291 if (!filterLine(line)) 292 pw.println(line); 293 } 294 } catch (Exception IOException) { 295 return stack; // return the stack unfiltered 296 } 297 return sw.toString(); 298 } 299 300 protected static boolean showStackRaw() { 301 return !getPreference("filterstack").equals("true") || fgFilterStack == false; 302 } 303 304 static boolean filterLine(String line) { 305 String[] patterns= new String[] { 306 "junit.framework.TestCase", 307 "junit.framework.TestResult", 308 "junit.framework.TestSuite", 309 "junit.framework.Assert.", // don't filter AssertionFailure 310 "junit.swingui.TestRunner", 311 "junit.awtui.TestRunner", 312 "junit.textui.TestRunner", 313 "java.lang.reflect.Method.invoke(" 314 }; 315 for (int i= 0; i < patterns.length; i++) { 316 if (line.indexOf(patterns[i]) > 0) 317 return true; 318 } 319 return false; 320 } 321 322 static { 323 fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength); 324 } 325 326 } 327