1. package junit.runner;
  2. import junit.framework.*;
  3. import java.lang.reflect.*;
  4. import java.text.NumberFormat;
  5. import java.io.*;
  6. import java.util.*;
  7. /**
  8. * Base class for all test runners.
  9. * This class was born live on stage in Sardinia during XP2000.
  10. */
  11. public abstract class BaseTestRunner implements TestListener {
  12. public static final String SUITE_METHODNAME= "suite";
  13. private static Properties fPreferences;
  14. static int fgMaxMessageLength= 500;
  15. static boolean fgFilterStack= true;
  16. boolean fLoading= true;
  17. /*
  18. * Implementation of TestListener
  19. */
  20. public synchronized void startTest(Test test) {
  21. testStarted(test.toString());
  22. }
  23. protected static void setPreferences(Properties preferences) {
  24. fPreferences= preferences;
  25. }
  26. protected static Properties getPreferences() {
  27. if (fPreferences == null) {
  28. fPreferences= new Properties();
  29. fPreferences.put("loading", "true");
  30. fPreferences.put("filterstack", "true");
  31. readPreferences();
  32. }
  33. return fPreferences;
  34. }
  35. public static void savePreferences() throws IOException {
  36. FileOutputStream fos= new FileOutputStream(getPreferencesFile());
  37. try {
  38. getPreferences().store(fos, "");
  39. } finally {
  40. fos.close();
  41. }
  42. }
  43. public void setPreference(String key, String value) {
  44. getPreferences().setProperty(key, value);
  45. }
  46. public synchronized void endTest(Test test) {
  47. testEnded(test.toString());
  48. }
  49. public synchronized void addError(final Test test, final Throwable t) {
  50. testFailed(TestRunListener.STATUS_ERROR, test, t);
  51. }
  52. public synchronized void addFailure(final Test test, final AssertionFailedError t) {
  53. testFailed(TestRunListener.STATUS_FAILURE, test, t);
  54. }
  55. // TestRunListener implementation
  56. public abstract void testStarted(String testName);
  57. public abstract void testEnded(String testName);
  58. public abstract void testFailed(int status, Test test, Throwable t);
  59. /**
  60. * Returns the Test corresponding to the given suite. This is
  61. * a template method, subclasses override runFailed(), clearStatus().
  62. */
  63. public Test getTest(String suiteClassName) {
  64. if (suiteClassName.length() <= 0) {
  65. clearStatus();
  66. return null;
  67. }
  68. Class testClass= null;
  69. try {
  70. testClass= loadSuiteClass(suiteClassName);
  71. } catch (ClassNotFoundException e) {
  72. String clazz= e.getMessage();
  73. if (clazz == null)
  74. clazz= suiteClassName;
  75. runFailed("Class not found \""+clazz+"\"");
  76. return null;
  77. } catch(Exception e) {
  78. runFailed("Error: "+e.toString());
  79. return null;
  80. }
  81. Method suiteMethod= null;
  82. try {
  83. suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]);
  84. } catch(Exception e) {
  85. // try to extract a test suite automatically
  86. clearStatus();
  87. return new TestSuite(testClass);
  88. }
  89. if (! Modifier.isStatic(suiteMethod.getModifiers())) {
  90. runFailed("Suite() method must be static");
  91. return null;
  92. }
  93. Test test= null;
  94. try {
  95. test= (Test)suiteMethod.invoke(null, new Class[0]); // static method
  96. if (test == null)
  97. return test;
  98. }
  99. catch (InvocationTargetException e) {
  100. runFailed("Failed to invoke suite():" + e.getTargetException().toString());
  101. return null;
  102. }
  103. catch (IllegalAccessException e) {
  104. runFailed("Failed to invoke suite():" + e.toString());
  105. return null;
  106. }
  107. clearStatus();
  108. return test;
  109. }
  110. /**
  111. * Returns the formatted string of the elapsed time.
  112. */
  113. public String elapsedTimeAsString(long runTime) {
  114. return NumberFormat.getInstance().format((double)runTime1000);
  115. }
  116. /**
  117. * Processes the command line arguments and
  118. * returns the name of the suite class to run or null
  119. */
  120. protected String processArguments(String[] args) {
  121. String suiteName= null;
  122. for (int i= 0; i < args.length; i++) {
  123. if (args[i].equals("-noloading")) {
  124. setLoading(false);
  125. } else if (args[i].equals("-nofilterstack")) {
  126. fgFilterStack= false;
  127. } else if (args[i].equals("-c")) {
  128. if (args.length > i+1)
  129. suiteName= extractClassName(args[i+1]);
  130. else
  131. System.out.println("Missing Test class name");
  132. i++;
  133. } else {
  134. suiteName= args[i];
  135. }
  136. }
  137. return suiteName;
  138. }
  139. /**
  140. * Sets the loading behaviour of the test runner
  141. */
  142. public void setLoading(boolean enable) {
  143. fLoading= enable;
  144. }
  145. /**
  146. * Extract the class name from a String in VA/Java style
  147. */
  148. public String extractClassName(String className) {
  149. if(className.startsWith("Default package for"))
  150. return className.substring(className.lastIndexOf(".")+1);
  151. return className;
  152. }
  153. /**
  154. * Truncates a String to the maximum length.
  155. */
  156. public static String truncate(String s) {
  157. if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength)
  158. s= s.substring(0, fgMaxMessageLength)+"...";
  159. return s;
  160. }
  161. /**
  162. * Override to define how to handle a failed loading of
  163. * a test suite.
  164. */
  165. protected abstract void runFailed(String message);
  166. /**
  167. * Returns the loaded Class for a suite name.
  168. */
  169. protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
  170. return getLoader().load(suiteClassName);
  171. }
  172. /**
  173. * Clears the status message.
  174. */
  175. protected void clearStatus() { // Belongs in the GUI TestRunner class
  176. }
  177. /**
  178. * Returns the loader to be used.
  179. */
  180. public TestSuiteLoader getLoader() {
  181. if (useReloadingTestSuiteLoader())
  182. return new ReloadingTestSuiteLoader();
  183. return new StandardTestSuiteLoader();
  184. }
  185. protected boolean useReloadingTestSuiteLoader() {
  186. return getPreference("loading").equals("true") && !inVAJava() && fLoading;
  187. }
  188. private static File getPreferencesFile() {
  189. String home= System.getProperty("user.home");
  190. return new File(home, "junit.properties");
  191. }
  192. private static void readPreferences() {
  193. InputStream is= null;
  194. try {
  195. is= new FileInputStream(getPreferencesFile());
  196. setPreferences(new Properties(getPreferences()));
  197. getPreferences().load(is);
  198. } catch (IOException e) {
  199. try {
  200. if (is != null)
  201. is.close();
  202. } catch (IOException e1) {
  203. }
  204. }
  205. }
  206. public static String getPreference(String key) {
  207. return getPreferences().getProperty(key);
  208. }
  209. public static int getPreference(String key, int dflt) {
  210. String value= getPreference(key);
  211. int intValue= dflt;
  212. if (value == null)
  213. return intValue;
  214. try {
  215. intValue= Integer.parseInt(value);
  216. } catch (NumberFormatException ne) {
  217. }
  218. return intValue;
  219. }
  220. public static boolean inVAJava() {
  221. try {
  222. Class.forName("com.ibm.uvm.tools.DebugSupport");
  223. }
  224. catch (Exception e) {
  225. return false;
  226. }
  227. return true;
  228. }
  229. /**
  230. * Returns a filtered stack trace
  231. */
  232. public static String getFilteredTrace(Throwable t) {
  233. StringWriter stringWriter= new StringWriter();
  234. PrintWriter writer= new PrintWriter(stringWriter);
  235. t.printStackTrace(writer);
  236. StringBuffer buffer= stringWriter.getBuffer();
  237. String trace= buffer.toString();
  238. return BaseTestRunner.getFilteredTrace(trace);
  239. }
  240. /**
  241. * Filters stack frames from internal JUnit classes
  242. */
  243. public static String getFilteredTrace(String stack) {
  244. if (showStackRaw())
  245. return stack;
  246. StringWriter sw= new StringWriter();
  247. PrintWriter pw= new PrintWriter(sw);
  248. StringReader sr= new StringReader(stack);
  249. BufferedReader br= new BufferedReader(sr);
  250. String line;
  251. try {
  252. while ((line= br.readLine()) != null) {
  253. if (!filterLine(line))
  254. pw.println(line);
  255. }
  256. } catch (Exception IOException) {
  257. return stack; // return the stack unfiltered
  258. }
  259. return sw.toString();
  260. }
  261. protected static boolean showStackRaw() {
  262. return !getPreference("filterstack").equals("true") || fgFilterStack == false;
  263. }
  264. static boolean filterLine(String line) {
  265. String[] patterns= new String[] {
  266. "junit.framework.TestCase",
  267. "junit.framework.TestResult",
  268. "junit.framework.TestSuite",
  269. "junit.framework.Assert.", // don't filter AssertionFailure
  270. "junit.swingui.TestRunner",
  271. "junit.awtui.TestRunner",
  272. "junit.textui.TestRunner",
  273. "java.lang.reflect.Method.invoke("
  274. };
  275. for (int i= 0; i < patterns.length; i++) {
  276. if (line.indexOf(patterns[i]) > 0)
  277. return true;
  278. }
  279. return false;
  280. }
  281. static {
  282. fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength);
  283. }
  284. }