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 */ startTest(Test test)38 public synchronized void startTest(Test test) { 39 testStarted(test.toString()); 40 } 41 setPreferences(Properties preferences)42 protected static void setPreferences(Properties preferences) { 43 fPreferences= preferences; 44 } 45 getPreferences()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 savePreferences()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 setPreference(String key, String value)66 public void setPreference(String key, String value) { 67 getPreferences().put(key, value); 68 } 69 endTest(Test test)70 public synchronized void endTest(Test test) { 71 testEnded(test.toString()); 72 } 73 addError(final Test test, final Throwable t)74 public synchronized void addError(final Test test, final Throwable t) { 75 testFailed(TestRunListener.STATUS_ERROR, test, t); 76 } 77 addFailure(final Test test, final AssertionFailedError t)78 public synchronized void addFailure(final Test test, final AssertionFailedError t) { 79 testFailed(TestRunListener.STATUS_FAILURE, test, t); 80 } 81 82 // TestRunListener implementation 83 testStarted(String testName)84 public abstract void testStarted(String testName); 85 testEnded(String testName)86 public abstract void testEnded(String testName); 87 testFailed(int status, Test test, Throwable t)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 */ getTest(String suiteClassName)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 */ elapsedTimeAsString(long runTime)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 */ processArguments(String[] args)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 */ setLoading(boolean enable)177 public void setLoading(boolean enable) { 178 fLoading= enable; 179 } 180 /** 181 * Extract the class name from a String in VA/Java style 182 */ extractClassName(String className)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 */ truncate(String s)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 */ runFailed(String message)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 getLoader()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 */ loadSuiteClass(String suiteClassName)219 protected Class<?> loadSuiteClass(String suiteClassName) throws ClassNotFoundException { 220 return Class.forName(suiteClassName); 221 } 222 223 /** 224 * Clears the status message. 225 */ clearStatus()226 protected void clearStatus() { // Belongs in the GUI TestRunner class 227 } 228 useReloadingTestSuiteLoader()229 protected boolean useReloadingTestSuiteLoader() { 230 return getPreference("loading").equals("true") && fLoading; 231 } 232 getPreferencesFile()233 private static File getPreferencesFile() { 234 String home= System.getProperty("user.home"); 235 return new File(home, "junit.properties"); 236 } 237 readPreferences()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 getPreference(String key)253 public static String getPreference(String key) { 254 return getPreferences().getProperty(key); 255 } 256 getPreference(String key, int dflt)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 */ getFilteredTrace(Throwable t)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 inVAJava()284 public static boolean inVAJava() { 285 return false; 286 } 287 // END android-changed 288 289 /** 290 * Filters stack frames from internal JUnit classes 291 */ getFilteredTrace(String stack)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 showStackRaw()316 protected static boolean showStackRaw() { 317 return !getPreference("filterstack").equals("true") || fgFilterStack == false; 318 } 319 filterLine(String line)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