Home | History | Annotate | Download | only in runner
      1 package junit.runner;
      2 
      3 import java.io.BufferedReader;
      4 import java.io.File;
      5 import java.io.FileInputStream;
      6 import java.io.FileOutputStream;
      7 import java.io.IOException;
      8 import java.io.InputStream;
      9 import java.io.PrintWriter;
     10 import java.io.StringReader;
     11 import java.io.StringWriter;
     12 import java.lang.reflect.InvocationTargetException;
     13 import java.lang.reflect.Method;
     14 import java.lang.reflect.Modifier;
     15 import java.text.NumberFormat;
     16 import java.util.Properties;
     17 
     18 import junit.framework.AssertionFailedError;
     19 import junit.framework.Test;
     20 import junit.framework.TestListener;
     21 import 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  */
     27 public 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      */
    210     public TestSuiteLoader getLoader() {
    211         if (useReloadingTestSuiteLoader())
    212             return new ReloadingTestSuiteLoader();
    213         return new StandardTestSuiteLoader();
    214     }
    215     // END android-changed
    216 
    217     /**
    218      * Returns the loaded Class for a suite name.
    219      */
    220     protected Class<?> loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
    221         return Class.forName(suiteClassName);
    222     }
    223 
    224     /**
    225      * Clears the status message.
    226      */
    227     protected void clearStatus() { // Belongs in the GUI TestRunner class
    228     }
    229 
    230     protected boolean useReloadingTestSuiteLoader() {
    231         return getPreference("loading").equals("true") && fLoading;
    232     }
    233 
    234     private static File getPreferencesFile() {
    235         String home= System.getProperty("user.home");
    236         return new File(home, "junit.properties");
    237     }
    238 
    239     private static void readPreferences() {
    240         InputStream is= null;
    241         try {
    242             is= new FileInputStream(getPreferencesFile());
    243             setPreferences(new Properties(getPreferences()));
    244             getPreferences().load(is);
    245         } catch (IOException e) {
    246             try {
    247                 if (is != null)
    248                     is.close();
    249             } catch (IOException e1) {
    250             }
    251         }
    252     }
    253 
    254     public static String getPreference(String key) {
    255         return getPreferences().getProperty(key);
    256     }
    257 
    258     public static int getPreference(String key, int dflt) {
    259         String value= getPreference(key);
    260         int intValue= dflt;
    261         if (value == null)
    262             return intValue;
    263         try {
    264             intValue= Integer.parseInt(value);
    265         } catch (NumberFormatException ne) {
    266         }
    267         return intValue;
    268     }
    269 
    270     /**
    271      * Returns a filtered stack trace
    272      */
    273     public static String getFilteredTrace(Throwable t) {
    274         StringWriter stringWriter= new StringWriter();
    275         PrintWriter writer= new PrintWriter(stringWriter);
    276         t.printStackTrace(writer);
    277         StringBuffer buffer= stringWriter.getBuffer();
    278         String trace= buffer.toString();
    279         return BaseTestRunner.getFilteredTrace(trace);
    280     }
    281 
    282     // BEGIN android-changed - add back this method for API compatibility
    283     /** @deprecated not present in JUnit4.10 */
    284     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 }
    343