Save This Page
Home » cactus-1.8.0-src » org.apache.cactus.integration.maven » [javadoc | source]
    1   /* 
    2    * ========================================================================
    3    * 
    4    * Licensed to the Apache Software Foundation (ASF) under one or more
    5    * contributor license agreements.  See the NOTICE file distributed with
    6    * this work for additional information regarding copyright ownership.
    7    * The ASF licenses this file to You under the Apache License, Version 2.0
    8    * (the "License"); you may not use this file except in compliance with
    9    * the License.  You may obtain a copy of the License at
   10    * 
   11    *   http://www.apache.org/licenses/LICENSE-2.0
   12    * 
   13    * Unless required by applicable law or agreed to in writing, software
   14    * distributed under the License is distributed on an "AS IS" BASIS,
   15    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   16    * See the License for the specific language governing permissions and
   17    * limitations under the License.
   18    * 
   19    * ========================================================================
   20    */
   21   package org.apache.cactus.integration.maven;
   22   
   23   import org.apache.tools.ant.DirectoryScanner;
   24   import org.apache.tools.ant.Project;
   25   import org.apache.tools.ant.types.FileSet;
   26   import org.apache.tools.ant.types.Path;
   27   import org.apache.commons.logging.Log;
   28   import org.apache.commons.logging.LogFactory;
   29   
   30   import java.util.List;
   31   import java.util.ArrayList;
   32   import java.util.Iterator;
   33   import java.io.File;
   34   import java.net.MalformedURLException;
   35   import java.net.URLClassLoader;
   36   import java.net.URL;
   37   import java.lang.reflect.Modifier;
   38   import java.lang.reflect.Method;
   39   
   40   import junit.framework.TestCase;
   41   
   42   /**
   43    * Process {@link FileSet} and extracts classes that are Cactus tests. As
   44    * a Cactus test can be a simple JUnit test case wrapped in a Cactus suite,
   45    * it is very difficult to find out only Cactus tests. Thus, in this version,
   46    * we are only finding JUnit tests.
   47    *
   48    * A class is considered to be a JUnit Test Case if:
   49    * <ul>
   50    *   <li>It extends {@link TestCase}</li>
   51    *   <li>It is not abstract</li>
   52    *   <li>It has at least one method that starts with "test", returns void and
   53    *   takes no parameters</li>
   54    * </ul>
   55    *
   56    * @version $Id: CactusScanner.java 238815 2004-02-29 16:34:44Z vmassol $
   57    */
   58   public class CactusScanner
   59   {
   60       /**
   61        * Log instance.
   62        */
   63       private Log log = LogFactory.getLog(CactusScanner.class);
   64   
   65       /**
   66        * The Ant project.
   67        */
   68       private Project project;
   69   
   70       /**
   71        * Lists of Cactus class names that were found in the {@link FileSet}.
   72        */
   73       private List cactusTests = new ArrayList();
   74   
   75       /**
   76        * @param theProject the Ant project that is currently executing
   77        */
   78       public void setProject(Project theProject)
   79       {
   80           this.project = theProject;
   81       }
   82   
   83       /**
   84        * Remove all Cactus class names that were found in the {@link Fileset}.
   85        */
   86       public void clear()
   87       {
   88           this.cactusTests.clear();
   89       }
   90   
   91       /**
   92        * @return the list of valid Cactus test cases
   93        */
   94       public Iterator iterator()
   95       {
   96           return this.cactusTests.iterator();
   97       }
   98   
   99       /**
  100        * Finds the Cactus test cases from a list of files.
  101        *
  102        * @param theFileset the list of files in which to look for Cactus tests
  103        * @param theClasspath the classpaths needed to load the test classes
  104        */
  105       public void processFileSet(FileSet theFileset, Path theClasspath)
  106       {
  107           DirectoryScanner ds = theFileset.getDirectoryScanner(this.project);
  108           ds.scan();
  109           String[] files = ds.getIncludedFiles();
  110   
  111           for (int i = 0; i < files.length; i++)
  112           {
  113               // The path is supposed to be a relative path that matches the
  114               // package directory structure. Thus we only need to replace
  115               // the directory separator char by a "." and remove the file
  116               // extension to get the FQN java class name.
  117   
  118               // Is it a java class file?
  119               if (files[i].endsWith(".class"))
  120               {
  121                   String fqn = files[i]
  122                       .substring(0, files[i].length() - ".class".length())
  123                       .replace(File.separatorChar, '.');
  124   
  125                   log.debug("Found candidate class: [" + fqn + "]");
  126   
  127                   // Is it a Cactus test case?
  128                   if (isJUnitTestCase(fqn, theClasspath))
  129                   {
  130                       log.debug("Found Cactus test case: [" + fqn + "]");
  131                       this.cactusTests.add(fqn);
  132                   }
  133               }
  134           }
  135       }
  136   
  137       /**
  138        * @param theClassName the fully qualified name of the class to check
  139        * @param theClasspath the classpaths needed to load the test classes
  140        * @return true if the class is a JUnit test case
  141        */
  142       private boolean isJUnitTestCase(String theClassName, Path theClasspath)
  143       {
  144           Class clazz = loadClass(theClassName, theClasspath);
  145           if (clazz == null)
  146           {
  147               return false;
  148           }
  149   
  150           Class testCaseClass = null;
  151           try
  152           {
  153               testCaseClass = clazz.getClassLoader().loadClass(
  154                   TestCase.class.getName());
  155           }
  156           catch (ClassNotFoundException e)
  157           {
  158               log.debug("Cannot load class", e);
  159               return false;
  160           }
  161   
  162           if (!testCaseClass.isAssignableFrom(clazz))
  163           {
  164               log.debug("Not a JUnit test as class [" + theClassName + "] does "
  165                   + "not inherit from [" + TestCase.class.getName()
  166                   + "]");
  167               return false;
  168           }
  169   
  170           // the class must not be abstract
  171           if (Modifier.isAbstract(clazz.getModifiers()))
  172           {
  173               log.debug("Not a JUnit test as class [" + theClassName + "] is "
  174                   + "abstract");
  175               return false;
  176           }
  177   
  178           // the class must have at least one test, i.e. a public method
  179           // starting with "test" and that takes no parameters
  180           boolean hasTestMethod = false;
  181           Method[] methods = clazz.getMethods();
  182           for (int i = 0; i < methods.length; i++)
  183           {
  184               if (methods[i].getName().startsWith("test")
  185                   && (methods[i].getReturnType() == Void.TYPE)
  186                   && (methods[i].getParameterTypes().length == 0))
  187               {
  188                   hasTestMethod = true;
  189                   break;
  190               }
  191           }
  192   
  193           if (!hasTestMethod)
  194           {
  195               log.debug("Not a JUnit test as class [" + theClassName + "] has "
  196                   + "no method that start with \"test\", returns void and has "
  197                   + "no parameters");
  198               return false;
  199           }
  200   
  201           return true;
  202       }
  203   
  204       /**
  205        * @param theClassName the fully qualified name of the class to check
  206        * @param theClasspath the classpaths needed to load the test classes
  207        * @return the class object loaded by reflection from its string name
  208        */
  209       private Class loadClass(String theClassName, Path theClasspath)
  210       {
  211           Class clazz = null;
  212           try
  213           {
  214               clazz = createClassLoader(theClasspath).loadClass(theClassName);
  215           }
  216           catch (ClassNotFoundException e)
  217           {
  218               log.error("Failed to load class [" + theClassName + "]", e);
  219           }
  220           return clazz;
  221       }
  222   
  223       /**
  224        * @param theClasspath the classpaths needed to load the test classes
  225        * @return a ClassLoader that has all the needed classpaths for loading
  226        *         the Cactus tests classes
  227        */
  228       private ClassLoader createClassLoader(Path theClasspath)
  229       {
  230           URL[] urls = new URL[theClasspath.size()];
  231   
  232           try
  233           {
  234               for (int i = 0; i < theClasspath.size(); i++)
  235               {
  236                   log.debug("Adding ["
  237                       + new File(theClasspath.list()[i]).toURL() + "] "
  238                       + "to class loader classpath");
  239                   urls[i] = new File(theClasspath.list()[i]).toURL();
  240               }
  241           }
  242           catch (MalformedURLException e)
  243           {
  244               log.debug("Invalid URL", e);
  245           }
  246   
  247           return new URLClassLoader(urls);
  248       }
  249   }

Save This Page
Home » cactus-1.8.0-src » org.apache.cactus.integration.maven » [javadoc | source]