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
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
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
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, new Class[0]);
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 in VA/Java style
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() {
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 public static boolean inMac() {
262 return System.getProperty("mrj.version") != null;
263 }
264
265
266 /***
267 * Returns a filtered stack trace
268 */
269 public static String getFilteredTrace(Throwable t) {
270 StringWriter stringWriter= new StringWriter();
271 PrintWriter writer= new PrintWriter(stringWriter);
272 t.printStackTrace(writer);
273 StringBuffer buffer= stringWriter.getBuffer();
274 String trace= buffer.toString();
275 return BaseTestRunner.getFilteredTrace(trace);
276 }
277
278 /***
279 * Filters stack frames from internal JUnit classes
280 */
281 public static String getFilteredTrace(String stack) {
282 if (showStackRaw())
283 return stack;
284
285 StringWriter sw= new StringWriter();
286 PrintWriter pw= new PrintWriter(sw);
287 StringReader sr= new StringReader(stack);
288 BufferedReader br= new BufferedReader(sr);
289
290 String line;
291 try {
292 while ((line= br.readLine()) != null) {
293 if (!filterLine(line))
294 pw.println(line);
295 }
296 } catch (Exception IOException) {
297 return stack;
298 }
299 return sw.toString();
300 }
301
302 protected static boolean showStackRaw() {
303 return !getPreference("filterstack").equals("true") || fgFilterStack == false;
304 }
305
306 static boolean filterLine(String line) {
307 String[] patterns= new String[] {
308 "junit.framework.TestCase",
309 "junit.framework.TestResult",
310 "junit.framework.TestSuite",
311 "junit.framework.Assert.",
312 "junit.swingui.TestRunner",
313 "junit.awtui.TestRunner",
314 "junit.textui.TestRunner",
315 "java.lang.reflect.Method.invoke("
316 };
317 for (int i= 0; i < patterns.length; i++) {
318 if (line.indexOf(patterns[i]) > 0)
319 return true;
320 }
321 return false;
322 }
323
324 static {
325 fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength);
326 }
327
328 }