[maven-plugin-testing-1.3] 02/10: New upstream version 2.0

Emmanuel Bourg ebourg-guest at moszumanska.debian.org
Thu Jul 20 10:29:08 UTC 2017


This is an automated email from the git hooks/post-receive script.

ebourg-guest pushed a commit to annotated tag debian/2.1-1
in repository maven-plugin-testing-1.3.

commit d5f99f2b72a596ce7fc615887d4e8733538d2f8c
Author: Emmanuel Bourg <ebourg at apache.org>
Date:   Mon Jul 17 23:54:10 2017 +0200

    New upstream version 2.0
---
 .gitignore                                         |    9 +
 maven-plugin-testing-harness/pom.xml               |   93 ++
 .../maven/plugin/testing/AbstractMojoTestCase.java |  665 +++++++++
 .../maven/plugin/testing/ArtifactStubFactory.java  |  587 ++++++++
 .../plugin/testing/ConfigurationException.java     |   58 +
 .../testing/ResolverExpressionEvaluatorStub.java   |  140 ++
 .../org/apache/maven/plugin/testing/SilentLog.java |  334 +++++
 .../maven/plugin/testing/stubs/ArtifactStub.java   |  510 +++++++
 .../testing/stubs/DefaultArtifactHandlerStub.java  |  202 +++
 .../plugin/testing/stubs/MavenProjectStub.java     | 1541 ++++++++++++++++++++
 .../testing/stubs/StubArtifactCollector.java       |   91 ++
 .../testing/stubs/StubArtifactRepository.java      |  250 ++++
 .../plugin/testing/stubs/StubArtifactResolver.java |  205 +++
 .../main/resources/META-INF/plexus/components.xml  |   39 +
 .../src/site/apt/examples/artifact.apt             |  218 +++
 .../site/apt/examples/complex-mojo-parameters.apt  |  186 +++
 .../src/site/apt/examples/multiproject.apt         |  123 ++
 .../src/site/apt/examples/repositories.apt         |  138 ++
 .../src/site/apt/getting-started/index.apt         |  186 +++
 .../src/site/apt/index.apt                         |   46 +
 maven-plugin-testing-harness/src/site/fml/faq.fml  |   72 +
 maven-plugin-testing-harness/src/site/site.xml     |   41 +
 .../plugin/testing/ArtifactStubFactoryTest.java    |   43 +
 .../plugin/testing/ExpressionEvaluatorMojo.java    |   64 +
 .../plugin/testing/ExpressionEvaluatorTest.java    |   87 ++
 .../maven/plugin/testing/MojoTestCaseTest.java     |  142 ++
 .../apache/maven/plugin/testing/SimpleMojo.java    |   50 +
 .../apache/maven/plugin/testing/TestSilentLog.java |   81 +
 maven-plugin-testing-tools/pom.xml                 |  109 ++
 .../apache/maven/shared/test/plugin/BuildTool.java |  268 ++++
 .../shared/test/plugin/ComponentTestTool.java      |  195 +++
 .../maven/shared/test/plugin/PluginTestTool.java   |  197 +++
 .../maven/shared/test/plugin/ProjectTool.java      |  497 +++++++
 .../maven/shared/test/plugin/RepositoryTool.java   |  353 +++++
 .../shared/test/plugin/TestToolsException.java     |   48 +
 maven-plugin-testing-tools/src/site/apt/index.apt  |  125 ++
 maven-plugin-testing-tools/src/site/site.xml       |   33 +
 .../maven/shared/test/plugin/ProjectToolTest.java  |  115 ++
 .../shared/test/plugin/RepositoryToolTest.java     |   87 ++
 .../src/test/resources/projects/basic/pom.xml      |   39 +
 .../projects/basic/src/main/java/ItMojo.java       |   14 +
 maven-test-tools/pom.xml                           |   55 +
 .../maven/shared/tools/easymock/MockManager.java   |   79 +
 .../shared/tools/easymock/TestFileManager.java     |  303 ++++
 .../maven/shared/tools/easymock/TestUtils.java     |  103 ++
 .../maven/shared/tools/test/ReflectiveSetter.java  |  175 +++
 maven-test-tools/src/site/apt/index.apt            |   32 +
 maven-test-tools/src/site/site.xml                 |   33 +
 pom.xml                                            |  266 ++++
 src/site/apt/index.apt                             |   44 +
 src/site/site.xml                                  |   36 +
 51 files changed, 9407 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..73fe292
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+target
+#eclipse
+.classpath
+.project
+.settings
+#idea
+*.iml
+.idea
+
diff --git a/maven-plugin-testing-harness/pom.xml b/maven-plugin-testing-harness/pom.xml
new file mode 100644
index 0000000..d8ae5d7
--- /dev/null
+++ b/maven-plugin-testing-harness/pom.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.plugin-testing</groupId>
+    <artifactId>maven-plugin-testing</artifactId>
+    <version>2.0</version>
+  </parent>
+
+  <artifactId>maven-plugin-testing-harness</artifactId>
+  <name>Maven Plugin Testing Mechanism</name>
+  <description>The Maven Plugin Testing Harness provides mechanisms to manage tests on Mojo.</description>
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/maven/plugin-testing/tags/maven-plugin-testing-2.0/maven-plugin-testing-harness</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/plugin-testing/tags/maven-plugin-testing-2.0/maven-plugin-testing-harness</developerConnection>
+    <url>http://svn.apache.org/viewvc/maven/plugin-testing/tags/maven-plugin-testing-2.0/maven-plugin-testing-harness</url>
+  </scm>
+
+  <dependencies>
+    <!-- maven -->
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-compat</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-model</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-aether-provider</artifactId>
+    </dependency>
+
+    <!-- plexus -->
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-archiver</artifactId>
+      <version>1.0-alpha-7</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-source-plugin</artifactId>
+        <configuration>
+          <attach>true</attach>
+        </configuration>
+        <executions>
+          <execution>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/AbstractMojoTestCase.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/AbstractMojoTestCase.java
new file mode 100644
index 0000000..ddafcb2
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/AbstractMojoTestCase.java
@@ -0,0 +1,665 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.execution.DefaultMavenExecutionRequest;
+import org.apache.maven.execution.DefaultMavenExecutionResult;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.internal.MojoDescriptorCreator;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.monitor.logging.DefaultLog;
+import org.apache.maven.plugin.Mojo;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.Parameter;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.repository.RepositorySystem;
+import org.apache.maven.repository.internal.MavenRepositorySystemSession;
+import org.codehaus.plexus.ContainerConfiguration;
+import org.codehaus.plexus.DefaultContainerConfiguration;
+import org.codehaus.plexus.DefaultPlexusContainer;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.PlexusContainerException;
+import org.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.classworlds.ClassWorld;
+import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
+import org.codehaus.plexus.component.configurator.ComponentConfigurator;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+import org.codehaus.plexus.component.repository.ComponentDescriptor;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
+import org.codehaus.plexus.logging.LoggerManager;
+import org.codehaus.plexus.util.InterpolationFilterReader;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.ReflectionUtils;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.xml.XmlStreamReader;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
+
+/**
+ * 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
+ * as the role hint for the mojo lookup.
+ * TODO: standardize the execution of the mojo and looking at the results, but could simply have a template method
+ * for verifying the state of the mojo post execution
+ * TODO: need a way to look at the state of the mojo without adding getters, this could be where we finally specify
+ * the expressions which extract values from the mojo.
+ * TODO: create a standard directory structure for picking up POMs to make this even easier, we really just need a testing
+ * descriptor and make this entirely declarative!
+ *
+ * @author jesse
+ * @version $Id: AbstractMojoTestCase.java 1340746 2012-05-20 14:52:12Z hboutemy $
+ */
+public abstract class AbstractMojoTestCase
+    extends PlexusTestCase
+{
+    private ComponentConfigurator configurator;
+
+    private PlexusContainer container;
+
+    private Map<String, MojoDescriptor> mojoDescriptors;
+    
+    /*
+     * for the harness I think we have decided against going the route of using the maven project builder.
+     * instead I think we are going to try and make an instance of the localrespository and assign that
+     * to either the project stub or into the mojo directly with injection...not sure yet though.
+     */
+    //private MavenProjectBuilder projectBuilder;
+
+    protected void setUp()
+        throws Exception
+    {
+        configurator = getContainer().lookup( ComponentConfigurator.class, "basic" );
+
+        InputStream is = getClass().getResourceAsStream( "/" + getPluginDescriptorLocation() );
+
+        XmlStreamReader reader = ReaderFactory.newXmlReader( is );
+
+        InterpolationFilterReader interpolationFilterReader =
+            new InterpolationFilterReader( new BufferedReader( reader ), container.getContext().getContextData() );
+
+        PluginDescriptor pluginDescriptor = new PluginDescriptorBuilder().build( interpolationFilterReader );
+
+        Artifact artifact =
+            lookup( RepositorySystem.class ).createArtifact( pluginDescriptor.getGroupId(),
+                                                             pluginDescriptor.getArtifactId(),
+                                                             pluginDescriptor.getVersion(), ".jar" );
+        artifact.setFile( new File( getBasedir() ).getCanonicalFile() );
+        pluginDescriptor.setPluginArtifact( artifact );
+        pluginDescriptor.setArtifacts( Arrays.asList( artifact ) );
+
+        for ( ComponentDescriptor<?> desc : pluginDescriptor.getComponents() )
+        {
+            getContainer().addComponentDescriptor( desc );
+        }
+
+        mojoDescriptors = new HashMap<String, MojoDescriptor>();
+        for ( MojoDescriptor mojoDescriptor : pluginDescriptor.getMojos() )
+        {
+            mojoDescriptors.put( mojoDescriptor.getGoal(), mojoDescriptor );
+        }
+    }
+
+    protected InputStream getPublicDescriptorStream()
+        throws Exception
+    {
+        return new FileInputStream( new File( getPluginDescriptorPath() ) );
+    }
+
+    protected String getPluginDescriptorPath()
+    {
+        return getBasedir() + "/target/classes/META-INF/maven/plugin.xml";
+    }
+
+    protected String getPluginDescriptorLocation()
+    {
+        return "META-INF/maven/plugin.xml";
+    }
+
+    protected void setupContainer()
+    {
+        ContainerConfiguration cc = setupContainerConfiguration();
+        try
+        {
+            container = new DefaultPlexusContainer( cc );
+        }
+        catch ( PlexusContainerException e )
+        {
+            e.printStackTrace();
+            fail( "Failed to create plexus container." );
+        }   
+    }
+
+    protected ContainerConfiguration setupContainerConfiguration()
+    {
+        ClassWorld classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
+
+        return new DefaultContainerConfiguration().setClassWorld( classWorld ).setName( "embedder" );
+    }
+    
+    protected PlexusContainer getContainer()
+    {
+        if ( container == null )
+        {
+            setupContainer();
+        }
+
+        return container;
+    }    
+    
+    /**
+     * Lookup the mojo leveraging the subproject pom
+     *
+     * @param goal
+     * @param pluginPom
+     * @return a Mojo instance
+     * @throws Exception
+     */
+    protected Mojo lookupMojo( String goal, String pluginPom )
+        throws Exception
+    {
+        return lookupMojo( goal, new File( pluginPom ) );
+    }
+
+    /**
+     * Lookup an empty mojo
+     *
+     * @param goal
+     * @param pluginPom
+     * @return a Mojo instance
+     * @throws Exception
+     */
+    protected Mojo lookupEmptyMojo( String goal, String pluginPom )
+        throws Exception
+    {
+        return lookupEmptyMojo( goal, new File( pluginPom ) );
+    }
+
+    /**
+     * Lookup the mojo leveraging the actual subprojects pom
+     *
+     * @param goal
+     * @param pom
+     * @return a Mojo instance
+     * @throws Exception
+     */
+    protected Mojo lookupMojo( String goal, File pom )
+        throws Exception
+    {
+        File pluginPom = new File( getBasedir(), "pom.xml" );
+
+        Xpp3Dom pluginPomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( pluginPom ) );
+
+        String artifactId = pluginPomDom.getChild( "artifactId" ).getValue();
+
+        String groupId = resolveFromRootThenParent( pluginPomDom, "groupId" );
+
+        String version = resolveFromRootThenParent( pluginPomDom, "version" );
+
+        PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
+
+        return lookupMojo( groupId, artifactId, version, goal, pluginConfiguration );
+    }
+
+    /**
+     * Lookup the mojo leveraging the actual subprojects pom
+     *
+     * @param goal
+     * @param pom
+     * @return a Mojo instance
+     * @throws Exception
+     */
+    protected Mojo lookupEmptyMojo( String goal, File pom )
+        throws Exception
+    {
+        File pluginPom = new File( getBasedir(), "pom.xml" );
+
+        Xpp3Dom pluginPomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( pluginPom ) );
+
+        String artifactId = pluginPomDom.getChild( "artifactId" ).getValue();
+
+        String groupId = resolveFromRootThenParent( pluginPomDom, "groupId" );
+
+        String version = resolveFromRootThenParent( pluginPomDom, "version" );
+
+        return lookupMojo( groupId, artifactId, version, goal, null );
+    }
+
+    /*
+     protected Mojo lookupMojo( String groupId, String artifactId, String version, String goal, File pom )
+     throws Exception
+     {
+     PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
+
+     return lookupMojo( groupId, artifactId, version, goal, pluginConfiguration );
+     }
+     */
+    /**
+     * lookup the mojo while we have all of the relavent information
+     *
+     * @param groupId
+     * @param artifactId
+     * @param version
+     * @param goal
+     * @param pluginConfiguration
+     * @return a Mojo instance
+     * @throws Exception
+     */
+    protected Mojo lookupMojo( String groupId, String artifactId, String version, String goal,
+                               PlexusConfiguration pluginConfiguration )
+        throws Exception
+    {
+        validateContainerStatus();
+
+        // pluginkey = groupId : artifactId : version : goal
+
+        Mojo mojo = (Mojo) lookup( Mojo.ROLE, groupId + ":" + artifactId + ":" + version + ":" + goal );
+
+        LoggerManager loggerManager = (LoggerManager) getContainer().lookup( LoggerManager.class );
+        
+        Log mojoLogger = new DefaultLog( loggerManager.getLoggerForComponent( Mojo.ROLE ) );
+
+        mojo.setLog( mojoLogger );
+
+        if ( pluginConfiguration != null )
+        {
+            /* requires v10 of plexus container for lookup on expression evaluator
+             ExpressionEvaluator evaluator = (ExpressionEvaluator) getContainer().lookup( ExpressionEvaluator.ROLE,
+                                                                                         "stub-evaluator" );
+             */
+            ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
+
+            configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
+        }
+
+        return mojo;
+    }
+
+    protected Mojo lookupConfiguredMojo( MavenProject project, String goal )
+        throws Exception
+    {
+        return lookupConfiguredMojo( newMavenSession( project ), newMojoExecution( goal ) );
+    }
+
+    protected Mojo lookupConfiguredMojo( MavenSession session, MojoExecution execution )
+        throws Exception, ComponentConfigurationException
+    {
+        MavenProject project = session.getCurrentProject();
+        MojoDescriptor mojoDescriptor = execution.getMojoDescriptor();
+
+        Mojo mojo = (Mojo) lookup( mojoDescriptor.getRole(), mojoDescriptor.getRoleHint() );
+
+        ExpressionEvaluator evaluator = new PluginParameterExpressionEvaluator( session, execution );
+
+        Xpp3Dom configuration = null;
+        Plugin plugin = project.getPlugin( mojoDescriptor.getPluginDescriptor().getPluginLookupKey() );
+        if ( plugin != null )
+        {
+            configuration = (Xpp3Dom) plugin.getConfiguration();
+        }
+        if ( configuration == null )
+        {
+            configuration = new Xpp3Dom( "configuration" );
+        }
+        configuration = Xpp3Dom.mergeXpp3Dom( execution.getConfiguration(), configuration );
+
+        PlexusConfiguration pluginConfiguration = new XmlPlexusConfiguration( configuration );
+
+        configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
+
+        return mojo;
+    }
+
+    protected MavenSession newMavenSession( MavenProject project )
+    {
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        MavenExecutionResult result = new DefaultMavenExecutionResult();
+
+        MavenSession session = new MavenSession( container, new MavenRepositorySystemSession(), request, result );
+        session.setCurrentProject( project );
+        session.setProjects( Arrays.asList( project ) );
+        return session;
+    }
+
+    protected MojoExecution newMojoExecution( String goal )
+    {
+        MojoDescriptor mojoDescriptor = mojoDescriptors.get( goal );
+        assertNotNull( mojoDescriptor );
+        MojoExecution execution = new MojoExecution( mojoDescriptor );
+        finalizeMojoConfiguration( execution );
+        return execution;
+    }
+
+    // copy&paste from org.apache.maven.lifecycle.internal.DefaultLifecycleExecutionPlanCalculator.finalizeMojoConfiguration(MojoExecution)
+    private void finalizeMojoConfiguration( MojoExecution mojoExecution )
+    {
+        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+
+        Xpp3Dom executionConfiguration = mojoExecution.getConfiguration();
+        if ( executionConfiguration == null )
+        {
+            executionConfiguration = new Xpp3Dom( "configuration" );
+        }
+
+        Xpp3Dom defaultConfiguration = MojoDescriptorCreator.convert( mojoDescriptor );;
+
+        Xpp3Dom finalConfiguration = new Xpp3Dom( "configuration" );
+
+        if ( mojoDescriptor.getParameters() != null )
+        {
+            for ( Parameter parameter : mojoDescriptor.getParameters() )
+            {
+                Xpp3Dom parameterConfiguration = executionConfiguration.getChild( parameter.getName() );
+
+                if ( parameterConfiguration == null )
+                {
+                    parameterConfiguration = executionConfiguration.getChild( parameter.getAlias() );
+                }
+
+                Xpp3Dom parameterDefaults = defaultConfiguration.getChild( parameter.getName() );
+
+                parameterConfiguration = Xpp3Dom.mergeXpp3Dom( parameterConfiguration, parameterDefaults, Boolean.TRUE );
+
+                if ( parameterConfiguration != null )
+                {
+                    parameterConfiguration = new Xpp3Dom( parameterConfiguration, parameter.getName() );
+
+                    if ( StringUtils.isEmpty( parameterConfiguration.getAttribute( "implementation" ) )
+                        && StringUtils.isNotEmpty( parameter.getImplementation() ) )
+                    {
+                        parameterConfiguration.setAttribute( "implementation", parameter.getImplementation() );
+                    }
+
+                    finalConfiguration.addChild( parameterConfiguration );
+                }
+            }
+        }
+
+        mojoExecution.setConfiguration( finalConfiguration );
+    }
+
+    /**
+     * @param artifactId
+     * @param pom
+     * @return the plexus configuration
+     * @throws Exception
+     */
+    protected PlexusConfiguration extractPluginConfiguration( String artifactId, File pom )
+        throws Exception
+    {
+        Reader reader = ReaderFactory.newXmlReader( pom );
+
+        Xpp3Dom pomDom = Xpp3DomBuilder.build( reader );
+
+        return extractPluginConfiguration( artifactId, pomDom );
+    }
+
+    /**
+     * @param artifactId
+     * @param pomDom
+     * @return the plexus configuration
+     * @throws Exception
+     */
+    protected PlexusConfiguration extractPluginConfiguration( String artifactId, Xpp3Dom pomDom )
+        throws Exception
+    {
+        Xpp3Dom pluginConfigurationElement = null;
+
+        Xpp3Dom buildElement = pomDom.getChild( "build" );
+        if ( buildElement != null )
+        {
+            Xpp3Dom pluginsRootElement = buildElement.getChild( "plugins" );
+
+            if ( pluginsRootElement != null )
+            {
+                Xpp3Dom[] pluginElements = pluginsRootElement.getChildren();
+
+                for ( Xpp3Dom pluginElement : pluginElements )
+                {
+                    String pluginElementArtifactId = pluginElement.getChild( "artifactId" ).getValue();
+
+                    if ( pluginElementArtifactId.equals( artifactId ) )
+                    {
+                        pluginConfigurationElement = pluginElement.getChild( "configuration" );
+
+                        break;
+                    }
+                }
+
+                if ( pluginConfigurationElement == null )
+                {
+                    throw new ConfigurationException( "Cannot find a configuration element for a plugin with an "
+                        + "artifactId of " + artifactId + "." );
+                }
+            }
+        }
+
+        if ( pluginConfigurationElement == null )
+        {
+            throw new ConfigurationException( "Cannot find a configuration element for a plugin with an artifactId of "
+                + artifactId + "." );
+        }
+
+        return new XmlPlexusConfiguration( pluginConfigurationElement );
+    }
+
+    /**
+     * Configure the mojo
+     *
+     * @param mojo
+     * @param artifactId
+     * @param pom
+     * @return a Mojo instance
+     * @throws Exception
+     */
+    protected Mojo configureMojo( Mojo mojo, String artifactId, File pom )
+        throws Exception
+    {
+        validateContainerStatus();
+
+        PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom );
+
+        ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
+
+        configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
+
+        return mojo;
+    }
+
+    /**
+     * Configure the mojo with the given plexus configuration
+     *
+     * @param mojo
+     * @param pluginConfiguration
+     * @return a Mojo instance
+     * @throws Exception
+     */
+    protected Mojo configureMojo( Mojo mojo, PlexusConfiguration pluginConfiguration )
+        throws Exception
+    {
+        validateContainerStatus();
+
+        ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub();
+
+        configurator.configureComponent( mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm() );
+
+        return mojo;
+    }
+
+    /**
+     * Convenience method to obtain the value of a variable on a mojo that might not have a getter.
+     *
+     * NOTE: the caller is responsible for casting to to what the desired type is.
+     *
+     * @param object
+     * @param variable
+     * @return object value of variable
+     * @throws IllegalArgumentException
+     */
+    protected Object getVariableValueFromObject( Object object, String variable )
+        throws IllegalAccessException
+    {
+        Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() );
+
+        field.setAccessible( true );
+
+        return field.get( object );
+    }
+
+    /**
+     * Convenience method to obtain all variables and values from the mojo (including its superclasses)
+     *
+     * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
+     *
+     * @param object
+     * @return map of variable names and values
+     */
+    protected Map<String, Object> getVariablesAndValuesFromObject( Object object )
+        throws IllegalAccessException
+    {
+        return getVariablesAndValuesFromObject( object.getClass(), object );
+    }
+
+    /**
+     * Convenience method to obtain all variables and values from the mojo (including its superclasses)
+     *
+     * Note: the values in the map are of type Object so the caller is responsible for casting to desired types.
+     *
+     * @param clazz
+     * @param object
+     * @return map of variable names and values
+     */
+    protected Map<String, Object> getVariablesAndValuesFromObject( Class<?> clazz, Object object )
+        throws IllegalAccessException
+    {
+        Map<String, Object> map = new HashMap<String, Object>();
+
+        Field[] fields = clazz.getDeclaredFields();
+
+        AccessibleObject.setAccessible( fields, true );
+
+        for ( Field field : fields )
+        {
+            map.put( field.getName(), field.get( object ) );
+        }
+
+        Class<?> superclass = clazz.getSuperclass();
+
+        if ( !Object.class.equals( superclass ) )
+        {
+            map.putAll( getVariablesAndValuesFromObject( superclass, object ) );
+        }
+
+        return map;
+    }
+
+    /**
+     * Convenience method to set values to variables in objects that don't have setters
+     *
+     * @param object
+     * @param variable
+     * @param value
+     * @throws IllegalAccessException
+     */
+    protected void setVariableValueToObject( Object object, String variable, Object value )
+        throws IllegalAccessException
+    {
+        Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() );
+
+        field.setAccessible( true );
+
+        field.set( object, value );
+    }
+
+    /**
+     * sometimes the parent element might contain the correct value so generalize that access
+     *
+     * TODO find out where this is probably done elsewhere
+     *
+     * @param pluginPomDom
+     * @param element
+     * @return
+     * @throws Exception
+     */
+    private String resolveFromRootThenParent( Xpp3Dom pluginPomDom, String element )
+        throws Exception
+    {
+        Xpp3Dom elementDom = pluginPomDom.getChild( element );
+
+        // parent might have the group Id so resolve it
+        if ( elementDom == null )
+        {
+            Xpp3Dom pluginParentDom = pluginPomDom.getChild( "parent" );
+
+            if ( pluginParentDom != null )
+            {
+                elementDom = pluginParentDom.getChild( element );
+
+                if ( elementDom == null )
+                {
+                    throw new Exception( "unable to determine " + element );
+                }
+
+                return elementDom.getValue();
+            }
+
+            throw new Exception( "unable to determine " + element );
+        }
+
+        return elementDom.getValue();
+    }
+
+    /**
+     * We should make sure this is called in each method that makes use of the container,
+     * otherwise we throw ugly NPE's
+     *
+     * crops up when the subclassing code defines the setUp method but doesn't call super.setUp()
+     *
+     * @throws Exception
+     */
+    private void validateContainerStatus()
+        throws Exception
+    {
+        if ( getContainer() != null )
+        {
+            return;
+        }
+
+        throw new Exception( "container is null, make sure super.setUp() is called" );
+    }
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/ArtifactStubFactory.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/ArtifactStubFactory.java
new file mode 100644
index 0000000..d870846
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/ArtifactStubFactory.java
@@ -0,0 +1,587 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.plugin.testing.stubs.DefaultArtifactHandlerStub;
+import org.codehaus.plexus.archiver.Archiver;
+import org.codehaus.plexus.archiver.ArchiverException;
+import org.codehaus.plexus.archiver.manager.ArchiverManager;
+import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
+import org.codehaus.plexus.archiver.war.WarArchiver;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.ReflectionUtils;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * This class creates artifacts to be used for testing purposes. It can optionally create actual files on the local disk
+ * for things like copying. It can create these files as archives with named files inside to be used for testing things
+ * like unpack. Also provided are some utility methods to quickly get a set of artifacts distinguished by various things
+ * like group,artifact,type,scope, etc It was originally developed for the dependency plugin, but can be useful in other
+ * plugins that need to simulate artifacts for unit tests.
+ *
+ * @author <a href="mailto:brianf at apache.org">Brian Fox</a>
+ * @version $Id: ArtifactStubFactory.java 1340745 2012-05-20 14:48:44Z hboutemy $
+ */
+public class ArtifactStubFactory
+{
+    private File workingDir;
+
+    private boolean createFiles;
+
+    private File srcFile;
+
+    private boolean createUnpackableFile;
+
+    private ArchiverManager archiverManager;
+
+    /**
+     * Default constructor. This should be used only if real files aren't needed...just the artifact objects
+     */
+    public ArtifactStubFactory()
+    {
+        this.workingDir = null;
+        this.createFiles = false;
+    }
+
+    /**
+     * This constructor is to be used if files are needed and to set a working dir
+     *
+     * @param workingDir
+     * @param createFiles
+     */
+    public ArtifactStubFactory( File workingDir, boolean createFiles )
+    {
+        this.workingDir = new File( workingDir, "localTestRepo" );
+        this.createFiles = createFiles;
+    }
+
+    /**
+     * If set, the file will be created as a zip/jar/war with a file inside that can be checked to exist after
+     * unpacking.
+     *
+     * @param archiverManager
+     */
+    public void setUnpackableFile( ArchiverManager archiverManager )
+    {
+        this.createUnpackableFile = true;
+        this.archiverManager = archiverManager;
+    }
+
+    /**
+     * @param groupId
+     * @param artifactId
+     * @param version
+     * @return a <code>DefaultArtifact</code> instance for the given parameters
+     * @throws IOException if any
+     * @see #createArtifact(String, String, String, String, String, String)
+     */
+    public Artifact createArtifact( String groupId, String artifactId, String version )
+        throws IOException
+    {
+        return createArtifact( groupId, artifactId, version, Artifact.SCOPE_COMPILE, "jar", "" );
+    }
+
+    /**
+     * @param groupId
+     * @param artifactId
+     * @param version
+     * @param scope
+     * @return a <code>DefaultArtifact</code> instance for the given parameters
+     * @throws IOException if any
+     * @see #createArtifact(String, String, String, String, String, String)
+     */
+    public Artifact createArtifact( String groupId, String artifactId, String version, String scope )
+        throws IOException
+    {
+        return createArtifact( groupId, artifactId, version, scope, "jar", "" );
+    }
+
+    /**
+     * @param groupId
+     * @param artifactId
+     * @param version
+     * @param scope
+     * @param type
+     * @param classifier
+     * @return a <code>DefaultArtifact</code> instance for the given parameters
+     * @throws IOException if any
+     * @see #createArtifact(String, String, VersionRange, String, String, String, boolean)
+     */
+    public Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type,
+                                    String classifier )
+        throws IOException
+    {
+        VersionRange vr = VersionRange.createFromVersion( version );
+        return createArtifact( groupId, artifactId, vr, scope, type, classifier, false );
+    }
+
+    /**
+     * @param groupId not null
+     * @param artifactId not null
+     * @param versionRange not null
+     * @param scope not null
+     * @param type not null
+     * @param classifier
+     * @param optional not null
+     * @return a <code>DefaultArtifact</code> instance
+     * @throws IOException if any
+     */
+    public Artifact createArtifact( String groupId, String artifactId, VersionRange versionRange, String scope,
+                                    String type, String classifier, boolean optional )
+        throws IOException
+    {
+        ArtifactHandler ah = new DefaultArtifactHandlerStub( type, classifier );
+
+        Artifact artifact =
+            new DefaultArtifact( groupId, artifactId, versionRange, scope, type, classifier, ah, optional );
+
+        // i have no idea why this needs to be done manually when isSnapshot is able to figure it out.
+        artifact.setRelease( !artifact.isSnapshot() );
+
+        if ( createFiles )
+        {
+            setArtifactFile( artifact, this.workingDir, this.srcFile, this.createUnpackableFile );
+        }
+        return artifact;
+    }
+
+    /**
+     * Creates a new empty file and attaches it to the artifact.
+     *
+     * @param artifact to attach the file to.
+     * @param workingDir where to locate the new file
+     * @throws IOException
+     */
+    public void setArtifactFile( Artifact artifact, File workingDir )
+        throws IOException
+    {
+        setArtifactFile( artifact, workingDir, null, false );
+    }
+
+    /**
+     * Copyies the srcFile to the workingDir and then attaches it to the artifact. If srcFile is null, a new empty file
+     * will be created.
+     *
+     * @param artifact to attach
+     * @param workingDir where to copy the srcFile.
+     * @param srcFile file to be attached.
+     * @throws IOException
+     */
+    public void setArtifactFile( Artifact artifact, File workingDir, File srcFile )
+        throws IOException
+    {
+        setArtifactFile( artifact, workingDir, srcFile, false );
+    }
+
+    /**
+     * Creates an unpackable file (zip,jar etc) containing an empty file.
+     *
+     * @param artifact to attach
+     * @param workingDir where to create the file.
+     * @throws IOException
+     */
+    public void setUnpackableArtifactFile( Artifact artifact, File workingDir )
+        throws IOException
+    {
+        setArtifactFile( artifact, workingDir, null, true );
+    }
+
+    /**
+     * Creates an unpackable file (zip,jar etc) containing the srcFile. If srcFile is null, a new empty file will be
+     * created.
+     *
+     * @param artifact to attach
+     * @param workingDir where to create the file.
+     * @param srcFile
+     * @throws IOException if any
+     */
+    public void setUnpackableArtifactFile( Artifact artifact, File workingDir, File srcFile )
+        throws IOException
+    {
+        setArtifactFile( artifact, workingDir, srcFile, true );
+    }
+
+    /**
+     * Creates a file that can be copied or unpacked based on the passed in artifact
+     *
+     * @param artifact
+     * @param workingDir
+     * @param srcFile
+     * @param createUnpackableFile
+     * @throws IOException if any
+     */
+    private void setArtifactFile( Artifact artifact, File workingDir, File srcFile, boolean createUnpackableFile )
+        throws IOException
+    {
+        if ( workingDir == null )
+        {
+            throw new IllegalArgumentException(
+                                                "The workingDir must be set." );
+        }
+
+        String fileName = getFormattedFileName( artifact, false );
+
+        File theFile = new File( workingDir, fileName );
+        theFile.getParentFile().mkdirs();
+
+        if ( srcFile == null )
+        {
+            theFile.createNewFile();
+        }
+        else if ( createUnpackableFile )
+        {
+            try
+            {
+                createUnpackableFile( artifact, theFile );
+            }
+            catch ( NoSuchArchiverException e )
+            {
+                throw new IOException( "NoSuchArchiverException: " + e.getMessage() );
+            }
+            catch ( ArchiverException e )
+            {
+                throw new IOException( "ArchiverException: " + e.getMessage() );
+            }
+        }
+        else
+        {
+            FileUtils.copyFile( srcFile, theFile );
+        }
+
+        artifact.setFile( theFile );
+    }
+
+    /**
+     * @param artifact
+     * @return
+     */
+    public static String getUnpackableFileName( Artifact artifact )
+    {
+        return "" + artifact.getGroupId() + "-" + artifact.getArtifactId() + "-" + artifact.getVersion() + "-"
+            + artifact.getClassifier() + "-" + artifact.getType() + ".txt";
+    }
+
+    /**
+     * @param artifact
+     * @param destFile
+     * @throws NoSuchArchiverException
+     * @throws ArchiverException if any
+     * @throws IOException if any
+     */
+    public void createUnpackableFile( Artifact artifact, File destFile )
+        throws NoSuchArchiverException, ArchiverException, IOException
+    {
+        Archiver archiver = archiverManager.getArchiver( destFile );
+
+        archiver.setDestFile( destFile );
+        archiver.addFile( srcFile, getUnpackableFileName( artifact ) );
+
+        try
+        {
+            setVariableValueToObject( archiver, "logger", new SilentLog() );
+        }
+        catch ( IllegalAccessException e )
+        {
+            System.out.println( "Unable to override logger with silent log." );
+            e.printStackTrace();
+        }
+        if ( archiver instanceof WarArchiver )
+        {
+            WarArchiver war = (WarArchiver) archiver;
+            // the use of this is counter-intuitive:
+            // http://jira.codehaus.org/browse/PLX-286
+            war.setIgnoreWebxml( false );
+        }
+        archiver.createArchive();
+    }
+
+    /**
+     * @return a <code>DefaultArtifact</code> instance for <code>testGroupId:release:jar:1.0</code>
+     * @throws IOException if any
+     */
+    public Artifact getReleaseArtifact()
+        throws IOException
+    {
+        return createArtifact( "testGroupId", "release", "1.0" );
+    }
+
+    /**
+     * @return a default <code>DefaultArtifact</code> instance for <code>testGroupId:snapshot:jar:2.0-SNAPSHOT</code>
+     * @throws IOException if any
+     */
+    public Artifact getSnapshotArtifact()
+        throws IOException
+    {
+        return createArtifact( "testGroupId", "snapshot", "2.0-SNAPSHOT" );
+    }
+
+    /**
+     * @return a default set of release and snapshot <code>DefaultArtifact</code>, i.e.:
+     * <code>testGroupId:snapshot:jar:2.0-SNAPSHOT, testGroupId:release:jar:1.0</code>
+     * @throws IOException if any
+     * @see #getReleaseArtifact()
+     * @see #getSnapshotArtifact()
+     */
+    public Set<Artifact> getReleaseAndSnapshotArtifacts()
+        throws IOException
+    {
+        Set<Artifact> set = new HashSet<Artifact>();
+        set.add( getReleaseArtifact() );
+        set.add( getSnapshotArtifact() );
+        return set;
+    }
+
+    /**
+     * @return a default set of <code>DefaultArtifact</code>, i.e.:
+     * <code>g:provided:jar:1.0, g:compile:jar:1.0, g:system:jar:1.0, g:test:jar:1.0, g:runtime:jar:1.0</code>
+     * @throws IOException if any
+     */
+    public Set<Artifact> getScopedArtifacts()
+        throws IOException
+    {
+        Set<Artifact> set = new HashSet<Artifact>();
+        set.add( createArtifact( "g", "compile", "1.0", Artifact.SCOPE_COMPILE ) );
+        set.add( createArtifact( "g", "provided", "1.0", Artifact.SCOPE_PROVIDED ) );
+        set.add( createArtifact( "g", "test", "1.0", Artifact.SCOPE_TEST ) );
+        set.add( createArtifact( "g", "runtime", "1.0", Artifact.SCOPE_RUNTIME ) );
+        set.add( createArtifact( "g", "system", "1.0", Artifact.SCOPE_SYSTEM ) );
+        return set;
+    }
+
+    /**
+     * @return a set of <code>DefaultArtifact</code>, i.e.:
+     * <code>g:d:zip:1.0, g:a:war:1.0, g:b:jar:1.0, g:c:sources:1.0, g:e:rar:1.0</code>
+     * @throws IOException if any
+     */
+    public Set<Artifact> getTypedArtifacts()
+        throws IOException
+    {
+        Set<Artifact> set = new HashSet<Artifact>();
+        set.add( createArtifact( "g", "a", "1.0", Artifact.SCOPE_COMPILE, "war", null ) );
+        set.add( createArtifact( "g", "b", "1.0", Artifact.SCOPE_COMPILE, "jar", null ) );
+        set.add( createArtifact( "g", "c", "1.0", Artifact.SCOPE_COMPILE, "sources", null ) );
+        set.add( createArtifact( "g", "d", "1.0", Artifact.SCOPE_COMPILE, "zip", null ) );
+        set.add( createArtifact( "g", "e", "1.0", Artifact.SCOPE_COMPILE, "rar", null ) );
+        return set;
+    }
+
+    /**
+     * @return a set of <code>DefaultArtifact</code>, i.e.:
+     * <code>g:c:jar:three:1.0, g:b:jar:two:1.0, g:d:jar:four:1.0, g:a:jar:one:1.0</code>
+     * @throws IOException if any
+     */
+    public Set<Artifact> getClassifiedArtifacts()
+        throws IOException
+    {
+        Set<Artifact> set = new HashSet<Artifact>();
+        set.add( createArtifact( "g", "a", "1.0", Artifact.SCOPE_COMPILE, "jar", "one" ) );
+        set.add( createArtifact( "g", "b", "1.0", Artifact.SCOPE_COMPILE, "jar", "two" ) );
+        set.add( createArtifact( "g", "c", "1.0", Artifact.SCOPE_COMPILE, "jar", "three" ) );
+        set.add( createArtifact( "g", "d", "1.0", Artifact.SCOPE_COMPILE, "jar", "four" ) );
+        return set;
+    }
+
+    /**
+     * @return a set of <code>DefaultArtifact</code>, i.e.:
+     * <code>g:d:zip:1.0, g:a:war:1.0, g:b:jar:1.0, g:e:rar:1.0</code>
+     * @throws IOException if any
+     */
+    public Set<Artifact> getTypedArchiveArtifacts()
+        throws IOException
+    {
+        Set<Artifact> set = new HashSet<Artifact>();
+        set.add( createArtifact( "g", "a", "1.0", Artifact.SCOPE_COMPILE, "war", null ) );
+        set.add( createArtifact( "g", "b", "1.0", Artifact.SCOPE_COMPILE, "jar", null ) );
+        set.add( createArtifact( "g", "d", "1.0", Artifact.SCOPE_COMPILE, "zip", null ) );
+        set.add( createArtifact( "g", "e", "1.0", Artifact.SCOPE_COMPILE, "rar", null ) );
+        return set;
+    }
+
+    /**
+     * @return a set of <code>DefaultArtifact</code>, i.e.:
+     * <code>g:one:jar:a:1.0, g:two:jar:a:1.0, g:four:jar:a:1.0, g:three:jar:a:1.0</code>
+     * @throws IOException if any
+     */
+    public Set<Artifact> getArtifactArtifacts()
+        throws IOException
+    {
+        Set<Artifact> set = new HashSet<Artifact>();
+        set.add( createArtifact( "g", "one", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
+        set.add( createArtifact( "g", "two", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
+        set.add( createArtifact( "g", "three", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
+        set.add( createArtifact( "g", "four", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
+        return set;
+    }
+
+    /**
+     * @return a set of <code>DefaultArtifact</code>, i.e.:
+     * <code>one:group-one:jar:a:1.0, three:group-three:jar:a:1.0, four:group-four:jar:a:1.0,
+     * two:group-two:jar:a:1.0</code>
+     * @throws IOException if any
+     */
+    public Set<Artifact> getGroupIdArtifacts()
+        throws IOException
+    {
+        Set<Artifact> set = new HashSet<Artifact>();
+        set.add( createArtifact( "one", "group-one", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
+        set.add( createArtifact( "two", "group-two", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
+        set.add( createArtifact( "three", "group-three", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
+        set.add( createArtifact( "four", "group-four", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
+        return set;
+    }
+
+    /**
+     * @return a set of <code>DefaultArtifact</code>
+     * @throws IOException if any
+     * @see #getTypedArtifacts()
+     * @see #getScopedArtifacts()
+     * @see #getReleaseAndSnapshotArtifacts()
+     */
+    public Set<Artifact> getMixedArtifacts()
+        throws IOException
+    {
+        Set<Artifact> set = new HashSet<Artifact>();
+        set.addAll( getTypedArtifacts() );
+        set.addAll( getScopedArtifacts() );
+        set.addAll( getReleaseAndSnapshotArtifacts() );
+        return set;
+    }
+
+    /**
+     * @return Returns the createFiles.
+     */
+    public boolean isCreateFiles()
+    {
+        return this.createFiles;
+    }
+
+    /**
+     * @param createFiles The createFiles to set.
+     */
+    public void setCreateFiles( boolean createFiles )
+    {
+        this.createFiles = createFiles;
+    }
+
+    /**
+     * @return Returns the workingDir.
+     */
+    public File getWorkingDir()
+    {
+        return this.workingDir;
+    }
+
+    /**
+     * @param workingDir The workingDir to set.
+     */
+    public void setWorkingDir( File workingDir )
+    {
+        this.workingDir = workingDir;
+    }
+
+    /**
+     * @return Returns the srcFile.
+     */
+    public File getSrcFile()
+    {
+        return this.srcFile;
+    }
+
+    /**
+     * @param srcFile The srcFile to set.
+     */
+    public void setSrcFile( File srcFile )
+    {
+        this.srcFile = srcFile;
+    }
+
+    /**
+     * Convenience method to set values to variables in objects that don't have setters
+     *
+     * @param object
+     * @param variable
+     * @param value
+     * @throws IllegalAccessException
+     */
+    public static void setVariableValueToObject( Object object, String variable, Object value )
+        throws IllegalAccessException
+    {
+        Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() );
+
+        field.setAccessible( true );
+
+        field.set( object, value );
+    }
+
+    /**
+     * Builds the file name. If removeVersion is set, then the file name must be reconstructed from the artifactId,
+     * Classifier (if used) and Type. Otherwise, this method returns the artifact file name.
+     *
+     * @param artifact File to be formatted.
+     * @param removeVersion Specifies if the version should be removed from the file name.
+     * @return Formatted file name in the format artifactId-[version]-[classifier].[type]
+     */
+    public static String getFormattedFileName( Artifact artifact, boolean removeVersion )
+    {
+        String destFileName = null;
+
+        // if there is a file and we aren't stripping the version, just get the
+        // name directly
+        if ( artifact.getFile() != null && !removeVersion )
+        {
+            destFileName = artifact.getFile().getName();
+        }
+        else
+        // if offline
+        {
+            String versionString = null;
+            if ( !removeVersion )
+            {
+                versionString = "-" + artifact.getVersion();
+            }
+            else
+            {
+                versionString = "";
+            }
+
+            String classifierString = "";
+
+            if ( StringUtils.isNotEmpty( artifact.getClassifier() ) )
+            {
+                classifierString = "-" + artifact.getClassifier();
+            }
+
+            destFileName = artifact.getArtifactId() + versionString + classifierString + "."
+                + artifact.getArtifactHandler().getExtension();
+        }
+        return destFileName;
+    }
+
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/ConfigurationException.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/ConfigurationException.java
new file mode 100644
index 0000000..1343567
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/ConfigurationException.java
@@ -0,0 +1,58 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * ConfigurationException
+ *
+ * @author jesse
+ * @version $Id: ConfigurationException.java 638332 2008-03-18 11:39:00Z bentmann $
+ */
+public class ConfigurationException
+    extends Exception
+{
+    /** serialVersionUID */
+    static final long serialVersionUID = -6180939638742159065L;
+
+    /**
+     * @param message The detailed message.
+     */
+    public ConfigurationException( String message )
+    {
+        super( message );
+    }
+
+    /**
+     * @param cause The detailed cause.
+     */
+    public ConfigurationException( Throwable cause )
+    {
+        super( cause );
+    }
+
+    /**
+     * @param message The detailed message.
+     * @param cause The detailed cause.
+     */
+    public ConfigurationException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/ResolverExpressionEvaluatorStub.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/ResolverExpressionEvaluatorStub.java
new file mode 100644
index 0000000..d940e63
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/ResolverExpressionEvaluatorStub.java
@@ -0,0 +1,140 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+
+import org.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+import org.apache.maven.artifact.repository.DefaultArtifactRepository;
+import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+
+/**
+ * Stub for {@link ExpressionEvaluator}
+ *
+ * @author jesse
+ * @version $Id: ResolverExpressionEvaluatorStub.java 638332 2008-03-18 11:39:00Z bentmann $
+ */
+public class ResolverExpressionEvaluatorStub
+    implements ExpressionEvaluator
+{
+    /** {@inheritDoc} */
+    public Object evaluate( String expr )
+        throws ExpressionEvaluationException
+    {
+
+        Object value = null;
+
+        if ( expr == null )
+        {
+            return null;
+        }
+
+        String expression = stripTokens( expr );
+
+        if ( expression.equals( expr ) )
+        {
+            int index = expr.indexOf( "${" );
+            if ( index >= 0 )
+            {
+                int lastIndex = expr.indexOf( "}", index );
+                if ( lastIndex >= 0 )
+                {
+                    String retVal = expr.substring( 0, index );
+
+                    if ( index > 0 && expr.charAt( index - 1 ) == '$' )
+                    {
+                        retVal += expr.substring( index + 1, lastIndex + 1 );
+                    }
+                    else
+                    {
+                        retVal += evaluate( expr.substring( index, lastIndex + 1 ) );
+                    }
+
+                    retVal += evaluate( expr.substring( lastIndex + 1 ) );
+                    return retVal;
+                }
+            }
+
+            // Was not an expression
+            if ( expression.indexOf( "$$" ) > -1 )
+            {
+                return expression.replaceAll( "\\$\\$", "\\$" );
+            }
+        }
+
+        if ( "basedir".equals( expression ) )
+        {
+            return PlexusTestCase.getBasedir();
+        }
+        else if ( expression.startsWith( "basedir" ) )
+        {
+            int pathSeparator = expression.indexOf( "/" );
+
+            if ( pathSeparator > 0 )
+            {
+                value = PlexusTestCase.getBasedir() + expression.substring( pathSeparator );
+            }
+            else
+            {
+                System.out.println( "Got expression '" + expression + "' that was not recognised" );
+            }
+            return value;
+        }
+        else if ( "localRepository".equals( expression ) )
+        {
+            File localRepo = new File( PlexusTestCase.getBasedir(), "target/local-repo" );
+            return new DefaultArtifactRepository( "localRepository", "file://" + localRepo.getAbsolutePath(),
+                                                  new DefaultRepositoryLayout() );
+        }
+        else
+        {
+            return expr;
+        }
+    }
+
+    private String stripTokens( String expr )
+    {
+        if ( expr.startsWith( "${" ) && expr.indexOf( "}" ) == expr.length() - 1 )
+        {
+            expr = expr.substring( 2, expr.length() - 1 );
+        }
+
+        return expr;
+    }
+
+    /** {@inheritDoc} */
+    public File alignToBaseDirectory( File file )
+    {
+        if ( file.getAbsolutePath().startsWith( PlexusTestCase.getBasedir() ) )
+        {
+            return file;
+        }
+        else if ( file.isAbsolute() )
+        {
+            return file;
+        }
+        else
+        {
+            return new File( PlexusTestCase.getBasedir(), file.getPath() );
+        }
+    }
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/SilentLog.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/SilentLog.java
new file mode 100644
index 0000000..7dd8acf
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/SilentLog.java
@@ -0,0 +1,334 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.plugin.logging.Log;
+import org.codehaus.plexus.logging.Logger;
+
+/**
+ * This logger implements both types of logs currently in use. It can be injected where needed
+ * to turn off logs during testing where they aren't desired.
+ *
+ * @author <a href="mailto:brianf at apache.org">Brian Fox</a>
+ * @version $Id: SilentLog.java 785452 2009-06-17 00:00:18Z olamy $
+ */
+public class SilentLog
+    implements Log, Logger
+{
+    /**
+     * @return <code>false</code>
+     * @see org.apache.maven.plugin.logging.Log#isDebugEnabled()
+     */
+    public boolean isDebugEnabled()
+    {
+        return false;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#debug(java.lang.CharSequence)
+     */
+    public void debug( CharSequence content )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#debug(java.lang.CharSequence, java.lang.Throwable)
+     */
+    public void debug( CharSequence content, Throwable error )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#debug(java.lang.Throwable)
+     */
+    public void debug( Throwable error )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>false</code>
+     * @see org.apache.maven.plugin.logging.Log#isInfoEnabled()
+     */
+    public boolean isInfoEnabled()
+    {
+        return false;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#info(java.lang.CharSequence)
+     */
+    public void info( CharSequence content )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#info(java.lang.CharSequence, java.lang.Throwable)
+     */
+    public void info( CharSequence content, Throwable error )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#info(java.lang.Throwable)
+     */
+    public void info( Throwable error )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#isWarnEnabled()
+     */
+    public boolean isWarnEnabled()
+    {
+        // nop
+        return false;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#warn(java.lang.CharSequence)
+     */
+    public void warn( CharSequence content )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#warn(java.lang.CharSequence, java.lang.Throwable)
+     */
+    public void warn( CharSequence content, Throwable error )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#warn(java.lang.Throwable)
+     */
+    public void warn( Throwable error )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>false</code>
+     * @see org.apache.maven.plugin.logging.Log#isErrorEnabled()
+     */
+    public boolean isErrorEnabled()
+    {
+        return false;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#error(java.lang.CharSequence)
+     */
+    public void error( CharSequence content )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#error(java.lang.CharSequence, java.lang.Throwable)
+     */
+    public void error( CharSequence content, Throwable error )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.plugin.logging.Log#error(java.lang.Throwable)
+     */
+    public void error( Throwable error )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.codehaus.plexus.logging.Logger#debug(java.lang.String)
+     */
+    public void debug( String message )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.codehaus.plexus.logging.Logger#debug(java.lang.String, java.lang.Throwable)
+     */
+    public void debug( String message, Throwable throwable )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.codehaus.plexus.logging.Logger#info(java.lang.String)
+     */
+    public void info( String message )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.codehaus.plexus.logging.Logger#info(java.lang.String, java.lang.Throwable)
+     */
+    public void info( String message, Throwable throwable )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.codehaus.plexus.logging.Logger#warn(java.lang.String)
+     */
+    public void warn( String message )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.codehaus.plexus.logging.Logger#warn(java.lang.String, java.lang.Throwable)
+     */
+    public void warn( String message, Throwable throwable )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.codehaus.plexus.logging.Logger#error(java.lang.String)
+     */
+    public void error( String message )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.codehaus.plexus.logging.Logger#error(java.lang.String, java.lang.Throwable)
+     */
+    public void error( String message, Throwable throwable )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.codehaus.plexus.logging.Logger#fatalError(java.lang.String)
+     */
+    public void fatalError( String message )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.codehaus.plexus.logging.Logger#fatalError(java.lang.String, java.lang.Throwable)
+     */
+    public void fatalError( String message, Throwable throwable )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>false</code>
+     * @see org.codehaus.plexus.logging.Logger#isFatalErrorEnabled()
+     */
+    public boolean isFatalErrorEnabled()
+    {
+        return false;
+    }
+
+    /**
+     * @return <code>null</code>
+     * @see org.codehaus.plexus.logging.Logger#getChildLogger(java.lang.String)
+     */
+    public Logger getChildLogger( String name )
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>0</code>
+     * @see org.codehaus.plexus.logging.Logger#getThreshold()
+     */
+    public int getThreshold()
+    {
+        return 0;
+    }
+
+    /**
+     * @return <code>null</code>
+     * @see org.codehaus.plexus.logging.Logger#getName()
+     */
+    public String getName()
+    {
+        return null;
+    }
+
+    public void setThreshold( int threshold )
+    {
+        // TODO Auto-generated method stub
+        
+    }
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/ArtifactStub.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/ArtifactStub.java
new file mode 100644
index 0000000..93507de
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/ArtifactStub.java
@@ -0,0 +1,510 @@
+package org.apache.maven.plugin.testing.stubs;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
+import org.apache.maven.artifact.versioning.VersionRange;
+
+/**
+ * Stub class for {@link Artifact} testing.
+ *
+ * @author jesse
+ * @version $Id: ArtifactStub.java 1340752 2012-05-20 15:20:59Z hboutemy $
+ */
+public class ArtifactStub
+    implements Artifact
+{
+    private String groupId;
+
+    private String artifactId;
+
+    private String version;
+
+    private String scope;
+
+    private String type;
+
+    private String classifier;
+
+    private File file;
+
+    private ArtifactRepository artifactRepository;
+
+    /**
+     * By default, return <code>0</code>
+     *
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    public int compareTo( Artifact artifact )
+    {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    /** {@inheritDoc} */
+    public String getArtifactId()
+    {
+        return artifactId;
+    }
+
+    /** {@inheritDoc} */
+    public String getVersion()
+    {
+        return version;
+    }
+
+    /** {@inheritDoc} */
+    public void setVersion( String version )
+    {
+        this.version = version;
+    }
+
+    /** {@inheritDoc} */
+    public String getScope()
+    {
+        return scope;
+    }
+
+    /** {@inheritDoc} */
+    public String getType()
+    {
+        return type;
+    }
+
+    /**
+     * Set a new type
+     *
+     * @param type
+     */
+    public void setType( String type )
+    {
+        this.type = type;
+    }
+
+    /** {@inheritDoc} */
+    public String getClassifier()
+    {
+        return classifier;
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasClassifier()
+    {
+        return classifier != null;
+    }
+
+    /** {@inheritDoc} */
+    public File getFile()
+    {
+        return file;
+    }
+
+    /** {@inheritDoc} */
+    public void setFile( File file )
+    {
+        this.file = file;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.Artifact#getBaseVersion()
+     */
+    public String getBaseVersion()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#setBaseVersion(java.lang.String)
+     */
+    public void setBaseVersion( String string )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.Artifact#getId()
+     */
+    public String getId()
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>groupId:artifactId:type:classifier</code>.
+     * @see org.apache.maven.artifact.Artifact#getDependencyConflictId()
+     */
+    public String getDependencyConflictId()
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append( getGroupId() );
+        buffer.append( ":" ).append( getArtifactId() );
+        buffer.append( ":" ).append( getType() );
+        buffer.append( ":" ).append( getClassifier() );
+
+        return buffer.toString();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#addMetadata(org.apache.maven.artifact.metadata.ArtifactMetadata)
+     */
+    public void addMetadata( ArtifactMetadata artifactMetadata )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.Artifact#getMetadataList()
+     */
+    public Collection<ArtifactMetadata> getMetadataList()
+    {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public void setRepository( ArtifactRepository artifactRepository )
+    {
+        this.artifactRepository = artifactRepository;
+    }
+
+    /** {@inheritDoc} */
+    public ArtifactRepository getRepository()
+    {
+        return artifactRepository;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#updateVersion(java.lang.String, org.apache.maven.artifact.repository.ArtifactRepository)
+     */
+    public void updateVersion( String string, ArtifactRepository artifactRepository )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.Artifact#getDownloadUrl()
+     */
+    public String getDownloadUrl()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#setDownloadUrl(java.lang.String)
+     */
+    public void setDownloadUrl( String string )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.Artifact#getDependencyFilter()
+     */
+    public ArtifactFilter getDependencyFilter()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#setDependencyFilter(org.apache.maven.artifact.resolver.filter.ArtifactFilter)
+     */
+    public void setDependencyFilter( ArtifactFilter artifactFilter )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.Artifact#getArtifactHandler()
+     */
+    public ArtifactHandler getArtifactHandler()
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.Artifact#getDependencyTrail()
+     */
+    public List<String> getDependencyTrail()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#setDependencyTrail(java.util.List)
+     */
+    public void setDependencyTrail( List<String> list )
+    {
+        // nop
+    }
+
+    /** {@inheritDoc} */
+    public void setScope( String scope )
+    {
+        this.scope = scope;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.Artifact#getVersionRange()
+     */
+    public VersionRange getVersionRange()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#setVersionRange(org.apache.maven.artifact.versioning.VersionRange)
+     */
+    public void setVersionRange( VersionRange versionRange )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#selectVersion(java.lang.String)
+     */
+    public void selectVersion( String string )
+    {
+        // nop
+    }
+
+    /** {@inheritDoc} */
+    public void setGroupId( String groupId )
+    {
+        this.groupId = groupId;
+    }
+
+    /** {@inheritDoc} */
+    public void setArtifactId( String artifactId )
+    {
+        this.artifactId = artifactId;
+    }
+
+    /**
+     * @return <code>false</code>.
+     * @see org.apache.maven.artifact.Artifact#isSnapshot()
+     */
+    public boolean isSnapshot()
+    {
+        return Artifact.VERSION_FILE_PATTERN.matcher( getVersion() ).matches()
+            || getVersion().endsWith( Artifact.SNAPSHOT_VERSION );
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#setResolved(boolean)
+     */
+    public void setResolved( boolean b )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>false</code>.
+     * @see org.apache.maven.artifact.Artifact#isResolved()
+     */
+    public boolean isResolved()
+    {
+        return false;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#setResolvedVersion(java.lang.String)
+     */
+    public void setResolvedVersion( String string )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#setArtifactHandler(org.apache.maven.artifact.handler.ArtifactHandler)
+     */
+    public void setArtifactHandler( ArtifactHandler artifactHandler )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>false</code>.
+     * @see org.apache.maven.artifact.Artifact#isRelease()
+     */
+    public boolean isRelease()
+    {
+        return !isSnapshot();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#setRelease(boolean)
+     */
+    public void setRelease( boolean b )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.Artifact#getAvailableVersions()
+     */
+    public List<ArtifactVersion> getAvailableVersions()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.Artifact#setAvailableVersions(java.util.List)
+     */
+    public void setAvailableVersions( List<ArtifactVersion> list )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>false</code>.
+     * @see org.apache.maven.artifact.Artifact#isOptional()
+     */
+    public boolean isOptional()
+    {
+        return false;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @param b
+     */
+    public void setOptional( boolean b )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.Artifact#getSelectedVersion()
+     */
+    public ArtifactVersion getSelectedVersion()
+        throws OverConstrainedVersionException
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>false</code>.
+     * @see org.apache.maven.artifact.Artifact#isSelectedVersionKnown()
+     */
+    public boolean isSelectedVersionKnown()
+        throws OverConstrainedVersionException
+    {
+        return false;
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        StringBuffer sb = new StringBuffer();
+        if ( getGroupId() != null )
+        {
+            sb.append( getGroupId() );
+            sb.append( ":" );
+        }
+        appendArtifactTypeClassifierString( sb );
+        if ( version != null )
+        {
+            sb.append( ":" );
+            sb.append( getVersion() );
+        }
+        if ( scope != null )
+        {
+            sb.append( ":" );
+            sb.append( scope );
+        }
+        return sb.toString();
+    }
+
+    private void appendArtifactTypeClassifierString( StringBuffer sb )
+    {
+        sb.append( getArtifactId() );
+        sb.append( ":" );
+        sb.append( getType() );
+        if ( hasClassifier() )
+        {
+            sb.append( ":" );
+            sb.append( getClassifier() );
+        }
+    }
+
+    public boolean isFromAuthoritativeRepository()
+    {
+        return true;
+    }
+
+    public void setFromAuthoritativeRepository( boolean fromAuthoritativeRepository )
+    {
+        // nothing
+    }
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/DefaultArtifactHandlerStub.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/DefaultArtifactHandlerStub.java
new file mode 100644
index 0000000..8bb4fec
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/DefaultArtifactHandlerStub.java
@@ -0,0 +1,202 @@
+package org.apache.maven.plugin.testing.stubs;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.artifact.handler.ArtifactHandler;
+
+/**
+ * Minimal artifact handler used by the stub factory to create unpackable archives.
+ *
+ * @author <a href="mailto:brianf at apache.org">Brian Fox</a>
+ * @version $Id: DefaultArtifactHandlerStub.java 638332 2008-03-18 11:39:00Z bentmann $
+ */
+public class DefaultArtifactHandlerStub
+    implements ArtifactHandler
+{
+    private String extension;
+
+    private String type;
+
+    private String classifier;
+
+    private String directory;
+
+    private String packaging;
+
+    private boolean includesDependencies;
+
+    private String language;
+
+    private boolean addedToClasspath;
+
+    /**
+     * @param t the artifact handler type
+     * @param c the artifact handler classifier
+     */
+    public DefaultArtifactHandlerStub( String t, String c )
+    {
+        type = t;
+        classifier = c;
+        if ( t.equals( "test-jar" ) )
+        {
+            extension = "jar";
+        }
+
+    }
+
+    /**
+     * @param type the artifact handler type
+     */
+    public DefaultArtifactHandlerStub( String type )
+    {
+        this.type = type;
+    }
+
+    /** {@inheritDoc} */
+    public String getExtension()
+    {
+        if ( extension == null )
+        {
+            extension = type;
+        }
+        return extension;
+    }
+
+    /**
+     * @return the artifact handler type
+     */
+    public String getType()
+    {
+        return type;
+    }
+
+    /** {@inheritDoc} */
+    public String getClassifier()
+    {
+        return classifier;
+    }
+
+    /** {@inheritDoc} */
+    public String getDirectory()
+    {
+        if ( directory == null )
+        {
+            directory = getPackaging() + "s";
+        }
+        return directory;
+    }
+
+    /** {@inheritDoc} */
+    public String getPackaging()
+    {
+        if ( packaging == null )
+        {
+            packaging = getType();
+        }
+        return packaging;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isIncludesDependencies()
+    {
+        return includesDependencies;
+    }
+
+    /** {@inheritDoc} */
+    public String getLanguage()
+    {
+        if ( language == null )
+        {
+            language = "none";
+        }
+
+        return language;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isAddedToClasspath()
+    {
+        return addedToClasspath;
+    }
+
+    /**
+     * @param theAddedToClasspath The addedToClasspath to set.
+     */
+    public void setAddedToClasspath( boolean theAddedToClasspath )
+    {
+        this.addedToClasspath = theAddedToClasspath;
+    }
+
+    /**
+     * @param theClassifier The classifier to set.
+     */
+    public void setClassifier( String theClassifier )
+    {
+        this.classifier = theClassifier;
+    }
+
+    /**
+     * @param theDirectory The directory to set.
+     */
+    public void setDirectory( String theDirectory )
+    {
+        this.directory = theDirectory;
+    }
+
+    /**
+     * @param theExtension The extension to set.
+     */
+    public void setExtension( String theExtension )
+    {
+        this.extension = theExtension;
+    }
+
+    /**
+     * @param theIncludesDependencies The includesDependencies to set.
+     */
+    public void setIncludesDependencies( boolean theIncludesDependencies )
+    {
+        this.includesDependencies = theIncludesDependencies;
+    }
+
+    /**
+     * @param theLanguage The language to set.
+     */
+    public void setLanguage( String theLanguage )
+    {
+        this.language = theLanguage;
+    }
+
+    /**
+     * @param thePackaging The packaging to set.
+     */
+    public void setPackaging( String thePackaging )
+    {
+        this.packaging = thePackaging;
+    }
+
+    /**
+     * @param theType The type to set.
+     */
+    public void setType( String theType )
+    {
+        this.type = theType;
+    }
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/MavenProjectStub.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/MavenProjectStub.java
new file mode 100644
index 0000000..f8d7e27
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/MavenProjectStub.java
@@ -0,0 +1,1541 @@
+package org.apache.maven.plugin.testing.stubs;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DependencyResolutionRequiredException;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.model.Build;
+import org.apache.maven.model.CiManagement;
+import org.apache.maven.model.Contributor;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.model.Developer;
+import org.apache.maven.model.DistributionManagement;
+import org.apache.maven.model.Extension;
+import org.apache.maven.model.IssueManagement;
+import org.apache.maven.model.License;
+import org.apache.maven.model.MailingList;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Organization;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginManagement;
+import org.apache.maven.model.Prerequisites;
+import org.apache.maven.model.Profile;
+import org.apache.maven.model.ReportPlugin;
+import org.apache.maven.model.Reporting;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.Resource;
+import org.apache.maven.model.Scm;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * Very simple stub of <code>MavenProject</code> object, going to take a lot of work to make it
+ * useful as a stub though.
+ *
+ * @author jesse
+ * @version $Id: MavenProjectStub.java 1340752 2012-05-20 15:20:59Z hboutemy $
+ */
+public class MavenProjectStub
+    extends MavenProject
+{
+    private String groupId;
+
+    private String artifactId;
+
+    private String name;
+
+    private Model model;
+
+    private MavenProject parent;
+
+    private File file;
+
+    private List<MavenProject> collectedProjects;
+
+    private List<Artifact> attachedArtifacts;
+
+    private List<String> compileSourceRoots;
+
+    private List<String> testCompileSourceRoots;
+
+    private List<String> scriptSourceRoots;
+
+    private List<ArtifactRepository> pluginArtifactRepositories;
+
+    private ArtifactRepository releaseArtifactRepository;
+
+    private ArtifactRepository snapshotArtifactRepository;
+
+    private List<Profile> activeProfiles;
+
+    private Set<Artifact> dependencyArtifacts;
+
+    private Artifact artifact;
+
+    private Map<String, Artifact> artifactMap;
+
+    private Model originalModel;
+
+    private Map<String, Artifact> pluginArtifactMap;
+
+    private Map<String, Artifact> reportArtifactMap;
+
+    private Map<String, Artifact> extensionArtifactMap;
+
+    private Map<String, MavenProject> projectReferences;
+
+    private Build buildOverlay;
+
+    private boolean executionRoot;
+
+    private List<Artifact> compileArtifacts;
+
+    private List<Dependency> compileDependencies;
+
+    private List<Dependency> systemDependencies;
+
+    private List<String> testClasspathElements;
+
+    private List<Dependency> testDependencies;
+
+    private List<String> systemClasspathElements;
+
+    private List<Artifact> systemArtifacts;
+
+    private List<Artifact> testArtifacts;
+
+    private List<Artifact> runtimeArtifacts;
+
+    private List<Dependency> runtimeDependencies;
+
+    private List<String> runtimeClasspathElements;
+
+    private String modelVersion;
+
+    private String packaging;
+
+    private String inceptionYear;
+
+    private String url;
+
+    private String description;
+
+    private String version;
+
+    private String defaultGoal;
+
+    private List<License> licenses;
+
+    private Build build;
+
+    /**
+     * Default constructor
+     */
+    public MavenProjectStub()
+    {
+        this( new Model() );
+    }
+
+    /**
+     * @param model the given model
+     */
+    public MavenProjectStub( Model model )
+    {
+        super( (Model) null );
+        this.model = model;
+    }
+
+    /**
+     * Loads the model for this stub from the specified POM. For convenience, any checked exception caused by I/O or
+     * parser errors will be wrapped into an unchecked exception.
+     * 
+     * @param pomFile The path to the POM file to load, must not be <code>null</code>. If this path is relative, it
+     *            is resolved against the return value of {@link #getBasedir()}.
+     */
+    protected void readModel( File pomFile )
+    {
+        if ( !pomFile.isAbsolute() )
+        {
+            pomFile = new File( getBasedir(), pomFile.getPath() );
+        }
+        try
+        {
+            setModel( new MavenXpp3Reader().read( ReaderFactory.newXmlReader( pomFile ) ) );
+        }
+        catch ( IOException e )
+        {
+            throw new RuntimeException( "Failed to read POM file: " + pomFile, e );
+        }
+        catch ( XmlPullParserException e )
+        {
+            throw new RuntimeException( "Failed to parse POM file: " + pomFile, e );
+        }
+    }
+
+    /**
+     * No project model is associated
+     *
+     * @param project the given project
+     */
+    public MavenProjectStub( MavenProject project )
+    {
+        super( (Model) null );
+    }
+
+    /**
+     * @param mavenProject
+     * @return an empty String
+     * @throws IOException if any
+     */
+    public String getModulePathAdjustment( MavenProject mavenProject )
+        throws IOException
+    {
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /** {@inheritDoc} */
+    public void setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+    }
+
+    /** {@inheritDoc} */
+    public Model getModel()
+    {
+        return model;
+    }
+
+    /** {@inheritDoc} */
+    public MavenProject getParent()
+    {
+        return parent;
+    }
+
+    /** {@inheritDoc} */
+    public void setParent( MavenProject mavenProject )
+    {
+        this.parent = mavenProject;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setRemoteArtifactRepositories(java.util.List)
+     */
+    public void setRemoteArtifactRepositories( List<ArtifactRepository> list )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getRemoteArtifactRepositories()
+     */
+    public List<ArtifactRepository> getRemoteArtifactRepositories()
+    {
+        return Collections.<ArtifactRepository>emptyList();
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasParent()
+    {
+        if ( parent != null )
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    public File getFile()
+    {
+        return file;
+    }
+
+    /** {@inheritDoc} */
+    public void setFile( File file )
+    {
+        this.file = file;
+    }
+
+    /** {@inheritDoc} */
+    public File getBasedir()
+    {
+        return new File( PlexusTestCase.getBasedir() );
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setDependencies(java.util.List)
+     */
+    public void setDependencies( List<Dependency> list )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getDependencies()
+     */
+    public List<Dependency> getDependencies()
+    {
+        return Collections.<Dependency>emptyList();
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getDependencyManagement()
+     */
+    public DependencyManagement getDependencyManagement()
+    {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public void addCompileSourceRoot( String string )
+    {
+        if ( compileSourceRoots == null )
+        {
+            compileSourceRoots = new ArrayList<String>( Collections.singletonList( string ) );
+        }
+        else
+        {
+            compileSourceRoots.add( string );
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void addScriptSourceRoot( String string )
+    {
+        if ( scriptSourceRoots == null )
+        {
+            scriptSourceRoots = new ArrayList<String>( Collections.singletonList( string ) );
+        }
+        else
+        {
+            scriptSourceRoots.add( string );
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void addTestCompileSourceRoot( String string )
+    {
+        if ( testCompileSourceRoots == null )
+        {
+            testCompileSourceRoots = new ArrayList<String>( Collections.singletonList( string ) );
+        }
+        else
+        {
+            testCompileSourceRoots.add( string );
+        }
+    }
+
+    /** {@inheritDoc} */
+    public List<String> getCompileSourceRoots()
+    {
+        return compileSourceRoots;
+    }
+
+    /** {@inheritDoc} */
+    public List<String> getScriptSourceRoots()
+    {
+        return scriptSourceRoots;
+    }
+
+    /** {@inheritDoc} */
+    public List<String> getTestCompileSourceRoots()
+    {
+        return testCompileSourceRoots;
+    }
+
+    /** {@inheritDoc} */
+    public List<String> getCompileClasspathElements()
+        throws DependencyResolutionRequiredException
+    {
+        return compileSourceRoots;
+    }
+
+    /**
+     * @param compileArtifacts
+     */
+    public void setCompileArtifacts( List<Artifact> compileArtifacts )
+    {
+        this.compileArtifacts = compileArtifacts;
+    }
+
+    /** {@inheritDoc} */
+    public List<Artifact> getCompileArtifacts()
+    {
+        return compileArtifacts;
+    }
+
+    /** {@inheritDoc} */
+    public List<Dependency> getCompileDependencies()
+    {
+        return compileDependencies;
+    }
+
+    /** {@inheritDoc} */
+    public List<String> getTestClasspathElements()
+        throws DependencyResolutionRequiredException
+    {
+        return testClasspathElements;
+    }
+
+    /** {@inheritDoc} */
+    public List<Artifact> getTestArtifacts()
+    {
+        return testArtifacts;
+    }
+
+    /** {@inheritDoc} */
+    public List<Dependency> getTestDependencies()
+    {
+        return testDependencies;
+    }
+
+    /** {@inheritDoc} */
+    public List<String> getRuntimeClasspathElements()
+        throws DependencyResolutionRequiredException
+    {
+        return runtimeClasspathElements;
+    }
+
+    /** {@inheritDoc} */
+    public List<Artifact> getRuntimeArtifacts()
+    {
+        return runtimeArtifacts;
+    }
+
+    /** {@inheritDoc} */
+    public List<Dependency> getRuntimeDependencies()
+    {
+        return runtimeDependencies;
+    }
+
+    /** {@inheritDoc} */
+    public List<String> getSystemClasspathElements()
+        throws DependencyResolutionRequiredException
+    {
+        return systemClasspathElements;
+    }
+
+    /** {@inheritDoc} */
+    public List<Artifact> getSystemArtifacts()
+    {
+        return systemArtifacts;
+    }
+
+    /**
+     * @param runtimeClasspathElements
+     */
+    public void setRuntimeClasspathElements( List<String> runtimeClasspathElements )
+    {
+        this.runtimeClasspathElements = runtimeClasspathElements;
+    }
+
+    /**
+     * @param attachedArtifacts
+     */
+    public void setAttachedArtifacts( List<Artifact> attachedArtifacts )
+    {
+        this.attachedArtifacts = attachedArtifacts;
+    }
+
+    /**
+     * @param compileSourceRoots
+     */
+    public void setCompileSourceRoots( List<String> compileSourceRoots )
+    {
+        this.compileSourceRoots = compileSourceRoots;
+    }
+
+    /**
+     * @param testCompileSourceRoots
+     */
+    public void setTestCompileSourceRoots( List<String> testCompileSourceRoots )
+    {
+        this.testCompileSourceRoots = testCompileSourceRoots;
+    }
+
+    /**
+     * @param scriptSourceRoots
+     */
+    public void setScriptSourceRoots( List<String> scriptSourceRoots )
+    {
+        this.scriptSourceRoots = scriptSourceRoots;
+    }
+
+    /**
+     * @param artifactMap
+     */
+    public void setArtifactMap( Map<String, Artifact> artifactMap )
+    {
+        this.artifactMap = artifactMap;
+    }
+
+    /**
+     * @param pluginArtifactMap
+     */
+    public void setPluginArtifactMap( Map<String, Artifact> pluginArtifactMap )
+    {
+        this.pluginArtifactMap = pluginArtifactMap;
+    }
+
+    /**
+     * @param reportArtifactMap
+     */
+    public void setReportArtifactMap( Map<String, Artifact> reportArtifactMap )
+    {
+        this.reportArtifactMap = reportArtifactMap;
+    }
+
+    /**
+     * @param extensionArtifactMap
+     */
+    public void setExtensionArtifactMap( Map<String, Artifact> extensionArtifactMap )
+    {
+        this.extensionArtifactMap = extensionArtifactMap;
+    }
+
+    /**
+     * @param projectReferences
+     */
+    public void setProjectReferences( Map<String, MavenProject> projectReferences )
+    {
+        this.projectReferences = projectReferences;
+    }
+
+    /**
+     * @param buildOverlay
+     */
+    public void setBuildOverlay( Build buildOverlay )
+    {
+        this.buildOverlay = buildOverlay;
+    }
+
+    /**
+     * @param compileDependencies
+     */
+    public void setCompileDependencies( List<Dependency> compileDependencies )
+    {
+        this.compileDependencies = compileDependencies;
+    }
+
+    /**
+     * @param systemDependencies
+     */
+    public void setSystemDependencies( List<Dependency> systemDependencies )
+    {
+        this.systemDependencies = systemDependencies;
+    }
+
+    /**
+     * @param testClasspathElements
+     */
+    public void setTestClasspathElements( List<String> testClasspathElements )
+    {
+        this.testClasspathElements = testClasspathElements;
+    }
+
+    /**
+     * @param testDependencies
+     */
+    public void setTestDependencies( List<Dependency> testDependencies )
+    {
+        this.testDependencies = testDependencies;
+    }
+
+    /**
+     * @param systemClasspathElements
+     */
+    public void setSystemClasspathElements( List<String> systemClasspathElements )
+    {
+        this.systemClasspathElements = systemClasspathElements;
+    }
+
+    /**
+     * @param systemArtifacts
+     */
+    public void setSystemArtifacts( List<Artifact> systemArtifacts )
+    {
+        this.systemArtifacts = systemArtifacts;
+    }
+
+    /**
+     * @param testArtifacts
+     */
+    public void setTestArtifacts( List<Artifact> testArtifacts )
+    {
+        this.testArtifacts = testArtifacts;
+    }
+
+    /**
+     * @param runtimeArtifacts
+     */
+    public void setRuntimeArtifacts( List<Artifact> runtimeArtifacts )
+    {
+        this.runtimeArtifacts = runtimeArtifacts;
+    }
+
+    /**
+     * @param runtimeDependencies
+     */
+    public void setRuntimeDependencies( List<Dependency> runtimeDependencies )
+    {
+        this.runtimeDependencies = runtimeDependencies;
+    }
+
+    /**
+     * @param model
+     */
+    public void setModel( Model model )
+    {
+        this.model = model;
+    }
+
+    /** {@inheritDoc} */
+    public List<Dependency> getSystemDependencies()
+    {
+        return systemDependencies;
+    }
+
+    /** {@inheritDoc} */
+    public void setModelVersion( String string )
+    {
+        this.modelVersion = string;
+    }
+
+    /** {@inheritDoc} */
+    public String getModelVersion()
+    {
+        return modelVersion;
+    }
+
+    /**
+     * By default, return an empty String.
+     *
+     * @see org.apache.maven.project.MavenProject#getId()
+     */
+    public String getId()
+    {
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    public void setGroupId( String string )
+    {
+        this.groupId = string;
+    }
+
+    /** {@inheritDoc} */
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    /** {@inheritDoc} */
+    public void setArtifactId( String string )
+    {
+        this.artifactId = string;
+    }
+
+    /** {@inheritDoc} */
+    public String getArtifactId()
+    {
+        return artifactId;
+    }
+
+    /** {@inheritDoc} */
+    public void setName( String string )
+    {
+        this.name = string;
+    }
+
+    /** {@inheritDoc} */
+    public String getName()
+    {
+        return name;
+    }
+
+    /** {@inheritDoc} */
+    public void setVersion( String string )
+    {
+        this.version = string;
+    }
+
+    /** {@inheritDoc} */
+    public String getVersion()
+    {
+        return version;
+    }
+
+    /** {@inheritDoc} */
+    public String getPackaging()
+    {
+        return packaging;
+    }
+
+    /** {@inheritDoc} */
+    public void setPackaging( String string )
+    {
+        this.packaging = string;
+    }
+
+    /** {@inheritDoc} */
+    public void setInceptionYear( String string )
+    {
+        this.inceptionYear = string;
+    }
+
+    /** {@inheritDoc} */
+    public String getInceptionYear()
+    {
+        return inceptionYear;
+    }
+
+    /** {@inheritDoc} */
+    public void setUrl( String string )
+    {
+        this.url = string;
+    }
+
+    /** {@inheritDoc} */
+    public String getUrl()
+    {
+        return url;
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getPrerequisites()
+     */
+    public Prerequisites getPrerequisites()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setIssueManagement(org.apache.maven.model.IssueManagement)
+     */
+    public void setIssueManagement( IssueManagement issueManagement )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getCiManagement()
+     */
+    public CiManagement getCiManagement()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setCiManagement(org.apache.maven.model.CiManagement)
+     */
+    public void setCiManagement( CiManagement ciManagement )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getIssueManagement()
+     */
+    public IssueManagement getIssueManagement()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setDistributionManagement(org.apache.maven.model.DistributionManagement)
+     */
+    public void setDistributionManagement( DistributionManagement distributionManagement )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getDistributionManagement()
+     */
+    public DistributionManagement getDistributionManagement()
+    {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public void setDescription( String string )
+    {
+        this.description = string;
+    }
+
+    /** {@inheritDoc} */
+    public String getDescription()
+    {
+        return description;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setOrganization(org.apache.maven.model.Organization)
+     */
+    public void setOrganization( Organization organization )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getOrganization()
+     */
+    public Organization getOrganization()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setScm(org.apache.maven.model.Scm)
+     */
+    public void setScm( Scm scm )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getScm()
+     */
+    public Scm getScm()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setMailingLists(java.util.List)
+     */
+    public void setMailingLists( List<MailingList> list )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getMailingLists()
+     */
+    public List<MailingList> getMailingLists()
+    {
+        return Collections.<MailingList>emptyList();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#addMailingList(org.apache.maven.model.MailingList)
+     */
+    public void addMailingList( MailingList mailingList )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setDevelopers(java.util.List)
+     */
+    public void setDevelopers( List<Developer> list )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getDevelopers()
+     */
+    public List<Developer> getDevelopers()
+    {
+        return Collections.<Developer>emptyList();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#addDeveloper(org.apache.maven.model.Developer)
+     */
+    public void addDeveloper( Developer developer )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setContributors(java.util.List)
+     */
+    public void setContributors( List<Contributor> list )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getContributors()
+     */
+    public List<Contributor> getContributors()
+    {
+        return Collections.<Contributor>emptyList();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#addContributor(org.apache.maven.model.Contributor)
+     */
+    public void addContributor( Contributor contributor )
+    {
+        // nop
+    }
+
+    /** {@inheritDoc} */
+    public void setBuild( Build build )
+    {
+        this.build = build;
+    }
+
+    /** {@inheritDoc} */
+    public Build getBuild()
+    {
+        return build;
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getResources()
+     */
+    public List<Resource> getResources()
+    {
+        return Collections.<Resource>emptyList();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getTestResources()
+     */
+    public List<Resource> getTestResources()
+    {
+        return Collections.<Resource>emptyList();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#addResource(org.apache.maven.model.Resource)
+     */
+    public void addResource( Resource resource )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#addTestResource(org.apache.maven.model.Resource)
+     */
+    public void addTestResource( Resource resource )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setReporting(org.apache.maven.model.Reporting)
+     */
+    public void setReporting( Reporting reporting )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getReporting()
+     */
+    public Reporting getReporting()
+    {
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    public void setLicenses( List<License> licenses )
+    {
+        this.licenses = licenses;
+    }
+
+    /** {@inheritDoc} */
+    public List<License> getLicenses()
+    {
+        return licenses;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#addLicense(org.apache.maven.model.License)
+     */
+    public void addLicense( License license )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setArtifacts(java.util.Set)
+     */
+    public void setArtifacts( Set<Artifact> set )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_SET</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getArtifacts()
+     */
+    public Set<Artifact> getArtifacts()
+    {
+        return Collections.<Artifact>emptySet();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_MAP</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getArtifactMap()
+     */
+    public Map<String, Artifact> getArtifactMap()
+    {
+        return Collections.<String, Artifact>emptyMap();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setPluginArtifacts(java.util.Set)
+     */
+    public void setPluginArtifacts( Set<Artifact> set )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_SET</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getPluginArtifacts()
+     */
+    public Set<Artifact> getPluginArtifacts()
+    {
+        return Collections.<Artifact>emptySet();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_MAP</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getPluginArtifactMap()
+     */
+    public Map<String, Artifact> getPluginArtifactMap()
+    {
+        return Collections.<String, Artifact>emptyMap();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setReportArtifacts(java.util.Set)
+     */
+    public void setReportArtifacts( Set<Artifact> set )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_SET</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getReportArtifacts()
+     */
+    public Set<Artifact> getReportArtifacts()
+    {
+        return Collections.<Artifact>emptySet();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_MAP</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getReportArtifactMap()
+     */
+    public Map<String, Artifact> getReportArtifactMap()
+    {
+        return Collections.<String, Artifact>emptyMap();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setExtensionArtifacts(java.util.Set)
+     */
+    public void setExtensionArtifacts( Set<Artifact> set )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_SET</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getExtensionArtifacts()
+     */
+    public Set<Artifact> getExtensionArtifacts()
+    {
+        return Collections.<Artifact>emptySet();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_MAP</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getExtensionArtifactMap()
+     */
+    public Map<String, Artifact> getExtensionArtifactMap()
+    {
+        return Collections.<String, Artifact>emptyMap();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setParentArtifact(org.apache.maven.artifact.Artifact)
+     */
+    public void setParentArtifact( Artifact artifact )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getParentArtifact()
+     */
+    public Artifact getParentArtifact()
+    {
+        return null;
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getRepositories()
+     */
+    public List<Repository> getRepositories()
+    {
+        return Collections.<Repository>emptyList();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getReportPlugins()
+     */
+    public List<ReportPlugin> getReportPlugins()
+    {
+        return Collections.<ReportPlugin>emptyList();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getBuildPlugins()
+     */
+    public List<Plugin> getBuildPlugins()
+    {
+        return Collections.<Plugin>emptyList();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getModules()
+     */
+    public List<String> getModules()
+    {
+        return Collections.<String>emptyList();
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getPluginManagement()
+     */
+    public PluginManagement getPluginManagement()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#addPlugin(org.apache.maven.model.Plugin)
+     */
+    public void addPlugin( Plugin plugin )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @param plugin
+     */
+    public void injectPluginManagementInfo( Plugin plugin )
+    {
+        // nop
+    }
+
+    /** {@inheritDoc} */
+    public List<MavenProject> getCollectedProjects()
+    {
+        return collectedProjects;
+    }
+
+    /** {@inheritDoc} */
+    public void setCollectedProjects( List<MavenProject> list )
+    {
+        this.collectedProjects = list;
+    }
+
+    /** {@inheritDoc} */
+    public void setPluginArtifactRepositories( List<ArtifactRepository> list )
+    {
+        this.pluginArtifactRepositories = list;
+    }
+
+    /** {@inheritDoc} */
+    public List<ArtifactRepository> getPluginArtifactRepositories()
+    {
+        return pluginArtifactRepositories;
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getDistributionManagementArtifactRepository()
+     */
+    public ArtifactRepository getDistributionManagementArtifactRepository()
+    {
+        return null;
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getPluginRepositories()
+     */
+    public List<Repository> getPluginRepositories()
+    {
+        return Collections.<Repository>emptyList();
+    }
+
+    /** {@inheritDoc} */
+    public void setActiveProfiles( List<Profile> list )
+    {
+        activeProfiles = list;
+    }
+
+    /** {@inheritDoc} */
+    public List<Profile> getActiveProfiles()
+    {
+        return activeProfiles;
+    }
+
+    /** {@inheritDoc} */
+    public void addAttachedArtifact( Artifact artifact )
+    {
+        if ( attachedArtifacts == null )
+        {
+            this.attachedArtifacts = new ArrayList<Artifact>( Collections.singletonList( artifact ) );
+        }
+        else
+        {
+            attachedArtifacts.add( artifact );
+        }
+    }
+
+    /** {@inheritDoc} */
+    public List<Artifact> getAttachedArtifacts()
+    {
+        return attachedArtifacts;
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getGoalConfiguration(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
+     */
+    public Xpp3Dom getGoalConfiguration( String string, String string1, String string2, String string3 )
+    {
+        return null;
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getReportConfiguration(java.lang.String, java.lang.String, java.lang.String)
+     */
+    public Xpp3Dom getReportConfiguration( String string, String string1, String string2 )
+    {
+        return null;
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getExecutionProject()
+     */
+    public MavenProject getExecutionProject()
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#setExecutionProject(org.apache.maven.project.MavenProject)
+     */
+    public void setExecutionProject( MavenProject mavenProject )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#writeModel(java.io.Writer)
+     */
+    public void writeModel( Writer writer )
+        throws IOException
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#writeOriginalModel(java.io.Writer)
+     */
+    public void writeOriginalModel( Writer writer )
+        throws IOException
+    {
+        // nop
+    }
+
+    /** {@inheritDoc} */
+    public Set<Artifact> getDependencyArtifacts()
+    {
+        return dependencyArtifacts;
+    }
+
+    /** {@inheritDoc} */
+    public void setDependencyArtifacts( Set<Artifact> set )
+    {
+        this.dependencyArtifacts = set;
+    }
+
+    /** {@inheritDoc} */
+    public void setReleaseArtifactRepository( ArtifactRepository artifactRepository )
+    {
+        this.releaseArtifactRepository = artifactRepository;
+    }
+
+    /** {@inheritDoc} */
+    public void setSnapshotArtifactRepository( ArtifactRepository artifactRepository )
+    {
+        this.snapshotArtifactRepository = artifactRepository;
+    }
+
+    /** {@inheritDoc} */
+    public void setOriginalModel( Model model )
+    {
+        this.originalModel = model;
+    }
+
+    /** {@inheritDoc} */
+    public Model getOriginalModel()
+    {
+        return originalModel;
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getBuildExtensions()
+     */
+    public List<Extension> getBuildExtensions()
+    {
+        return Collections.<Extension>emptyList();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_SET</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#createArtifacts(org.apache.maven.artifact.factory.ArtifactFactory, java.lang.String, org.apache.maven.artifact.resolver.filter.ArtifactFilter)
+     */
+    public Set<Artifact> createArtifacts( ArtifactFactory artifactFactory, String string, ArtifactFilter artifactFilter )
+    {
+        return Collections.<Artifact>emptySet();
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#addProjectReference(org.apache.maven.project.MavenProject)
+     */
+    public void addProjectReference( MavenProject mavenProject )
+    {
+        // nop
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.project.MavenProject#attachArtifact(java.lang.String, java.lang.String, java.io.File)
+     */
+    public void attachArtifact( String string, String string1, File file )
+    {
+        // nop
+    }
+
+    /**
+     * By default, return a new instance of <code>Properties</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getProperties()
+     */
+    public Properties getProperties()
+    {
+        return new Properties();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_LIST</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getFilters()
+     */
+    public List<String> getFilters()
+    {
+        return Collections.<String>emptyList();
+    }
+
+    /**
+     * By default, return <code>Collections.EMPTY_MAP</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#getProjectReferences()
+     */
+    public Map<String, MavenProject> getProjectReferences()
+    {
+        return Collections.<String, MavenProject>emptyMap();
+    }
+
+    /** {@inheritDoc} */
+    public boolean isExecutionRoot()
+    {
+        return executionRoot;
+    }
+
+    /** {@inheritDoc} */
+    public void setExecutionRoot( boolean b )
+    {
+        this.executionRoot = b;
+    }
+
+    /** {@inheritDoc} */
+    public String getDefaultGoal()
+    {
+        return defaultGoal;
+    }
+
+    /**
+     * By default, return <code>null</code>.
+     *
+     * @see org.apache.maven.project.MavenProject#replaceWithActiveArtifact(org.apache.maven.artifact.Artifact)
+     */
+    public Artifact replaceWithActiveArtifact( Artifact artifact )
+    {
+        return null;
+    }
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/StubArtifactCollector.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/StubArtifactCollector.java
new file mode 100644
index 0000000..b38ccab
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/StubArtifactCollector.java
@@ -0,0 +1,91 @@
+package org.apache.maven.plugin.testing.stubs;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.RepositoryRequest;
+import org.apache.maven.artifact.resolver.ArtifactCollector;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.artifact.resolver.ResolutionListener;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.repository.legacy.resolver.conflict.ConflictResolver;
+
+/**
+ * @author <a href="mailto:brianf at apache.org">Brian Fox</a>
+ * @version $Id: StubArtifactCollector.java 834917 2009-11-11 15:40:37Z olamy $
+ */
+public class StubArtifactCollector
+    implements ArtifactCollector
+{
+    /**
+     * Default constructor
+     */
+    public StubArtifactCollector()
+    {
+        super();
+    }
+
+    public ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
+                                             Map managedVersions, ArtifactResolutionRequest repositoryRequest,
+                                             ArtifactMetadataSource source, ArtifactFilter filter,
+                                             List<ResolutionListener> listeners,
+                                             List<ConflictResolver> conflictResolvers )
+    {
+        return new ArtifactResolutionResult();
+    }
+
+    public ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
+                                             Map managedVersions, ArtifactRepository localRepository,
+                                             List<ArtifactRepository> remoteRepositories,
+                                             ArtifactMetadataSource source, ArtifactFilter filter,
+                                             List<ResolutionListener> listeners,
+                                             List<ConflictResolver> conflictResolvers )
+    {
+        return new ArtifactResolutionResult();
+    }
+
+    public ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
+                                             Map managedVersions, ArtifactRepository localRepository,
+                                             List<ArtifactRepository> remoteRepositories,
+                                             ArtifactMetadataSource source, ArtifactFilter filter,
+                                             List<ResolutionListener> listeners )
+    {
+        return new ArtifactResolutionResult();
+    }
+
+    public ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
+                                             ArtifactRepository localRepository,
+                                             List<ArtifactRepository> remoteRepositories,
+                                             ArtifactMetadataSource source, ArtifactFilter filter,
+                                             List<ResolutionListener> listeners )
+        throws ArtifactResolutionException
+    {
+        return new ArtifactResolutionResult();
+    }
+
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/StubArtifactRepository.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/StubArtifactRepository.java
new file mode 100644
index 0000000..ae1bde1
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/StubArtifactRepository.java
@@ -0,0 +1,250 @@
+package org.apache.maven.plugin.testing.stubs;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.Authentication;
+import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+import org.apache.maven.repository.Proxy;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:brianf at apache.org">Brian Fox</a>
+ * @version $Id: StubArtifactRepository.java 1206336 2011-11-25 21:41:59Z olamy $
+ */
+public class StubArtifactRepository
+    implements ArtifactRepository
+{
+    private String baseDir = null;
+
+    /**
+     * Default constructor
+     *
+     * @param dir the basedir
+     */
+    public StubArtifactRepository( String dir )
+    {
+        baseDir = dir;
+    }
+
+    /**
+     * @return the <code>artifactId</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#pathOf(org.apache.maven.artifact.Artifact)
+     */
+    public String pathOf( Artifact artifact )
+    {
+        return artifact.getId();
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#pathOfRemoteRepositoryMetadata(org.apache.maven.artifact.metadata.ArtifactMetadata)
+     */
+    public String pathOfRemoteRepositoryMetadata( ArtifactMetadata artifactMetadata )
+    {
+        return null;
+    }
+
+    /**
+     * @return the filename of this metadata on the local repository.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#pathOfLocalRepositoryMetadata(org.apache.maven.artifact.metadata.ArtifactMetadata, org.apache.maven.artifact.repository.ArtifactRepository)
+     */
+    public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
+    {
+        return metadata.getLocalFilename( repository );
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#getUrl()
+     */
+    public String getUrl()
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>basedir</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#getBasedir()
+     */
+    public String getBasedir()
+    {
+        return baseDir;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#getProtocol()
+     */
+    public String getProtocol()
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#getId()
+     */
+    public String getId()
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#getSnapshots()
+     */
+    public ArtifactRepositoryPolicy getSnapshots()
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#getReleases()
+     */
+    public ArtifactRepositoryPolicy getReleases()
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#getLayout()
+     */
+    public ArtifactRepositoryLayout getLayout()
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#getKey()
+     */
+    public String getKey()
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>false</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#isUniqueVersion()
+     */
+    public boolean isUniqueVersion()
+    {
+        return false;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#setBlacklisted(boolean)
+     */
+    public void setBlacklisted( boolean blackListed )
+    {
+        // nop
+    }
+
+    /**
+     * @return <code>false</code>.
+     * @see org.apache.maven.artifact.repository.ArtifactRepository#isBlacklisted()
+     */
+    public boolean isBlacklisted()
+    {
+        return false;
+    }
+
+    public Artifact find( Artifact artifact )
+    {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Authentication getAuthentication()
+    {
+        return null;
+    }
+
+    public Proxy getProxy()
+    {
+        return null;
+    }
+
+    public void setAuthentication( Authentication authentication )
+    {
+
+    }
+
+    public void setId( String id )
+    {
+
+    }
+
+    public void setLayout( ArtifactRepositoryLayout layout )
+    {
+
+    }
+
+    public void setProxy( Proxy proxy )
+    {
+
+    }
+
+    public void setReleaseUpdatePolicy( ArtifactRepositoryPolicy policy )
+    {
+
+    }
+
+    public void setSnapshotUpdatePolicy( ArtifactRepositoryPolicy policy )
+    {
+
+    }
+
+    public void setUrl( String url )
+    {
+
+    }
+
+    public List<String> findVersions( Artifact artifact )
+    {
+        return Collections.emptyList();
+    }
+
+    public boolean isProjectAware()
+    {
+        return false;
+    }
+
+    public List<ArtifactRepository> getMirroredRepositories()
+    {
+        return new ArrayList<ArtifactRepository>( 0 );
+    }
+
+    public void setMirroredRepositories( List<ArtifactRepository> artifactRepositories )
+    {
+        // no op
+    }
+}
diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/StubArtifactResolver.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/StubArtifactResolver.java
new file mode 100644
index 0000000..77d3b32
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/stubs/StubArtifactResolver.java
@@ -0,0 +1,205 @@
+package org.apache.maven.plugin.testing.stubs;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.artifact.resolver.ResolutionListener;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.plugin.testing.ArtifactStubFactory;
+import org.apache.maven.wagon.events.TransferListener;
+
+/**
+ * Stub resolver. The constructor allows the specification of the exception to throw so that handling can be tested too.
+ *
+ * @author <a href="mailto:brianf at apache.org">Brian Fox</a>
+ * @version $Id: StubArtifactResolver.java 1340752 2012-05-20 15:20:59Z hboutemy $
+ */
+public class StubArtifactResolver
+    implements ArtifactResolver
+{
+    private boolean throwArtifactResolutionException;
+
+    private boolean throwArtifactNotFoundException;
+
+    private ArtifactStubFactory factory;
+
+    /**
+     * Default constructor
+     *
+     * @param factory
+     * @param throwArtifactResolutionException
+     * @param throwArtifactNotFoundException
+     */
+    public StubArtifactResolver( ArtifactStubFactory factory, boolean throwArtifactResolutionException,
+                                boolean throwArtifactNotFoundException )
+    {
+        this.throwArtifactNotFoundException = throwArtifactNotFoundException;
+        this.throwArtifactResolutionException = throwArtifactResolutionException;
+        this.factory = factory;
+    }
+
+    /**
+     * Creates dummy file and sets it in the artifact to simulate resolution
+     *
+     * @see org.apache.maven.artifact.resolver.ArtifactResolver#resolve(org.apache.maven.artifact.Artifact, java.util.List, org.apache.maven.artifact.repository.ArtifactRepository)
+     */
+    public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository )
+        throws ArtifactResolutionException, ArtifactNotFoundException
+    {
+        if ( !this.throwArtifactNotFoundException && !this.throwArtifactResolutionException )
+        {
+            try
+            {
+                if ( factory != null )
+                {
+                    factory.setArtifactFile( artifact, factory.getWorkingDir() );
+                }
+            }
+            catch ( IOException e )
+            {
+                throw new ArtifactResolutionException( "IOException: " + e.getMessage(), artifact, e );
+            }
+        }
+        else
+        {
+            if ( throwArtifactResolutionException )
+            {
+                throw new ArtifactResolutionException( "Catch!", artifact );
+            }
+
+            throw new ArtifactNotFoundException( "Catch!", artifact );
+        }
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.resolver.ArtifactResolver#resolveTransitively(java.util.Set, org.apache.maven.artifact.Artifact, java.util.List, org.apache.maven.artifact.repository.ArtifactRepository, org.apache.maven.artifact.metadata.ArtifactMetadataSource)
+     */
+    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
+                                                        List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository,
+                                                        ArtifactMetadataSource source )
+        throws ArtifactResolutionException, ArtifactNotFoundException
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.resolver.ArtifactResolver#resolveTransitively(java.util.Set, org.apache.maven.artifact.Artifact, java.util.List, org.apache.maven.artifact.repository.ArtifactRepository, org.apache.maven.artifact.metadata.ArtifactMetadataSource, java.util.List)
+     */
+    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
+                                                        List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository,
+                                                        ArtifactMetadataSource source, List<ResolutionListener> listeners )
+        throws ArtifactResolutionException, ArtifactNotFoundException
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.resolver.ArtifactResolver#resolveTransitively(java.util.Set, org.apache.maven.artifact.Artifact, org.apache.maven.artifact.repository.ArtifactRepository, java.util.List, org.apache.maven.artifact.metadata.ArtifactMetadataSource, org.apache.maven.artifact.resolver.filter.ArtifactFilter)
+     */
+    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
+                                                        ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories,
+                                                        ArtifactMetadataSource source, ArtifactFilter filter )
+        throws ArtifactResolutionException, ArtifactNotFoundException
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.resolver.ArtifactResolver#resolveTransitively(java.util.Set, org.apache.maven.artifact.Artifact, java.util.Map, org.apache.maven.artifact.repository.ArtifactRepository, java.util.List, org.apache.maven.artifact.metadata.ArtifactMetadataSource)
+     */
+    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
+                                                        Map managedVersions, ArtifactRepository localRepository,
+                                                        List<ArtifactRepository> remoteRepositories, ArtifactMetadataSource source )
+        throws ArtifactResolutionException, ArtifactNotFoundException
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.resolver.ArtifactResolver#resolveTransitively(java.util.Set, org.apache.maven.artifact.Artifact, java.util.Map, org.apache.maven.artifact.repository.ArtifactRepository, java.util.List, org.apache.maven.artifact.metadata.ArtifactMetadataSource, org.apache.maven.artifact.resolver.filter.ArtifactFilter)
+     */
+    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
+                                                        Map managedVersions, ArtifactRepository localRepository,
+                                                        List<ArtifactRepository> remoteRepositories, ArtifactMetadataSource source,
+                                                        ArtifactFilter filter )
+        throws ArtifactResolutionException, ArtifactNotFoundException
+    {
+        return null;
+    }
+
+    /**
+     * @return <code>null</code>.
+     * @see org.apache.maven.artifact.resolver.ArtifactResolver#resolveTransitively(java.util.Set, org.apache.maven.artifact.Artifact, java.util.Map, org.apache.maven.artifact.repository.ArtifactRepository, java.util.List, org.apache.maven.artifact.metadata.ArtifactMetadataSource, org.apache.maven.artifact.resolver.filter.ArtifactFilter, java.util.List)
+     */
+    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
+                                                        Map managedVersions, ArtifactRepository localRepository,
+                                                        List<ArtifactRepository> remoteRepositories, ArtifactMetadataSource source,
+                                                        ArtifactFilter filter, List<ResolutionListener> listeners )
+        throws ArtifactResolutionException, ArtifactNotFoundException
+    {
+        return null;
+    }
+
+    /**
+     * By default, do nothing.
+     *
+     * @see org.apache.maven.artifact.resolver.ArtifactResolver#resolveAlways(org.apache.maven.artifact.Artifact, java.util.List, org.apache.maven.artifact.repository.ArtifactRepository)
+     */
+    public void resolveAlways( Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository )
+        throws ArtifactResolutionException, ArtifactNotFoundException
+    {
+        // nop
+    }
+
+    public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository,
+                         TransferListener downloadMonitor )
+        throws ArtifactResolutionException, ArtifactNotFoundException
+    {
+        // TODO Auto-generated method stub
+        
+    }
+    
+    public ArtifactResolutionResult collect( ArtifactResolutionRequest request )
+    {
+        return null;
+    }
+
+    public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
+    {
+        return null;
+    }
+}
diff --git a/maven-plugin-testing-harness/src/main/resources/META-INF/plexus/components.xml b/maven-plugin-testing-harness/src/main/resources/META-INF/plexus/components.xml
new file mode 100644
index 0000000..915d02a
--- /dev/null
+++ b/maven-plugin-testing-harness/src/main/resources/META-INF/plexus/components.xml
@@ -0,0 +1,39 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<component-set>
+  <components>
+    <component>
+      <role>org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator</role>
+      <role-hint>stub-evaluator</role-hint>
+      <implementation>org.apache.maven.plugin.testing.StubResolverExpressionEvaluator</implementation>
+      <requirements>
+        <requirement>
+          <role>org.codehaus.plexus.PlexusContainer</role>
+          <field-name>container</field-name>
+        </requirement>
+      </requirements>
+    </component>
+    <component>
+      <role>org.apache.maven.artifact.Artifact</role>
+      <role-hint>stub</role-hint>
+      <implementation>org.apache.maven.plugin.testing.stubs.StubArtifact</implementation>
+    </component>
+  </components>
+</component-set>
\ No newline at end of file
diff --git a/maven-plugin-testing-harness/src/site/apt/examples/artifact.apt b/maven-plugin-testing-harness/src/site/apt/examples/artifact.apt
new file mode 100644
index 0000000..c5aa970
--- /dev/null
+++ b/maven-plugin-testing-harness/src/site/apt/examples/artifact.apt
@@ -0,0 +1,218 @@
+ ------
+ Testing Project Artifact
+ ------
+ Vincent Siveton
+ ------
+ February 2008
+ ------
+
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+Testing Project Artifact
+
+ <<Note>>: This example improves the {{{../getting-started/index.html}cookbook}} to play with artifact handler.
+
+ Sometimes, your Mojo uses project artifact and ArtifactHandler mechanisms. For instance, you could need to
+ filter on Java projects, i.e.:
+
+-----
+public class MyMojo
+    extends AbstractMojo
+{
+    /**
+     * The Maven Project.
+     *
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    protected MavenProject project;
+
+    public void execute()
+        throws MojoExecutionException
+    {
+        ...
+
+        ArtifactHandler artifactHandler = project.getArtifact().getArtifactHandler();
+        if ( "java".equals( artifactHandler.getLanguage() ) )
+        {
+            ...
+        }
+
+        ...
+     }
+}
+-----
+
+* Create Stubs
+
+-----
+public class MyArtifactHandlerStub
+    extends DefaultArtifactHandler
+{
+    private String language;
+
+    public String getLanguage()
+    {
+        if ( language == null )
+        {
+            language = "java";
+        }
+
+        return language;
+    }
+
+    public void setLanguage( String language )
+    {
+        this.language = language;
+    }
+}
+-----
+
+-----
+public class MyArtifactStub
+    extends ArtifactStub
+{
+    private String groupId;
+
+    private String artifactId;
+
+    private String version;
+
+    private String packaging;
+
+    private VersionRange versionRange;
+
+    private ArtifactHandler handler;
+
+    /**
+     * @param groupId
+     * @param artifactId
+     * @param version
+     * @param packaging
+     */
+    public ProjectInfoPluginArtifactStub( String groupId, String artifactId,
+                                          String version, String packaging )
+    {
+        this.groupId = groupId;
+        this.artifactId = artifactId;
+        this.version = version;
+        this.packaging = packaging;
+        versionRange = VersionRange.createFromVersion( version );
+    }
+
+    /** {@inheritDoc} */
+    public void setGroupId( String groupId )
+    {
+        this.groupId = groupId;
+    }
+
+    /** {@inheritDoc} */
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    /** {@inheritDoc} */
+    public void setArtifactId( String artifactId )
+    {
+        this.artifactId = artifactId;
+    }
+
+    /** {@inheritDoc} */
+    public String getArtifactId()
+    {
+        return artifactId;
+    }
+
+    /** {@inheritDoc} */
+    public void setVersion( String version )
+    {
+        this.version = version;
+    }
+
+    /** {@inheritDoc} */
+    public String getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * @param packaging
+     */
+    public void setPackaging( String packaging )
+    {
+        this.packaging = packaging;
+    }
+
+    /**
+     * @return the packaging
+     */
+    public String getPackaging()
+    {
+        return packaging;
+    }
+
+    /** {@inheritDoc} */
+    public VersionRange getVersionRange()
+    {
+        return versionRange;
+    }
+
+    /** {@inheritDoc} */
+    public void setVersionRange( VersionRange versionRange )
+    {
+        this.versionRange = versionRange;
+    }
+
+    /** {@inheritDoc} */
+    public ArtifactHandler getArtifactHandler()
+    {
+        return handler;
+    }
+
+    /** {@inheritDoc} */
+    public void setArtifactHandler( ArtifactHandler handler )
+    {
+        this.handler = handler;
+    }
+}
+-----
+
+-----
+public class MyProjectStub
+    extends MavenProjectStub
+{
+    /**
+     * Default constructor
+     */
+    public MyProjectStub()
+    {
+        ...
+
+        Artifact artifact = new MyArtifactStub( getGroupId(), getArtifactId(),
+                                                getVersion(), getPackaging() );
+        artifact.setArtifactHandler( new MyArtifactHandlerStub() );
+        setArtifact( artifact );
+
+        ...
+    }
+
+    ...
+}
+-----
diff --git a/maven-plugin-testing-harness/src/site/apt/examples/complex-mojo-parameters.apt b/maven-plugin-testing-harness/src/site/apt/examples/complex-mojo-parameters.apt
new file mode 100644
index 0000000..7a9caf9
--- /dev/null
+++ b/maven-plugin-testing-harness/src/site/apt/examples/complex-mojo-parameters.apt
@@ -0,0 +1,186 @@
+ ------
+ Testing Complex Mojo Parameters
+ ------
+ Vincent Siveton
+ ------
+ February 2008
+ ------
+
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+Testing Complex Mojo Parameters
+
+ <<Note>>: This example improves the {{{../getting-started/index.html}cookbook}} for testing complex Mojo parameters.
+
+ In real plugin development, you will use specific Maven objects like <<<MavenProject>>>, <<<ArtifactRepository>>> or
+ <<<MavenSettings>>>. You could use them by defining stubs.
+
+ Suppose that you have the following dependencies in the maven-my-plugin pom:
+
+-----
+<project>
+  ...
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-artifact</artifactId>
+      <version>2.0.8</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-project</artifactId>
+      <version>2.0.8</version>
+    </dependency>
+    ...
+  </dependencies>
+</project>
+-----
+
+ You will add the following in the <<<MyMojo>>>:
+
+-----
+public class MyMojo
+    extends AbstractMojo
+{
+    /**
+     * The Maven Project.
+     *
+     * @parameter expression="${project}"
+     * @required
+     * @readonly
+     */
+    protected MavenProject project;
+
+    /**
+     * Local Repository.
+     *
+     * @parameter expression="${localRepository}"
+     * @required
+     * @readonly
+     */
+    protected ArtifactRepository localRepository;
+
+    /**
+     * The Maven Settings.
+     *
+     * @parameter default-value="${settings}"
+     * @required
+     * @readonly
+     */
+    private Settings settings;
+
+    ...
+}
+-----
+
+* Create Stubs
+
+  You need to create stub objects to run <<<MyMojoTest#testSomething()>>>. By convention, the package name should
+  reflect the stubs, i.e. in our case <<<org.apache.maven.plugin.my.stubs>>>.
+
+-----
+public class MyProjectStub
+    extends MavenProjectStub
+{
+    /**
+     * Default constructor
+     */
+    public MyProjectStub()
+    {
+        MavenXpp3Reader pomReader = new MavenXpp3Reader();
+        Model model;
+        try
+        {
+            model = pomReader.read( ReaderFactory.newXmlReader( new File( getBasedir(), "pom.xml" ) ) );
+            setModel( model );
+        }
+        catch ( Exception e )
+        {
+            throw new RuntimeException( e );
+        }
+
+        setGroupId( model.getGroupId() );
+        setArtifactId( model.getArtifactId() );
+        setVersion( model.getVersion() );
+        setName( model.getName() );
+        setUrl( model.getUrl() );
+        setPackaging( model.getPackaging() );
+
+        Build build = new Build();
+        build.setFinalName( model.getArtifactId() );
+        build.setDirectory( getBasedir() + "/target" );
+        build.setSourceDirectory( getBasedir() + "/src/main/java" );
+        build.setOutputDirectory( getBasedir() + "/target/classes" );
+        build.setTestSourceDirectory( getBasedir() + "/src/test/java" );
+        build.setTestOutputDirectory( getBasedir() + "/target/test-classes" );
+        setBuild( build );
+
+        List compileSourceRoots = new ArrayList();
+        compileSourceRoots.add( getBasedir() + "/src/main/java" );
+        setCompileSourceRoots( compileSourceRoots );
+
+        List testCompileSourceRoots = new ArrayList();
+        testCompileSourceRoots.add( getBasedir() + "/src/test/java" );
+        setTestCompileSourceRoots( testCompileSourceRoots );
+    }
+
+    /** {@inheritDoc} */
+    public File getBasedir()
+    {
+        return new File( super.getBasedir() + "/src/test/resources/unit/project-to-test/" );
+    }
+}
+-----
+
+-----
+public class SettingsStub
+    extends Settings
+{
+    /** {@inheritDoc} */
+    public List getProxies()
+    {
+        return Collections.EMPTY_LIST;
+    }
+}
+-----
+
+* Configure <<<project-to-test>>> pom
+
+-----
+<project>
+  ...
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-my-plugin</artifactId>
+        <configuration>
+          <!-- Specify where this pom will output files -->
+          <outputDirectory>target/test-harness/project-to-test</outputDirectory>
+
+          <!-- By default <<<${basedir}/target/local-repo", where basedir refers
+               to the basedir of maven-my-plugin. -->
+          <localRepository>${localRepository}</localRepository>
+          <!-- The defined stubs -->
+          <project implementation="org.apache.maven.plugin.my.stubs.MyProjectStub"/>
+          <settings implementation="org.apache.maven.plugin.my.stubs.SettingsStub"/>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
+-----
diff --git a/maven-plugin-testing-harness/src/site/apt/examples/multiproject.apt b/maven-plugin-testing-harness/src/site/apt/examples/multiproject.apt
new file mode 100644
index 0000000..1564723
--- /dev/null
+++ b/maven-plugin-testing-harness/src/site/apt/examples/multiproject.apt
@@ -0,0 +1,123 @@
+ ------
+ Testing Multiproject
+ ------
+ Vincent Siveton
+ ------
+ February 2008
+ ------
+
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+Testing Multiproject
+
+ <<Note>>: This example improves the {{{../getting-started/index.html}cookbook}} for multi-project testing.
+
+ Your Mojo should have <<<@aggregator>>> parameter, i.e.:
+
+------
+/**
+ * @goal touch
+ * @aggregator
+ */
+public class MyMojo
+    extends AbstractMojo
+{
+  ...
+}
+------
+
+ To test a Mojo in a multiproject area, you need to define several stubs, i.e. for the main test project and its modules.
+
+* Create Stubs
+
+ Stub for the main test project:
+
+-----
+public class MyProjectStub
+    extends MavenProjectStub
+{
+    /**
+     * Default constructor
+     */
+    public MyProjectStub()
+    {
+        ...
+
+        setExecutionRoot( true );
+    }
+
+    /** {@inheritDoc} */
+    public MavenProject getExecutionProject()
+    {
+        return this;
+    }
+}
+-----
+
+ Stubs for the subprojects:
+
+-----
+public class SubProject1Stub
+    extends MavenProjectStub
+{
+    /**
+     * Default constructor
+     */
+    public SubProject1Stub()
+    {
+        ...
+    }
+}
+-----
+
+-----
+public class SubProject2Stub
+    extends MavenProjectStub
+{
+    /**
+     * Default constructor
+     */
+    public SubProject2Stub()
+    {
+        ...
+    }
+}
+-----
+
+* Configure <<<project-to-test>>> pom
+
+-----
+<project>
+  ...
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-my-plugin</artifactId>
+        <configuration>
+          ...
+          <project implementation="org.apache.maven.plugin.my.stubs.MyProjectStub"/>
+          <reactorProjects>
+            <project implementation="org.apache.maven.plugin.my.stubs.SubProject1Stub"/>
+            <project implementation="org.apache.maven.plugin.my.stubs.SubProject2Stub"/>
+          </reactorProjects>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
+-----
diff --git a/maven-plugin-testing-harness/src/site/apt/examples/repositories.apt b/maven-plugin-testing-harness/src/site/apt/examples/repositories.apt
new file mode 100644
index 0000000..b3b7388
--- /dev/null
+++ b/maven-plugin-testing-harness/src/site/apt/examples/repositories.apt
@@ -0,0 +1,138 @@
+ ------
+ Testing Using Repositories
+ ------
+ Vincent Siveton
+ ------
+ February 2008
+ ------
+
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+Testing Using Repositories
+
+ <<Note>>: This example improves the {{{../getting-started/index.html}cookbook}} for testing repositories.
+
+ When developing a Maven plugin you often need to play with repositories. Suppose that the MyMojo needs
+ to download artifacts into your local repository, i.e.:
+
+-----
+public class MyMojo
+    extends AbstractMojo
+{
+    /**
+     * Used for resolving artifacts
+     *
+     * @component
+     */
+    private ArtifactResolver resolver;
+
+    /**
+     * Factory for creating artifact objects
+     *
+     * @component
+     */
+    private ArtifactFactory factory;
+
+    /**
+     * Local Repository.
+     *
+     * @parameter expression="${localRepository}"
+     * @required
+     * @readonly
+     */
+    private ArtifactRepository localRepository;
+
+    public void execute()
+        throws MojoExecutionException
+    {
+        ...
+
+        Artifact artifact = factory.createArtifact( "junit", "junit", "3.8.1", "compile", "jar" );
+        try
+        {
+            resolver.resolve( artifact, project.getRemoteArtifactRepositories(), localRepository );
+        }
+        catch ( ArtifactResolutionException e )
+        {
+            throw new MojoExecutionException( "Unable to resolve artifact:" + artifact, e );
+        }
+        catch ( ArtifactNotFoundException e )
+        {
+            throw new MojoExecutionException( "Unable to find artifact:" + artifact, e );
+        }
+
+        ...
+     }
+}
+-----
+
+* Create Stubs
+
+ Stub for the test project:
+
+-----
+public class MyProjectStub
+    extends MavenProjectStub
+{
+    /**
+     * Default constructor
+     */
+    public MyProjectStub()
+    {
+        ...
+    }
+
+    /** {@inheritDoc} */
+    public List getRemoteArtifactRepositories()
+    {
+        ArtifactRepository repository = new DefaultArtifactRepository( "central", "http://repo.maven.apache.org/maven2",
+                                                                       new DefaultRepositoryLayout() );
+
+        return Collections.singletonList( repository );
+    }
+}
+-----
+
+* Configure <<<project-to-test>>> pom
+
+-----
+<project>
+  ...
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-my-plugin</artifactId>
+        <configuration>
+          <!-- Specify where this pom will output files -->
+          <outputDirectory>${basedir}/target/test-harness/project-to-test</outputDirectory>
+
+          <!-- By default <<<${basedir}/target/local-repo", where basedir refers
+               to the basedir of maven-my-plugin. -->
+          <localRepository>${localRepository}</localRepository>
+          <!-- The defined stub -->
+          <project implementation="org.apache.maven.plugin.my.stubs.MyProjectStub"/>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
+-----
+
+** Execute test
+
+ Calling <<<mvn test>>> will create <<<$\{basedir\}/target/local-repo/junitjunit/3.8.1/junit-3.8.1.jar>>> file.
diff --git a/maven-plugin-testing-harness/src/site/apt/getting-started/index.apt b/maven-plugin-testing-harness/src/site/apt/getting-started/index.apt
new file mode 100644
index 0000000..9646298
--- /dev/null
+++ b/maven-plugin-testing-harness/src/site/apt/getting-started/index.apt
@@ -0,0 +1,186 @@
+ ------
+ How To Use Maven Plugin Testing Harness
+ ------
+ Vincent Siveton
+ ------
+ 2008-08-27
+ ------
+
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+Cookbook: How To Use Maven Plugin Testing Harness?
+
+ This guide is intended as a reference for those developing Maven plugins, with self-contained references and
+ solutions for common testing cases.
+
+* Prerequisites
+
+ We assume that you have already created a plugin. In this cookbook, we make reference to <<<MyMojo>>> in
+ <<<maven-my-plugin>>> which is generated by the Maven Archetype Plugin, i.e.:
+
+-----
+mvn archetype:create \
+  -DgroupId=org.apache.maven.plugin.my \
+  -DartifactId=maven-my-plugin \
+  -DarchetypeArtifactId=maven-archetype-mojo
+-----
+
+ The generated structure should be:
+
+-----
+maven-my-plugin
+  |- pom.xml
+  +- src/
+   +- main/
+      +- java/
+        +- org/
+          +- apache/
+            +- maven/
+              +- plugin/
+                +- my/
+                  |- MyMojo.java
+-----
+
+* Recipe
+
+** Add <<<maven-plugin-testing-harness>>> dependency
+
+ As usual, just add <<<maven-plugin-testing-harness>>> as following in your pom. Be sure to specify <<<test>>> scope.
+
+-----
+<project>
+  ...
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven.plugin-testing</groupId>
+      <artifactId>maven-plugin-testing-harness</artifactId>
+      <scope>test</scope>
+    </dependency>
+    ...
+  </dependencies>
+  ...
+</project>
+-----
+
+** Create a <<<MyMojoTest>>>
+
+ Create a <<<MyMojoTest>>> (by convention) class in <<<src/test/java/org/apache/maven/plugin/my>>> directory.
+ This class should extend <<<AbstractMojoTestCase>>> from <<<maven-plugin-testing-harness>>>.
+
+-----
+public class MyMojoTest
+    extends AbstractMojoTestCase
+{
+    /** {@inheritDoc} */
+    protected void setUp()
+        throws Exception
+    {
+        // required
+        super.setUp();
+
+        ...
+    }
+
+    /** {@inheritDoc} */
+    protected void tearDown()
+        throws Exception
+    {
+        // required
+        super.tearDown();
+
+        ...
+    }
+
+    /**
+     * @throws Exception if any
+     */
+    public void testSomething()
+        throws Exception
+    {
+        File pom = getTestFile( "src/test/resources/unit/project-to-test/pom.xml" );
+        assertNotNull( pom );
+        assertTrue( pom.exists() );
+
+        MyMojo myMojo = (MyMojo) lookupMojo( "touch", pom );
+        assertNotNull( myMojo );
+        myMojo.execute();
+
+        ...
+    }
+}
+-----
+
+  In this case, <<<testSomething()>>> will test <<<MyMojo>>> against a Maven project called <<<project-to-test>>>.
+
+  <<Note>>: By convention, Mojo unit tests should be in the test resources directory.
+
+** Configuring <<<project-to-test>>> pom
+
+  Just create a pom as usual. The names for groupId and artifactId don't really matter since this project will not be deployed.
+
+-----
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+                      http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.plugin.my.unit</groupId>
+  <artifactId>project-to-test</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>jar</packaging>
+  <name>Test MyMojo</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-my-plugin</artifactId>
+        <configuration>
+          <!-- Specify the MyMojo parameter -->
+          <outputDirectory>target/test-harness/project-to-test</outputDirectory>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
+-----
+
+** Execute test
+
+ As usual, just call:
+
+-----
+mvn test
+-----
+
+* Resources
+
+ [[1]] {{{http://maven.apache.org/guides/plugin/guide-java-plugin-development.html}Guide to Developing Java Plugins}}
+
+ [[2]] {{{http://maven.apache.org/guides/mini/guide-configuring-plugins.html}Guide to Configuring Plugins}}
+
+ []
diff --git a/maven-plugin-testing-harness/src/site/apt/index.apt b/maven-plugin-testing-harness/src/site/apt/index.apt
new file mode 100644
index 0000000..bbdca2f
--- /dev/null
+++ b/maven-plugin-testing-harness/src/site/apt/index.apt
@@ -0,0 +1,46 @@
+ ------
+ Introduction
+ ------
+ Vincent Siveton
+ ------
+ February 2008
+ ------
+
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+Maven Plugin Testing Harness
+
+ The Maven Plugin Testing Harness provides mechanisms to manage tests on Mojos, i.e. by pre-constructing the
+ {{{http://plexus.codehaus.org}Plexus}} components, providing stub objects for Maven functionality such as projects,
+ and populating fields from an XML file that resembles the plugin configuration in the POM.
+
+ The best way to start is to read the cookbook {{{./getting-started/index.html}How to use Maven Plugin Testing Harness}}.
+
+* Examples
+
+   The following examples shows how to use the Testing Harness in more advanced usecases:
+
+   * {{{./examples/complex-mojo-parameters.html}Testing Complex Mojo Parameters}}
+
+   * {{{./examples/multiproject.html}Testing Multiproject}}
+
+   * {{{./examples/repositories.html}Testing Using Repositories}}
+
+   * {{{./examples/artifact.html}Testing Project Artifact}}
+
+   []
diff --git a/maven-plugin-testing-harness/src/site/fml/faq.fml b/maven-plugin-testing-harness/src/site/fml/faq.fml
new file mode 100644
index 0000000..bcc7712
--- /dev/null
+++ b/maven-plugin-testing-harness/src/site/fml/faq.fml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<faqs id="FAQ" title="Frequently Asked Questions">
+  <part id="General">
+    <faq id="What is a Mojo Testing Harness">
+      <question>What is a Mojo Testing Harness?</question>
+      <answer>
+        <p>
+          A unit test attempts to verify a mojo as an isolated unit, by mocking out the rest of the Maven environment.
+          A mojo unit test does not attempt to run your plugin in the context of a real Maven build.
+          Unit tests are designed to be fast.
+        </p>
+        <p>
+          This testing library is <b>NOT</b> designed for integration or functional testing:
+          <a href="/plugins/maven-invoker-plugin/"><code>maven-invoker-plugin</code></a> is the way to go if you need it,
+          which gives you a complete Maven environment at the cost of more resources and time consuptions.
+        </p>
+      </answer>
+    </faq>
+    <faq id="What kinds of unit tests are supported">
+      <question>What kind of unit tests are supported?</question>
+      <answer>
+        <p>
+          <dl>
+            <dt>TestCase from JUnit</dt>
+            <dd>You could use the <a href="http://junit.org/">JUnit framework</a> to test your plugin in
+              the same way you'd write any other JUnit test cases, i.e. by writing a test class which extends
+              <i>TestCase</i>.</dd>
+            <dt>TestCase from Plexus</dt>
+            <dd>Mojos are written to take specific advantage of the <a href="http://plexus.codehaus.org/plexus-containers/">Plexus
+              container</a>. If you need Plexus container services, you could write your class which extends <i>PlexusTestCase</i>,
+              instead of <i>TestCase</i>.</dd>
+            <dt>TestCase from Testing Harness</dt>
+            <dd>If you need to inject Maven objects into your mojo, you could use the <i>maven-plugin-testing-harness</i>.
+              The <i>maven-plugin-testing-harness</i> is explicitly intended to test the
+              <i>org.apache.maven.reporting.AbstractMavenReport#execute()</i> implementation.</dd>
+          </dl>
+        </p>
+      </answer>
+    </faq>
+    <faq id="Maven 2.x compatibility">
+      <question>Is Mojo Testing Harness 2.x compatible with Maven 2.x?</question>
+      <answer>
+        <p>
+          Mojo Testing Harness 2.0+ requires Maven 3.0. This does not necessary mean that your mojos will be 
+          incompatible with Maven 2.x, it only means that mojo unit tests use Maven 3.x libraries to mock Maven
+          environment. Still, if you want to be absolutely sure your mojo is compatible with Maven 2.x, then you probably want
+          to use Mojo Testing Harness 1.x.
+        </p>
+      </answer>
+    </faq>
+  </part>
+</faqs>
diff --git a/maven-plugin-testing-harness/src/site/site.xml b/maven-plugin-testing-harness/src/site/site.xml
new file mode 100644
index 0000000..479f0ce
--- /dev/null
+++ b/maven-plugin-testing-harness/src/site/site.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd">
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Getting Started" href="/getting-started/index.html"/>
+      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <item name="FAQ" href="/faq.html"/>
+    </menu>
+
+    <menu name="Examples">
+      <item name="Testing Complex Mojo Parameters" href="/examples/complex-mojo-parameters.html"/>
+      <item name="Testing Multiproject" href="/examples/multiproject.html"/>
+      <item name="Testing Repositories" href="/examples/repositories.html"/>
+      <item name="Testing Project Artifact" href="/examples/artifact.html"/>
+    </menu>
+  </body>
+</project>
diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ArtifactStubFactoryTest.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ArtifactStubFactoryTest.java
new file mode 100644
index 0000000..75d7836
--- /dev/null
+++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ArtifactStubFactoryTest.java
@@ -0,0 +1,43 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+public class ArtifactStubFactoryTest
+    extends TestCase
+{
+    public void testVersionChecks() throws IOException
+    {
+        ArtifactStubFactory factory = new ArtifactStubFactory();
+        assertTrue(factory.getReleaseArtifact().isRelease());
+        assertFalse(factory.getReleaseArtifact().isSnapshot());
+        assertTrue(factory.getSnapshotArtifact().isSnapshot());
+        assertFalse(factory.getSnapshotArtifact().isRelease());
+    }
+
+    public void testCreateFiles() throws IOException
+    {
+        ArtifactStubFactory factory = new ArtifactStubFactory();
+        assertFalse(factory.isCreateFiles());
+    }
+}
diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ExpressionEvaluatorMojo.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ExpressionEvaluatorMojo.java
new file mode 100644
index 0000000..9c0a125
--- /dev/null
+++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ExpressionEvaluatorMojo.java
@@ -0,0 +1,64 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * @author Edwin Punzalan
+ * @version $Id: ExpressionEvaluatorMojo.java 638332 2008-03-18 11:39:00Z bentmann $
+ */
+public class ExpressionEvaluatorMojo
+    extends AbstractMojo
+{
+    private String basedir;
+
+    private ArtifactRepository localRepository;
+
+    private String workdir;
+
+    /** {@inheritDoc} */
+    public void execute()
+        throws MojoExecutionException, MojoFailureException
+    {
+        if ( StringUtils.isEmpty( basedir ) )
+        {
+            throw new MojoExecutionException( "basedir was not injected." );
+        }
+
+        if ( localRepository == null )
+        {
+            throw new MojoExecutionException( "localRepository was not injected." );
+        }
+
+        if ( StringUtils.isEmpty( workdir ) )
+        {
+            throw new MojoExecutionException( "workdir was not injected." );
+        }
+        else if ( !workdir.startsWith( basedir ) )
+        {
+            throw new MojoExecutionException( "workdir does not start with basedir." );
+        }
+    }
+}
diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ExpressionEvaluatorTest.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ExpressionEvaluatorTest.java
new file mode 100644
index 0000000..df7b4cc
--- /dev/null
+++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ExpressionEvaluatorTest.java
@@ -0,0 +1,87 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
+
+import java.io.StringReader;
+
+/**
+ * @author Edwin Punzalan
+ * @version $Id: ExpressionEvaluatorTest.java 638332 2008-03-18 11:39:00Z bentmann $
+ */
+public class ExpressionEvaluatorTest
+    extends AbstractMojoTestCase
+{
+    private Xpp3Dom pomDom;
+
+    private PlexusConfiguration pluginConfiguration;
+
+    /** {@inheritDoc} */
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        StringBuffer pom = new StringBuffer();
+
+        pom.append( "<project>" ).append( "\n" );
+        pom.append( "  <build>" ).append( "\n" );
+        pom.append( "    <plugins>" ).append( "\n" );
+        pom.append( "      <plugin>" ).append( "\n" );
+        pom.append( "        <artifactId>maven-test-mojo</artifactId>" ).append( "\n" );
+        pom.append( "        <configuration>" ).append( "\n" );
+        pom.append( "          <basedir>${basedir}</basedir>" ).append( "\n" );
+        pom.append( "          <workdir>${basedir}/workDirectory</workdir>" ).append( "\n" );
+        pom.append( "          <localRepository>${localRepository}</localRepository>" ).append( "\n" );
+        pom.append( "        </configuration>" ).append( "\n" );
+        pom.append( "      </plugin>" ).append( "\n" );
+        pom.append( "    </plugins>" ).append( "\n" );
+        pom.append( "  </build>" ).append( "\n" );
+        pom.append( "</project>" ).append( "\n" );
+
+        pomDom = Xpp3DomBuilder.build( new StringReader( pom.toString() ) );
+
+        pluginConfiguration = extractPluginConfiguration( "maven-test-mojo", pomDom );
+    }
+
+    /**
+     * @throws Exception if any
+     */
+    public void testInjection()
+        throws Exception
+    {
+        ExpressionEvaluatorMojo mojo = new ExpressionEvaluatorMojo();
+
+        mojo = (ExpressionEvaluatorMojo) configureMojo( mojo, pluginConfiguration );
+
+        try
+        {
+            mojo.execute();
+        }
+        catch ( MojoExecutionException e )
+        {
+            fail( e.getMessage() );
+        }
+    }
+}
diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/MojoTestCaseTest.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/MojoTestCaseTest.java
new file mode 100644
index 0000000..82dc34f
--- /dev/null
+++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/MojoTestCaseTest.java
@@ -0,0 +1,142 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
+
+import java.io.StringReader;
+import java.util.Map;
+
+/**
+ * @author Jason van Zyl
+ * @version $Id: MojoTestCaseTest.java 638332 2008-03-18 11:39:00Z bentmann $
+ */
+public class MojoTestCaseTest
+    extends AbstractMojoTestCase
+{
+    private String pom;
+
+    private Xpp3Dom pomDom;
+
+    private PlexusConfiguration pluginConfiguration;
+
+    /** {@inheritDoc} */
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        pom =
+            "<project>" +
+                "<build>" +
+                "<plugins>" +
+                "<plugin>" +
+                "<artifactId>maven-simple-plugin</artifactId>" +
+                "<configuration>" +
+                "<keyOne>valueOne</keyOne>" +
+                "<keyTwo>valueTwo</keyTwo>" +
+                "</configuration>" +
+                "</plugin>" +
+                "</plugins>" +
+                "</build>" +
+                "</project>";
+
+        pomDom = Xpp3DomBuilder.build( new StringReader( pom ) );
+
+        pluginConfiguration = extractPluginConfiguration( "maven-simple-plugin", pomDom );
+    }
+
+    /**
+     * @throws Exception if any
+     */
+    public void testPluginConfigurationExtraction()
+        throws Exception
+    {
+        assertEquals( "valueOne", pluginConfiguration.getChild( "keyOne" ).getValue() );
+
+        assertEquals( "valueTwo", pluginConfiguration.getChild( "keyTwo" ).getValue() );
+    }
+
+    /**
+     * @throws Exception if any
+     */
+    public void testMojoConfiguration()
+        throws Exception
+    {
+        SimpleMojo mojo = new SimpleMojo();
+
+        mojo = (SimpleMojo) configureMojo( mojo, pluginConfiguration );
+
+        assertEquals( "valueOne", mojo.getKeyOne() );
+
+        assertEquals( "valueTwo", mojo.getKeyTwo() );
+    }
+
+    /**
+     * @throws Exception if any
+     */
+    public void testVariableAccessWithoutGetter()
+        throws Exception
+    {
+        SimpleMojo mojo = new SimpleMojo();
+
+        mojo = (SimpleMojo) configureMojo( mojo, pluginConfiguration );
+
+        assertEquals( "valueOne", (String)getVariableValueFromObject( mojo, "keyOne" ) );
+
+        assertEquals( "valueTwo", (String)getVariableValueFromObject( mojo, "keyTwo" ) );
+    }
+
+    /**
+     * @throws Exception if any
+     */
+     public void testVariableAccessWithoutGetter2()
+        throws Exception
+    {
+        SimpleMojo mojo = new SimpleMojo();
+
+        mojo = (SimpleMojo) configureMojo( mojo, pluginConfiguration );
+
+        Map map = getVariablesAndValuesFromObject( mojo );
+
+        assertEquals( "valueOne", (String)map.get( "keyOne" ) );
+
+        assertEquals( "valueTwo", (String)map.get( "keyTwo" ) );
+    }
+
+    /**
+     * @throws Exception if any
+     */
+    public void testSettingMojoVariables()
+        throws Exception
+    {
+        SimpleMojo mojo = new SimpleMojo();
+
+        mojo = (SimpleMojo) configureMojo( mojo, pluginConfiguration );
+
+        setVariableValueToObject( mojo, "keyOne", "myValueOne" );
+
+        assertEquals( "myValueOne", (String)getVariableValueFromObject( mojo, "keyOne" ) );
+
+    }
+
+}
diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/SimpleMojo.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/SimpleMojo.java
new file mode 100644
index 0000000..6589a0f
--- /dev/null
+++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/SimpleMojo.java
@@ -0,0 +1,50 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+
+/**
+ * @author Jason van Zyl
+ * @version $Id: SimpleMojo.java 638332 2008-03-18 11:39:00Z bentmann $
+ */
+public class SimpleMojo
+    extends AbstractMojo
+{
+    private String keyOne;
+
+    private String keyTwo;
+
+    public String getKeyOne()
+    {
+        return keyOne;
+    }
+
+    public String getKeyTwo()
+    {
+        return keyTwo;
+    }
+
+    public void execute()
+        throws MojoExecutionException
+    {
+    }
+}
diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/TestSilentLog.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/TestSilentLog.java
new file mode 100644
index 0000000..4d782df
--- /dev/null
+++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/TestSilentLog.java
@@ -0,0 +1,81 @@
+package org.apache.maven.plugin.testing;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import junit.framework.TestCase;
+
+import org.apache.maven.plugin.logging.Log;
+import org.codehaus.plexus.logging.Logger;
+
+public class TestSilentLog
+    extends TestCase
+{
+
+    public void testLog()
+    {
+        Log log = new SilentLog();
+        String text = new String( "Text" );
+        Throwable e = new RuntimeException();
+        log.debug( text );
+        log.debug( text, e );
+        log.debug( e );
+        log.info( text );
+        log.info( text, e );
+        log.info( e );
+        log.warn( text );
+        log.warn( text, e );
+        log.warn( e );
+        log.error( text );
+        log.error( text, e );
+        log.error( e );
+        log.isDebugEnabled();
+        log.isErrorEnabled();
+        log.isWarnEnabled();
+        log.isInfoEnabled();
+    }
+
+    public void testLogger()
+    {
+        Logger log = new SilentLog();
+        String text = new String( "Text" );
+        Throwable e = new RuntimeException();
+
+        log.debug( text );
+        log.debug( text, e );
+        log.error( text );
+        log.error( text, e );
+        log.warn( text );
+        log.warn( text, e );
+        log.info( text );
+        log.info( text, e );
+
+        log.fatalError( text );
+        log.fatalError( text, e );
+        log.getChildLogger( text );
+        log.getName();
+        log.getThreshold();
+        log.isDebugEnabled();
+        log.isErrorEnabled();
+        log.isFatalErrorEnabled();
+        log.isInfoEnabled();
+        log.isWarnEnabled();
+    }
+
+}
diff --git a/maven-plugin-testing-tools/pom.xml b/maven-plugin-testing-tools/pom.xml
new file mode 100644
index 0000000..0ed611d
--- /dev/null
+++ b/maven-plugin-testing-tools/pom.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.plugin-testing</groupId>
+    <artifactId>maven-plugin-testing</artifactId>
+    <version>2.0</version>
+  </parent>
+
+  <artifactId>maven-plugin-testing-tools</artifactId>
+  <name>Maven Plugin Testing Tools</name>
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/maven/plugin-testing/tags/maven-plugin-testing-2.0/maven-plugin-testing-tools</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/plugin-testing/tags/maven-plugin-testing-2.0/maven-plugin-testing-tools</developerConnection>
+    <url>http://svn.apache.org/viewvc/maven/plugin-testing/tags/maven-plugin-testing-2.0/maven-plugin-testing-tools</url>
+  </scm>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-model</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-core</artifactId>
+    </dependency>    
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-compat</artifactId>
+    </dependency>    
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-aether-provider</artifactId>
+    </dependency>    
+    <dependency>
+      <groupId>org.apache.maven.shared</groupId>
+      <artifactId>maven-invoker</artifactId>
+      <version>2.0.10</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.plugin-testing</groupId>
+      <artifactId>maven-test-tools</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-file</artifactId>
+      <version>2.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <systemProperties>
+            <property>
+              <name>maven.home</name>
+              <value>${maven.home}</value>
+            </property>
+          </systemProperties>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-component-metadata</artifactId>
+        <version>${plexusVersion}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>generate-metadata</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+    </plugins>
+  </build>
+</project>
diff --git a/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/BuildTool.java b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/BuildTool.java
new file mode 100644
index 0000000..5b3bd95
--- /dev/null
+++ b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/BuildTool.java
@@ -0,0 +1,268 @@
+package org.apache.maven.shared.test.plugin;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.maven.shared.invoker.DefaultInvocationRequest;
+import org.apache.maven.shared.invoker.DefaultInvoker;
+import org.apache.maven.shared.invoker.InvocationOutputHandler;
+import org.apache.maven.shared.invoker.InvocationRequest;
+import org.apache.maven.shared.invoker.InvocationResult;
+import org.apache.maven.shared.invoker.Invoker;
+import org.apache.maven.shared.invoker.MavenInvocationException;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+
+/**
+ * Test-tool used to execute Maven builds in order to test plugin functionality.
+ *
+ * @author jdcasey
+ * @version $Id: BuildTool.java 1185951 2011-10-19 02:43:50Z ifedorenko $
+ */
+ at Component(role=BuildTool.class)
+public class BuildTool
+    implements Initializable, Disposable
+{
+    /** Plexus role */
+    public static final String ROLE = BuildTool.class.getName();
+
+    private Invoker mavenInvoker;
+
+    /**
+     * Build a standard InvocationRequest using the specified test-build POM, command-line properties,
+     * goals, and output logfile. Then, execute Maven using this standard request. Return the result
+     * of the invocation.
+     *
+     * @param pom The test-build POM
+     * @param properties command-line properties to fine-tune the test build, or test parameter
+     *   extraction from CLI properties
+     * @param goals The list of goals and/or lifecycle phases to execute during this build
+     * @param buildLogFile The logfile used to capture build output
+     * @return The result of the Maven invocation, including exit value and any execution exceptions
+     *   resulting from the Maven invocation.
+     * @throws TestToolsException if any
+     */
+    public InvocationResult executeMaven( File pom, Properties properties, List goals, File buildLogFile )
+        throws TestToolsException
+    {
+        InvocationRequest request = createBasicInvocationRequest( pom, properties, goals, buildLogFile );
+
+        return executeMaven( request );
+    }
+
+    /**
+     * Execute a test build using a customized InvocationRequest. Normally, this request would be
+     * created using the <code>createBasicInvocationRequest</code> method in this class.
+     *
+     * @param request The customized InvocationRequest containing the configuration used to execute
+     *   the current test build
+     * @return The result of the Maven invocation, containing exit value, along with any execution
+     *   exceptions resulting from the [attempted] Maven invocation.
+     * @throws TestToolsException if any
+     */
+    public InvocationResult executeMaven( InvocationRequest request )
+        throws TestToolsException
+    {
+        try
+        {
+            return mavenInvoker.execute( request );
+        }
+        catch ( MavenInvocationException e )
+        {
+            throw new TestToolsException( "Error executing maven.", e );
+        }
+        finally
+        {
+            closeHandlers( request );
+        }
+    }
+
+    /**
+     * Detect the location of the local Maven installation, and start up the MavenInvoker using that
+     * path. Detection uses the system property <code>maven.home</code>, and falls back to the shell
+     * environment variable <code>M2_HOME</code>.
+     *
+     * @throws IOException in case the shell environment variables cannot be read
+     */
+    private void startInvoker()
+        throws IOException
+    {
+        if ( mavenInvoker == null )
+        {
+            mavenInvoker = new DefaultInvoker();
+
+            if ( System.getProperty( "maven.home" ) == null )
+            {
+                Properties envars = CommandLineUtils.getSystemEnvVars();
+
+                String mavenHome = envars.getProperty( "M2_HOME" );
+
+                if ( mavenHome != null )
+                {
+                    mavenInvoker.setMavenHome( new File( mavenHome ) );
+                }
+            }
+        }
+    }
+
+    /**
+     * If we're logging output to a logfile using standard output handlers, make sure these are
+     * closed.
+     *
+     * @param request
+     */
+    private void closeHandlers( InvocationRequest request )
+    {
+        InvocationOutputHandler outHandler = request.getOutputHandler( null );
+
+        if ( outHandler != null && ( outHandler instanceof LoggerHandler ) )
+        {
+            ( (LoggerHandler) outHandler ).close();
+        }
+
+        InvocationOutputHandler errHandler = request.getErrorHandler( null );
+
+        if ( errHandler != null && ( outHandler == null || errHandler != outHandler )
+            && ( errHandler instanceof LoggerHandler ) )
+        {
+            ( (LoggerHandler) errHandler ).close();
+        }
+    }
+
+    /**
+     * Construct a standardized InvocationRequest given the test-build POM, a set of CLI properties,
+     * a list of goals to execute, and the location of a log file to which build output should be
+     * directed. The resulting InvocationRequest can then be customized by the test class before
+     * being used to execute a test build. Both standard-out and standard-error will be directed
+     * to the specified log file.
+     *
+     * @param pom The POM for the test build
+     * @param properties The command-line properties for use in this test build
+     * @param goals The goals and/or lifecycle phases to execute during the test build
+     * @param buildLogFile Location to which build output should be logged
+     * @return The standardized InvocationRequest for the test build, ready for any necessary
+     *   customizations.
+     */
+    public InvocationRequest createBasicInvocationRequest( File pom, Properties properties, List goals,
+                                                           File buildLogFile )
+    {
+        InvocationRequest request = new DefaultInvocationRequest();
+
+        request.setPomFile( pom );
+
+        request.setGoals( goals );
+
+        request.setProperties( properties );
+
+        LoggerHandler handler = new LoggerHandler( buildLogFile );
+
+        request.setOutputHandler( handler );
+        request.setErrorHandler( handler );
+
+        return request;
+    }
+
+    private static final class LoggerHandler
+        implements InvocationOutputHandler
+    {
+        private static final String LS = System.getProperty( "line.separator" );
+
+        private final File output;
+
+        private FileWriter writer;
+
+        LoggerHandler( File logFile )
+        {
+            output = logFile;
+        }
+
+        /** {@inheritDoc} */
+        public void consumeLine( String line )
+        {
+            if ( writer == null )
+            {
+                try
+                {
+                    output.getParentFile().mkdirs();
+                    writer = new FileWriter( output );
+                }
+                catch ( IOException e )
+                {
+                    throw new IllegalStateException( "Failed to open build log: " + output + "\n\nError: "
+                        + e.getMessage() );
+                }
+            }
+
+            try
+            {
+                writer.write( line + LS );
+                writer.flush();
+            }
+            catch ( IOException e )
+            {
+                throw new IllegalStateException( "Failed to write to build log: " + output + " output:\n\n\'" + line
+                    + "\'\n\nError: " + e.getMessage() );
+            }
+        }
+
+        void close()
+        {
+            IOUtil.close( writer );
+        }
+    }
+
+    /**
+     * Initialize this tool once it's been instantiated and composed, in order to start up the
+     * MavenInvoker instance.
+     *
+     * @throws InitializationException if any
+     */
+    public void initialize()
+        throws InitializationException
+    {
+        try
+        {
+            startInvoker();
+        }
+        catch ( IOException e )
+        {
+            throw new InitializationException( "Error detecting maven home.", e );
+        }
+    }
+
+    /**
+     * Not currently used; when this API switches to use the Maven Embedder, it will be used to
+     * shutdown the embedder and its associated container, to free up JVM memory.
+     */
+    public void dispose()
+    {
+        // TODO: When we switch to the embedder, use this to deallocate the MavenEmbedder, along
+        // with the PlexusContainer and ClassRealm that it wraps.
+    }
+}
diff --git a/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/ComponentTestTool.java b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/ComponentTestTool.java
new file mode 100644
index 0000000..0cba81a
--- /dev/null
+++ b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/ComponentTestTool.java
@@ -0,0 +1,195 @@
+package org.apache.maven.shared.test.plugin;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.util.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Test tool that provides a single point of access for staging a maven component artifact - along with its
+ * POM lineage - into a clean test-time local repository. This involves modifying the component POM to
+ * provide a stable test-time version for test-build POMs to reference, then installing the component
+ * jar and associated POMs (including those ancestors that are reachable using <relativePath>)
+ * into the test local repository.
+ *
+ * <p>
+ * <b>WARNING:</b> Currently, the <code>RepositoryTool</code> will not
+ * resolve parent POMs that exist <b>only</b> in your normal local repository, and are not reachable
+ * using the relativePath element. This may result in failed test builds, as one or more of the
+ * component's ancestor POMs cannot be resolved.
+ * </p>
+ *
+ * @author jdcasey
+ * @version $Id: ComponentTestTool.java 1185951 2011-10-19 02:43:50Z ifedorenko $
+ */
+ at Component( role = ComponentTestTool.class )
+public class ComponentTestTool
+{
+    /** Plexus role */
+    public static final String ROLE = ComponentTestTool.class.getName();
+
+    @Requirement
+    private ProjectTool projectTool;
+
+    @Requirement
+    private RepositoryTool repositoryTool;
+
+    /**
+     * Stage the component, using a stable version, into a temporary local-repository directory that is
+     * generated by this method. When the component is staged, return the local repository base directory
+     * for use in test builds.
+     *
+     * @param pomFile current POM file
+     * @param testVersion The test version for the component, used for reference in test-build POMs and
+     * fully-qualified goals
+     * @return The base-directory location of the generated local repository
+     * @throws TestToolsException if any
+     */
+    public File prepareComponentForIntegrationTesting( File pomFile, String testVersion )
+        throws TestToolsException
+    {
+        return prepareForTesting( pomFile, testVersion, false, null );
+    }
+
+    /**
+     * Stage the component, using a stable version, into a temporary local-repository directory that is
+     * generated by this method. When the component is staged, return the local repository base directory
+     * for use in test builds. This method also skips unit testing during component jar production,
+     * since it is assumed that executing these tests would lead to a recursive test-and-build loop.
+     *
+     * @param pomFile current POM file
+     * @param testVersion The test version for the component, used for reference in test-build POMs and
+     * fully-qualified goals
+     * @return The base-directory location of the generated local repository
+     * @throws TestToolsException if any
+     */
+    public File prepareComponentForUnitTestingWithMavenBuilds( File pomFile, String testVersion )
+        throws TestToolsException
+    {
+        return prepareForTesting( pomFile, testVersion, true, null );
+    }
+
+    /**
+     * Stage the component, using a stable version, into the specified local-repository directory.
+     * When the component is staged, return the local repository base directory for verification.
+     *
+     * @param pomFile current POM file
+     * @param testVersion The test version for the component, used for reference in test-build POMs and
+     *   fully-qualified goals
+     * @param localRepositoryDir The base-directory location of the test local repository, into which
+     *   the component's test version should be staged.
+     * @return The base-directory location of the generated local repository
+     * @throws TestToolsException if any
+     */
+    public File prepareComponentForIntegrationTesting( File pomFile, String testVersion, File localRepositoryDir )
+        throws TestToolsException
+    {
+        return prepareForTesting( pomFile, testVersion, false, localRepositoryDir );
+    }
+
+    /**
+     * Stage the component, using a stable version, into the specified local-repository directory.
+     * When the component is staged, return the local repository base directory for verification. This
+     * method also skips unit testing during component jar production, since it is assumed that
+     * executing these tests would lead to a recursive test-and-build loop.
+     *
+     * @param pomFile current POM file
+     * @param testVersion The test version for the component, used for reference in test-build POMs and
+     * fully-qualified goals
+     * @param localRepositoryDir The base-directory location of the test local repository, into which
+     * the component's test version should be staged.
+     * @return The base-directory location of the generated local repository
+     * @throws TestToolsException if any
+     */
+    public File prepareComponentForUnitTestingWithMavenBuilds( File pomFile, String testVersion,
+                                                               File localRepositoryDir )
+        throws TestToolsException
+    {
+        return prepareForTesting( pomFile, testVersion, true, localRepositoryDir );
+    }
+
+    private File prepareForTesting( File pomFile, String testVersion, boolean skipUnitTests, File localRepositoryDir )
+        throws TestToolsException
+    {
+        File realProjectDir = pomFile.getParentFile();
+        try
+        {
+            realProjectDir = realProjectDir.getCanonicalFile();
+        }
+        catch ( IOException e )
+        {
+            throw new TestToolsException( "Failed to stage component for testing.", e );
+        }
+
+        try
+        {
+            final File tmpDir = File.createTempFile( "component-IT-staging-project", "" );
+
+            tmpDir.delete();
+
+            tmpDir.mkdirs();
+
+            Runtime.getRuntime().addShutdownHook( new Thread( new Runnable()
+            {
+                public void run()
+                {
+                    try
+                    {
+                        FileUtils.deleteDirectory( tmpDir );
+                    }
+                    catch ( IOException e )
+                    {
+                        // it'll get cleaned up when the temp dir is purged next...
+                    }
+                }
+
+            } ) );
+
+            FileUtils.copyDirectoryStructure( realProjectDir, tmpDir );
+        }
+        catch ( IOException e )
+        {
+            throw new TestToolsException( "Failed to create temporary staging directory for component project.", e );
+        }
+
+        File buildLog = new File( "target/test-build-logs/setup.build.log" );
+
+        buildLog.getParentFile().mkdirs();
+
+        File localRepoDir = localRepositoryDir;
+
+        if ( localRepoDir == null )
+        {
+            localRepoDir = new File( "target/test-local-repository" );
+        }
+
+        MavenProject project = projectTool.packageProjectArtifact( pomFile, testVersion, skipUnitTests, buildLog );
+
+        repositoryTool.createLocalRepositoryFromComponentProject( project, new File( realProjectDir, "pom.xml" ),
+                                                                  localRepoDir );
+
+        return localRepoDir;
+    }
+}
diff --git a/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/PluginTestTool.java b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/PluginTestTool.java
new file mode 100644
index 0000000..cb1c571
--- /dev/null
+++ b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/PluginTestTool.java
@@ -0,0 +1,197 @@
+package org.apache.maven.shared.test.plugin;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.util.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Test tool that provides a single point of access for staging a plugin artifact - along with its
+ * POM lineage - into a clean test-time local repository. This involves modifying the plugin POM to
+ * provide a stable test-time version for test-build POMs to reference, then installing the plugin
+ * jar and associated POMs (including those ancestors that are reachable using <relativePath>)
+ * into the test local repository.
+ *
+ * <p>
+ * <b>WARNING:</b> Currently, the <code>RepositoryTool</code> will not
+ * resolve parent POMs that exist <b>only</b> in your normal local repository, and are not reachable
+ * using the relativePath element. This may result in failed test builds, as one or more of the
+ * plugin's ancestor POMs cannot be resolved.
+ * </p>
+ *
+ * @author jdcasey
+ * @version $Id: PluginTestTool.java 1185951 2011-10-19 02:43:50Z ifedorenko $
+ */
+ at Component( role = PluginTestTool.class )
+public class PluginTestTool
+{
+    /** Plexus role */
+    public static final String ROLE = PluginTestTool.class.getName();
+
+    @Requirement
+    private ProjectTool projectTool;
+
+    @Requirement
+    private RepositoryTool repositoryTool;
+
+    /**
+     * Stage the plugin, using a stable version, into a temporary local-repository directory that is
+     * generated by this method. When the plugin is staged, return the local repository base directory
+     * for use in test builds.
+     *
+     * @param pomFile current POM file
+     * @param testVersion The test version for the plugin, used for reference in test-build POMs and
+     *   fully-qualified goals
+     * @return The base-directory location of the generated local repository
+     * @throws TestToolsException if any
+     */
+    public File preparePluginForIntegrationTesting( File pomFile, String testVersion )
+        throws TestToolsException
+    {
+        return prepareForTesting( pomFile, testVersion, false, null );
+    }
+
+    /**
+     * Stage the plugin, using a stable version, into a temporary local-repository directory that is
+     * generated by this method. When the plugin is staged, return the local repository base directory
+     * for use in test builds. This method also skips unit testing during plugin jar production,
+     * since it is assumed that executing these tests would lead to a recursive test-and-build loop.
+     *
+     * @param pomFile current POM file
+     * @param testVersion The test version for the plugin, used for reference in test-build POMs and
+     *   fully-qualified goals
+     * @return The base-directory location of the generated local repository
+     * @throws TestToolsException if any
+     */
+    public File preparePluginForUnitTestingWithMavenBuilds( File pomFile, String testVersion )
+        throws TestToolsException
+    {
+        return prepareForTesting( pomFile, testVersion, true, null );
+    }
+
+    /**
+     * Stage the plugin, using a stable version, into the specified local-repository directory.
+     * When the plugin is staged, return the local repository base directory for verification.
+     *
+     * @param pomFile current POM file
+     * @param testVersion The test version for the plugin, used for reference in test-build POMs and
+     *   fully-qualified goals
+     * @param localRepositoryDir The base-directory location of the test local repository, into which
+     *   the plugin's test version should be staged.
+     * @return The base-directory location of the generated local repository
+     * @throws TestToolsException if any
+     */
+    public File preparePluginForIntegrationTesting( File pomFile, String testVersion, File localRepositoryDir )
+        throws TestToolsException
+    {
+        return prepareForTesting( pomFile, testVersion, false, localRepositoryDir );
+    }
+
+    /**
+     * Stage the plugin, using a stable version, into the specified local-repository directory.
+     * When the plugin is staged, return the local repository base directory for verification. This
+     * method also skips unit testing during plugin jar production, since it is assumed that
+     * executing these tests would lead to a recursive test-and-build loop.
+     *
+     * @param pomFile current POM file
+     * @param testVersion The test version for the plugin, used for reference in test-build POMs and
+     *   fully-qualified goals
+     * @param localRepositoryDir The base-directory location of the test local repository, into which
+     *   the plugin's test version should be staged.
+     * @return The base-directory location of the generated local repository
+     * @throws TestToolsException if any
+     */
+    public File preparePluginForUnitTestingWithMavenBuilds( File pomFile, String testVersion, File localRepositoryDir )
+        throws TestToolsException
+    {
+        return prepareForTesting( pomFile, testVersion, true, localRepositoryDir );
+    }
+
+    private File prepareForTesting( File pomFile, String testVersion, boolean skipUnitTests, File localRepositoryDir )
+        throws TestToolsException
+    {
+        File realProjectDir = pomFile.getParentFile();
+
+        try
+        {
+            realProjectDir = realProjectDir.getCanonicalFile();
+        }
+        catch ( IOException e )
+        {
+            throw new TestToolsException( "Failed to stage plugin for testing.", e );
+        }
+
+        try
+        {
+            final File tmpDir = File.createTempFile( "plugin-IT-staging-project", "" );
+
+            tmpDir.delete();
+
+            tmpDir.mkdirs();
+
+            Runtime.getRuntime().addShutdownHook( new Thread( new Runnable()
+            {
+
+                public void run()
+                {
+                    try
+                    {
+                        FileUtils.deleteDirectory( tmpDir );
+                    }
+                    catch ( IOException e )
+                    {
+                        // it'll get cleaned up when the temp dir is purged next...
+                    }
+                }
+
+            } ) );
+
+            FileUtils.copyDirectoryStructure( realProjectDir, tmpDir );
+        }
+        catch ( IOException e )
+        {
+            throw new TestToolsException( "Failed to create temporary staging directory for plugin project.", e );
+        }
+
+        File buildLog = new File( "target/test-build-logs/setup.build.log" );
+
+        buildLog.getParentFile().mkdirs();
+
+        File localRepoDir = localRepositoryDir;
+
+        if ( localRepoDir == null )
+        {
+            localRepoDir = new File( "target/test-local-repository" );
+        }
+
+        MavenProject project = projectTool.packageProjectArtifact( pomFile, testVersion, skipUnitTests, buildLog );
+
+        repositoryTool.createLocalRepositoryFromComponentProject( project, new File( realProjectDir, "pom.xml" ),
+                                                                  localRepoDir );
+
+        return localRepoDir;
+    }
+
+}
diff --git a/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/ProjectTool.java b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/ProjectTool.java
new file mode 100644
index 0000000..5842dd7
--- /dev/null
+++ b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/ProjectTool.java
@@ -0,0 +1,497 @@
+package org.apache.maven.shared.test.plugin;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.UnknownRepositoryLayoutException;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
+import org.apache.maven.model.Build;
+import org.apache.maven.model.DeploymentRepository;
+import org.apache.maven.model.DistributionManagement;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.Site;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingException;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.artifact.ProjectArtifactMetadata;
+import org.apache.maven.repository.internal.MavenRepositorySystemSession;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.WriterFactory;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * Testing tool used to read MavenProject instances from pom.xml files, and to create plugin jar
+ * files (package phase of the normal build process) for distribution to a test local repository
+ * directory.
+ *
+ * @author jdcasey
+ * @version $Id: ProjectTool.java 1185951 2011-10-19 02:43:50Z ifedorenko $
+ */
+ at Component( role = ProjectTool.class )
+public class ProjectTool
+{
+    /** Plexus role */
+    public static final String ROLE = ProjectTool.class.getName();
+
+    public static final String INTEGRATION_TEST_DEPLOYMENT_REPO_URL = "integration-test.deployment.repo.url";
+
+    @Requirement
+    private BuildTool buildTool;
+
+    @Requirement
+    private RepositoryTool repositoryTool;
+
+    @Requirement
+    private ProjectBuilder projectBuilder;
+
+    @Requirement
+    private ArtifactHandlerManager artifactHandlerManager;
+
+    @Requirement
+    private ArtifactFactory artifactFactory;
+
+    @Requirement
+    private ArtifactRepositoryFactory artifactRepositoryFactory;
+
+    /**
+     * Construct a MavenProject instance from the specified POM file.
+     *
+     * @param pomFile current POM file
+     * @return the Maven project from a file
+     * @throws TestToolsException if any
+     */
+    public MavenProject readProject( File pomFile )
+        throws TestToolsException
+    {
+        return readProject( pomFile, repositoryTool.findLocalRepositoryDirectory() );
+    }
+
+    /**
+     * Construct a MavenProject instance from the specified POM file, using the specified local
+     * repository directory to resolve ancestor POMs as needed.
+     *
+     * @param pomFile current POM file
+     * @param localRepositoryBasedir
+     * @return the Maven project from a file and a local repo
+     * @throws TestToolsException if any
+     */
+    public MavenProject readProject( File pomFile, File localRepositoryBasedir )
+        throws TestToolsException
+    {
+        try
+        {
+            ArtifactRepository localRepository = repositoryTool
+                .createLocalArtifactRepositoryInstance( localRepositoryBasedir );
+
+            ProjectBuildingRequest request = new DefaultProjectBuildingRequest();
+            return projectBuilder.build( pomFile, request ).getProject();
+        }
+        catch ( ProjectBuildingException e )
+        {
+            throw new TestToolsException( "Error building MavenProject instance from test pom: " + pomFile, e );
+        }
+    }
+
+    /**
+     * Construct a MavenProject instance from the specified POM file with dependencies.
+     *
+     * @param pomFile current POM file
+     * @return the Maven project with dependencies from a file
+     * @throws TestToolsException if any
+     */
+    public MavenProject readProjectWithDependencies( File pomFile )
+        throws TestToolsException
+    {
+        return readProjectWithDependencies( pomFile, repositoryTool.findLocalRepositoryDirectory() );
+    }
+
+    /**
+     * Construct a MavenProject instance from the specified POM file with dependencies, using the specified local
+     * repository directory to resolve ancestor POMs as needed.
+     *
+     * @param pomFile current POM file
+     * @param localRepositoryBasedir
+     * @return the Maven project with dependencies from a file and a local repo
+     * @throws TestToolsException if any
+     */
+    public MavenProject readProjectWithDependencies( File pomFile, File localRepositoryBasedir )
+        throws TestToolsException
+    {
+        try
+        {
+            ArtifactRepository localRepository = repositoryTool
+                .createLocalArtifactRepositoryInstance( localRepositoryBasedir );
+
+            ProjectBuildingRequest request = new DefaultProjectBuildingRequest();
+            return projectBuilder.build( pomFile, request ).getProject();
+        }
+        catch ( ProjectBuildingException e )
+        {
+            throw new TestToolsException( "Error building MavenProject instance from test pom: " + pomFile, e );
+        }
+    }
+
+    /**
+     * Run the plugin's Maven build up to the package phase, in order to produce a jar file for
+     * distribution to a test-time local repository. The testVersion parameter specifies the version
+     * to be used in the <version/> element of the plugin configuration, and also in fully
+     * qualified, unambiguous goal invocations (as in
+     * org.apache.maven.plugins:maven-eclipse-plugin:test:eclipse).
+     *
+     * @param pomFile The plugin's POM
+     * @param testVersion The version to use for testing this plugin. To promote test resiliency,
+     *   this version should remain unchanged, regardless of what plugin version is under
+     *   development.
+     * @param skipUnitTests In cases where test builds occur during the unit-testing phase (usually
+     *   a bad testing smell), the plugin jar must be produced <b>without</b> running unit tests.
+     *   Otherwise, the testing process will result in a recursive loop of building a plugin jar and
+     *   trying to unit test it during the build. In these cases, set this flag to <code>true</code>.
+     * @return The resulting MavenProject, after the test version and skip flag (for unit tests)
+     *   have been appropriately configured.
+     * @throws TestToolsException if any
+     */
+    public MavenProject packageProjectArtifact( File pomFile, String testVersion, boolean skipUnitTests )
+        throws TestToolsException
+    {
+        return packageProjectArtifact( pomFile, testVersion, skipUnitTests, null );
+    }
+
+    /**
+     * Run the plugin's Maven build up to the package phase, in order to produce a jar file for
+     * distribution to a test-time local repository. The testVersion parameter specifies the version
+     * to be used in the <version/> element of the plugin configuration, and also in fully
+     * qualified, unambiguous goal invocations (as in
+     * org.apache.maven.plugins:maven-eclipse-plugin:test:eclipse).
+     *
+     * @param pomFile The plugin's POM
+     * @param testVersion The version to use for testing this plugin. To promote test resiliency,
+     *   this version should remain unchanged, regardless of what plugin version is under
+     *   development.
+     * @param skipUnitTests In cases where test builds occur during the unit-testing phase (usually
+     *   a bad testing smell), the plugin jar must be produced <b>without</b> running unit tests.
+     *   Otherwise, the testing process will result in a recursive loop of building a plugin jar and
+     *   trying to unit test it during the build. In these cases, set this flag to <code>true</code>.
+     * @param logFile The file to which build output should be logged, in order to allow later
+     *   inspection in case this build fails.
+     * @return The resulting MavenProject, after the test version and skip flag (for unit tests)
+     *   have been appropriately configured.
+     * @throws TestToolsException if any
+     */
+    public MavenProject packageProjectArtifact( File pomFile, String testVersion, boolean skipUnitTests, File logFile )
+        throws TestToolsException
+    {
+        PomInfo pomInfo = manglePomForTesting( pomFile, testVersion, skipUnitTests );
+
+        Properties properties = new Properties();
+
+        List goals = new ArrayList();
+        goals.add( "package" );
+
+        File buildLog = logFile == null ? pomInfo.getBuildLogFile() : logFile;
+        System.out.println( "Now Building test version of the plugin...\nUsing staged plugin-pom: "
+            + pomInfo.getPomFile().getAbsolutePath() );
+
+        buildTool.executeMaven( pomInfo.getPomFile(), properties, goals, buildLog );
+
+        File artifactFile = new File( pomInfo.getPomFile().getParentFile(),
+                                      pomInfo.getBuildDirectory() + "/" + pomInfo.getFinalName() );
+        System.out.println( "Using IT Plugin Jar: " + artifactFile.getAbsolutePath() );
+        try
+        {
+            ProjectBuildingRequest request = new DefaultProjectBuildingRequest();
+            request.setLocalRepository( artifactRepositoryFactory.createArtifactRepository( "local", new File( "target/localrepo" ).getCanonicalFile().toURL().toExternalForm(), "default", null, null ) );
+            request.setRepositorySession( new MavenRepositorySystemSession() );
+            MavenProject project = projectBuilder.build( pomInfo.getPomFile(), request ).getProject();
+
+            Artifact artifact = artifactFactory.createArtifact( project.getGroupId(), project.getArtifactId(), project
+                .getVersion(), null, project.getPackaging() );
+
+            artifact.setFile( artifactFile );
+            artifact.addMetadata( new ProjectArtifactMetadata( artifact, project.getFile() ) );
+
+            project.setArtifact( artifact );
+
+            return project;
+        }
+        catch ( ProjectBuildingException e )
+        {
+            throw new TestToolsException(
+                                          "Error building MavenProject instance from test pom: " + pomInfo.getPomFile(),
+                                          e );
+        }
+        catch ( UnknownRepositoryLayoutException e )
+        {
+            throw new TestToolsException(
+                                         "Error building ArtifactRepository instance from test pom: " + pomInfo.getPomFile(),
+                                         e );
+        }
+        catch ( IOException e )
+        {
+            throw new TestToolsException(
+                                         "Error building ArtifactRepository instance from test pom: " + pomInfo.getPomFile(),
+                                         e );
+        }
+    }
+
+    /**
+     * Inject a special version for testing, to allow tests to unambiguously reference the plugin
+     * currently under test. If test builds will be executed from the unit-testing phase, also inject
+     * <skip>true</skip> into the configuration of the <code>maven-surefire-plugin</code>
+     * to allow production of a test-only version of the plugin jar without running unit tests.
+     *
+     * @param pomFile The plugin POM
+     * @param testVersion The version that allows test builds to reference the plugin under test
+     * @param skipUnitTests If true, configure the surefire plugin to skip unit tests
+     * @return Information about mangled POM, including the temporary file to which it was written.
+     * @throws TestToolsException if any
+     */
+    protected PomInfo manglePomForTesting( File pomFile, String testVersion, boolean skipUnitTests )
+        throws TestToolsException
+    {
+        File input = pomFile;
+
+        File output = new File( pomFile.getParentFile(), "pom-" + testVersion + ".xml" );
+        output.deleteOnExit();
+
+        Reader reader = null;
+        Writer writer = null;
+
+        Model model = null;
+        String finalName = null;
+        String buildDirectory = null;
+
+        try
+        {
+            reader = ReaderFactory.newXmlReader( input );
+
+            model = new MavenXpp3Reader().read( reader );
+        }
+        catch ( IOException e )
+        {
+            throw new TestToolsException( "Error creating test-time version of POM for: " + input, e );
+        }
+        catch ( XmlPullParserException e )
+        {
+            throw new TestToolsException( "Error creating test-time version of POM for: " + input, e );
+        }
+        finally
+        {
+            IOUtil.close( reader );
+        }
+
+        try
+        {
+            model.setVersion( testVersion );
+
+            Build build = model.getBuild();
+            if ( build == null )
+            {
+                build = new Build();
+            }
+            buildDirectory = build.getDirectory();
+
+            if ( buildDirectory == null )
+            {
+                buildDirectory = "target";
+            }
+
+            buildDirectory = ( buildDirectory + File.separatorChar + "it-build-target" );
+            build.setDirectory( buildDirectory );
+            build.setOutputDirectory( buildDirectory + File.separatorChar + "classes" );
+            System.out.println( "Using " + build.getDirectory() + " and " + build.getOutputDirectory()
+                + " to build IT version of plugin" );
+            model.setBuild( build );
+
+            finalName = build.getFinalName();
+
+            if ( finalName == null )
+            {
+                ArtifactHandler handler = artifactHandlerManager.getArtifactHandler( model.getPackaging() );
+
+                String ext = handler.getExtension();
+
+                finalName = model.getArtifactId() + "-" + model.getVersion() + "." + ext;
+            }
+
+            DistributionManagement distMgmt = new DistributionManagement();
+
+            DeploymentRepository deployRepo = new DeploymentRepository();
+
+            deployRepo.setId( "integration-test.output" );
+
+            File tmpDir = FileUtils.createTempFile( "integration-test-repo", "", null );
+            String tmpUrl = tmpDir.toURL().toExternalForm();
+
+            deployRepo.setUrl( tmpUrl );
+
+            distMgmt.setRepository( deployRepo );
+            distMgmt.setSnapshotRepository( deployRepo );
+
+            Repository localAsRemote = new Repository();
+            localAsRemote.setId( "testing.mainLocalAsRemote" );
+
+            File localRepoDir = repositoryTool.findLocalRepositoryDirectory();
+            localAsRemote.setUrl( localRepoDir.toURL().toExternalForm() );
+
+            model.addRepository( localAsRemote );
+            model.addPluginRepository( localAsRemote );
+
+            Site site = new Site();
+
+            site.setId( "integration-test.output" );
+            site.setUrl( tmpUrl );
+
+            distMgmt.setSite( site );
+
+            model.setDistributionManagement( distMgmt );
+
+            model.addProperty( INTEGRATION_TEST_DEPLOYMENT_REPO_URL, tmpUrl );
+
+            if ( skipUnitTests )
+            {
+                List plugins = build.getPlugins();
+                Plugin plugin = null;
+                for ( Iterator iter = plugins.iterator(); iter.hasNext(); )
+                {
+                    Plugin plug = (Plugin) iter.next();
+
+                    if ( "maven-surefire-plugin".equals( plug.getArtifactId() ) )
+                    {
+                        plugin = plug;
+                        break;
+                    }
+                }
+
+                if ( plugin == null )
+                {
+                    plugin = new Plugin();
+                    plugin.setArtifactId( "maven-surefire-plugin" );
+                    build.addPlugin( plugin );
+                }
+
+                Xpp3Dom configDom = (Xpp3Dom) plugin.getConfiguration();
+                if ( configDom == null )
+                {
+                    configDom = new Xpp3Dom( "configuration" );
+                    plugin.setConfiguration( configDom );
+                }
+
+                Xpp3Dom skipDom = new Xpp3Dom( "skip" );
+                skipDom.setValue( "true" );
+
+                configDom.addChild( skipDom );
+            }
+
+            writer = WriterFactory.newXmlWriter( output );
+
+            new MavenXpp3Writer().write( writer, model );
+        }
+        catch ( IOException e )
+        {
+            throw new TestToolsException( "Error creating test-time version of POM for: " + input, e );
+        }
+        finally
+        {
+            IOUtil.close( writer );
+        }
+
+        return new PomInfo( output, model.getGroupId(), model.getArtifactId(), model.getVersion(),
+                            model.getBuild().getDirectory(), model.getBuild().getOutputDirectory(), finalName );
+    }
+
+    static final class PomInfo
+    {
+        private final File pomFile;
+
+        private final String groupId;
+
+        private final String artifactId;
+
+        private final String version;
+
+        private final String finalName;
+
+        private final String buildDirectory;
+
+        private final String buildOutputDirectory;
+
+        PomInfo( File pomFile, String groupId, String artifactId, String version, String buildDirectory,
+                 String buildOutputDirectory, String finalName )
+        {
+            this.pomFile = pomFile;
+            this.groupId = groupId;
+            this.artifactId = artifactId;
+            this.version = version;
+            this.buildDirectory = buildDirectory;
+            this.buildOutputDirectory = buildOutputDirectory;
+            this.finalName = finalName;
+        }
+
+        File getPomFile()
+        {
+            return pomFile;
+        }
+
+        String getBuildDirectory()
+        {
+            return buildDirectory;
+        }
+
+        String getBuildOutputDirectory()
+        {
+            return buildOutputDirectory;
+        }
+
+        String getFinalName()
+        {
+            return finalName;
+        }
+
+        File getBuildLogFile()
+        {
+            return new File( buildDirectory + "/test-build-logs/" + groupId + "_" + artifactId + "_" + version
+                + ".build.log" );
+        }
+    }
+}
diff --git a/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/RepositoryTool.java b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/RepositoryTool.java
new file mode 100644
index 0000000..30bd492
--- /dev/null
+++ b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/RepositoryTool.java
@@ -0,0 +1,353 @@
+package org.apache.maven.shared.test.plugin;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.MalformedURLException;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.installer.ArtifactInstallationException;
+import org.apache.maven.artifact.installer.ArtifactInstaller;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
+import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+import org.apache.maven.execution.DefaultMavenExecutionRequest;
+import org.apache.maven.execution.DefaultMavenExecutionResult;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.plugin.LegacySupport;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.artifact.ProjectArtifactMetadata;
+import org.apache.maven.repository.internal.MavenRepositorySystemSession;
+import org.apache.maven.settings.MavenSettingsBuilder;
+import org.apache.maven.settings.Settings;
+import org.codehaus.plexus.PlexusConstants;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.context.Context;
+import org.codehaus.plexus.context.ContextException;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * Tools to access and manage Maven repositories for test builds, including construction of a local
+ * repository directory structure.
+ *
+ * <p>
+ * <b>WARNING:</b> Currently, the <code>createLocalRepositoryFromPlugin</code> method will not
+ * resolve parent POMs that exist <b>only</b> in your normal local repository, and are not reachable
+ * using the relativePath element. This may result in failed test builds, as one or more of the
+ * plugin's ancestor POMs cannot be resolved.
+ * </p>
+ *
+ * @author jdcasey
+ * @version $Id: RepositoryTool.java 1185951 2011-10-19 02:43:50Z ifedorenko $
+ */
+ at Component( role = RepositoryTool.class )
+public class RepositoryTool
+    implements Contextualizable
+{
+    /** Plexus role */
+    public static final String ROLE = RepositoryTool.class.getName();
+
+    @Requirement
+    private ArtifactRepositoryFactory repositoryFactory;
+
+    @Requirement
+    private MavenSettingsBuilder settingsBuilder;
+
+    @Requirement
+    private ArtifactFactory artifactFactory;
+
+    @Requirement
+    private ArtifactInstaller artifactInstaller;
+
+    @Requirement
+    private LegacySupport legacySupport;
+
+    // contextualized.
+    private PlexusContainer container;
+
+    /**
+     * Lookup and return the location of the normal Maven local repository.
+     *
+     * @return the location of the normal Maven local repository.
+     * @throws TestToolsException if any
+     */
+    public File findLocalRepositoryDirectory()
+        throws TestToolsException
+    {
+        String localRepo = System.getProperty( "maven.local.repo" );
+        if ( StringUtils.isNotEmpty( localRepo ) )
+        {
+            return new File( localRepo );
+        }
+
+        Settings settings;
+        try
+        {
+            DefaultMavenExecutionRequest request = new DefaultMavenExecutionRequest();
+            request.setUserSettingsFile( new File( System.getProperty( "user.home" ), ".m2/settings.xml" ) );
+            request.setGlobalSettingsFile( new File( System.getProperty( "maven.home" ), "conf/settings.xml" ) );
+            settings = settingsBuilder.buildSettings( request );
+        }
+        catch ( IOException e )
+        {
+            throw new TestToolsException( "Error building Maven settings.", e );
+        }
+        catch ( XmlPullParserException e )
+        {
+            throw new TestToolsException( "Error building Maven settings.", e );
+        }
+
+        if ( settings == null || settings.getLocalRepository() == null
+            || settings.getLocalRepository().trim().length() < 1 )
+        {
+            return new File( System.getProperty( "user.home" ), ".m2/repository" );
+        }
+
+        return new File( settings.getLocalRepository() );
+    }
+
+    /**
+     * Construct an ArtifactRepository instance that refers to the normal Maven local repository.
+     *
+     * @return an ArtifactRepository instance
+     * @throws TestToolsException if any
+     */
+    public ArtifactRepository createLocalArtifactRepositoryInstance()
+        throws TestToolsException
+    {
+        File localRepoDir = findLocalRepositoryDirectory();
+
+        return createLocalArtifactRepositoryInstance( localRepoDir );
+    }
+
+    /**
+     * Construct an ArtifactRepository instance that refers to the test-time Maven local repository.
+     *
+     * @param localRepositoryDirectory The location of the local repository to be used for test builds.
+     * @return an ArtifactRepository instance
+     * @throws TestToolsException if any
+     */
+    public ArtifactRepository createLocalArtifactRepositoryInstance( File localRepositoryDirectory )
+        throws TestToolsException
+    {
+        ArtifactRepositoryLayout defaultLayout;
+        try
+        {
+            defaultLayout = (ArtifactRepositoryLayout) container.lookup( ArtifactRepositoryLayout.ROLE, "default" );
+        }
+        catch ( ComponentLookupException e )
+        {
+            throw new TestToolsException( "Error retrieving default repository layout.", e );
+        }
+
+        try
+        {
+            return repositoryFactory.createArtifactRepository( "local", localRepositoryDirectory.toURL()
+                .toExternalForm(), defaultLayout, null, null );
+        }
+        catch ( MalformedURLException e )
+        {
+            throw new TestToolsException( "Error converting local repo directory to a URL.", e );
+        }
+    }
+
+    /**
+     * Install a test version of a plugin - along with its POM, and as many ancestor POMs as can be
+     * reached using the <relativePath/> element - to a clean local repository directory for
+     * use in test builds.
+     *
+     * <p>
+     * <b>WARNING:</b> Currently, this method will not resolve parent POMs that exist <b>only</b> in
+     * your normal local repository, and are not reachable using the relativePath element. This may
+     * result in failed test builds, as one or more of the plugin's ancestor POMs cannot be resolved.
+     * </p>
+     *
+     * @param project
+     * @param realPomFile
+     * @param targetLocalRepoBasedir
+     * @throws TestToolsException if any
+     */
+    public void createLocalRepositoryFromComponentProject( MavenProject project, File realPomFile,
+                                                           File targetLocalRepoBasedir )
+        throws TestToolsException
+    {
+        Artifact artifact = project.getArtifact();
+
+        if ( "pom".equals( project.getPackaging() ) )
+        {
+            artifact.setFile( project.getFile() );
+        }
+
+        ArtifactRepository localRepository = createLocalArtifactRepositoryInstance( targetLocalRepoBasedir );
+
+        String localPath = localRepository.pathOf( artifact );
+
+        File destination = new File( localRepository.getBasedir(), localPath );
+        if ( !destination.getParentFile().exists() )
+        {
+            destination.getParentFile().mkdirs();
+        }
+
+        legacySupport.setSession( new MavenSession( container, new MavenRepositorySystemSession(),
+                                                    new DefaultMavenExecutionRequest(),
+                                                    new DefaultMavenExecutionResult() ) );
+        try
+        {
+            artifactInstaller.install( artifact.getFile(), artifact, localRepository );
+        }
+        catch ( ArtifactInstallationException e )
+        {
+            throw new TestToolsException( "Error installing plugin artifact to target local repository: "
+                + targetLocalRepoBasedir, e );
+        }
+        finally
+        {
+            legacySupport.setSession( null );
+        }
+
+        installLocallyReachableAncestorPoms( realPomFile, localRepository );
+    }
+
+    /**
+     * Traverse <relativePath/> links for successive POMs in the plugin's ancestry, installing
+     * each one into the test-time local repository.
+     *
+     * @param realPomFile The real plugin POM; a starting point, but the POM is already installed,
+     *   so we won't actually install this file, only use it to locate parents.
+     * @param localRepo The test-time local repository instance
+     * @throws TestToolsException if any
+     */
+    private void installLocallyReachableAncestorPoms( File realPomFile, ArtifactRepository localRepo )
+        throws TestToolsException
+    {
+        MavenXpp3Reader pomReader = new MavenXpp3Reader();
+
+        File pom = realPomFile;
+
+        boolean firstPass = true;
+
+        while ( pom != null )
+        {
+
+            if ( !pom.exists() )
+            {
+                pom = null;
+                break;
+            }
+
+            String pomGroupId = null;
+            String pomArtifactId = null;
+            String pomVersion = null;
+
+            Reader reader = null;
+
+            File currentPom = pom;
+
+            try
+            {
+                reader = ReaderFactory.newXmlReader( pom );
+
+                Model model = pomReader.read( reader );
+
+                pomGroupId = model.getGroupId();
+                pomArtifactId = model.getArtifactId();
+                pomVersion = model.getVersion();
+
+                Parent parent = model.getParent();
+                if ( parent != null )
+                {
+                    pom = new File( pom.getParentFile(), parent.getRelativePath() );
+
+                    if ( pomGroupId == null )
+                    {
+                        pomGroupId = parent.getGroupId();
+                    }
+
+                    if ( pomVersion == null )
+                    {
+                        pomVersion = parent.getVersion();
+                    }
+                }
+                else
+                {
+                    pom = null;
+                }
+            }
+            catch ( IOException e )
+            {
+                throw new TestToolsException( "Error reading ancestor POM: " + currentPom, e );
+            }
+            catch ( XmlPullParserException e )
+            {
+                throw new TestToolsException( "Error reading ancestor POM: " + currentPom, e );
+            }
+            finally
+            {
+                IOUtil.close( reader );
+            }
+
+            if ( !firstPass )
+            {
+                Artifact pomArtifact = artifactFactory.createProjectArtifact( pomGroupId, pomArtifactId, pomVersion );
+                pomArtifact.addMetadata( new ProjectArtifactMetadata( pomArtifact, currentPom ) );
+
+                try
+                {
+                    artifactInstaller.install( currentPom, pomArtifact, localRepo );
+                }
+                catch ( ArtifactInstallationException e )
+                {
+                    throw new TestToolsException( "Error installing ancestor POM: " + currentPom
+                        + " to target local repository: " + localRepo.getBasedir(), e );
+                }
+            }
+            else
+            {
+                firstPass = false;
+            }
+        }
+    }
+
+    /**
+     * Retrieve the PlexusContainer instance used to instantiate this component. The container is
+     * used to retrieve the default ArtifactRepositoryLayout component, for use in constructing
+     * instances of ArtifactRepository that can be used to access local repositories.
+     *
+     * @see org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable#contextualize(org.codehaus.plexus.context.Context)
+     */
+    public void contextualize( Context context )
+        throws ContextException
+    {
+        this.container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
+    }
+}
diff --git a/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/TestToolsException.java b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/TestToolsException.java
new file mode 100644
index 0000000..10ad319
--- /dev/null
+++ b/maven-plugin-testing-tools/src/main/java/org/apache/maven/shared/test/plugin/TestToolsException.java
@@ -0,0 +1,48 @@
+package org.apache.maven.shared.test.plugin;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Wrap errors when Test Tools exception occurred.
+ *
+ * @version $Id: TestToolsException.java 677115 2008-07-16 00:16:13Z vsiveton $
+ */
+public class TestToolsException
+    extends Exception
+{
+    static final long serialVersionUID = -2578830270609952507L;
+
+    /**
+     * @param message given message
+     * @param cause given cause
+     */
+    public TestToolsException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+    /**
+     * @param message a given message
+     */
+    public TestToolsException( String message )
+    {
+        super( message );
+    }
+}
diff --git a/maven-plugin-testing-tools/src/site/apt/index.apt b/maven-plugin-testing-tools/src/site/apt/index.apt
new file mode 100644
index 0000000..4d3568e
--- /dev/null
+++ b/maven-plugin-testing-tools/src/site/apt/index.apt
@@ -0,0 +1,125 @@
+  ---
+  Introduction
+  ---
+  John Casey
+  ---
+  13 November 2006
+  ---
+  
+Maven Plugin Testing Tools
+
+  This API is meant to provide a series of convenience tools for developers wishing to test Maven 
+  plugins. The primary focus of the library is on integration testing, since it is not well-supported
+  with current tools and approaches.
+
+* Special Problems with Plugin Integration Testing
+
+  Maven plugins represent a somewhat special need in terms of integration testing. Like many 
+  component-oriented systems, Maven provides much of the runtime context essential for testing a 
+  plugin in its "natural environment". This means that, in order to properly test the integration of
+  any particular plugin into the larger system, the developer should really execute Maven builds
+  that test particular features of the plugin in question.
+  
+  However, running test builds from within the plugin's own build presents some special problems.
+  Since we're using Maven to build the Maven plugin, we have to deal with the fact that a previous
+  version of the plugin could be active within the current build (not a great practice, but sometimes
+  unavoidable). This means that Maven must either be smart enough to unload the existing plugin-version
+  from the runtime context and load the newer version - and correspondingly, unload the test version
+  and reload the older version for other, later builds in the same reactor. As an alternative, the
+  integration-testing of the plugin could fork separate Maven builds, and track the output in order
+  to verify results and determine whether the build succeeds. The latter approach, while much slower
+  and somewhat dependent on local-system configuration, is currently the most robust way to avoid 
+  existing versions of the plugin under test.
+  
+  In addition to plugin-version inconsistencies, integration-testing of Maven plugins must cope with
+  the need to cleanup after themselves. Remember, Maven only loads plugins from its own local repository
+  (possibly after resolving them from a remote repository). Because of this, the only practical way 
+  to use the current plugin within an integration-test build is to install it into some sort of local 
+  repository, then direct Maven to use that local repository for the build. To avoid side effects in
+  other builds (remember, we're building Maven plugins here... and they're used to build other projects),
+  it's critical to avoid using the main local repository used for normal Maven builds. Therefore,
+  plugin integration tests require a custom local repository, to which the integration-testing builds
+  can be directed. Further complicating this testing scenario is the fact that the plugin's parent
+  POM or one of its ancestor POMs could be a snapshot which has been installed in the main local
+  repository, but which is not reachable using the plugin-POM's <<<\<relativePath/\>>>>
+  parent-element.<+>
+  
+  <+ All of this seems to indicate that the best approach for ensuring the presence of all required
+  POMs and plugins is to use the normal local repository to construct a new local repository for
+  testing purposes. Work on this is ongoing.>
+  
+  Finally, in order to support integration-testing of plugins, it's important to give the developer
+  an API by which to bootstrap the testing environment (and ideally, detect when it's already been 
+  bootstrapped), and to also provide a robust API for executing builds and verifying results.
+  
+* A Note on Test-Suite Maintenance
+
+  Since failure to grasp the use cases of any system is a virtual guarantee that it will not meet
+  the needs of the user, it's important to understand how integration tests are really used.
+  
+  First and foremost, integration tests are used as a one-way valve, to ensure that no feature of
+  the application - in our case, a Maven plugin - regresses as the result of unrelated development.
+  A good set of tests - of which the integration tests are, well, integral - can provide the developer
+  with freedom to implement new features with the confidence that he's able to effectively build on
+  the foundations of previous versions.
+  
+  However, it's important to understand that regression-prevention is not the sole purpose of an
+  integration test. A secondary but critical use case deals with how integration tests are added to
+  the plugin. One has only to consider how bugs are reported on a flawed system to understand. Since
+  users usually report bugs, bug reports originate outside of the system. In the case of a Maven
+  plugin, this means users are most likely able to supply examples of the failing behavior in the
+  form of failing builds. In order to make immediate and direct use of what the user gives us, it's
+  critical that integration tests are designed to be augmented using build examples from the user,
+  with as little rewriting as possible.
+  
+  To that end, the approach for integration testing in this library will be the execution of sample
+  builds that use the plugin in question, then verify the results, either in the logs, the resulting
+  exit code, or the project files it produces.
+  
+* Integration-Testing Requirements
+
+  To summarize, this library strives to satisfy the following requirements for integration testing 
+  of Maven plugins:
+  
+  * Trigger Maven builds using test projects, without incurring any sort of conflict with plugins
+    already in use within the current (this plugin's) build.
+    
+  * Construct a local repository into which the test version of the plugin can be installed, 
+    allowing the main local repository to remain untouched by the tests. Integration tests can be 
+    directed to use this test-time local repository instead of the normal location.
+    
+  * Support tracking and analysis of results from Maven builds spawned during integration testing. 
+    As far as is reasonable, test builds should be configured in the same way as normal project 
+    builds, to make the most of test cases submitted by users along with the issues they file.
+    
+  []
+    
+* Utilities Included in this Library
+
+  For more information on the APIs described below, see the {{{./apidocs/index.html}JavaDocs}}.
+
+  * <<PluginTestTool>> - The main entry point for setting up the plugin-testing environment, this
+    utility orchestrates the ProjectTool, RepositoryTool, and BuildTool in order to produce a local
+    repository containing the plugin jar, plus any ancestor POM files that are reachable using the
+    <<<\<relativePath/\>>>> element of the parent specification.
+    
+    In order to make test projects more resilient to changes in the plugin's version, this tool
+    allows the developer to specify a testing version for the plugin, so any reference to the plugin
+    can be unambiguous and avoid accidentally referring to a plugin version resolved from outside.
+    
+  * <<ProjectTool>> - This testing tool provides APIs for creating a testable plugin jar file,
+    optionally skipping the unit tests for the plugin (after all, it's conceivable that the unit 
+    tests themselves may be using these tools).
+    
+  * <<RepositoryTool>> - The RepositoryTool provides methods for assembling artifact repositories to
+    support testing. This tool is responsible for assembling the local repository that is used 
+    during integration testing - complete with the test version of the plugin itself, along with all
+    of the ancestor POMs that are reachable via <<<\<relativePath/\>>>>.
+    
+  * <<BuildTool>> - This tool's purpose is fairly self-explanatory; it is used to execute Maven
+    builds. It provides a fairly generic API for running builds, for the simple reason that a single
+    test may need to run multiple builds. For normal use cases, it's a good idea to wrap the
+    BuildTool API using a standard project-testing method that will standardize the options used to
+    run a similar set of test builds.
+    
+  []
diff --git a/maven-plugin-testing-tools/src/site/site.xml b/maven-plugin-testing-tools/src/site/site.xml
new file mode 100644
index 0000000..b6412d5
--- /dev/null
+++ b/maven-plugin-testing-tools/src/site/site.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd">
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+  </body>
+</project>
diff --git a/maven-plugin-testing-tools/src/test/java/org/apache/maven/shared/test/plugin/ProjectToolTest.java b/maven-plugin-testing-tools/src/test/java/org/apache/maven/shared/test/plugin/ProjectToolTest.java
new file mode 100644
index 0000000..9da1498
--- /dev/null
+++ b/maven-plugin-testing-tools/src/test/java/org/apache/maven/shared/test/plugin/ProjectToolTest.java
@@ -0,0 +1,115 @@
+package org.apache.maven.shared.test.plugin;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.artifact.ProjectArtifactMetadata;
+import org.apache.maven.shared.test.plugin.ProjectTool.PomInfo;
+import org.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * @version $Id: ProjectToolTest.java 881038 2009-11-16 23:14:09Z bentmann $
+ */
+public class ProjectToolTest
+    extends PlexusTestCase
+{
+
+    private File getPom( String test )
+        throws IOException
+    {
+        File src = new File( "src/test/resources/projects/" + test );
+        File dst = new File( "target/unit/projects/" + test );
+
+        FileUtils.copyDirectoryStructureIfModified( src, dst );
+
+        return new File( dst, "pom.xml" );
+    }
+
+    public void testManglePomForTesting_ShouldPopulateOutDirAndFinalName()
+        throws Exception
+    {
+        ProjectTool tool = (ProjectTool) lookup( ProjectTool.ROLE, "default" );
+
+        File pomFile = getPom( "basic" );
+
+        PomInfo info = tool.manglePomForTesting( pomFile, "test", true );
+
+        assertEquals( "target"+File.separatorChar+"it-build-target", info.getBuildDirectory() );
+        assertEquals( "maven-it-plugin-test.jar", info.getFinalName() );
+        assertEquals( "target"+File.separatorChar+"it-build-target"+File.separatorChar+"classes",info.getBuildOutputDirectory() );
+    }
+
+    public void testPackageProjectArtifact_ShouldPopulateArtifactFileWithJarLocation()
+        throws Exception
+    {
+        ProjectTool tool = (ProjectTool) lookup( ProjectTool.ROLE, "default" );
+
+        File pomFile = getPom( "basic" );
+
+        MavenProject project = tool.packageProjectArtifact( pomFile, "test", true );
+
+        String expectedPath = "target/unit/projects/basic/target/it-build-target/maven-it-plugin-test.jar";
+
+        // be nice with windows
+        String actualPath = StringUtils.replace( project.getArtifact().getFile().getPath(), "\\", "/" );
+
+        assertEquals( expectedPath, actualPath );
+    }
+
+    public void testPackageProjectArtifact_ShouldPopulateWithCorrectArtifactAndMetadata()
+        throws Exception
+    {
+        ProjectTool tool = (ProjectTool) lookup( ProjectTool.ROLE, "default" );
+
+        File pomFile = getPom( "basic" );
+
+        MavenProject project = tool.packageProjectArtifact( pomFile, "test", true );
+
+        Artifact artifact = project.getArtifact();
+
+        assertEquals( "maven-plugin", artifact.getType() );
+        assertTrue( "Missing " + artifact.getFile(), artifact.getFile().exists() );
+
+        Collection metadata = artifact.getMetadataList();
+
+        boolean foundPomMetadata = false;
+
+        for ( Iterator it = metadata.iterator(); it.hasNext(); )
+        {
+            ArtifactMetadata metadataItem = (ArtifactMetadata) it.next();
+
+            if ( metadataItem instanceof ProjectArtifactMetadata )
+            {
+                foundPomMetadata = true;
+            }
+        }
+
+        assertTrue( foundPomMetadata );
+    }
+}
diff --git a/maven-plugin-testing-tools/src/test/java/org/apache/maven/shared/test/plugin/RepositoryToolTest.java b/maven-plugin-testing-tools/src/test/java/org/apache/maven/shared/test/plugin/RepositoryToolTest.java
new file mode 100644
index 0000000..9b3ab5e
--- /dev/null
+++ b/maven-plugin-testing-tools/src/test/java/org/apache/maven/shared/test/plugin/RepositoryToolTest.java
@@ -0,0 +1,87 @@
+package org.apache.maven.shared.test.plugin;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.artifact.ProjectArtifactMetadata;
+import org.apache.maven.shared.tools.easymock.TestFileManager;
+import org.codehaus.plexus.PlexusTestCase;
+
+/**
+ * @version $Id: RepositoryToolTest.java 677115 2008-07-16 00:16:13Z vsiveton $
+ */
+public class RepositoryToolTest
+    extends PlexusTestCase
+{
+    private TestFileManager fileManager;
+
+    public void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        fileManager = new TestFileManager( "RepositoryToolTest.", "" );
+    }
+
+    public void tearDown()
+        throws Exception
+    {
+        super.tearDown();
+
+        fileManager.cleanUp();
+    }
+
+    public void testCreateLocalRepositoryFromPlugin_ShouldWriteJarAndPom()
+        throws Exception
+    {
+        RepositoryTool repoTool = (RepositoryTool) lookup( RepositoryTool.ROLE, "default" );
+
+        File tempDir = fileManager.createTempDir();
+
+        String pomContent = "<project><modelVersion>4.0.0</modelVersion></project>";
+        String jarContent = "This is a test";
+
+        File pom = fileManager.createFile( tempDir, "pom.xml", pomContent );
+        File jar = fileManager.createFile( tempDir, "artifact-test.jar", jarContent );
+
+        MavenProject pluginProject = new MavenProject();
+
+        ArtifactFactory artifactFactory = (ArtifactFactory) lookup( ArtifactFactory.ROLE );
+
+        Artifact pluginArtifact = artifactFactory.createArtifact( "group", "artifact", "test", null, "jar" );
+        pluginArtifact.setFile( jar );
+        pluginArtifact.addMetadata( new ProjectArtifactMetadata( pluginArtifact, pom ) );
+
+        pluginProject.setArtifact( pluginArtifact );
+        pluginProject.setFile( pom );
+
+        File targetLocalRepoBasedir = fileManager.createTempDir();
+
+        repoTool.createLocalRepositoryFromComponentProject( pluginProject, pom, targetLocalRepoBasedir );
+
+        fileManager.assertFileExistence( targetLocalRepoBasedir, "group/artifact/test/artifact-test.pom", true );
+        fileManager.assertFileContents( targetLocalRepoBasedir, "group/artifact/test/artifact-test.jar", jarContent );
+
+    }
+}
diff --git a/maven-plugin-testing-tools/src/test/resources/projects/basic/pom.xml b/maven-plugin-testing-tools/src/test/resources/projects/basic/pom.xml
new file mode 100644
index 0000000..962c792
--- /dev/null
+++ b/maven-plugin-testing-tools/src/test/resources/projects/basic/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.its.plugins</groupId>
+  <artifactId>maven-it-plugin</artifactId>
+  <version>2.0-SNAPSHOT</version>
+  <packaging>maven-plugin</packaging>
+
+  <name>Maven IT Plugin</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>2.0</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/maven-plugin-testing-tools/src/test/resources/projects/basic/src/main/java/ItMojo.java b/maven-plugin-testing-tools/src/test/resources/projects/basic/src/main/java/ItMojo.java
new file mode 100644
index 0000000..d8132df
--- /dev/null
+++ b/maven-plugin-testing-tools/src/test/resources/projects/basic/src/main/java/ItMojo.java
@@ -0,0 +1,14 @@
+import org.apache.maven.plugin.*;
+
+/**
+ * @goal it
+ */
+public class ItMojo
+    extends AbstractMojo
+{
+
+    public void execute()
+    {
+    }
+
+}
diff --git a/maven-test-tools/pom.xml b/maven-test-tools/pom.xml
new file mode 100644
index 0000000..0fdf28c
--- /dev/null
+++ b/maven-test-tools/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.plugin-testing</groupId>
+    <artifactId>maven-plugin-testing</artifactId>
+    <version>2.0</version>
+  </parent>
+
+  <artifactId>maven-test-tools</artifactId>
+  <name>Maven Testing Tools</name>
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/maven/plugin-testing/tags/maven-plugin-testing-2.0/maven-test-tools</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/plugin-testing/tags/maven-plugin-testing-2.0/maven-test-tools</developerConnection>
+    <url>http://svn.apache.org/viewvc/maven/plugin-testing/tags/maven-plugin-testing-2.0/maven-test-tools</url>
+  </scm>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <version>1.2_Java1.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/maven-test-tools/src/main/java/org/apache/maven/shared/tools/easymock/MockManager.java b/maven-test-tools/src/main/java/org/apache/maven/shared/tools/easymock/MockManager.java
new file mode 100644
index 0000000..e270837
--- /dev/null
+++ b/maven-test-tools/src/main/java/org/apache/maven/shared/tools/easymock/MockManager.java
@@ -0,0 +1,79 @@
+package org.apache.maven.shared.tools.easymock;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.easymock.MockControl;
+
+/**
+ * Manager of MockControl
+ *
+ * @version $Id: MockManager.java 677117 2008-07-16 00:29:56Z vsiveton $
+ * @see MockControl
+ */
+public class MockManager
+{
+    private List mockControls = new ArrayList();
+
+    /**
+     * @param control to be add to the manager
+     */
+    public void add( MockControl control )
+    {
+        mockControls.add( control );
+    }
+
+    /**
+     * Clear all controls from the manager
+     */
+    public void clear()
+    {
+        mockControls.clear();
+    }
+
+    /**
+     * @see MockControl#replay()
+     */
+    public void replayAll()
+    {
+        for ( Iterator it = mockControls.iterator(); it.hasNext(); )
+        {
+            MockControl control = (MockControl) it.next();
+
+            control.replay();
+        }
+    }
+
+    /**
+     * @see MockControl#verify()
+     */
+    public void verifyAll()
+    {
+        for ( Iterator it = mockControls.iterator(); it.hasNext(); )
+        {
+            MockControl control = (MockControl) it.next();
+
+            control.verify();
+        }
+    }
+}
diff --git a/maven-test-tools/src/main/java/org/apache/maven/shared/tools/easymock/TestFileManager.java b/maven-test-tools/src/main/java/org/apache/maven/shared/tools/easymock/TestFileManager.java
new file mode 100644
index 0000000..f2e5514
--- /dev/null
+++ b/maven-test-tools/src/main/java/org/apache/maven/shared/tools/easymock/TestFileManager.java
@@ -0,0 +1,303 @@
+package org.apache.maven.shared.tools.easymock;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.Assert;
+
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.IOUtil;
+
+/**
+ * @version $Id: TestFileManager.java 677117 2008-07-16 00:29:56Z vsiveton $
+ */
+public class TestFileManager
+{
+    /** Temp dir from "java.io.tmpdir" property */
+    public static final String TEMP_DIR_PATH = System.getProperty( "java.io.tmpdir" );
+
+    private List filesToDelete = new ArrayList();
+
+    private final String baseFilename;
+
+    private final String fileSuffix;
+
+    private StackTraceElement callerInfo;
+
+    private Thread cleanupWarning;
+
+    private boolean warnAboutCleanup = false;
+
+    /**
+     * Default constructor
+     *
+     * @param baseFilename
+     * @param fileSuffix
+     */
+    public TestFileManager( String baseFilename, String fileSuffix )
+    {
+        this.baseFilename = baseFilename;
+        this.fileSuffix = fileSuffix;
+
+        initializeCleanupMonitoring();
+    }
+
+    private void initializeCleanupMonitoring()
+    {
+        callerInfo = new NullPointerException().getStackTrace()[2];
+
+        Runnable warning = new Runnable()
+        {
+            /** {@inheritDoc} */
+            public void run()
+            {
+                maybeWarnAboutCleanUp();
+            }
+
+        };
+
+        cleanupWarning = new Thread( warning );
+
+        Runtime.getRuntime().addShutdownHook( cleanupWarning );
+    }
+
+    protected void maybeWarnAboutCleanUp()
+    {
+        if ( warnAboutCleanup )
+        {
+            System.out.println( "[WARNING] TestFileManager from: " + callerInfo.getClassName() + " not cleaned up!" );
+        }
+    }
+
+    /**
+     * @param toDelete
+     */
+    public void markForDeletion( File toDelete )
+    {
+        filesToDelete.add( toDelete );
+        warnAboutCleanup = true;
+    }
+
+    /**
+     * @return a temp dir
+     */
+    public synchronized File createTempDir()
+    {
+        try
+        {
+            Thread.sleep( 20 );
+        }
+        catch ( InterruptedException e )
+        {
+            // ignored
+        }
+
+        File dir = new File( TEMP_DIR_PATH, baseFilename + System.currentTimeMillis() );
+
+        dir.mkdirs();
+        markForDeletion( dir );
+
+        return dir;
+    }
+
+    /**
+     * @return a temp file
+     * @throws IOException if any
+     * @todo maybe use {@link FileUtils#createTempFile(String, String, File)}
+     */
+    public synchronized File createTempFile()
+        throws IOException
+    {
+        File tempFile = File.createTempFile( baseFilename, fileSuffix );
+        tempFile.deleteOnExit();
+        markForDeletion( tempFile );
+
+        return tempFile;
+    }
+
+    /**
+     * @throws IOException if any
+     */
+    public void cleanUp()
+        throws IOException
+    {
+        for ( Iterator it = filesToDelete.iterator(); it.hasNext(); )
+        {
+            File file = (File) it.next();
+
+            if ( file.exists() )
+            {
+                if ( file.isDirectory() )
+                {
+                    FileUtils.deleteDirectory( file );
+                }
+                else
+                {
+                    file.delete();
+                }
+            }
+
+            it.remove();
+        }
+
+        warnAboutCleanup = false;
+    }
+
+    /**
+     * @param dir
+     * @param filename
+     * @param shouldExist
+     */
+    public void assertFileExistence( File dir, String filename, boolean shouldExist )
+    {
+        File file = new File( dir, filename );
+
+        if ( shouldExist )
+        {
+            Assert.assertTrue( file.exists() );
+        }
+        else
+        {
+            Assert.assertFalse( file.exists() );
+        }
+    }
+
+    /**
+     * @param dir
+     * @param filename
+     * @param contentsTest
+     * @throws IOException if any
+     */
+    public void assertFileContents( File dir, String filename, String contentsTest )
+        throws IOException
+    {
+        assertFileExistence( dir, filename, true );
+
+        File file = new File( dir, filename );
+
+        FileReader reader = null;
+        StringWriter writer = new StringWriter();
+
+        try
+        {
+            reader = new FileReader( file );
+
+            IOUtil.copy( reader, writer );
+        }
+        finally
+        {
+            IOUtil.close( reader );
+        }
+
+        Assert.assertEquals( contentsTest, writer.toString() );
+    }
+
+    /**
+     * @param dir
+     * @param filename
+     * @param contents
+     * @return
+     * @throws IOException if any
+     */
+    public File createFile( File dir, String filename, String contents )
+        throws IOException
+    {
+        File file = new File( dir, filename );
+
+        file.getParentFile().mkdirs();
+
+        FileWriter writer = null;
+
+        try
+        {
+            writer = new FileWriter( file );
+
+            IOUtil.copy( new StringReader( contents ), writer );
+        }
+        finally
+        {
+            IOUtil.close( writer );
+        }
+
+        markForDeletion( file );
+
+        return file;
+    }
+
+    /**
+     * @param file
+     * @return
+     * @throws IOException if any
+     */
+    public String getFileContents( File file )
+        throws IOException
+    {
+        String result = null;
+
+        FileReader reader = null;
+        try
+        {
+            reader = new FileReader( file );
+
+            StringWriter writer = new StringWriter();
+
+            IOUtil.copy( reader, writer );
+
+            result = writer.toString();
+        }
+        finally
+        {
+            IOUtil.close( reader );
+        }
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    protected void finalize()
+        throws Throwable
+    {
+        maybeWarnAboutCleanUp();
+
+        super.finalize();
+    }
+
+    /**
+     * @param filename
+     * @param content
+     * @return
+     * @throws IOException if any
+     */
+    public File createFile( String filename, String content )
+        throws IOException
+    {
+        File dir = createTempDir();
+        return createFile( dir, filename, content );
+    }
+}
diff --git a/maven-test-tools/src/main/java/org/apache/maven/shared/tools/easymock/TestUtils.java b/maven-test-tools/src/main/java/org/apache/maven/shared/tools/easymock/TestUtils.java
new file mode 100644
index 0000000..206e0cd
--- /dev/null
+++ b/maven-test-tools/src/main/java/org/apache/maven/shared/tools/easymock/TestUtils.java
@@ -0,0 +1,103 @@
+package org.apache.maven.shared.tools.easymock;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.codehaus.plexus.util.IOUtil;
+
+/**
+ * @version $Id: TestUtils.java 677117 2008-07-16 00:29:56Z vsiveton $
+ */
+public final class TestUtils
+{
+    private TestUtils()
+    {
+        //nop
+    }
+
+    /**
+     * @param file
+     * @param testStr
+     * @throws IOException if any
+     */
+    public static void writeToFile( File file, String testStr )
+        throws IOException
+    {
+        FileWriter fw = null;
+        try
+        {
+            fw = new FileWriter( file );
+            fw.write( testStr );
+        }
+        finally
+        {
+            IOUtil.close( fw );
+        }
+    }
+
+    /**
+     * @param file
+     * @return
+     * @throws IOException if any
+     * @todo maybe used {@link IOUtil#toString(java.io.Reader)}
+     */
+    public static String readFile( File file )
+        throws IOException
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        BufferedReader reader = new BufferedReader( new FileReader( file ) );
+
+        String line = null;
+
+        while ( ( line = reader.readLine() ) != null )
+        {
+            if ( buffer.length() > 0 )
+            {
+                buffer.append( '\n' );
+            }
+
+            buffer.append( line );
+        }
+
+        return buffer.toString();
+    }
+
+    /**
+     * @param error
+     * @return
+     */
+    public static String toString( Throwable error )
+    {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter( sw );
+
+        error.printStackTrace( pw );
+
+        return sw.toString();
+    }
+}
diff --git a/maven-test-tools/src/main/java/org/apache/maven/shared/tools/test/ReflectiveSetter.java b/maven-test-tools/src/main/java/org/apache/maven/shared/tools/test/ReflectiveSetter.java
new file mode 100644
index 0000000..0398368
--- /dev/null
+++ b/maven-test-tools/src/main/java/org/apache/maven/shared/tools/test/ReflectiveSetter.java
@@ -0,0 +1,175 @@
+package org.apache.maven.shared.tools.test;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.codehaus.plexus.util.ReflectionUtils;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * @version $Id: ReflectiveSetter.java 677117 2008-07-16 00:29:56Z vsiveton $
+ */
+public class ReflectiveSetter
+{
+    private Map cachedPropertySetters = new HashMap();
+
+    private final Class targetClass;
+
+    /**
+     * @param targetClass
+     */
+    public ReflectiveSetter( Class targetClass )
+    {
+        this.targetClass = targetClass;
+    }
+
+    /**
+     * @param propertyName
+     * @param value
+     * @param target
+     * @throws Throwable
+     */
+    public void setProperty( String propertyName, Object value, Object target )
+        throws Throwable
+    {
+
+        String preferredMethodName = "set" + StringUtils.capitalizeFirstLetter( propertyName );
+
+        Setter setter = null;
+
+        Method method = ReflectionUtils.getSetter( preferredMethodName, targetClass );
+
+        if ( method != null )
+        {
+            setter = new MethodSetter( propertyName, method );
+        }
+        else
+        {
+            Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( propertyName, targetClass );
+
+            setter = new FieldSetter( propertyName, field );
+        }
+
+        if ( setter == null )
+        {
+            throw new IllegalArgumentException( "No such property: " + propertyName + " in: " + targetClass
+                + ". Searched for: {method:" + preferredMethodName + ", method:" + propertyName + ", field:"
+                + propertyName + "}" );
+        }
+
+        cachedPropertySetters.put( setter.getProperty(), setter );
+
+        try
+        {
+            setter.set( value, target );
+        }
+        catch ( InvocationTargetException e )
+        {
+            throw e.getTargetException();
+        }
+    }
+
+    private interface Setter
+    {
+        void set( Object value, Object target )
+            throws IllegalArgumentException, IllegalAccessException, InvocationTargetException;
+
+        String getProperty();
+    }
+
+    private static class MethodSetter
+        implements Setter
+    {
+        private Method method;
+
+        private String name;
+
+        MethodSetter( String name, Method method )
+        {
+            this.name = name;
+            this.method = method;
+        }
+
+        /** {@inheritDoc} */
+        public String getProperty()
+        {
+            return name;
+        }
+
+        /** {@inheritDoc} */
+        public void set( Object value, Object target )
+            throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
+        {
+            boolean wasAccessible = method.isAccessible();
+
+            method.setAccessible( true );
+            try
+            {
+                method.invoke( target, new Object[] { value } );
+            }
+            finally
+            {
+                method.setAccessible( wasAccessible );
+            }
+        }
+    }
+
+    private static class FieldSetter
+        implements Setter
+    {
+        private Field field;
+
+        private String name;
+
+        FieldSetter( String name, Field field )
+        {
+            this.name = name;
+            this.field = field;
+        }
+
+        /** {@inheritDoc} */
+        public String getProperty()
+        {
+            return name;
+        }
+
+        /** {@inheritDoc} */
+        public void set( Object value, Object target )
+            throws IllegalArgumentException, IllegalAccessException, InvocationTargetException
+        {
+            boolean wasAccessible = field.isAccessible();
+
+            field.setAccessible( true );
+            try
+            {
+                field.set( target, value );
+            }
+            finally
+            {
+                field.setAccessible( wasAccessible );
+            }
+        }
+    }
+}
diff --git a/maven-test-tools/src/site/apt/index.apt b/maven-test-tools/src/site/apt/index.apt
new file mode 100644
index 0000000..7cb8af1
--- /dev/null
+++ b/maven-test-tools/src/site/apt/index.apt
@@ -0,0 +1,32 @@
+ ------
+ Introduction
+ ------
+ Vincent Siveton
+ ------
+ 2008-07-15
+ ------
+
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+~~ NOTE: For help with the syntax of this file, see:
+~~ http://maven.apache.org/doxia/references/apt-format.html
+
+Maven Testing Tools
+
+ The Maven Plugin Testing Tools is a framework which encapsulates {{{http://www.easymock.org/}Easymock}} objects to
+ provide testing mechanisms.
diff --git a/maven-test-tools/src/site/site.xml b/maven-test-tools/src/site/site.xml
new file mode 100644
index 0000000..b6412d5
--- /dev/null
+++ b/maven-test-tools/src/site/site.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.0.0 http://maven.apache.org/xsd/decoration-1.0.0.xsd">
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+  </body>
+</project>
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..a612cf6
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>maven-parent</artifactId>
+    <groupId>org.apache.maven</groupId>
+    <version>21</version>
+    <relativePath>../pom/maven/pom.xml</relativePath>
+  </parent>
+
+  <groupId>org.apache.maven.plugin-testing</groupId>
+  <artifactId>maven-plugin-testing</artifactId>
+  <version>2.0</version>
+  <packaging>pom</packaging>
+
+  <name>Maven Plugin Testing</name>
+  <description>The Maven Plugin Testing contains the necessary modules to be able to test Maven Plugins.</description>
+  <url>http://maven.apache.org/plugin-testing/</url>
+  <inceptionYear>2008</inceptionYear>
+
+  <mailingLists>
+    <mailingList>
+      <name>Maven User List</name>
+      <subscribe>users-subscribe at maven.apache.org</subscribe>
+      <unsubscribe>users-unsubscribe at maven.apache.org</unsubscribe>
+      <post>users at maven.apache.org</post>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-users</archive>
+      <otherArchives>
+        <otherArchive>http://www.mail-archive.com/users@maven.apache.org/</otherArchive>
+        <otherArchive>http://www.nabble.com/Maven---Users-f178.html</otherArchive>
+        <otherArchive>http://maven.users.markmail.org/</otherArchive>
+      </otherArchives>
+    </mailingList>
+    <mailingList>
+      <name>Maven Developer List</name>
+      <subscribe>dev-subscribe at maven.apache.org</subscribe>
+      <unsubscribe>dev-unsubscribe at maven.apache.org</unsubscribe>
+      <post>dev at maven.apache.org</post>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-dev</archive>
+      <otherArchives>
+        <otherArchive>http://www.mail-archive.com/dev@maven.apache.org/</otherArchive>
+        <otherArchive>http://www.nabble.com/Maven-Developers-f179.html</otherArchive>
+        <otherArchive>http://maven.dev.markmail.org/</otherArchive>
+      </otherArchives>
+    </mailingList>
+    <mailingList>
+      <name>Maven Issues List</name>
+      <subscribe>issues-subscribe at maven.apache.org</subscribe>
+      <unsubscribe>issues-unsubscribe at maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-issues/</archive>
+      <otherArchives>
+        <otherArchive>http://www.mail-archive.com/issues@maven.apache.org</otherArchive>
+        <otherArchive>http://www.nabble.com/Maven---Issues-f15573.html</otherArchive>
+        <otherArchive>http://maven.issues.markmail.org/</otherArchive>
+      </otherArchives>
+    </mailingList>
+    <mailingList>
+      <name>Maven Commits List</name>
+      <subscribe>commits-subscribe at maven.apache.org</subscribe>
+      <unsubscribe>commits-unsubscribe at maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-commits</archive>
+      <otherArchives>
+        <otherArchive>http://www.mail-archive.com/commits@maven.apache.org</otherArchive>
+        <otherArchive>http://www.nabble.com/Maven---Commits-f15575.html</otherArchive>
+        <otherArchive>http://maven.commits.markmail.org/</otherArchive>
+      </otherArchives>
+    </mailingList>
+
+    <!-- duplication from parent pom - temporary until they inherit properly -->
+    <mailingList>
+      <name>Maven Announcements List</name>
+      <post>announce at maven.apache.org</post>
+      <subscribe>announce-subscribe at maven.apache.org</subscribe>
+      <unsubscribe>announce-unsubscribe at maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-announce/</archive>
+      <otherArchives>
+        <otherArchive>http://www.mail-archive.com/announce@maven.apache.org</otherArchive>
+        <otherArchive>http://www.nabble.com/Maven-Announcements-f15617.html</otherArchive>
+        <otherArchive>http://maven.announce.markmail.org/</otherArchive>
+      </otherArchives>
+    </mailingList>
+    <mailingList>
+      <name>Maven Notifications List</name>
+      <subscribe>notifications-subscribe at maven.apache.org</subscribe>
+      <unsubscribe>notifications-unsubscribe at maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-notifications/</archive>
+      <otherArchives>
+        <otherArchive>http://www.mail-archive.com/notifications@maven.apache.org</otherArchive>
+        <otherArchive>http://www.nabble.com/Maven---Notifications-f15574.html</otherArchive>
+        <otherArchive>http://maven.notifications.markmail.org/</otherArchive>
+      </otherArchives>
+    </mailingList>
+  </mailingLists>
+
+  <prerequisites>
+    <maven>3.0</maven>
+  </prerequisites>
+
+  <modules>
+    <module>maven-plugin-testing-harness</module>
+    <module>maven-plugin-testing-tools</module>
+    <module>maven-test-tools</module>
+  </modules>
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/maven/plugin-testing/tags/maven-plugin-testing-2.0</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/plugin-testing/tags/maven-plugin-testing-2.0</developerConnection>
+    <url>http://svn.apache.org/viewvc/maven/plugin-testing/tags/maven-plugin-testing-2.0</url>
+  </scm>
+  <issueManagement>
+    <system>jira</system>
+    <url>http://jira.codehaus.org/browse/MPLUGINTESTING</url>
+  </issueManagement>
+  <distributionManagement>
+    <site>
+      <id>apache.website</id>
+      <url>scp://people.apache.org/www/maven.apache.org/plugin-testing/</url>
+    </site>
+  </distributionManagement>
+
+  <properties>
+    <mavenVersion>3.0.3</mavenVersion>
+    <plexusVersion>1.5.1</plexusVersion>
+  </properties>
+
+  <dependencyManagement>
+    <dependencies>
+    
+      <!-- maven -->
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-core</artifactId>
+        <version>${mavenVersion}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-compat</artifactId>
+        <version>${mavenVersion}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-model</artifactId>
+        <version>${mavenVersion}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-plugin-api</artifactId>
+        <version>${mavenVersion}</version>
+      </dependency>    
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-aether-provider</artifactId>
+        <version>${mavenVersion}</version>
+      </dependency>    
+    
+      <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-utils</artifactId>
+        <version>2.0.1</version>
+      </dependency>    
+    
+      <dependency>
+        <groupId>junit</groupId>
+        <artifactId>junit</artifactId>
+        <version>4.10</version>
+      </dependency>    
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+  
+    <!-- misc -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    
+  </dependencies>
+  
+  
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <configuration>
+            <systemProperties>
+              <property>
+                <name>java.io.tmpdir</name>
+                <value>${java.io.tmpdir}</value>
+              </property>
+            </systemProperties>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>2.4</version>
+        </plugin>        
+        <plugin>
+          <artifactId>maven-site-plugin</artifactId>
+          <version>3.0</version>
+          <configuration>
+            <stagingSiteURL>scp://people.apache.org/www/maven.apache.org/plugin-testing/${project.artifactId}-${project.version}</stagingSiteURL>
+          </configuration>
+        </plugin>
+        <plugin>
+          <artifactId>maven-release-plugin</artifactId>
+          <configuration>
+            <tagBase>https://svn.apache.org/repos/asf/maven/plugin-testing/tags</tagBase>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <artifactId>maven-site-plugin</artifactId>
+        <inherited>false</inherited>
+        <executions>
+          <execution>
+            <id>attach-descriptor</id>
+            <goals>
+              <goal>attach-descriptor</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>reporting</id>
+      <reporting>
+        <plugins>
+          <plugin>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <version>2.8.1</version>
+          </plugin>
+        </plugins>
+      </reporting>
+    </profile>
+  </profiles>
+</project>
diff --git a/src/site/apt/index.apt b/src/site/apt/index.apt
new file mode 100644
index 0000000..9148009
--- /dev/null
+++ b/src/site/apt/index.apt
@@ -0,0 +1,44 @@
+ ------
+ Introduction
+ ------
+ Vincent Siveton
+ ------
+ 2008-07-15
+ ------
+
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+~~ NOTE: For help with the syntax of this file, see:
+~~ http://maven.apache.org/doxia/references/apt-format.html
+
+Maven Plugin Testing
+
+ The Maven Plugin Testing Modules contains the necessary tools to be able to test Maven Plugins.
+
+* Matrix Comparison
+
+*-----------------------------------------------------------------------------+---------------------------------------------------------+
+|| <<Testing Module for Maven Plugins>>                                       || <<Overview>> 
+*-----------------------------------------------------------------------------+---------------------------------------------------------+
+| {{{./maven-plugin-testing-harness/index.html}maven-plugin-testing-harness}} | Framework to test Maven Plugins with Maven Mock projects.
+*-----------------------------------------------------------------------------+---------------------------------------------------------+
+| {{{./maven-plugin-testing-tools/index.html}maven-plugin-testing-tools}}     | A set of useful tools to help the Maven Plugin testing.
+*-----------------------------------------------------------------------------+---------------------------------------------------------+
+| {{{./maven-test-tools/index.html}maven-test-tools}}                         | Framework to test Maven Plugins with {{{http://www.easymock.org/}Easymock}} objects.
+*-----------------------------------------------------------------------------+---------------------------------------------------------+
+
diff --git a/src/site/site.xml b/src/site/site.xml
new file mode 100644
index 0000000..c9b2c7d
--- /dev/null
+++ b/src/site/site.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project>
+  <body>
+    <breadcrumbs>
+      <!-- TODO: This breadcrumb should be removed when it has been solved in the parent -->
+      <item name="Maven" href="http://maven.apache.org/index.html" />
+      <item name="Plugin Testing" href="http://maven.apache.org/plugin-testing/index.html" />
+    </breadcrumbs>
+
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+    </menu>
+
+    <menu ref="modules" />
+  </body>
+</project>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/maven-plugin-testing-1.3.git



More information about the pkg-java-commits mailing list