blob: b2fa16c91da24993a4619d2368c0a5e6592ab8a8 [file] [log] [blame]
Paul Duffineef35dd2016-12-12 12:22:31 +00001package junit.runner;
2
3import java.io.BufferedReader;
4import java.io.File;
5import java.io.FileInputStream;
6import java.io.FileOutputStream;
7import java.io.IOException;
8import java.io.InputStream;
9import java.io.PrintWriter;
10import java.io.StringReader;
11import java.io.StringWriter;
12import java.lang.reflect.InvocationTargetException;
13import java.lang.reflect.Method;
14import java.lang.reflect.Modifier;
15import java.text.NumberFormat;
16import java.util.Properties;
17
18import junit.framework.AssertionFailedError;
19import junit.framework.Test;
20import junit.framework.TestListener;
21import 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 */
27public 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 */
38 public synchronized void startTest(Test test) {
39 testStarted(test.toString());
40 }
41
42 protected static void setPreferences(Properties preferences) {
43 fPreferences= preferences;
44 }
45
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
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
66 public void setPreference(String key, String value) {
67 getPreferences().put(key, value);
68 }
69
70 public synchronized void endTest(Test test) {
71 testEnded(test.toString());
72 }
73
74 public synchronized void addError(final Test test, final Throwable t) {
75 testFailed(TestRunListener.STATUS_ERROR, test, t);
76 }
77
78 public synchronized void addFailure(final Test test, final AssertionFailedError t) {
79 testFailed(TestRunListener.STATUS_FAILURE, test, t);
80 }
81
82 // TestRunListener implementation
83
84 public abstract void testStarted(String testName);
85
86 public abstract void testEnded(String testName);
87
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 */
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 */
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 */
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 */
177 public void setLoading(boolean enable) {
178 fLoading= enable;
179 }
180 /**
181 * Extract the class name from a String in VA/Java style
182 */
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 */
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 */
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 */
Paul Duffin2d86c7a2018-02-16 13:11:05 +0000210 @Deprecated
Paul Duffineef35dd2016-12-12 12:22:31 +0000211 public TestSuiteLoader getLoader() {
212 return new StandardTestSuiteLoader();
213 }
214 // END android-changed
215
216 /**
217 * Returns the loaded Class for a suite name.
218 */
219 protected Class<?> loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
220 return Class.forName(suiteClassName);
221 }
222
223 /**
224 * Clears the status message.
225 */
226 protected void clearStatus() { // Belongs in the GUI TestRunner class
227 }
228
229 protected boolean useReloadingTestSuiteLoader() {
230 return getPreference("loading").equals("true") && fLoading;
231 }
232
233 private static File getPreferencesFile() {
234 String home= System.getProperty("user.home");
235 return new File(home, "junit.properties");
236 }
237
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
253 public static String getPreference(String key) {
254 return getPreferences().getProperty(key);
255 }
256
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 */
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 */
Paul Duffin2d86c7a2018-02-16 13:11:05 +0000283 @Deprecated
Paul Duffineef35dd2016-12-12 12:22:31 +0000284 public static boolean inVAJava() {
285 return false;
286 }
287 // END android-changed
288
289 /**
290 * Filters stack frames from internal JUnit classes
291 */
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
316 protected static boolean showStackRaw() {
317 return !getPreference("filterstack").equals("true") || fgFilterStack == false;
318 }
319
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}