Coverage Report - org.apache.maven.plugin.testing.AbstractMojoTestCase
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractMojoTestCase
53%
57/107
50%
15/30
2,095
 
 1  
 package org.apache.maven.plugin.testing;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.BufferedReader;
 23  
 import java.io.File;
 24  
 import java.io.FileInputStream;
 25  
 import java.io.InputStream;
 26  
 import java.io.Reader;
 27  
 import java.lang.reflect.AccessibleObject;
 28  
 import java.lang.reflect.Field;
 29  
 import java.util.HashMap;
 30  
 import java.util.Map;
 31  
 
 32  
 import org.apache.maven.monitor.logging.DefaultLog;
 33  
 import org.apache.maven.plugin.Mojo;
 34  
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 35  
 import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
 36  
 import org.apache.maven.plugin.logging.Log;
 37  
 import org.codehaus.plexus.ContainerConfiguration;
 38  
 import org.codehaus.plexus.DefaultContainerConfiguration;
 39  
 import org.codehaus.plexus.DefaultPlexusContainer;
 40  
 import org.codehaus.plexus.PlexusContainer;
 41  
 import org.codehaus.plexus.PlexusContainerException;
 42  
 import org.codehaus.plexus.PlexusTestCase;
 43  
 import org.codehaus.plexus.classworlds.ClassWorld;
 44  
 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
 45  
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
 46  
 import org.codehaus.plexus.component.repository.ComponentDescriptor;
 47  
 import org.codehaus.plexus.configuration.PlexusConfiguration;
 48  
 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
 49  
 import org.codehaus.plexus.logging.LoggerManager;
 50  
 import org.codehaus.plexus.util.InterpolationFilterReader;
 51  
 import org.codehaus.plexus.util.ReaderFactory;
 52  
 import org.codehaus.plexus.util.ReflectionUtils;
 53  
 import org.codehaus.plexus.util.xml.XmlStreamReader;
 54  
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 55  
 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
 56  
 
 57  
 /**
 58  
  * TODO: add a way to use the plugin POM for the lookup so that the user doesn't have to provide the a:g:v:goal
 59  
  * as the role hint for the mojo lookup.
 60  
  * TODO: standardize the execution of the mojo and looking at the results, but could simply have a template method
 61  
  * for verifying the state of the mojo post execution
 62  
  * TODO: need a way to look at the state of the mojo without adding getters, this could be where we finally specify
 63  
  * the expressions which extract values from the mojo.
 64  
  * TODO: create a standard directory structure for picking up POMs to make this even easier, we really just need a testing
 65  
  * descriptor and make this entirely declarative!
 66  
  *
 67  
  * @author jesse
 68  
  * @version $Id: AbstractMojoTestCase.java 805786 2009-08-19 13:04:24Z bentmann $
 69  
  */
 70  6
 public abstract class AbstractMojoTestCase
 71  
     extends PlexusTestCase
 72  
 {
 73  
     private ComponentConfigurator configurator;
 74  
 
 75  
     private PlexusContainer container;
 76  
     
 77  
     /*
 78  
      * for the harness I think we have decided against going the route of using the maven project builder.
 79  
      * instead I think we are going to try and make an instance of the localrespository and assign that
 80  
      * to either the project stub or into the mojo directly with injection...not sure yet though.
 81  
      */
 82  
     //private MavenProjectBuilder projectBuilder;
 83  
 
 84  
     protected void setUp()
 85  
         throws Exception
 86  
     {
 87  6
         configurator = getContainer().lookup( ComponentConfigurator.class, "basic" );
 88  
 
 89  6
         InputStream is = getClass().getResourceAsStream( "/" + getPluginDescriptorLocation() );
 90  
 
 91  6
         XmlStreamReader reader = ReaderFactory.newXmlReader( is );
 92  
 
 93  6
         InterpolationFilterReader interpolationFilterReader =
 94  
             new InterpolationFilterReader( new BufferedReader( reader ), container.getContext().getContextData() );
 95  
 
 96  6
         PluginDescriptor pluginDescriptor = new PluginDescriptorBuilder().build( interpolationFilterReader );
 97  
 
 98  6
         for ( ComponentDescriptor<?> desc : pluginDescriptor.getComponents() )
 99  
         {
 100  24
             getContainer().addComponentDescriptor( desc );
 101  
         }
 102  6
     }
 103  
 
 104  
     protected InputStream getPublicDescriptorStream()
 105  
         throws Exception
 106  
     {
 107  0
         return new FileInputStream( new File( getPluginDescriptorPath() ) );
 108  
     }
 109  
 
 110  
     protected String getPluginDescriptorPath()
 111  
     {
 112  0
         return getBasedir() + "/target/classes/META-INF/maven/plugin.xml";
 113  
     }
 114  
 
 115  
     protected String getPluginDescriptorLocation()
 116  
     {
 117  6
         return "META-INF/maven/plugin.xml";
 118  
     }
 119  
 
 120  
     protected void setupContainer()
 121  
     {
 122  6
         ClassWorld classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
 123  
 
 124  6
         ContainerConfiguration cc =
 125  
             new DefaultContainerConfiguration().setClassWorld( classWorld ).setName( "embedder" );
 126  
         try
 127  
         {
 128  6
             container = new DefaultPlexusContainer( cc );
 129  
         }
 130  0
         catch ( PlexusContainerException e )
 131  
         {
 132  0
             e.printStackTrace();
 133  0
             fail( "Failed to create plexus container." );
 134  6
         }   
 135  6
     }
 136  
     
 137  
     protected PlexusContainer getContainer()
 138  
     {
 139  40
         if ( container == null )
 140  
         {
 141  6
             setupContainer();
 142  
         }
 143  
 
 144  40
         return container;
 145  
     }    
 146  
     
 147  
     /**
 148  
      * Lookup the mojo leveraging the subproject pom
 149  
      *
 150  
      * @param goal
 151  
      * @param pluginPom
 152  
      * @return a Mojo instance
 153  
      * @throws Exception
 154  
      */
 155  
     protected Mojo lookupMojo( String goal, String pluginPom )
 156  
         throws Exception
 157  
     {
 158  0
         return lookupMojo( goal, new File( pluginPom ) );
 159  
     }
 160  
 
 161  
     /**
 162  
      * Lookup an empty mojo
 163  
      *
 164  
      * @param goal
 165  
      * @param pluginPom
 166  
      * @return a Mojo instance
 167  
      * @throws Exception
 168  
      */
 169  
     protected Mojo lookupEmptyMojo( String goal, String pluginPom )
 170  
         throws Exception
 171  
     {
 172  0
         return lookupEmptyMojo( goal, new File( pluginPom ) );
 173  
     }
 174  
 
 175  
     /**
 176  
      * Lookup the mojo leveraging the actual subprojects pom
 177  
      *
 178  
      * @param goal
 179  
      * @param pom
 180  
      * @return a Mojo instance
 181  
      * @throws Exception
 182  
      */
 183  
     protected Mojo lookupMojo( String goal, File pom )
 184  
         throws Exception
 185  
     {
 186  0
         File pluginPom = new File( getBasedir(), "pom.xml" );
 187  
 
 188  0
         Xpp3Dom pluginPomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( pluginPom ) );
 189  
 
 190  0
         String artifactId = pluginPomDom.getChild( "artifactId" ).getValue();
 191  
 
 192  0
         String groupId = resolveFromRootThenParent( pluginPomDom, "groupId" );
 193  
 
 194  0
         String version = resolveFromRootThenParent( pluginPomDom, "version" );
 195  
 
 196  0
         PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
 197  
 
 198  0
         return lookupMojo( groupId, artifactId, version, goal, pluginConfiguration );
 199  
     }
 200  
 
 201  
     /**
 202  
      * Lookup the mojo leveraging the actual subprojects pom
 203  
      *
 204  
      * @param goal
 205  
      * @param pom
 206  
      * @return a Mojo instance
 207  
      * @throws Exception
 208  
      */
 209  
     protected Mojo lookupEmptyMojo( String goal, File pom )
 210  
         throws Exception
 211  
     {
 212  0
         File pluginPom = new File( getBasedir(), "pom.xml" );
 213  
 
 214  0
         Xpp3Dom pluginPomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( pluginPom ) );
 215  
 
 216  0
         String artifactId = pluginPomDom.getChild( "artifactId" ).getValue();
 217  
 
 218  0
         String groupId = resolveFromRootThenParent( pluginPomDom, "groupId" );
 219  
 
 220  0
         String version = resolveFromRootThenParent( pluginPomDom, "version" );
 221  
 
 222  0
         return lookupMojo( groupId, artifactId, version, goal, null );
 223  
     }
 224  
 
 225  
     /*
 226  
      protected Mojo lookupMojo( String groupId, String artifactId, String version, String goal, File pom )
 227  
      throws Exception
 228  
      {
 229  
      PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
 230  
 
 231  
      return lookupMojo( groupId, artifactId, version, goal, pluginConfiguration );
 232  
      }
 233  
      */
 234  
     /**
 235  
      * lookup the mojo while we have all of the relavent information
 236  
      *
 237  
      * @param groupId
 238  
      * @param artifactId
 239  
      * @param version
 240  
      * @param goal
 241  
      * @param pluginConfiguration
 242  
      * @return a Mojo instance
 243  
      * @throws Exception
 244  
      */
 245  
     protected Mojo lookupMojo( String groupId, String artifactId, String version, String goal,
 246  
                                PlexusConfiguration pluginConfiguration )
 247  
         throws Exception
 248  
     {
 249  0
         validateContainerStatus();
 250  
 
 251  
         // pluginkey = groupId : artifactId : version : goal
 252  
 
 253  0
         Mojo mojo = (Mojo) lookup( Mojo.ROLE, groupId + ":" + artifactId + ":" + version + ":" + goal );
 254  
 
 255  0
         LoggerManager loggerManager = (LoggerManager) getContainer().lookup( LoggerManager.class );
 256  
         
 257  0
         Log mojoLogger = new DefaultLog( loggerManager.getLoggerForComponent( Mojo.ROLE ) );
 258  
 
 259  0
         mojo.setLog( mojoLogger );
 260  
 
 261  0
         if ( pluginConfiguration != null )
 262  
         {
 263  
             /* requires v10 of plexus container for lookup on expression evaluator
 264  
              ExpressionEvaluator evaluator = (ExpressionEvaluator) getContainer().lookup( ExpressionEvaluator.ROLE,
 265  
                                                                                          "stub-evaluator" );
 266  
              */
 267  0
             ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
 268  
 
 269  0
             configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
 270  
         }
 271  
 
 272  0
         return mojo;
 273  
     }
 274  
 
 275  
     /**
 276  
      * @param artifactId
 277  
      * @param pom
 278  
      * @return the plexus configuration
 279  
      * @throws Exception
 280  
      */
 281  
     protected PlexusConfiguration extractPluginConfiguration( String artifactId, File pom )
 282  
         throws Exception
 283  
     {
 284  0
         Reader reader = ReaderFactory.newXmlReader( pom );
 285  
 
 286  0
         Xpp3Dom pomDom = Xpp3DomBuilder.build( reader );
 287  
 
 288  0
         return extractPluginConfiguration( artifactId, pomDom );
 289  
     }
 290  
 
 291  
     /**
 292  
      * @param artifactId
 293  
      * @param pomDom
 294  
      * @return the plexus configuration
 295  
      * @throws Exception
 296  
      */
 297  
     protected PlexusConfiguration extractPluginConfiguration( String artifactId, Xpp3Dom pomDom )
 298  
         throws Exception
 299  
     {
 300  6
         Xpp3Dom pluginConfigurationElement = null;
 301  
 
 302  6
         Xpp3Dom buildElement = pomDom.getChild( "build" );
 303  6
         if ( buildElement != null )
 304  
         {
 305  6
             Xpp3Dom pluginsRootElement = buildElement.getChild( "plugins" );
 306  
 
 307  6
             if ( pluginsRootElement != null )
 308  
             {
 309  6
                 Xpp3Dom[] pluginElements = pluginsRootElement.getChildren();
 310  
 
 311  6
                 for ( int i = 0; i < pluginElements.length; i++ )
 312  
                 {
 313  6
                     Xpp3Dom pluginElement = pluginElements[i];
 314  
 
 315  6
                     String pluginElementArtifactId = pluginElement.getChild( "artifactId" ).getValue();
 316  
 
 317  6
                     if ( pluginElementArtifactId.equals( artifactId ) )
 318  
                     {
 319  6
                         pluginConfigurationElement = pluginElement.getChild( "configuration" );
 320  
 
 321  6
                         break;
 322  
                     }
 323  
                 }
 324  
 
 325  6
                 if ( pluginConfigurationElement == null )
 326  
                 {
 327  0
                     throw new ConfigurationException( "Cannot find a configuration element for a plugin with an "
 328  
                         + "artifactId of " + artifactId + "." );
 329  
                 }
 330  
             }
 331  
         }
 332  
 
 333  6
         if ( pluginConfigurationElement == null )
 334  
         {
 335  0
             throw new ConfigurationException( "Cannot find a configuration element for a plugin with an artifactId of "
 336  
                 + artifactId + "." );
 337  
         }
 338  
 
 339  6
         return new XmlPlexusConfiguration( pluginConfigurationElement );
 340  
     }
 341  
 
 342  
     /**
 343  
      * Configure the mojo
 344  
      *
 345  
      * @param mojo
 346  
      * @param artifactId
 347  
      * @param pom
 348  
      * @return a Mojo instance
 349  
      * @throws Exception
 350  
      */
 351  
     protected Mojo configureMojo( Mojo mojo, String artifactId, File pom )
 352  
         throws Exception
 353  
     {
 354  0
         validateContainerStatus();
 355  
 
 356  0
         PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
 357  
 
 358  0
         ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
 359  
 
 360  0
         configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
 361  
 
 362  0
         return mojo;
 363  
     }
 364  
 
 365  
     /**
 366  
      * Configure the mojo with the given plexus configuration
 367  
      *
 368  
      * @param mojo
 369  
      * @param pluginConfiguration
 370  
      * @return a Mojo instance
 371  
      * @throws Exception
 372  
      */
 373  
     protected Mojo configureMojo( Mojo mojo, PlexusConfiguration pluginConfiguration )
 374  
         throws Exception
 375  
     {
 376  5
         validateContainerStatus();
 377  
 
 378  5
         ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
 379  
 
 380  5
         configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
 381  
 
 382  5
         return mojo;
 383  
     }
 384  
 
 385  
     /**
 386  
      * Convenience method to obtain the value of a variable on a mojo that might not have a getter.
 387  
      *
 388  
      * NOTE: the caller is responsible for casting to to what the desired type is.
 389  
      *
 390  
      * @param object
 391  
      * @param variable
 392  
      * @return object value of variable
 393  
      * @throws IllegalArgumentException
 394  
      */
 395  
     protected Object getVariableValueFromObject( Object object, String variable )
 396  
         throws IllegalAccessException
 397  
     {
 398  3
         Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() );
 399  
 
 400  3
         field.setAccessible( true );
 401  
 
 402  3
         return field.get( object );
 403  
     }
 404  
 
 405  
     /**
 406  
      * Convenience method to obtain all variables and values from the mojo (including its superclasses)
 407  
      *
 408  
      * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
 409  
      *
 410  
      * @param object
 411  
      * @return map of variable names and values
 412  
      */
 413  
     protected Map getVariablesAndValuesFromObject( Object object )
 414  
         throws IllegalAccessException
 415  
     {
 416  1
         return getVariablesAndValuesFromObject( object.getClass(), object );
 417  
     }
 418  
 
 419  
     /**
 420  
      * Convenience method to obtain all variables and values from the mojo (including its superclasses)
 421  
      *
 422  
      * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
 423  
      *
 424  
      * @param clazz
 425  
      * @param object
 426  
      * @return map of variable names and values
 427  
      */
 428  
     protected Map getVariablesAndValuesFromObject( Class clazz, Object object )
 429  
         throws IllegalAccessException
 430  
     {
 431  2
         Map map = new HashMap();
 432  
 
 433  2
         Field[] fields = clazz.getDeclaredFields();
 434  
 
 435  2
         AccessibleObject.setAccessible( fields, true );
 436  
 
 437  6
         for ( int i = 0; i < fields.length; ++i )
 438  
         {
 439  4
             Field field = fields[i];
 440  
 
 441  4
             map.put( field.getName(), field.get( object ) );
 442  
 
 443  
         }
 444  
 
 445  2
         Class superclass = clazz.getSuperclass();
 446  
 
 447  2
         if ( !Object.class.equals( superclass ) )
 448  
         {
 449  1
             map.putAll( getVariablesAndValuesFromObject( superclass, object ) );
 450  
         }
 451  
 
 452  2
         return map;
 453  
     }
 454  
 
 455  
     /**
 456  
      * Convenience method to set values to variables in objects that don't have setters
 457  
      *
 458  
      * @param object
 459  
      * @param variable
 460  
      * @param value
 461  
      * @throws IllegalAccessException
 462  
      */
 463  
     protected void setVariableValueToObject( Object object, String variable, Object value )
 464  
         throws IllegalAccessException
 465  
     {
 466  1
         Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() );
 467  
 
 468  1
         field.setAccessible( true );
 469  
 
 470  1
         field.set( object, value );
 471  1
     }
 472  
 
 473  
     /**
 474  
      * sometimes the parent element might contain the correct value so generalize that access
 475  
      *
 476  
      * TODO find out where this is probably done elsewhere
 477  
      *
 478  
      * @param pluginPomDom
 479  
      * @param element
 480  
      * @return
 481  
      * @throws Exception
 482  
      */
 483  
     private String resolveFromRootThenParent( Xpp3Dom pluginPomDom, String element )
 484  
         throws Exception
 485  
     {
 486  0
         Xpp3Dom elementDom = pluginPomDom.getChild( element );
 487  
 
 488  
         // parent might have the group Id so resolve it
 489  0
         if ( elementDom == null )
 490  
         {
 491  0
             Xpp3Dom pluginParentDom = pluginPomDom.getChild( "parent" );
 492  
 
 493  0
             if ( pluginParentDom != null )
 494  
             {
 495  0
                 elementDom = pluginParentDom.getChild( element );
 496  
 
 497  0
                 if ( elementDom == null )
 498  
                 {
 499  0
                     throw new Exception( "unable to determine " + element );
 500  
                 }
 501  
 
 502  0
                 return elementDom.getValue();
 503  
             }
 504  
 
 505  0
             throw new Exception( "unable to determine " + element );
 506  
         }
 507  
 
 508  0
         return elementDom.getValue();
 509  
     }
 510  
 
 511  
     /**
 512  
      * We should make sure this is called in each method that makes use of the container,
 513  
      * otherwise we throw ugly NPE's
 514  
      *
 515  
      * crops up when the subclassing code defines the setUp method but doesn't call super.setUp()
 516  
      *
 517  
      * @throws Exception
 518  
      */
 519  
     private void validateContainerStatus()
 520  
         throws Exception
 521  
     {
 522  5
         if ( getContainer() != null )
 523  
         {
 524  5
             return;
 525  
         }
 526  
 
 527  0
         throw new Exception( "container is null, make sure super.setUp() is called" );
 528  
     }
 529  
 }