Upgrade junit.runner classes to their JUnit4.10 implementation.

Bug 5826326

Change-Id: If7e4c48a4369c1056dee5a2049c891bb6ab7d8d0
diff --git a/test-runner/src/android/test/AssertionFailedError.java b/test-runner/src/android/test/AssertionFailedError.java
index 7af5806..b3ac6d1 100644
--- a/test-runner/src/android/test/AssertionFailedError.java
+++ b/test-runner/src/android/test/AssertionFailedError.java
@@ -19,8 +19,7 @@
 /**
  * Thrown when an assertion failed.
  * 
- * Note:  Most users of this class should simply use junit.framework.AssertionFailedError,
- * which provides the same functionality.
+ * @deprecated use junit.framework.AssertionFailedError
  */
 public class AssertionFailedError extends Error {
     
diff --git a/test-runner/src/android/test/ComparisonFailure.java b/test-runner/src/android/test/ComparisonFailure.java
index e7e9698..3fa76f5 100644
--- a/test-runner/src/android/test/ComparisonFailure.java
+++ b/test-runner/src/android/test/ComparisonFailure.java
@@ -19,8 +19,7 @@
 /**
  * Thrown when an assert equals for Strings failed.
  * 
- * Note:  Most users of this class should simply use junit.framework.ComparisonFailure,
- * which provides the same functionality at a lighter weight.
+ * @deprecated use junit.framework.ComparisonFailure
  */
 public class ComparisonFailure extends AssertionFailedError {
     private junit.framework.ComparisonFailure mComparison;
diff --git a/test-runner/src/junit/runner/BaseTestRunner.java b/test-runner/src/junit/runner/BaseTestRunner.java
index e073ef7..8cfd7fa 100644
--- a/test-runner/src/junit/runner/BaseTestRunner.java
+++ b/test-runner/src/junit/runner/BaseTestRunner.java
@@ -1,10 +1,24 @@
 package junit.runner;
 
-import junit.framework.*;
-import java.lang.reflect.*;
+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.io.*;
-import java.util.*;
+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.
@@ -19,8 +33,8 @@
     boolean fLoading= true;
 
     /*
-    * Implementation of TestListener
-    */
+     * Implementation of TestListener
+     */
     public synchronized void startTest(Test test) {
         testStarted(test.toString());
     }
@@ -32,9 +46,9 @@
     protected static Properties getPreferences() {
         if (fPreferences == null) {
             fPreferences= new Properties();
-             fPreferences.put("loading", "true");
-             fPreferences.put("filterstack", "true");
-              readPreferences();
+            fPreferences.put("loading", "true");
+            fPreferences.put("filterstack", "true");
+            readPreferences();
         }
         return fPreferences;
     }
@@ -48,8 +62,9 @@
         }
     }
 
+    // android-changed remove 'static' qualifier for API compatibility
     public void setPreference(String key, String value) {
-        getPreferences().setProperty(key, value);
+        getPreferences().put(key, value);
     }
 
     public synchronized void endTest(Test test) {
@@ -97,8 +112,8 @@
         Method suiteMethod= null;
         try {
             suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]);
-         } catch(Exception e) {
-             // try to extract a test suite automatically
+        } catch(Exception e) {
+            // try to extract a test suite automatically
             clearStatus();
             return new TestSuite(testClass);
         }
@@ -108,7 +123,7 @@
         }
         Test test= null;
         try {
-            test= (Test)suiteMethod.invoke(null); // static method
+            test= (Test)suiteMethod.invoke(null, (Object[])new Class[0]); // static method
             if (test == null)
                 return test;
         }
@@ -163,7 +178,7 @@
         fLoading= enable;
     }
     /**
-     * Extract the class name from a String
+     * Extract the class name from a String in VA/Java style
      */
     public String extractClassName(String className) {
         if(className.startsWith("Default package for"))
@@ -186,11 +201,24 @@
      */
     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
+     */
+    public TestSuiteLoader getLoader() {
+        if (useReloadingTestSuiteLoader())
+            return new ReloadingTestSuiteLoader();
+        return new StandardTestSuiteLoader();
+    }
+    // END android-changed
+
     /**
      * Returns the loaded Class for a suite name.
      */
-    protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
-        return getLoader().load(suiteClassName);
+    protected Class<?> loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
+        return Class.forName(suiteClassName);
     }
 
     /**
@@ -199,29 +227,20 @@
     protected void clearStatus() { // Belongs in the GUI TestRunner class
     }
 
-    /**
-     * Returns the loader to be used.
-     */
-    public TestSuiteLoader getLoader() {
-        if (useReloadingTestSuiteLoader())
-            return new ReloadingTestSuiteLoader();
-        return new StandardTestSuiteLoader();
-    }
-
     protected boolean useReloadingTestSuiteLoader() {
-        return getPreference("loading").equals("true") && !inVAJava() && fLoading;
+        return getPreference("loading").equals("true") && fLoading;
     }
 
     private static File getPreferencesFile() {
-         String home= System.getProperty("user.home");
-         return new File(home, "junit.properties");
-     }
+        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()));
+    private static void readPreferences() {
+        InputStream is= null;
+        try {
+            is= new FileInputStream(getPreferencesFile());
+            setPreferences(new Properties(getPreferences()));
             getPreferences().load(is);
         } catch (IOException e) {
             try {
@@ -230,32 +249,22 @@
             } catch (IOException e1) {
             }
         }
-     }
+    }
 
-     public static String getPreference(String key) {
-         return getPreferences().getProperty(key);
-     }
+    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;
-     }
-
-     public static boolean inVAJava() {
+    public static int getPreference(String key, int dflt) {
+        String value= getPreference(key);
+        int intValue= dflt;
+        if (value == null)
+            return intValue;
         try {
-            Class.forName("com.ibm.uvm.tools.DebugSupport");
+            intValue= Integer.parseInt(value);
+        } catch (NumberFormatException ne) {
         }
-        catch (Exception e) {
-            return false;
-        }
-        return true;
+        return intValue;
     }
 
     /**
@@ -270,6 +279,13 @@
         return BaseTestRunner.getFilteredTrace(trace);
     }
 
+    // BEGIN android-changed - add back this method for API compatibility
+    /** @deprecated not present in JUnit4.10 */
+    public static boolean inVAJava() {
+        return false;
+    }
+    // END android-changed
+
     /**
      * Filters stack frames from internal JUnit classes
      */
@@ -303,14 +319,14 @@
 
     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("
+                "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)
@@ -319,8 +335,8 @@
         return false;
     }
 
-     static {
-         fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength);
-     }
+    static {
+        fgMaxMessageLength= getPreference("maxmessage", fgMaxMessageLength);
+    }
 
 }
diff --git a/test-runner/src/junit/runner/ClassPathTestCollector.java b/test-runner/src/junit/runner/ClassPathTestCollector.java
index 8a3c702..f48ddee 100644
--- a/test-runner/src/junit/runner/ClassPathTestCollector.java
+++ b/test-runner/src/junit/runner/ClassPathTestCollector.java
@@ -13,69 +13,69 @@
  * {@hide} - Not needed for 1.0 SDK
  */
 public abstract class ClassPathTestCollector implements TestCollector {
-	
-	static final int SUFFIX_LENGTH= ".class".length();
-	
-	public ClassPathTestCollector() {
-	}
-	
-	public Enumeration collectTests() {
-		String classPath= System.getProperty("java.class.path");
-		Hashtable result = collectFilesInPath(classPath);
-		return result.elements();
-	}
 
-	public Hashtable collectFilesInPath(String classPath) {
-		Hashtable result= collectFilesInRoots(splitClassPath(classPath));
-		return result;
-	}
-	
-	Hashtable collectFilesInRoots(Vector roots) {
-		Hashtable result= new Hashtable(100);
-		Enumeration e= roots.elements();
-		while (e.hasMoreElements()) 
-			gatherFiles(new File((String)e.nextElement()), "", result);
-		return result;
-	}
+    static final int SUFFIX_LENGTH= ".class".length();
 
-	void gatherFiles(File classRoot, String classFileName, Hashtable result) {
-		File thisRoot= new File(classRoot, classFileName);
-		if (thisRoot.isFile()) {
-			if (isTestClass(classFileName)) {
-				String className= classNameFromFile(classFileName);
-				result.put(className, className);
-			}
-			return;
-		}		
-		String[] contents= thisRoot.list();
-		if (contents != null) { 
-			for (int i= 0; i < contents.length; i++) 
-				gatherFiles(classRoot, classFileName+File.separatorChar+contents[i], result);		
-		}
-	}
-	
-	Vector splitClassPath(String classPath) {
-		Vector result= new Vector();
-		String separator= System.getProperty("path.separator");
-		StringTokenizer tokenizer= new StringTokenizer(classPath, separator);
-		while (tokenizer.hasMoreTokens()) 
-			result.addElement(tokenizer.nextToken());
-		return result;
-	}
-	
-	protected boolean isTestClass(String classFileName) {
-		return 
-			classFileName.endsWith(".class") && 
-			classFileName.indexOf('$') < 0 &&
-			classFileName.indexOf("Test") > 0;
-	}
-	
-	protected String classNameFromFile(String classFileName) {
-		// convert /a/b.class to a.b
-		String s= classFileName.substring(0, classFileName.length()-SUFFIX_LENGTH);
-		String s2= s.replace(File.separatorChar, '.');
-		if (s2.startsWith("."))
-			return s2.substring(1);
-		return s2;
-	}	
+    public ClassPathTestCollector() {
+    }
+
+    public Enumeration collectTests() {
+        String classPath= System.getProperty("java.class.path");
+        Hashtable result = collectFilesInPath(classPath);
+        return result.elements();
+    }
+
+    public Hashtable collectFilesInPath(String classPath) {
+        Hashtable result= collectFilesInRoots(splitClassPath(classPath));
+        return result;
+    }
+
+    Hashtable collectFilesInRoots(Vector roots) {
+        Hashtable result= new Hashtable(100);
+        Enumeration e= roots.elements();
+        while (e.hasMoreElements())
+            gatherFiles(new File((String)e.nextElement()), "", result);
+        return result;
+    }
+
+    void gatherFiles(File classRoot, String classFileName, Hashtable result) {
+        File thisRoot= new File(classRoot, classFileName);
+        if (thisRoot.isFile()) {
+            if (isTestClass(classFileName)) {
+                String className= classNameFromFile(classFileName);
+                result.put(className, className);
+            }
+            return;
+        }
+        String[] contents= thisRoot.list();
+        if (contents != null) {
+            for (int i= 0; i < contents.length; i++)
+                gatherFiles(classRoot, classFileName+File.separatorChar+contents[i], result);
+        }
+    }
+
+    Vector splitClassPath(String classPath) {
+        Vector result= new Vector();
+        String separator= System.getProperty("path.separator");
+        StringTokenizer tokenizer= new StringTokenizer(classPath, separator);
+        while (tokenizer.hasMoreTokens())
+            result.addElement(tokenizer.nextToken());
+        return result;
+    }
+
+    protected boolean isTestClass(String classFileName) {
+        return
+                classFileName.endsWith(".class") &&
+                classFileName.indexOf('$') < 0 &&
+                classFileName.indexOf("Test") > 0;
+    }
+
+    protected String classNameFromFile(String classFileName) {
+        // convert /a/b.class to a.b
+        String s= classFileName.substring(0, classFileName.length()-SUFFIX_LENGTH);
+        String s2= s.replace(File.separatorChar, '.');
+        if (s2.startsWith("."))
+            return s2.substring(1);
+        return s2;
+    }
 }
diff --git a/test-runner/src/junit/runner/FailureDetailView.java b/test-runner/src/junit/runner/FailureDetailView.java
index 7108cec..1b8365a 100644
--- a/test-runner/src/junit/runner/FailureDetailView.java
+++ b/test-runner/src/junit/runner/FailureDetailView.java
@@ -1,7 +1,7 @@
 package junit.runner;
 
 // The following line was removed for compatibility with Android libraries.
-//import java.awt.Component; 
+//import java.awt.Component;
 
 import junit.framework.*;
 
@@ -17,12 +17,12 @@
     //   */
     //  public Component getComponent();
 
-	/**
-	 * Shows details of a TestFailure
-	 */
-	public void showFailure(TestFailure failure);
-	/**
-	 * Clears the view
-	 */
-	public void clear();
+    /**
+     * Shows details of a TestFailure
+     */
+    public void showFailure(TestFailure failure);
+    /**
+     * Clears the view
+     */
+    public void clear();
 }
diff --git a/test-runner/src/junit/runner/LoadingTestCollector.java b/test-runner/src/junit/runner/LoadingTestCollector.java
index b1760b1..489d9d6 100644
--- a/test-runner/src/junit/runner/LoadingTestCollector.java
+++ b/test-runner/src/junit/runner/LoadingTestCollector.java
@@ -12,59 +12,59 @@
  * {@hide} - Not needed for 1.0 SDK
  */
 public class LoadingTestCollector extends ClassPathTestCollector {
-	
-	TestCaseClassLoader fLoader;
-	
-	public LoadingTestCollector() {
-		fLoader= new TestCaseClassLoader();
-	}
-	
-	protected boolean isTestClass(String classFileName) {	
-		try {
-			if (classFileName.endsWith(".class")) {
-				Class testClass= classFromFile(classFileName);
-				return (testClass != null) && isTestClass(testClass);
-			}
-		} 
-		catch (ClassNotFoundException expected) {
-		}
-		catch (NoClassDefFoundError notFatal) {
-		} 
-		return false;
-	}
-	
-	Class classFromFile(String classFileName) throws ClassNotFoundException {
-		String className= classNameFromFile(classFileName);
-		if (!fLoader.isExcluded(className))
-			return fLoader.loadClass(className, false);
-		return null;
-	}
-	
-	boolean isTestClass(Class testClass) {
-		if (hasSuiteMethod(testClass))
-			return true;
-		if (Test.class.isAssignableFrom(testClass) &&
-			Modifier.isPublic(testClass.getModifiers()) &&
-			hasPublicConstructor(testClass)) 
-			return true;
-		return false;
-	}
-	
-	boolean hasSuiteMethod(Class testClass) {
-		try {
-			testClass.getMethod(BaseTestRunner.SUITE_METHODNAME, new Class[0]);
-	 	} catch(Exception e) {
-	 		return false;
-		}
-		return true;
-	}
-	
-	boolean hasPublicConstructor(Class testClass) {
-		try {
-			TestSuite.getTestConstructor(testClass);
-		} catch(NoSuchMethodException e) {
-			return false;
-		}
-		return true;
-	}
+
+    TestCaseClassLoader fLoader;
+
+    public LoadingTestCollector() {
+        fLoader= new TestCaseClassLoader();
+    }
+
+    protected boolean isTestClass(String classFileName) {
+        try {
+            if (classFileName.endsWith(".class")) {
+                Class testClass= classFromFile(classFileName);
+                return (testClass != null) && isTestClass(testClass);
+            }
+        }
+        catch (ClassNotFoundException expected) {
+        }
+        catch (NoClassDefFoundError notFatal) {
+        }
+        return false;
+    }
+
+    Class classFromFile(String classFileName) throws ClassNotFoundException {
+        String className= classNameFromFile(classFileName);
+        if (!fLoader.isExcluded(className))
+            return fLoader.loadClass(className, false);
+        return null;
+    }
+
+    boolean isTestClass(Class testClass) {
+        if (hasSuiteMethod(testClass))
+            return true;
+        if (Test.class.isAssignableFrom(testClass) &&
+                Modifier.isPublic(testClass.getModifiers()) &&
+                hasPublicConstructor(testClass))
+            return true;
+        return false;
+    }
+
+    boolean hasSuiteMethod(Class testClass) {
+        try {
+            testClass.getMethod(BaseTestRunner.SUITE_METHODNAME, new Class[0]);
+        } catch(Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+    boolean hasPublicConstructor(Class testClass) {
+        try {
+            TestSuite.getTestConstructor(testClass);
+        } catch(NoSuchMethodException e) {
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/test-runner/src/junit/runner/ReloadingTestSuiteLoader.java b/test-runner/src/junit/runner/ReloadingTestSuiteLoader.java
index a6d84fe..c4d80d0 100644
--- a/test-runner/src/junit/runner/ReloadingTestSuiteLoader.java
+++ b/test-runner/src/junit/runner/ReloadingTestSuiteLoader.java
@@ -5,16 +5,16 @@
  * {@hide} - Not needed for 1.0 SDK
  */
 public class ReloadingTestSuiteLoader implements TestSuiteLoader {
-	
-	public Class load(String suiteClassName) throws ClassNotFoundException {
-		return createLoader().loadClass(suiteClassName, true);
-	}
-	
-	public Class reload(Class aClass) throws ClassNotFoundException {
-		return createLoader().loadClass(aClass.getName(), true);
-	}
-	
-	protected TestCaseClassLoader createLoader() {
-		return new TestCaseClassLoader();
-	}
+
+    public Class load(String suiteClassName) throws ClassNotFoundException {
+        return createLoader().loadClass(suiteClassName, true);
+    }
+
+    public Class reload(Class aClass) throws ClassNotFoundException {
+        return createLoader().loadClass(aClass.getName(), true);
+    }
+
+    protected TestCaseClassLoader createLoader() {
+        return new TestCaseClassLoader();
+    }
 }
diff --git a/test-runner/src/junit/runner/SimpleTestCollector.java b/test-runner/src/junit/runner/SimpleTestCollector.java
index 543168f8..6cb0e19 100644
--- a/test-runner/src/junit/runner/SimpleTestCollector.java
+++ b/test-runner/src/junit/runner/SimpleTestCollector.java
@@ -8,14 +8,14 @@
  * {@hide} - Not needed for 1.0 SDK
  */
 public class SimpleTestCollector extends ClassPathTestCollector {
-	
-	public SimpleTestCollector() {
-	}
-	
-	protected boolean isTestClass(String classFileName) {
-		return 
-			classFileName.endsWith(".class") && 
-			classFileName.indexOf('$') < 0 &&
-			classFileName.indexOf("Test") > 0;
-	}
+
+    public SimpleTestCollector() {
+    }
+
+    protected boolean isTestClass(String classFileName) {
+        return
+                classFileName.endsWith(".class") &&
+                classFileName.indexOf('$') < 0 &&
+                classFileName.indexOf("Test") > 0;
+    }
 }
diff --git a/test-runner/src/junit/runner/Sorter.java b/test-runner/src/junit/runner/Sorter.java
index 66f551e..7731f66 100644
--- a/test-runner/src/junit/runner/Sorter.java
+++ b/test-runner/src/junit/runner/Sorter.java
@@ -11,29 +11,29 @@
  * {@hide} - Not needed for 1.0 SDK
  */
 public class Sorter {
-	public static interface Swapper {
-		public void swap(Vector values, int left, int right);
-	}
-		
-	public static void sortStrings(Vector values , int left, int right, Swapper swapper) { 
-		int oleft= left;
-		int oright= right;
-		String mid= (String)values.elementAt((left + right) / 2); 
-		do { 
-			while (((String)(values.elementAt(left))).compareTo(mid) < 0)  
-				left++; 
-			while (mid.compareTo((String)(values.elementAt(right))) < 0)  
-				right--; 
-			if (left <= right) {
-				swapper.swap(values, left, right); 
-				left++; 
-				right--; 
-			} 
-		} while (left <= right);
-		
-		if (oleft < right) 
-			sortStrings(values, oleft, right, swapper); 
-		if (left < oright) 
-			 sortStrings(values, left, oright, swapper); 
-	}
+    public static interface Swapper {
+        public void swap(Vector values, int left, int right);
+    }
+
+    public static void sortStrings(Vector values , int left, int right, Swapper swapper) {
+        int oleft= left;
+        int oright= right;
+        String mid= (String)values.elementAt((left + right) / 2);
+        do {
+            while (((String)(values.elementAt(left))).compareTo(mid) < 0)
+                left++;
+            while (mid.compareTo((String)(values.elementAt(right))) < 0)
+                right--;
+            if (left <= right) {
+                swapper.swap(values, left, right);
+                left++;
+                right--;
+            }
+        } while (left <= right);
+
+        if (oleft < right)
+            sortStrings(values, oleft, right, swapper);
+        if (left < oright)
+            sortStrings(values, left, oright, swapper);
+    }
 }
diff --git a/test-runner/src/junit/runner/StandardTestSuiteLoader.java b/test-runner/src/junit/runner/StandardTestSuiteLoader.java
index bce7dec..381e684 100644
--- a/test-runner/src/junit/runner/StandardTestSuiteLoader.java
+++ b/test-runner/src/junit/runner/StandardTestSuiteLoader.java
@@ -5,16 +5,16 @@
  * {@hide} - Not needed for 1.0 SDK
  */
 public class StandardTestSuiteLoader implements TestSuiteLoader {
-	/**
-	 * Uses the system class loader to load the test class
-	 */
-	public Class load(String suiteClassName) throws ClassNotFoundException {
-		return Class.forName(suiteClassName);
-	}
-	/**
-	 * Uses the system class loader to load the test class
-	 */
-	public Class reload(Class aClass) throws ClassNotFoundException {
-		return aClass;
-	}
+    /**
+     * Uses the system class loader to load the test class
+     */
+    public Class load(String suiteClassName) throws ClassNotFoundException {
+        return Class.forName(suiteClassName);
+    }
+    /**
+     * Uses the system class loader to load the test class
+     */
+    public Class reload(Class aClass) throws ClassNotFoundException {
+        return aClass;
+    }
 }
diff --git a/test-runner/src/junit/runner/TestCaseClassLoader.java b/test-runner/src/junit/runner/TestCaseClassLoader.java
index 3a510c6..09eec7f 100644
--- a/test-runner/src/junit/runner/TestCaseClassLoader.java
+++ b/test-runner/src/junit/runner/TestCaseClassLoader.java
@@ -14,7 +14,7 @@
  * loader. They will be shared across test runs.
  * <p>
  * The list of excluded package paths is specified in
- * a properties file "excluded.properties" that is located in 
+ * a properties file "excluded.properties" that is located in
  * the same place as the TestCaseClassLoader class.
  * <p>
  * <b>Known limitation:</b> the TestCaseClassLoader cannot load classes
@@ -22,204 +22,204 @@
  * {@hide} - Not needed for 1.0 SDK
  */
 public class TestCaseClassLoader extends ClassLoader {
-	/** scanned class path */
-	private Vector fPathItems;
-	/** default excluded paths */
-	private String[] defaultExclusions= {
-		"junit.framework.", 
-		"junit.extensions.", 
-		"junit.runner."
-	};
-	/** name of excluded properties file */
-	static final String EXCLUDED_FILE= "excluded.properties";
-	/** excluded paths */
-	private Vector fExcluded;
-	 
-	/**
-	 * Constructs a TestCaseLoader. It scans the class path
-	 * and the excluded package paths
-	 */
-	public TestCaseClassLoader() {
-		this(System.getProperty("java.class.path"));
-	}
-	
-	/**
-	 * Constructs a TestCaseLoader. It scans the class path
-	 * and the excluded package paths
-	 */
-	public TestCaseClassLoader(String classPath) {
-		scanPath(classPath);
-		readExcludedPackages();
-	}
+    /** scanned class path */
+    private Vector fPathItems;
+    /** default excluded paths */
+    private String[] defaultExclusions= {
+            "junit.framework.",
+            "junit.extensions.",
+            "junit.runner."
+    };
+    /** name of excluded properties file */
+    static final String EXCLUDED_FILE= "excluded.properties";
+    /** excluded paths */
+    private Vector fExcluded;
 
-	private void scanPath(String classPath) {
-		String separator= System.getProperty("path.separator");
-		fPathItems= new Vector(10);
-		StringTokenizer st= new StringTokenizer(classPath, separator);
-		while (st.hasMoreTokens()) {
-			fPathItems.addElement(st.nextToken());
-		}
-	}
-	
-	public URL getResource(String name) {
-		return ClassLoader.getSystemResource(name);
-	}
-	
-	public InputStream getResourceAsStream(String name) {
-		return ClassLoader.getSystemResourceAsStream(name);
-	} 
-	
-	public boolean isExcluded(String name) {
-		for (int i= 0; i < fExcluded.size(); i++) {
-			if (name.startsWith((String) fExcluded.elementAt(i))) {
-				return true;
-			}
-		}
-		return false;	
-	}
-	
-	public synchronized Class loadClass(String name, boolean resolve)
-		throws ClassNotFoundException {
-			
-		Class c= findLoadedClass(name);
-		if (c != null)
-			return c;
-		//
-		// Delegate the loading of excluded classes to the
-		// standard class loader.
-		//
-		if (isExcluded(name)) {
-			try {
-				c= findSystemClass(name);
-				return c;
-			} catch (ClassNotFoundException e) {
-				// keep searching
-			}
-		}
-		if (c == null) {
-			byte[] data= lookupClassData(name);
-			if (data == null)
-				throw new ClassNotFoundException();
-			c= defineClass(name, data, 0, data.length);
-		}
-		if (resolve) 
-			resolveClass(c);
-		return c;
-	}
-	
-	private byte[] lookupClassData(String className) throws ClassNotFoundException {
-		byte[] data= null;
-		for (int i= 0; i < fPathItems.size(); i++) {
-			String path= (String) fPathItems.elementAt(i);
-			String fileName= className.replace('.', '/')+".class";
-			if (isJar(path)) {
-				data= loadJarData(path, fileName);
-			} else {
-				data= loadFileData(path, fileName);
-			}
-			if (data != null)
-				return data;
-		}
-		throw new ClassNotFoundException(className);
-	}
-		
-	boolean isJar(String pathEntry) {
-		return pathEntry.endsWith(".jar") ||
-		       pathEntry.endsWith(".apk") ||
-                       pathEntry.endsWith(".zip");
-	}
+    /**
+     * Constructs a TestCaseLoader. It scans the class path
+     * and the excluded package paths
+     */
+    public TestCaseClassLoader() {
+        this(System.getProperty("java.class.path"));
+    }
 
-	private byte[] loadFileData(String path, String fileName) {
-		File file= new File(path, fileName);
-		if (file.exists()) { 
-			return getClassData(file);
-		}
-		return null;
-	}
-	
-	private byte[] getClassData(File f) {
-		try {
-			FileInputStream stream= new FileInputStream(f);
-			ByteArrayOutputStream out= new ByteArrayOutputStream(1000);
-			byte[] b= new byte[1000];
-			int n;
-			while ((n= stream.read(b)) != -1) 
-				out.write(b, 0, n);
-			stream.close();
-			out.close();
-			return out.toByteArray();
+    /**
+     * Constructs a TestCaseLoader. It scans the class path
+     * and the excluded package paths
+     */
+    public TestCaseClassLoader(String classPath) {
+        scanPath(classPath);
+        readExcludedPackages();
+    }
 
-		} catch (IOException e) {
-		}
-		return null;
-	}
+    private void scanPath(String classPath) {
+        String separator= System.getProperty("path.separator");
+        fPathItems= new Vector(10);
+        StringTokenizer st= new StringTokenizer(classPath, separator);
+        while (st.hasMoreTokens()) {
+            fPathItems.addElement(st.nextToken());
+        }
+    }
 
-	private byte[] loadJarData(String path, String fileName) {
-		ZipFile zipFile= null;
-		InputStream stream= null;
-		File archive= new File(path);
-		if (!archive.exists())
-			return null;
-		try {
-			zipFile= new ZipFile(archive);
-		} catch(IOException io) {
-			return null;
-		}
-		ZipEntry entry= zipFile.getEntry(fileName);
-		if (entry == null)
-			return null;
-		int size= (int) entry.getSize();
-		try {
-			stream= zipFile.getInputStream(entry);
-			byte[] data= new byte[size];
-			int pos= 0;
-			while (pos < size) {
-				int n= stream.read(data, pos, data.length - pos);
-				pos += n;
-			}
-			zipFile.close();
-			return data;
-		} catch (IOException e) {
-		} finally {
-			try {
-				if (stream != null)
-					stream.close();
-			} catch (IOException e) {
-			}
-		}
-		return null;
-	}
-	
-	private void readExcludedPackages() {		
-		fExcluded= new Vector(10);
-		for (int i= 0; i < defaultExclusions.length; i++)
-			fExcluded.addElement(defaultExclusions[i]);
-			
-		InputStream is= getClass().getResourceAsStream(EXCLUDED_FILE);
-		if (is == null) 
-			return;
-		Properties p= new Properties();
-		try {
-			p.load(is);
-		}
-		catch (IOException e) {
-			return;
-		} finally {
-			try {
-				is.close();
-			} catch (IOException e) {
-			}
-		}
-		for (Enumeration e= p.propertyNames(); e.hasMoreElements(); ) {
-			String key= (String)e.nextElement();
-			if (key.startsWith("excluded.")) {
-				String path= p.getProperty(key);
-				path= path.trim();
-				if (path.endsWith("*"))
-					path= path.substring(0, path.length()-1);
-				if (path.length() > 0) 
-					fExcluded.addElement(path);				
-			}
-		}
-	}
+    public URL getResource(String name) {
+        return ClassLoader.getSystemResource(name);
+    }
+
+    public InputStream getResourceAsStream(String name) {
+        return ClassLoader.getSystemResourceAsStream(name);
+    }
+
+    public boolean isExcluded(String name) {
+        for (int i= 0; i < fExcluded.size(); i++) {
+            if (name.startsWith((String) fExcluded.elementAt(i))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public synchronized Class loadClass(String name, boolean resolve)
+            throws ClassNotFoundException {
+
+        Class c= findLoadedClass(name);
+        if (c != null)
+            return c;
+        //
+        // Delegate the loading of excluded classes to the
+        // standard class loader.
+        //
+        if (isExcluded(name)) {
+            try {
+                c= findSystemClass(name);
+                return c;
+            } catch (ClassNotFoundException e) {
+                // keep searching
+            }
+        }
+        if (c == null) {
+            byte[] data= lookupClassData(name);
+            if (data == null)
+                throw new ClassNotFoundException();
+            c= defineClass(name, data, 0, data.length);
+        }
+        if (resolve)
+            resolveClass(c);
+        return c;
+    }
+
+    private byte[] lookupClassData(String className) throws ClassNotFoundException {
+        byte[] data= null;
+        for (int i= 0; i < fPathItems.size(); i++) {
+            String path= (String) fPathItems.elementAt(i);
+            String fileName= className.replace('.', '/')+".class";
+            if (isJar(path)) {
+                data= loadJarData(path, fileName);
+            } else {
+                data= loadFileData(path, fileName);
+            }
+            if (data != null)
+                return data;
+        }
+        throw new ClassNotFoundException(className);
+    }
+
+    boolean isJar(String pathEntry) {
+        return pathEntry.endsWith(".jar") ||
+                pathEntry.endsWith(".apk") ||
+                pathEntry.endsWith(".zip");
+    }
+
+    private byte[] loadFileData(String path, String fileName) {
+        File file= new File(path, fileName);
+        if (file.exists()) {
+            return getClassData(file);
+        }
+        return null;
+    }
+
+    private byte[] getClassData(File f) {
+        try {
+            FileInputStream stream= new FileInputStream(f);
+            ByteArrayOutputStream out= new ByteArrayOutputStream(1000);
+            byte[] b= new byte[1000];
+            int n;
+            while ((n= stream.read(b)) != -1)
+                out.write(b, 0, n);
+            stream.close();
+            out.close();
+            return out.toByteArray();
+
+        } catch (IOException e) {
+        }
+        return null;
+    }
+
+    private byte[] loadJarData(String path, String fileName) {
+        ZipFile zipFile= null;
+        InputStream stream= null;
+        File archive= new File(path);
+        if (!archive.exists())
+            return null;
+        try {
+            zipFile= new ZipFile(archive);
+        } catch(IOException io) {
+            return null;
+        }
+        ZipEntry entry= zipFile.getEntry(fileName);
+        if (entry == null)
+            return null;
+        int size= (int) entry.getSize();
+        try {
+            stream= zipFile.getInputStream(entry);
+            byte[] data= new byte[size];
+            int pos= 0;
+            while (pos < size) {
+                int n= stream.read(data, pos, data.length - pos);
+                pos += n;
+            }
+            zipFile.close();
+            return data;
+        } catch (IOException e) {
+        } finally {
+            try {
+                if (stream != null)
+                    stream.close();
+            } catch (IOException e) {
+            }
+        }
+        return null;
+    }
+
+    private void readExcludedPackages() {
+        fExcluded= new Vector(10);
+        for (int i= 0; i < defaultExclusions.length; i++)
+            fExcluded.addElement(defaultExclusions[i]);
+
+        InputStream is= getClass().getResourceAsStream(EXCLUDED_FILE);
+        if (is == null)
+            return;
+        Properties p= new Properties();
+        try {
+            p.load(is);
+        }
+        catch (IOException e) {
+            return;
+        } finally {
+            try {
+                is.close();
+            } catch (IOException e) {
+            }
+        }
+        for (Enumeration e= p.propertyNames(); e.hasMoreElements(); ) {
+            String key= (String)e.nextElement();
+            if (key.startsWith("excluded.")) {
+                String path= p.getProperty(key);
+                path= path.trim();
+                if (path.endsWith("*"))
+                    path= path.substring(0, path.length()-1);
+                if (path.length() > 0)
+                    fExcluded.addElement(path);
+            }
+        }
+    }
 }
diff --git a/test-runner/src/junit/runner/TestCollector.java b/test-runner/src/junit/runner/TestCollector.java
index 208dccd..3ac9d9e 100644
--- a/test-runner/src/junit/runner/TestCollector.java
+++ b/test-runner/src/junit/runner/TestCollector.java
@@ -5,13 +5,13 @@
 
 /**
  * Collects Test class names to be presented
- * by the TestSelector. 
+ * by the TestSelector.
  * @see TestSelector
  * {@hide} - Not needed for 1.0 SDK
  */
 public interface TestCollector {
-	/**
-	 * Returns an enumeration of Strings with qualified class names
-	 */
-	public Enumeration collectTests();
+    /**
+     * Returns an enumeration of Strings with qualified class names
+     */
+    public Enumeration collectTests();
 }
diff --git a/test-runner/src/junit/runner/TestRunListener.java b/test-runner/src/junit/runner/TestRunListener.java
index 0e95819..0410f0c 100644
--- a/test-runner/src/junit/runner/TestRunListener.java
+++ b/test-runner/src/junit/runner/TestRunListener.java
@@ -6,15 +6,15 @@
  * making it suitable for remote test execution.
  * {@hide} - Not needed for 1.0 SDK
  */
- public interface TestRunListener {
-     /* test status constants*/
-     public static final int STATUS_ERROR= 1;
-     public static final int STATUS_FAILURE= 2;
+public interface TestRunListener {
+    /* test status constants*/
+    public static final int STATUS_ERROR= 1;
+    public static final int STATUS_FAILURE= 2;
 
-     public void testRunStarted(String testSuiteName, int testCount);
-     public void testRunEnded(long elapsedTime);
-     public void testRunStopped(long elapsedTime);
-     public void testStarted(String testName);
-     public void testEnded(String testName);
-     public void testFailed(int status, String testName, String trace);
+    public void testRunStarted(String testSuiteName, int testCount);
+    public void testRunEnded(long elapsedTime);
+    public void testRunStopped(long elapsedTime);
+    public void testStarted(String testName);
+    public void testEnded(String testName);
+    public void testFailed(int status, String testName, String trace);
 }
diff --git a/test-runner/src/junit/runner/TestSuiteLoader.java b/test-runner/src/junit/runner/TestSuiteLoader.java
index 39a4cf7..581ea23 100644
--- a/test-runner/src/junit/runner/TestSuiteLoader.java
+++ b/test-runner/src/junit/runner/TestSuiteLoader.java
@@ -4,6 +4,6 @@
  * An interface to define how a test suite should be loaded.
  */
 public interface TestSuiteLoader {
-	abstract public Class load(String suiteClassName) throws ClassNotFoundException;
-	abstract public Class reload(Class aClass) throws ClassNotFoundException;
+    abstract public Class load(String suiteClassName) throws ClassNotFoundException;
+    abstract public Class reload(Class aClass) throws ClassNotFoundException;
 }
diff --git a/test-runner/src/junit/runner/Version.java b/test-runner/src/junit/runner/Version.java
index b4541ab..4a6dc85 100644
--- a/test-runner/src/junit/runner/Version.java
+++ b/test-runner/src/junit/runner/Version.java
@@ -4,11 +4,17 @@
  * This class defines the current version of JUnit
  */
 public class Version {
-	private Version() {
-		// don't instantiate
-	}
+    private Version() {
+        // don't instantiate
+    }
 
-	public static String id() {
-		return "3.8.1";
-	}
+    public static String id() {
+        return "4.10";
+    }
+
+    // android-changed
+    /** @hide - not needed for public API */
+    public static void main(String[] args) {
+        System.out.println(id());
+    }
 }
diff --git a/test-runner/src/junit/textui/ResultPrinter.java b/test-runner/src/junit/textui/ResultPrinter.java
index 5c97112..4b26558 100644
--- a/test-runner/src/junit/textui/ResultPrinter.java
+++ b/test-runner/src/junit/textui/ResultPrinter.java
@@ -14,129 +14,129 @@
 import junit.runner.BaseTestRunner;
 
 public class ResultPrinter implements TestListener {
-	PrintStream fWriter;
-	int fColumn= 0;
-	
-	public ResultPrinter(PrintStream writer) {
-		fWriter= writer;
-	}
-	
-	/* API for use by textui.TestRunner
-	 */
+    PrintStream fWriter;
+    int fColumn= 0;
 
-	synchronized void print(TestResult result, long runTime) {
-		printHeader(runTime);
-	    printErrors(result);
-	    printFailures(result);
-	    printFooter(result);
-	}
+    public ResultPrinter(PrintStream writer) {
+        fWriter= writer;
+    }
 
-	void printWaitPrompt() {
-		getWriter().println();
-		getWriter().println("<RETURN> to continue");
-	}
-	
-	/* Internal methods 
-	 */
+    /* API for use by textui.TestRunner
+     */
 
-	protected void printHeader(long runTime) {
-		getWriter().println();
-		getWriter().println("Time: "+elapsedTimeAsString(runTime));
-	}
-	
-	protected void printErrors(TestResult result) {
-		printDefects(result.errors(), result.errorCount(), "error");
-	}
-	
-	protected void printFailures(TestResult result) {
-		printDefects(result.failures(), result.failureCount(), "failure");
-	}
-	
-	protected void printDefects(Enumeration booBoos, int count, String type) {
-		if (count == 0) return;
-		if (count == 1)
-			getWriter().println("There was " + count + " " + type + ":");
-		else
-			getWriter().println("There were " + count + " " + type + "s:");
-		for (int i= 1; booBoos.hasMoreElements(); i++) {
-			printDefect((TestFailure) booBoos.nextElement(), i);
-		}
-	}
-	
-	public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes
-		printDefectHeader(booBoo, count);
-		printDefectTrace(booBoo);
-	}
+    synchronized void print(TestResult result, long runTime) {
+        printHeader(runTime);
+        printErrors(result);
+        printFailures(result);
+        printFooter(result);
+    }
 
-	protected void printDefectHeader(TestFailure booBoo, int count) {
-		// I feel like making this a println, then adding a line giving the throwable a chance to print something
-		// before we get to the stack trace.
-		getWriter().print(count + ") " + booBoo.failedTest());
-	}
+    void printWaitPrompt() {
+        getWriter().println();
+        getWriter().println("<RETURN> to continue");
+    }
 
-	protected void printDefectTrace(TestFailure booBoo) {
-		getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace()));
-	}
+    /* Internal methods
+     */
 
-	protected void printFooter(TestResult result) {
-		if (result.wasSuccessful()) {
-			getWriter().println();
-			getWriter().print("OK");
-			getWriter().println (" (" + result.runCount() + " test" + (result.runCount() == 1 ? "": "s") + ")");
+    protected void printHeader(long runTime) {
+        getWriter().println();
+        getWriter().println("Time: "+elapsedTimeAsString(runTime));
+    }
 
-		} else {
-			getWriter().println();
-			getWriter().println("FAILURES!!!");
-			getWriter().println("Tests run: "+result.runCount()+ 
-				         ",  Failures: "+result.failureCount()+
-				         ",  Errors: "+result.errorCount());
-		}
-	    getWriter().println();
-	}
+    protected void printErrors(TestResult result) {
+        printDefects(result.errors(), result.errorCount(), "error");
+    }
+
+    protected void printFailures(TestResult result) {
+        printDefects(result.failures(), result.failureCount(), "failure");
+    }
+
+    protected void printDefects(Enumeration<TestFailure> booBoos, int count, String type) {
+        if (count == 0) return;
+        if (count == 1)
+            getWriter().println("There was " + count + " " + type + ":");
+        else
+            getWriter().println("There were " + count + " " + type + "s:");
+        for (int i= 1; booBoos.hasMoreElements(); i++) {
+            printDefect(booBoos.nextElement(), i);
+        }
+    }
+
+    public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes
+        printDefectHeader(booBoo, count);
+        printDefectTrace(booBoo);
+    }
+
+    protected void printDefectHeader(TestFailure booBoo, int count) {
+        // I feel like making this a println, then adding a line giving the throwable a chance to print something
+        // before we get to the stack trace.
+        getWriter().print(count + ") " + booBoo.failedTest());
+    }
+
+    protected void printDefectTrace(TestFailure booBoo) {
+        getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace()));
+    }
+
+    protected void printFooter(TestResult result) {
+        if (result.wasSuccessful()) {
+            getWriter().println();
+            getWriter().print("OK");
+            getWriter().println (" (" + result.runCount() + " test" + (result.runCount() == 1 ? "": "s") + ")");
+
+        } else {
+            getWriter().println();
+            getWriter().println("FAILURES!!!");
+            getWriter().println("Tests run: "+result.runCount()+
+                    ",  Failures: "+result.failureCount()+
+                    ",  Errors: "+result.errorCount());
+        }
+        getWriter().println();
+    }
 
 
-	/**
-	 * Returns the formatted string of the elapsed time.
-	 * Duplicated from BaseTestRunner. Fix it.
-	 */
-	protected String elapsedTimeAsString(long runTime) {
-            // The following line was altered for compatibility with
-            // Android libraries.
-	    return Double.toString((double)runTime/1000);
-	}
+    /**
+     * Returns the formatted string of the elapsed time.
+     * Duplicated from BaseTestRunner. Fix it.
+     */
+    protected String elapsedTimeAsString(long runTime) {
+        // The following line was altered for compatibility with
+        // Android libraries.
+        return Double.toString((double)runTime/1000);
+    }
 
-	public PrintStream getWriter() {
-		return fWriter;
-	}
-	/**
-	 * @see junit.framework.TestListener#addError(Test, Throwable)
-	 */
-	public void addError(Test test, Throwable t) {
-		getWriter().print("E");
-	}
+    public PrintStream getWriter() {
+        return fWriter;
+    }
+    /**
+     * @see junit.framework.TestListener#addError(Test, Throwable)
+     */
+    public void addError(Test test, Throwable t) {
+        getWriter().print("E");
+    }
 
-	/**
-	 * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
-	 */
-	public void addFailure(Test test, AssertionFailedError t) {
-		getWriter().print("F");
-	}
+    /**
+     * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
+     */
+    public void addFailure(Test test, AssertionFailedError t) {
+        getWriter().print("F");
+    }
 
-	/**
-	 * @see junit.framework.TestListener#endTest(Test)
-	 */
-	public void endTest(Test test) {
-	}
+    /**
+     * @see junit.framework.TestListener#endTest(Test)
+     */
+    public void endTest(Test test) {
+    }
 
-	/**
-	 * @see junit.framework.TestListener#startTest(Test)
-	 */
-	public void startTest(Test test) {
-		getWriter().print(".");
-		if (fColumn++ >= 40) {
-			getWriter().println();
-			fColumn= 0;
-		}
-	}
+    /**
+     * @see junit.framework.TestListener#startTest(Test)
+     */
+    public void startTest(Test test) {
+        getWriter().print(".");
+        if (fColumn++ >= 40) {
+            getWriter().println();
+            fColumn= 0;
+        }
+    }
 
 }
diff --git a/test-runner/src/junit/textui/TestRunner.java b/test-runner/src/junit/textui/TestRunner.java
index 8bdc325..e955e0e 100644
--- a/test-runner/src/junit/textui/TestRunner.java
+++ b/test-runner/src/junit/textui/TestRunner.java
@@ -3,187 +3,201 @@
 
 import java.io.PrintStream;
 
-import junit.framework.*;
-import junit.runner.*;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+import junit.runner.BaseTestRunner;
+import junit.runner.Version;
 
 /**
  * A command line based tool to run tests.
  * <pre>
  * java junit.textui.TestRunner [-wait] TestCaseClass
  * </pre>
- * TestRunner expects the name of a TestCase class as argument.
- * If this class defines a static <code>suite</code> method it 
- * will be invoked and the returned test is run. Otherwise all 
+ * 
+ * <p>TestRunner expects the name of a TestCase class as argument.
+ * If this class defines a static <code>suite</code> method it
+ * will be invoked and the returned test is run. Otherwise all
  * the methods starting with "test" having no arguments are run.
  * <p>
  * When the wait command line argument is given TestRunner
  * waits until the users types RETURN.
  * <p>
  * TestRunner prints a trace as the tests are executed followed by a
- * summary at the end. 
+ * summary at the end.
  */
 public class TestRunner extends BaseTestRunner {
-	private ResultPrinter fPrinter;
-	
-	public static final int SUCCESS_EXIT= 0;
-	public static final int FAILURE_EXIT= 1;
-	public static final int EXCEPTION_EXIT= 2;
+    private ResultPrinter fPrinter;
 
-	/**
-	 * Constructs a TestRunner.
-	 */
-	public TestRunner() {
-		this(System.out);
-	}
+    public static final int SUCCESS_EXIT= 0;
+    public static final int FAILURE_EXIT= 1;
+    public static final int EXCEPTION_EXIT= 2;
 
-	/**
-	 * Constructs a TestRunner using the given stream for all the output
-	 */
-	public TestRunner(PrintStream writer) {
-		this(new ResultPrinter(writer));
-	}
-	
-	/**
-	 * Constructs a TestRunner using the given ResultPrinter all the output
-	 */
-	public TestRunner(ResultPrinter printer) {
-		fPrinter= printer;
-	}
-	
-	/**
-	 * Runs a suite extracted from a TestCase subclass.
-	 */
-	static public void run(Class testClass) {
-		run(new TestSuite(testClass));
-	}
+    /**
+     * Constructs a TestRunner.
+     */
+    public TestRunner() {
+        this(System.out);
+    }
 
-	/**
-	 * Runs a single test and collects its results.
-	 * This method can be used to start a test run
-	 * from your program.
-	 * <pre>
-	 * public static void main (String[] args) {
-	 *     test.textui.TestRunner.run(suite());
-	 * }
-	 * </pre>
-	 */
-	static public TestResult run(Test test) {
-		TestRunner runner= new TestRunner();
-		return runner.doRun(test);
-	}
+    /**
+     * Constructs a TestRunner using the given stream for all the output
+     */
+    public TestRunner(PrintStream writer) {
+        this(new ResultPrinter(writer));
+    }
 
-	/**
-	 * Runs a single test and waits until the user
-	 * types RETURN.
-	 */
-	static public void runAndWait(Test suite) {
-		TestRunner aTestRunner= new TestRunner();
-		aTestRunner.doRun(suite, true);
-	}
+    /**
+     * Constructs a TestRunner using the given ResultPrinter all the output
+     */
+    public TestRunner(ResultPrinter printer) {
+        fPrinter= printer;
+    }
 
-	/**
-	 * Always use the StandardTestSuiteLoader. Overridden from
-	 * BaseTestRunner.
-	 */
-	public TestSuiteLoader getLoader() {
-		return new StandardTestSuiteLoader();
-	}
+    /**
+     * Runs a suite extracted from a TestCase subclass.
+     */
+    static public void run(Class<? extends TestCase> testClass) {
+        run(new TestSuite(testClass));
+    }
 
-	public void testFailed(int status, Test test, Throwable t) {
-	}
-	
-	public void testStarted(String testName) {
-	}
-	
-	public void testEnded(String testName) {
-	}
+    /**
+     * Runs a single test and collects its results.
+     * This method can be used to start a test run
+     * from your program.
+     * <pre>
+     * public static void main (String[] args) {
+     *    test.textui.TestRunner.run(suite());
+     * }
+     * </pre>
+     */
+    static public TestResult run(Test test) {
+        TestRunner runner= new TestRunner();
+        return runner.doRun(test);
+    }
 
-	/**
-	 * Creates the TestResult to be used for the test run.
-	 */
-	protected TestResult createTestResult() {
-		return new TestResult();
-	}
-	
-	public TestResult doRun(Test test) {
-		return doRun(test, false);
-	}
-	
-	public TestResult doRun(Test suite, boolean wait) {
-		TestResult result= createTestResult();
-		result.addListener(fPrinter);
-		long startTime= System.currentTimeMillis();
-		suite.run(result);
-		long endTime= System.currentTimeMillis();
-		long runTime= endTime-startTime;
-		fPrinter.print(result, runTime);
+    /**
+     * Runs a single test and waits until the user
+     * types RETURN.
+     */
+    static public void runAndWait(Test suite) {
+        TestRunner aTestRunner= new TestRunner();
+        aTestRunner.doRun(suite, true);
+    }
 
-		pause(wait);
-		return result;
-	}
+    @Override
+    public void testFailed(int status, Test test, Throwable t) {
+    }
 
-	protected void pause(boolean wait) {
-		if (!wait) return;
-		fPrinter.printWaitPrompt();
-		try {
-			System.in.read();
-		}
-		catch(Exception e) {
-		}
-	}
-	
-	public static void main(String args[]) {
-		TestRunner aTestRunner= new TestRunner();
-		try {
-			TestResult r= aTestRunner.start(args);
-			if (!r.wasSuccessful()) 
-				System.exit(FAILURE_EXIT);
-			System.exit(SUCCESS_EXIT);
-		} catch(Exception e) {
-			System.err.println(e.getMessage());
-			System.exit(EXCEPTION_EXIT);
-		}
-	}
+    @Override
+    public void testStarted(String testName) {
+    }
 
-	/**
-	 * Starts a test run. Analyzes the command line arguments
-	 * and runs the given test suite.
-	 */
-	protected TestResult start(String args[]) throws Exception {
-		String testCase= "";
-		boolean wait= false;
-		
-		for (int i= 0; i < args.length; i++) {
-			if (args[i].equals("-wait"))
-				wait= true;
-			else if (args[i].equals("-c")) 
-				testCase= extractClassName(args[++i]);
-			else if (args[i].equals("-v"))
-				System.err.println("JUnit "+Version.id()+" by Kent Beck and Erich Gamma");
-			else
-				testCase= args[i];
-		}
-		
-		if (testCase.equals("")) 
-			throw new Exception("Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class");
+    @Override
+    public void testEnded(String testName) {
+    }
 
-		try {
-			Test suite= getTest(testCase);
-			return doRun(suite, wait);
-		}
-		catch(Exception e) {
-			throw new Exception("Could not create and run test suite: "+e);
-		}
-	}
-		
-	protected void runFailed(String message) {
-		System.err.println(message);
-		System.exit(FAILURE_EXIT);
-	}
-	
-	public void setPrinter(ResultPrinter printer) {
-		fPrinter= printer;
-	}
-		
-	
+    /**
+     * Creates the TestResult to be used for the test run.
+     */
+    protected TestResult createTestResult() {
+        return new TestResult();
+    }
+
+    public TestResult doRun(Test test) {
+        return doRun(test, false);
+    }
+
+    public TestResult doRun(Test suite, boolean wait) {
+        TestResult result= createTestResult();
+        result.addListener(fPrinter);
+        long startTime= System.currentTimeMillis();
+        suite.run(result);
+        long endTime= System.currentTimeMillis();
+        long runTime= endTime-startTime;
+        fPrinter.print(result, runTime);
+
+        pause(wait);
+        return result;
+    }
+
+    protected void pause(boolean wait) {
+        if (!wait) return;
+        fPrinter.printWaitPrompt();
+        try {
+            System.in.read();
+        }
+        catch(Exception e) {
+        }
+    }
+
+    public static void main(String args[]) {
+        TestRunner aTestRunner= new TestRunner();
+        try {
+            TestResult r= aTestRunner.start(args);
+            if (!r.wasSuccessful())
+                System.exit(FAILURE_EXIT);
+            System.exit(SUCCESS_EXIT);
+        } catch(Exception e) {
+            System.err.println(e.getMessage());
+            System.exit(EXCEPTION_EXIT);
+        }
+    }
+
+    /**
+     * Starts a test run. Analyzes the command line arguments
+     * and runs the given test suite.
+     */
+    public TestResult start(String args[]) throws Exception {
+        String testCase= "";
+        String method= "";
+        boolean wait= false;
+
+        for (int i= 0; i < args.length; i++) {
+            if (args[i].equals("-wait"))
+                wait= true;
+            else if (args[i].equals("-c"))
+                testCase= extractClassName(args[++i]);
+            else if (args[i].equals("-m")) {
+                String arg= args[++i];
+                int lastIndex= arg.lastIndexOf('.');
+                testCase= arg.substring(0, lastIndex);
+                method= arg.substring(lastIndex + 1);
+            } else if (args[i].equals("-v"))
+                System.err.println("JUnit " + Version.id() + " by Kent Beck and Erich Gamma");
+            else
+                testCase= args[i];
+        }
+
+        if (testCase.equals(""))
+            throw new Exception("Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class");
+
+        try {
+            if (!method.equals(""))
+                return runSingleMethod(testCase, method, wait);
+            Test suite= getTest(testCase);
+            return doRun(suite, wait);
+        } catch (Exception e) {
+            throw new Exception("Could not create and run test suite: " + e);
+        }
+    }
+
+    protected TestResult runSingleMethod(String testCase, String method, boolean wait) throws Exception {
+        Class<? extends TestCase> testClass= loadSuiteClass(testCase).asSubclass(TestCase.class);
+        Test test= TestSuite.createTest(testClass, method);
+        return doRun(test, wait);
+    }
+
+    @Override
+    protected void runFailed(String message) {
+        System.err.println(message);
+        System.exit(FAILURE_EXIT);
+    }
+
+    public void setPrinter(ResultPrinter printer) {
+        fPrinter= printer;
+    }
+
+
 }