3 import junit.framework.*;
4 import java.lang.reflect.*;
5 import java.text.NumberFormat;
10 * Base class for all test runners.
11 * This class was born live on stage in Sardinia during XP2000.
13 public abstract class BaseTestRunner implements TestListener {
14 public static final String SUITE_METHODNAME= "suite";
16 private static Properties fPreferences;
17 static int fgMaxMessageLength= 500;
18 static boolean fgFilterStack= true;
19 boolean fLoading= true;
22 * Implementation of TestListener
24 public synchronized void startTest(Test test) {
25 testStarted(test.toString());
28 protected static void setPreferences(Properties preferences) {
29 fPreferences= preferences;
32 protected static Properties getPreferences() {
33 if (fPreferences == null) {
34 fPreferences= new Properties();
35 fPreferences.put("loading", "true");
36 fPreferences.put("filterstack", "true");
42 public static void savePreferences() throws IOException {
43 FileOutputStream fos= new FileOutputStream(getPreferencesFile());
45 getPreferences().store(fos, "");
51 public void setPreference(String key, String value) {
52 getPreferences().setProperty(key, value);
55 public synchronized void endTest(Test test) {
56 testEnded(test.toString());
59 public synchronized void addError(final Test test, final Throwable t) {
60 testFailed(TestRunListener.STATUS_ERROR, test, t);
63 public synchronized void addFailure(final Test test, final AssertionFailedError t) {
64 testFailed(TestRunListener.STATUS_FAILURE, test, t);
67 // TestRunListener implementation
69 public abstract void testStarted(String testName);
71 public abstract void testEnded(String testName);
73 public abstract void testFailed(int status, Test test, Throwable t);
76 * Returns the Test corresponding to the given suite. This is
77 * a template method, subclasses override runFailed(), clearStatus().
79 public Test getTest(String suiteClassName) {
80 if (suiteClassName.length() <= 0) {
84 Class testClass= null;
86 testClass= loadSuiteClass(suiteClassName);
87 } catch (ClassNotFoundException e) {
88 String clazz= e.getMessage();
90 clazz= suiteClassName;
91 runFailed("Class not found \""+clazz+"\"");
93 } catch(Exception e) {
94 runFailed("Error: "+e.toString());
97 Method suiteMethod= null;
99 suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]);
100 } catch(Exception e) {
101 // try to extract a test suite automatically
103 return new TestSuite(testClass);
105 if (! Modifier.isStatic(suiteMethod.getModifiers())) {
106 runFailed("Suite() method must be static");
111 test= (Test)suiteMethod.invoke(null); // static method
115 catch (InvocationTargetException e) {
116 runFailed("Failed to invoke suite():" + e.getTargetException().toString());
119 catch (IllegalAccessException e) {
120 runFailed("Failed to invoke suite():" + e.toString());
129 * Returns the formatted string of the elapsed time.
131 public String elapsedTimeAsString(long runTime) {
132 return NumberFormat.getInstance().format((double)runTime/1000);
136 * Processes the command line arguments and
137 * returns the name of the suite class to run or null
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")) {
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]);
150 System.out.println("Missing Test class name");
160 * Sets the loading behaviour of the test runner
162 public void setLoading(boolean enable) {
166 * Extract the class name from a String in VA/Java style
168 public String extractClassName(String className) {
169 if(className.startsWith("Default package for"))
170 return className.substring(className.lastIndexOf(".")+1);
175 * Truncates a String to the maximum length.
177 public static String truncate(String s) {
178 if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength)
179 s= s.substring(0, fgMaxMessageLength)+"...";
184 * Override to define how to handle a failed loading of
187 protected abstract void runFailed(String message);
190 * Returns the loaded Class for a suite name.
192 protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
193 return getLoader().load(suiteClassName);
197 * Clears the status message.
199 protected void clearStatus() { // Belongs in the GUI TestRunner class
203 * Returns the loader to be used.
205 public TestSuiteLoader getLoader() {
206 if (useReloadingTestSuiteLoader())
207 return new ReloadingTestSuiteLoader();
208 return new StandardTestSuiteLoader();
211 protected boolean useReloadingTestSuiteLoader() {
212 return getPreference("loading").equals("true") && !inVAJava() && fLoading;
215 private static File getPreferencesFile() {
216 String home= System.getProperty("user.home");
217 return new File(home, "junit.properties");
220 private static void readPreferences() {
221 InputStream is= null;
223 is= new FileInputStream(getPreferencesFile());
224 setPreferences(new Properties(getPreferences()));
225 getPreferences().load(is);
226 } catch (IOException e) {
230 } catch (IOException e1) {
235 public static String getPreference(String key) {
236 return getPreferences().getProperty(key);
239 public static int getPreference(String key, int dflt) {
240 String value= getPreference(key);
245 intValue= Integer.parseInt(value);
246 } catch (NumberFormatException ne) {
251 public static boolean inVAJava() {
253 Class.forName("com.ibm.uvm.tools.DebugSupport");
255 catch (Exception e) {
262 * Returns a filtered stack trace
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);
274 * Filters stack frames from internal JUnit classes
276 public static String getFilteredTrace(String stack) {
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
290 while ((line= br.readLine()) != null) {
291 if (!filterLine(line))
294 } catch (Exception IOException) {
295 return stack; // return the stack unfiltered
297 return sw.toString();
300 protected static boolean showStackRaw() {
301 return !getPreference("filterstack").equals("true") || fgFilterStack == false;
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("
315 for (int i= 0; i < patterns.length; i++) {
316 if (line.indexOf(patterns[i]) > 0)
323 fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength);