|  | package junit.runner; | 
|  |  | 
|  | import java.io.BufferedReader; | 
|  | import java.io.File; | 
|  | import java.io.FileInputStream; | 
|  | import java.io.FileOutputStream; | 
|  | import java.io.IOException; | 
|  | import java.io.InputStream; | 
|  | import java.io.PrintWriter; | 
|  | import java.io.StringReader; | 
|  | import java.io.StringWriter; | 
|  | import java.lang.reflect.InvocationTargetException; | 
|  | import java.lang.reflect.Method; | 
|  | import java.lang.reflect.Modifier; | 
|  | import java.text.NumberFormat; | 
|  | import java.util.Properties; | 
|  |  | 
|  | import junit.framework.AssertionFailedError; | 
|  | import junit.framework.Test; | 
|  | import junit.framework.TestListener; | 
|  | import junit.framework.TestSuite; | 
|  |  | 
|  | /** | 
|  | * Base class for all test runners. | 
|  | * This class was born live on stage in Sardinia during XP2000. | 
|  | */ | 
|  | public abstract class BaseTestRunner implements TestListener { | 
|  | public static final String SUITE_METHODNAME= "suite"; | 
|  |  | 
|  | private static Properties fPreferences; | 
|  | static int fgMaxMessageLength= 500; | 
|  | static boolean fgFilterStack= true; | 
|  | boolean fLoading= true; | 
|  |  | 
|  | /* | 
|  | * Implementation of TestListener | 
|  | */ | 
|  | public synchronized void startTest(Test test) { | 
|  | testStarted(test.toString()); | 
|  | } | 
|  |  | 
|  | protected static void setPreferences(Properties preferences) { | 
|  | fPreferences= preferences; | 
|  | } | 
|  |  | 
|  | protected static Properties getPreferences() { | 
|  | if (fPreferences == null) { | 
|  | fPreferences= new Properties(); | 
|  | fPreferences.put("loading", "true"); | 
|  | fPreferences.put("filterstack", "true"); | 
|  | readPreferences(); | 
|  | } | 
|  | return fPreferences; | 
|  | } | 
|  |  | 
|  | public static void savePreferences() throws IOException { | 
|  | FileOutputStream fos= new FileOutputStream(getPreferencesFile()); | 
|  | try { | 
|  | getPreferences().store(fos, ""); | 
|  | } finally { | 
|  | fos.close(); | 
|  | } | 
|  | } | 
|  |  | 
|  | // android-changed remove 'static' qualifier for API compatibility | 
|  | public void setPreference(String key, String value) { | 
|  | getPreferences().put(key, value); | 
|  | } | 
|  |  | 
|  | public synchronized void endTest(Test test) { | 
|  | testEnded(test.toString()); | 
|  | } | 
|  |  | 
|  | public synchronized void addError(final Test test, final Throwable t) { | 
|  | testFailed(TestRunListener.STATUS_ERROR, test, t); | 
|  | } | 
|  |  | 
|  | public synchronized void addFailure(final Test test, final AssertionFailedError t) { | 
|  | testFailed(TestRunListener.STATUS_FAILURE, test, t); | 
|  | } | 
|  |  | 
|  | // TestRunListener implementation | 
|  |  | 
|  | public abstract void testStarted(String testName); | 
|  |  | 
|  | public abstract void testEnded(String testName); | 
|  |  | 
|  | public abstract void testFailed(int status, Test test, Throwable t); | 
|  |  | 
|  | /** | 
|  | * Returns the Test corresponding to the given suite. This is | 
|  | * a template method, subclasses override runFailed(), clearStatus(). | 
|  | */ | 
|  | public Test getTest(String suiteClassName) { | 
|  | if (suiteClassName.length() <= 0) { | 
|  | clearStatus(); | 
|  | return null; | 
|  | } | 
|  | Class<?> testClass= null; | 
|  | try { | 
|  | testClass= loadSuiteClass(suiteClassName); | 
|  | } catch (ClassNotFoundException e) { | 
|  | String clazz= e.getMessage(); | 
|  | if (clazz == null) | 
|  | clazz= suiteClassName; | 
|  | runFailed("Class not found \""+clazz+"\""); | 
|  | return null; | 
|  | } catch(Exception e) { | 
|  | runFailed("Error: "+e.toString()); | 
|  | return null; | 
|  | } | 
|  | Method suiteMethod= null; | 
|  | try { | 
|  | suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]); | 
|  | } catch(Exception e) { | 
|  | // try to extract a test suite automatically | 
|  | clearStatus(); | 
|  | return new TestSuite(testClass); | 
|  | } | 
|  | if (! Modifier.isStatic(suiteMethod.getModifiers())) { | 
|  | runFailed("Suite() method must be static"); | 
|  | return null; | 
|  | } | 
|  | Test test= null; | 
|  | try { | 
|  | test= (Test)suiteMethod.invoke(null, (Object[])new Class[0]); // static method | 
|  | if (test == null) | 
|  | return test; | 
|  | } | 
|  | catch (InvocationTargetException e) { | 
|  | runFailed("Failed to invoke suite():" + e.getTargetException().toString()); | 
|  | return null; | 
|  | } | 
|  | catch (IllegalAccessException e) { | 
|  | runFailed("Failed to invoke suite():" + e.toString()); | 
|  | return null; | 
|  | } | 
|  |  | 
|  | clearStatus(); | 
|  | return test; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns the formatted string of the elapsed time. | 
|  | */ | 
|  | public String elapsedTimeAsString(long runTime) { | 
|  | return NumberFormat.getInstance().format((double)runTime/1000); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Processes the command line arguments and | 
|  | * returns the name of the suite class to run or null | 
|  | */ | 
|  | protected String processArguments(String[] args) { | 
|  | String suiteName= null; | 
|  | for (int i= 0; i < args.length; i++) { | 
|  | if (args[i].equals("-noloading")) { | 
|  | setLoading(false); | 
|  | } else if (args[i].equals("-nofilterstack")) { | 
|  | fgFilterStack= false; | 
|  | } else if (args[i].equals("-c")) { | 
|  | if (args.length > i+1) | 
|  | suiteName= extractClassName(args[i+1]); | 
|  | else | 
|  | System.out.println("Missing Test class name"); | 
|  | i++; | 
|  | } else { | 
|  | suiteName= args[i]; | 
|  | } | 
|  | } | 
|  | return suiteName; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Sets the loading behaviour of the test runner | 
|  | */ | 
|  | public void setLoading(boolean enable) { | 
|  | fLoading= enable; | 
|  | } | 
|  | /** | 
|  | * Extract the class name from a String in VA/Java style | 
|  | */ | 
|  | public String extractClassName(String className) { | 
|  | if(className.startsWith("Default package for")) | 
|  | return className.substring(className.lastIndexOf(".")+1); | 
|  | return className; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Truncates a String to the maximum length. | 
|  | */ | 
|  | public static String truncate(String s) { | 
|  | if (fgMaxMessageLength != -1 && s.length() > fgMaxMessageLength) | 
|  | s= s.substring(0, fgMaxMessageLength)+"..."; | 
|  | return s; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Override to define how to handle a failed loading of | 
|  | * a test suite. | 
|  | */ | 
|  | protected abstract void runFailed(String message); | 
|  |  | 
|  | // BEGIN android-changed - add back getLoader() for API compatibility | 
|  | /** | 
|  | * Returns the loader to be used. | 
|  | * | 
|  | * @deprecated not present in JUnit4.10 | 
|  | */ | 
|  | @Deprecated | 
|  | public TestSuiteLoader getLoader() { | 
|  | return new StandardTestSuiteLoader(); | 
|  | } | 
|  | // END android-changed | 
|  |  | 
|  | /** | 
|  | * Returns the loaded Class for a suite name. | 
|  | */ | 
|  | protected Class<?> loadSuiteClass(String suiteClassName) throws ClassNotFoundException { | 
|  | return Class.forName(suiteClassName); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Clears the status message. | 
|  | */ | 
|  | protected void clearStatus() { // Belongs in the GUI TestRunner class | 
|  | } | 
|  |  | 
|  | protected boolean useReloadingTestSuiteLoader() { | 
|  | return getPreference("loading").equals("true") && fLoading; | 
|  | } | 
|  |  | 
|  | private static File getPreferencesFile() { | 
|  | String home= System.getProperty("user.home"); | 
|  | return new File(home, "junit.properties"); | 
|  | } | 
|  |  | 
|  | private static void readPreferences() { | 
|  | InputStream is= null; | 
|  | try { | 
|  | is= new FileInputStream(getPreferencesFile()); | 
|  | setPreferences(new Properties(getPreferences())); | 
|  | getPreferences().load(is); | 
|  | } catch (IOException e) { | 
|  | try { | 
|  | if (is != null) | 
|  | is.close(); | 
|  | } catch (IOException e1) { | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | public static String getPreference(String key) { | 
|  | return getPreferences().getProperty(key); | 
|  | } | 
|  |  | 
|  | public static int getPreference(String key, int dflt) { | 
|  | String value= getPreference(key); | 
|  | int intValue= dflt; | 
|  | if (value == null) | 
|  | return intValue; | 
|  | try { | 
|  | intValue= Integer.parseInt(value); | 
|  | } catch (NumberFormatException ne) { | 
|  | } | 
|  | return intValue; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a filtered stack trace | 
|  | */ | 
|  | public static String getFilteredTrace(Throwable t) { | 
|  | StringWriter stringWriter= new StringWriter(); | 
|  | PrintWriter writer= new PrintWriter(stringWriter); | 
|  | t.printStackTrace(writer); | 
|  | StringBuffer buffer= stringWriter.getBuffer(); | 
|  | String trace= buffer.toString(); | 
|  | return BaseTestRunner.getFilteredTrace(trace); | 
|  | } | 
|  |  | 
|  | // BEGIN android-changed - add back this method for API compatibility | 
|  | /** @deprecated not present in JUnit4.10 */ | 
|  | @Deprecated | 
|  | public static boolean inVAJava() { | 
|  | return false; | 
|  | } | 
|  | // END android-changed | 
|  |  | 
|  | /** | 
|  | * Filters stack frames from internal JUnit classes | 
|  | */ | 
|  | public static String getFilteredTrace(String stack) { | 
|  | if (showStackRaw()) | 
|  | return stack; | 
|  |  | 
|  | StringWriter sw= new StringWriter(); | 
|  | PrintWriter pw= new PrintWriter(sw); | 
|  | StringReader sr= new StringReader(stack); | 
|  | // BEGIN android-changed | 
|  | // Use a sensible default buffer size | 
|  | BufferedReader br= new BufferedReader(sr, 1000); | 
|  | // END android-changed | 
|  |  | 
|  | String line; | 
|  | try { | 
|  | while ((line= br.readLine()) != null) { | 
|  | if (!filterLine(line)) | 
|  | pw.println(line); | 
|  | } | 
|  | } catch (Exception IOException) { | 
|  | return stack; // return the stack unfiltered | 
|  | } | 
|  | return sw.toString(); | 
|  | } | 
|  |  | 
|  | protected static boolean showStackRaw() { | 
|  | return !getPreference("filterstack").equals("true") || fgFilterStack == false; | 
|  | } | 
|  |  | 
|  | static boolean filterLine(String line) { | 
|  | String[] patterns= new String[] { | 
|  | "junit.framework.TestCase", | 
|  | "junit.framework.TestResult", | 
|  | "junit.framework.TestSuite", | 
|  | "junit.framework.Assert.", // don't filter AssertionFailure | 
|  | "junit.swingui.TestRunner", | 
|  | "junit.awtui.TestRunner", | 
|  | "junit.textui.TestRunner", | 
|  | "java.lang.reflect.Method.invoke(" | 
|  | }; | 
|  | for (int i= 0; i < patterns.length; i++) { | 
|  | if (line.indexOf(patterns[i]) > 0) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static { | 
|  | fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength); | 
|  | } | 
|  |  | 
|  | } |