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