blob: e073ef789fc63949604cdea617a8ca4db5d62253 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001package junit.runner;
2
3import junit.framework.*;
4import java.lang.reflect.*;
5import java.text.NumberFormat;
6import java.io.*;
7import java.util.*;
8
9/**
10 * Base class for all test runners.
11 * This class was born live on stage in Sardinia during XP2000.
12 */
13public 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}