|     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       * 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, new Class[0]); // 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 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() { // 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   		BufferedReader br= new BufferedReader(sr);
 | 
      |   284   
  285   		String line;
  286   		try {
 | 
      |   287   			while ((line= br.readLine()) != null) {
  288   				if (!filterLine(line))
  289   					pw.println(line);
 | 
      |   290   			}
 | 
      |   291   		} catch (Exception IOException) {
 | 
      |   292 > 			return stack; // return the stack unfiltered
 | 
      |   293   		}
 | 
      |   294   		return sw.toString();
 | 
      |   295   	}
  296   
  297   	protected static boolean showStackRaw() {
 | 
      |   298   		return !getPreference("filterstack").equals("true") || fgFilterStack == false;
 | 
      |   299   	}
  300   
  301   	static boolean filterLine(String line) {
 | 
      |   302   		String[] patterns= new String[] {
 | 
      |   303   			"junit.framework.TestCase",
  304   			"junit.framework.TestResult",
  305   			"junit.framework.TestSuite",
  306   			"junit.framework.Assert.", // don't filter AssertionFailure
  307   			"junit.swingui.TestRunner",
  308   			"junit.awtui.TestRunner",
  309   			"junit.textui.TestRunner",
  310   			"java.lang.reflect.Method.invoke("
  311   		};
 | 
      |   312   		for (int i= 0; i < patterns.length; i++) {
  313   			if (line.indexOf(patterns[i]) > 0)
  314   				return true;
 | 
      |   315   		}
 | 
      |   316   		return false;
 | 
      |   317   	}
  318   
  319    	static {
 | 
      |   320    		fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength);
  321    	}
 | 
      |   322   
  323   } |