diff --git a/maven-plugin-testing-harness/pom.xml b/maven-plugin-testing-harness/pom.xml index db78ea99..b9d73472 100644 --- a/maven-plugin-testing-harness/pom.xml +++ b/maven-plugin-testing-harness/pom.xml @@ -25,7 +25,7 @@ under the License. org.apache.maven.plugin-testing maven-plugin-testing - 3.4.0-SNAPSHOT + 4.0.0-SNAPSHOT maven-plugin-testing-harness @@ -34,6 +34,12 @@ under the License. + + org.apache.maven + maven-api-core + ${mavenVersion} + provided + org.apache.maven maven-core @@ -60,7 +66,7 @@ under the License. org.apache.maven - maven-aether-provider + maven-resolver-provider ${mavenVersion} provided @@ -81,10 +87,21 @@ under the License. plexus-archiver 4.3.0 + + + org.codehaus.plexus + plexus-testing + 1.1.0 + junit junit 4.13.2 + + org.mockito + mockito-core + 4.6.1 + diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/ConfigurationException.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/ConfigurationException.java new file mode 100644 index 00000000..6d2ea581 --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/ConfigurationException.java @@ -0,0 +1,57 @@ +package org.apache.maven.api.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 + */ +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/api/plugin/testing/InjectMojo.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/InjectMojo.java new file mode 100644 index 00000000..313dbba5 --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/InjectMojo.java @@ -0,0 +1,38 @@ +package org.apache.maven.api.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.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * + */ +@Retention( RetentionPolicy.RUNTIME ) +public @interface InjectMojo +{ + + String goal(); + + String pom(); + + boolean empty() default false; + +} diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java new file mode 100644 index 00000000..358180af --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java @@ -0,0 +1,502 @@ +package org.apache.maven.api.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.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.google.inject.internal.ProviderMethodsModule; +import org.apache.maven.api.MojoExecution; +import org.apache.maven.api.Project; +import org.apache.maven.api.Session; +import org.apache.maven.api.plugin.Log; +import org.apache.maven.api.plugin.Mojo; +import org.apache.maven.api.xml.Dom; +import org.apache.maven.configuration.internal.EnhancedComponentConfigurator; +import org.apache.maven.internal.impl.DefaultLog; +import org.apache.maven.lifecycle.internal.MojoDescriptorCreator; +import org.apache.maven.plugin.PluginParameterExpressionEvaluatorV4; +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.codehaus.plexus.DefaultPlexusContainer; +import org.codehaus.plexus.PlexusContainer; +import org.codehaus.plexus.component.configurator.ComponentConfigurator; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; +import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator; +import org.codehaus.plexus.component.repository.ComponentDescriptor; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; +import org.codehaus.plexus.testing.PlexusExtension; +import org.codehaus.plexus.util.InterpolationFilterReader; +import org.codehaus.plexus.util.ReaderFactory; +import org.codehaus.plexus.util.ReflectionUtils; +import org.codehaus.plexus.util.xml.XmlStreamReader; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.codehaus.plexus.util.xml.Xpp3DomBuilder; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.ParameterResolver; +import org.slf4j.LoggerFactory; + +/** + * + */ +public class MojoExtension extends PlexusExtension implements ParameterResolver +{ + + @Override + public boolean supportsParameter( ParameterContext parameterContext, ExtensionContext extensionContext ) + throws ParameterResolutionException + { + return parameterContext.isAnnotated( InjectMojo.class ) + || parameterContext.getDeclaringExecutable().isAnnotationPresent( InjectMojo.class ); + } + + @Override + public Object resolveParameter( ParameterContext parameterContext, ExtensionContext extensionContext ) + throws ParameterResolutionException + { + try + { + InjectMojo injectMojo = parameterContext.findAnnotation( InjectMojo.class ).orElseGet( + () -> parameterContext.getDeclaringExecutable().getAnnotation( InjectMojo.class ) ); + List mojoParameters = parameterContext.findRepeatableAnnotations( MojoParameter.class ); + Class holder = parameterContext.getTarget().get().getClass(); + PluginDescriptor descriptor = extensionContext.getStore( ExtensionContext.Namespace.GLOBAL ) + .get( PluginDescriptor.class, PluginDescriptor.class ); + return lookupMojo( holder, injectMojo, mojoParameters, descriptor ); + } + catch ( Exception e ) + { + throw new ParameterResolutionException( "Unable to resolve parameter", e ); + } + } + + @Override + public void beforeEach( ExtensionContext context ) + throws Exception + { + Field field = PlexusExtension.class.getDeclaredField( "basedir" ); + field.setAccessible( true ); + field.set( null, getBasedir() ); + field = PlexusExtension.class.getDeclaredField( "context" ); + field.setAccessible( true ); + field.set( this, context ); + + getContainer().addComponent( getContainer(), PlexusContainer.class.getName() ); + + ( (DefaultPlexusContainer) getContainer() ).addPlexusInjector( Collections.emptyList(), + binder -> + { + binder.install( ProviderMethodsModule.forObject( context.getRequiredTestInstance() ) ); + binder.requestInjection( context.getRequiredTestInstance() ); + binder.bind( Log.class ).toInstance( new DefaultLog( + LoggerFactory.getLogger( "anonymous" ) ) ); + } ); + + Map map = getContainer().getContext().getContextData(); + + ClassLoader classLoader = context.getRequiredTestClass().getClassLoader(); + try ( InputStream is = Objects.requireNonNull( classLoader.getResourceAsStream( getPluginDescriptorLocation() ), + "Unable to find plugin descriptor: " + getPluginDescriptorLocation() ); + Reader reader = new BufferedReader( new XmlStreamReader( is ) ); + InterpolationFilterReader interpolationReader = new InterpolationFilterReader( reader, map, "${", "}" ) ) + { + + PluginDescriptor pluginDescriptor = new PluginDescriptorBuilder().build( interpolationReader ); + +// Artifact artifact = +// lookup( RepositorySystem.class ).createArtifact( pluginDescriptor.getGroupId(), +// pluginDescriptor.getArtifactId(), +// pluginDescriptor.getVersion(), ".jar" ); +// +// artifact.setFile( getPluginArtifactFile() ); +// pluginDescriptor.setPluginArtifact( artifact ); +// pluginDescriptor.setArtifacts( Collections.singletonList( artifact ) ); + + context.getStore( ExtensionContext.Namespace.GLOBAL ) + .put( PluginDescriptor.class, pluginDescriptor ); + + for ( ComponentDescriptor desc : pluginDescriptor.getComponents() ) + { + getContainer().addComponentDescriptor( desc ); + } + } + } + + protected String getPluginDescriptorLocation() + { + return "META-INF/maven/plugin.xml"; + } + + private Mojo lookupMojo( Class holder, InjectMojo injectMojo, List mojoParameters, + PluginDescriptor descriptor ) throws Exception + { + String goal = injectMojo.goal(); + String pom = injectMojo.pom(); + String[] coord = mojoCoordinates( goal ); + Xpp3Dom pomDom; + if ( pom.startsWith( "file:" ) ) + { + Path path = Paths.get( getBasedir() ).resolve( pom.substring( "file:".length() ) ); + pomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( path.toFile() ) ); + } + else if ( pom.startsWith( "classpath:" ) ) + { + URL url = holder.getResource( pom.substring( "classpath:".length() ) ); + if ( url == null ) + { + throw new IllegalStateException( "Unable to find pom on classpath: " + pom ); + } + pomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( url.openStream() ) ); + } + else if ( pom.contains( "" ) ) + { + pomDom = Xpp3DomBuilder.build( new StringReader( pom ) ); + } + else + { + Path path = Paths.get( getBasedir() ).resolve( pom ); + pomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( path.toFile() ) ); + } + Dom pluginConfiguration = extractPluginConfiguration( coord[1], pomDom ); + if ( !mojoParameters.isEmpty() ) + { + List children = mojoParameters.stream() + .map( mp -> new org.apache.maven.internal.xml.Xpp3Dom( mp.name(), mp.value() ) ) + .collect( Collectors.toList() ); + Dom config = new org.apache.maven.internal.xml.Xpp3Dom( "configuration", + null, null, children, null ); + pluginConfiguration = Dom.merge( config, pluginConfiguration ); + } + Mojo mojo = lookupMojo( coord, pluginConfiguration, descriptor ); + return mojo; + } + + protected String[] mojoCoordinates( String goal ) + throws Exception + { + if ( goal.matches( ".*:.*:.*:.*" ) ) + { + return goal.split( ":" ); + } + else + { + Path pluginPom = Paths.get( getBasedir(), "pom.xml" ); + Xpp3Dom pluginPomDom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( pluginPom.toFile() ) ); + String artifactId = pluginPomDom.getChild( "artifactId" ).getValue(); + String groupId = resolveFromRootThenParent( pluginPomDom, "groupId" ); + String version = resolveFromRootThenParent( pluginPomDom, "version" ); + return new String[] { groupId, artifactId, version, goal }; + } + } + + /** + * lookup the mojo while we have all of the relavent information + */ + protected Mojo lookupMojo( String[] coord, Dom pluginConfiguration, PluginDescriptor descriptor ) + throws Exception + { + // pluginkey = groupId : artifactId : version : goal + Mojo mojo = lookup( Mojo.class, coord[0] + ":" + coord[1] + ":" + coord[2] + ":" + coord[3] ); + for ( MojoDescriptor mojoDescriptor : descriptor.getMojos() ) + { + if ( Objects.equals( mojoDescriptor.getImplementation(), mojo.getClass().getName() ) ) + { + if ( pluginConfiguration != null ) + { + pluginConfiguration = finalizeConfig( pluginConfiguration, mojoDescriptor ); + } + } + } + if ( pluginConfiguration != null ) + { + Session session = getContainer().lookup( Session.class ); + Project project; + try + { + project = getContainer().lookup( Project.class ); + } + catch ( ComponentLookupException e ) + { + project = null; + } + org.apache.maven.plugin.MojoExecution mojoExecution; + try + { + MojoExecution me = getContainer().lookup( MojoExecution.class ); + mojoExecution = new org.apache.maven.plugin.MojoExecution( + new org.apache.maven.model.Plugin( me.getPlugin() ), + me.getGoal(), + me.getExecutionId() + ); + } + catch ( ComponentLookupException e ) + { + mojoExecution = null; + } + ExpressionEvaluator evaluator = new WrapEvaluator( getContainer(), + new PluginParameterExpressionEvaluatorV4( session, project, mojoExecution ) ); + ComponentConfigurator configurator = new EnhancedComponentConfigurator(); + configurator.configureComponent( mojo, new XmlPlexusConfiguration( new Xpp3Dom( pluginConfiguration ) ), + evaluator, getContainer().getContainerRealm() ); + } + + return mojo; + } + + private Dom finalizeConfig( Dom config, MojoDescriptor mojoDescriptor ) + { + List children = new ArrayList<>(); + if ( mojoDescriptor != null && mojoDescriptor.getParameters() != null ) + { + Dom defaultConfiguration = MojoDescriptorCreator.convert( mojoDescriptor ).getDom(); + for ( Parameter parameter : mojoDescriptor.getParameters() ) + { + Dom parameterConfiguration = config.getChild( parameter.getName() ); + if ( parameterConfiguration == null ) + { + parameterConfiguration = config.getChild( parameter.getAlias() ); + } + Dom parameterDefaults = defaultConfiguration.getChild( parameter.getName() ); + parameterConfiguration = Dom.merge( parameterConfiguration, parameterDefaults, Boolean.TRUE ); + if ( parameterConfiguration != null ) + { + Map attributes = new HashMap<>( parameterConfiguration.getAttributes() ); + if ( isEmpty( parameterConfiguration.getAttribute( "implementation" ) ) + && !isEmpty( parameter.getImplementation() ) ) + { + attributes.put( "implementation", parameter.getImplementation() ); + } + parameterConfiguration = new org.apache.maven.internal.xml.Xpp3Dom( + parameter.getName(), parameterConfiguration.getValue(), + attributes, parameterConfiguration.getChildren(), + parameterConfiguration.getInputLocation() ); + + children.add( parameterConfiguration ); + } + } + } + return new org.apache.maven.internal.xml.Xpp3Dom( "configuration", null, null, children, null ); + } + + private boolean isEmpty( String str ) + { + return str == null || str.isEmpty(); + } + + private static Optional child( Xpp3Dom element, String name ) + { + return Optional.ofNullable( element.getChild( name ) ); + } + + private static Stream children( Xpp3Dom element ) + { + return Stream.of( element.getChildren() ); + } + + public static Dom extractPluginConfiguration( String artifactId, Xpp3Dom pomDom ) + throws Exception + { + Xpp3Dom pluginConfigurationElement = child( pomDom, "build" ) + .flatMap( buildElement -> child( buildElement, "plugins" ) ) + .map( MojoExtension::children ) + .orElseGet( Stream::empty ) + .filter( e -> e.getChild( "artifactId" ).getValue().equals( artifactId ) ) + .findFirst() + .flatMap( buildElement -> child( buildElement, "configuration" ) ) + .orElseThrow( () -> new ConfigurationException( + "Cannot find a configuration element for a plugin with an " + + "artifactId of " + artifactId + "." ) ); + return pluginConfigurationElement.getDom(); + } + + /** + * sometimes the parent element might contain the correct value so generalize that access + * + * TODO find out where this is probably done elsewhere + */ + private static String resolveFromRootThenParent( Xpp3Dom pluginPomDom, String element ) + throws Exception + { + return Optional.ofNullable( + child( pluginPomDom, element ) + .orElseGet( () -> child( pluginPomDom, "parent" ) + .flatMap( e -> child( e, element ) ) + .orElse( null ) ) ) + .map( Xpp3Dom::getValue ) + .orElseThrow( () -> new Exception( "unable to determine " + element ) ); + } + + + /** + * 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 + */ + public static 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 + */ + public static Map 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 + */ + public static Map getVariablesAndValuesFromObject( Class clazz, Object object ) + throws IllegalAccessException + { + Map map = new HashMap<>(); + 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 + */ + public static void setVariableValueToObject( Object object, String variable, Object value ) + throws IllegalAccessException + { + Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() ); + Objects.requireNonNull( field, "Field " + variable + " not found" ); + field.setAccessible( true ); + field.set( object, value ); + } + + static class WrapEvaluator implements TypeAwareExpressionEvaluator + { + + private final PlexusContainer container; + private final TypeAwareExpressionEvaluator evaluator; + + WrapEvaluator( PlexusContainer container, TypeAwareExpressionEvaluator evaluator ) + { + this.container = container; + this.evaluator = evaluator; + } + + @Override + public Object evaluate( String expression ) throws ExpressionEvaluationException + { + return evaluate( expression, null ); + } + + @Override + public Object evaluate( String expression, Class type ) throws ExpressionEvaluationException + { + Object value = evaluator.evaluate( expression, type ); + if ( value == null ) + { + String expr = stripTokens( expression ); + if ( expr != null ) + { + try + { + value = container.lookup( type, expr ); + } + catch ( ComponentLookupException e ) + { + // nothing + } + } + } + return value; + } + + private String stripTokens( String expr ) + { + if ( expr.startsWith( "${" ) && expr.endsWith( "}" ) ) + { + return expr.substring( 2, expr.length() - 1 ); + } + return null; + } + + @Override + public File alignToBaseDirectory( File path ) + { + return evaluator.alignToBaseDirectory( path ); + } + } + +} diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoParameter.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoParameter.java new file mode 100644 index 00000000..ebd284d2 --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoParameter.java @@ -0,0 +1,35 @@ +package org.apache.maven.api.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.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Mojo parameter + */ +@Retention( RetentionPolicy.RUNTIME ) +@Repeatable( MojoParameters.class ) +public @interface MojoParameter +{ + String name(); + String value(); +} diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoParameters.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoParameters.java new file mode 100644 index 00000000..53c8dd9e --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoParameters.java @@ -0,0 +1,32 @@ +package org.apache.maven.api.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.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Mojo parameters container + */ +@Retention( RetentionPolicy.RUNTIME ) +public @interface MojoParameters +{ + MojoParameter[] value(); +} diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoTest.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoTest.java new file mode 100644 index 00000000..4f4b1a94 --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/MojoTest.java @@ -0,0 +1,37 @@ +package org.apache.maven.api.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.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * + */ +@Retention( RetentionPolicy.RUNTIME ) +@ExtendWith( MojoExtension.class ) +@Target( ElementType.TYPE ) +public @interface MojoTest +{ +} diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/ResolverExpressionEvaluatorStub.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/ResolverExpressionEvaluatorStub.java new file mode 100644 index 00000000..b35b2b0a --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/ResolverExpressionEvaluatorStub.java @@ -0,0 +1,154 @@ +package org.apache.maven.api.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.util.Map; + +import org.codehaus.plexus.PlexusTestCase; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; +import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; +import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator; +import org.codehaus.plexus.testing.PlexusExtension; +import org.eclipse.aether.repository.LocalRepository; + +/** + * Stub for {@link ExpressionEvaluator} + * + * @author jesse + */ +public class ResolverExpressionEvaluatorStub + implements TypeAwareExpressionEvaluator +{ + + private final Map properties; + + public ResolverExpressionEvaluatorStub( Map properties ) + { + this.properties = properties; + } + + /** {@inheritDoc} */ + @Override + public Object evaluate( String expr ) + throws ExpressionEvaluationException + { + return evaluate( expr, null ); + } + + /** {@inheritDoc} */ + @Override + public Object evaluate( String expr, Class type ) + 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 + return expression.contains( "$$" ) + ? expression.replaceAll( "\\$\\$", "\\$" ) + : expression; + } + else + { + if ( "basedir".equals( expression ) || "project.basedir".equals( expression ) ) + { + value = PlexusExtension.getBasedir(); + } + else if ( expression.startsWith( "basedir" ) || expression.startsWith( "project.basedir" ) ) + { + int pathSeparator = expression.indexOf( "/" ); + if ( pathSeparator > 0 ) + { + value = PlexusTestCase.getBasedir() + expression.substring( pathSeparator ); + } + } + else if ( "localRepository".equals( expression ) ) + { + File localRepo = new File( PlexusTestCase.getBasedir(), "target/local-repo" ); + return new LocalRepository( "file://" + localRepo.getAbsolutePath() ); + } + if ( value == null && properties != null && properties.containsKey( expression ) ) + { + value = properties.get( expression ); + } + return value; + } + } + + private String stripTokens( String expr ) + { + if ( expr.startsWith( "${" ) && expr.indexOf( "}" ) == expr.length() - 1 ) + { + expr = expr.substring( 2, expr.length() - 1 ); + } + + return expr; + } + + /** {@inheritDoc} */ + @Override + public File alignToBaseDirectory( File file ) + { + if ( file.getAbsolutePath().startsWith( PlexusExtension.getBasedir() ) ) + { + return file; + } + else if ( file.isAbsolute() ) + { + return file; + } + else + { + return new File( PlexusExtension.getBasedir(), file.getPath() ); + } + } +} diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/ArtifactStub.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/ArtifactStub.java new file mode 100644 index 00000000..70b7d896 --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/ArtifactStub.java @@ -0,0 +1,200 @@ +package org.apache.maven.api.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.Objects; + +import org.apache.maven.api.Artifact; +import org.apache.maven.api.ArtifactCoordinate; +import org.apache.maven.api.Version; +import org.apache.maven.api.VersionRange; +import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.internal.impl.DefaultVersionParser; + +/** + * + */ +public class ArtifactStub implements Artifact +{ + private String groupId; + private String artifactId; + private String classifier; + private String version; + private String extension; + + public ArtifactStub() + { + groupId = ""; + artifactId = ""; + version = ""; + classifier = ""; + extension = ""; + } + + public ArtifactStub( String groupId, String artifactId, String classifier, String version, String extension ) + { + this.groupId = groupId; + this.artifactId = artifactId; + this.classifier = classifier; + this.version = version; + this.extension = extension; + } + + @Nonnull + @Override + public String getGroupId() + { + return groupId; + } + + public void setGroupId( String groupId ) + { + this.groupId = groupId; + } + + @Nonnull + @Override + public String getArtifactId() + { + return artifactId; + } + + public void setArtifactId( String artifactId ) + { + this.artifactId = artifactId; + } + + @Nonnull + @Override + public String getClassifier() + { + return classifier; + } + + public void setClassifier( String classifier ) + { + this.classifier = classifier; + } + + @Nonnull + @Override + public Version getVersion() + { + return new DefaultVersionParser().parseVersion( version ); + } + + public void setVersion( String version ) + { + this.version = version; + } + + @Nonnull + @Override + public String getExtension() + { + return extension; + } + + public void setExtension( String extension ) + { + this.extension = extension; + } + + @Override + public boolean isSnapshot() + { + return false; + } + + @Override + public ArtifactCoordinate toCoordinate() + { + return new ArtifactCoordinate() + { + @Override + public String getGroupId() + { + return groupId; + } + + @Override + public String getArtifactId() + { + return artifactId; + } + + @Override + public String getClassifier() + { + return classifier; + } + + @Override + public VersionRange getVersion() + { + return new DefaultVersionParser().parseVersionRange( version ); + } + + @Override + public String getExtension() + { + return extension; + } + }; + } + + @Override + public String toString() + { + return "ArtifactStub[" + + "groupId='" + groupId + '\'' + + ", artifactId='" + artifactId + '\'' + + ", classifier='" + classifier + '\'' + + ", version='" + version + '\'' + + ", extension='" + extension + '\'' + + ']'; + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( !( o instanceof ArtifactStub ) ) + { + return false; + } + ArtifactStub that = ( ArtifactStub ) o; + return Objects.equals( groupId, that.groupId ) + && Objects.equals( artifactId, that.artifactId ) + && Objects.equals( classifier, that.classifier ) + && Objects.equals( version, that.version ) + && Objects.equals( extension, that.extension ); + } + + @Override + public int hashCode() + { + return Objects.hash( groupId, artifactId, classifier, version, extension ); + } + +} diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/MojoExecutionStub.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/MojoExecutionStub.java new file mode 100644 index 00000000..0e01bfc8 --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/MojoExecutionStub.java @@ -0,0 +1,76 @@ +package org.apache.maven.api.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.Optional; + +import org.apache.maven.api.MojoExecution; +import org.apache.maven.api.model.Plugin; +import org.apache.maven.api.xml.Dom; + +/** + * Stub for {@link MojoExecution}. + */ +public class MojoExecutionStub implements MojoExecution +{ + private final String artifactId; + private final String executionId; + private final String goal; + private final Dom dom; + + public MojoExecutionStub( String artifactId, String executionId, String goal ) + { + this( artifactId, executionId, goal, null ); + } + + public MojoExecutionStub( String artifactId, String executionId, String goal, Dom dom ) + { + this.artifactId = artifactId; + this.executionId = executionId; + this.goal = goal; + this.dom = dom; + } + + @Override + public Plugin getPlugin() + { + return Plugin.newBuilder() + .artifactId( artifactId ) + .build(); + } + + @Override + public String getExecutionId() + { + return executionId; + } + + @Override + public String getGoal() + { + return goal; + } + + @Override + public Optional getConfiguration() + { + return Optional.ofNullable( dom ); + } +} diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/ProjectStub.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/ProjectStub.java new file mode 100644 index 00000000..283959ae --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/ProjectStub.java @@ -0,0 +1,202 @@ +package org.apache.maven.api.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.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import org.apache.maven.api.Artifact; +import org.apache.maven.api.DependencyCoordinate; +import org.apache.maven.api.Project; +import org.apache.maven.api.RemoteRepository; +import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.model.Model; + +/** + * @author Olivier Lamy + * @since 1.0-beta-1 + * + */ +public class ProjectStub + implements Project +{ + + private Model model = Model.newInstance(); + private Path basedir; + private File pomPath; + private boolean executionRoot; + private Artifact artifact; + + public void setModel( Model model ) + { + this.model = model; + } + + @Nonnull + @Override + public String getGroupId() + { + return model.getGroupId(); + } + + @Nonnull + @Override + public String getArtifactId() + { + return model.getArtifactId(); + } + + @Nonnull + @Override + public String getVersion() + { + return model.getVersion(); + } + + public String getName() + { + return model.getName(); + } + + @Nonnull + @Override + public String getPackaging() + { + return model.getPackaging(); + } + + @Nonnull + @Override + public Artifact getArtifact() + { + return artifact; + } + + @Nonnull + @Override + public Model getModel() + { + return model; + } + + @Nonnull + @Override + public Optional getPomPath() + { + return Optional.ofNullable( pomPath ).map( File::toPath ); + } + + @Nonnull + @Override + public List getDependencies() + { + return null; + } + + @Nonnull + @Override + public List getManagedDependencies() + { + return null; + } + + @Override + public Optional getBasedir() + { + return Optional.ofNullable( basedir ); + } + + public void setBasedir( Path basedir ) + { + this.basedir = basedir; + } + + @Override + public boolean isExecutionRoot() + { + return executionRoot; + } + + @Override + public Optional getParent() + { + return Optional.empty(); + } + + @Override + public List getRemoteProjectRepositories() + { + return Collections.emptyList(); + } + + @Override + public List getRemotePluginRepositories() + { + return Collections.emptyList(); + } + + public void setGroupId( String groupId ) + { + model = model.withGroupId( groupId ); + } + + public void setArtifactId( String artifactId ) + { + model = model.withArtifactId( artifactId ); + } + + public void setVersion( String version ) + { + model = model.withVersion( version ); + } + + public void setName( String name ) + { + model = model.withName( name ); + } + + public void setPackaging( String packaging ) + { + model = model.withPackaging( packaging ); + } + + public void setArtifact( Artifact artifact ) + { + this.artifact = artifact; + } + + public void setPomPath( File pomPath ) + { + this.pomPath = pomPath; + } + + public void setExecutionRoot( boolean executionRoot ) + { + this.executionRoot = executionRoot; + } + + public void setMavenModel( org.apache.maven.model.Model model ) + { + this.model = model.getDelegate(); + } +} diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/SessionStub.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/SessionStub.java new file mode 100644 index 00000000..c6d23054 --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/plugin/testing/stubs/SessionStub.java @@ -0,0 +1,299 @@ +package org.apache.maven.api.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.net.URI; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + +import org.apache.maven.api.Artifact; +import org.apache.maven.api.LocalRepository; +import org.apache.maven.api.Project; +import org.apache.maven.api.RemoteRepository; +import org.apache.maven.api.Session; +import org.apache.maven.api.model.Model; +import org.apache.maven.api.model.Repository; +import org.apache.maven.api.services.ArtifactDeployer; +import org.apache.maven.api.services.ArtifactDeployerRequest; +import org.apache.maven.api.services.ArtifactFactory; +import org.apache.maven.api.services.ArtifactFactoryRequest; +import org.apache.maven.api.services.ArtifactInstaller; +import org.apache.maven.api.services.ArtifactInstallerRequest; +import org.apache.maven.api.services.ArtifactManager; +import org.apache.maven.api.services.LocalRepositoryManager; +import org.apache.maven.api.services.ProjectBuilder; +import org.apache.maven.api.services.ProjectBuilderRequest; +import org.apache.maven.api.services.ProjectBuilderResult; +import org.apache.maven.api.services.ProjectManager; +import org.apache.maven.api.services.RepositoryFactory; +import org.apache.maven.api.services.xml.ModelXmlFactory; +import org.apache.maven.internal.impl.DefaultModelXmlFactory; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.mockito.ArgumentMatchers; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.withSettings; + +/** + * + */ +public class SessionStub +{ + + public static Session getMockSession( String localRepo ) + { + LocalRepository localRepository = mock( LocalRepository.class ); + when( localRepository.getId() ).thenReturn( "local" ); + when( localRepository.getPath() ).thenReturn( Paths.get( localRepo ) ); + return getMockSession( localRepository ); + } + + public static Session getMockSession( LocalRepository localRepository ) + { + Session session = mock( Session.class ); + + RepositoryFactory repositoryFactory = mock( RepositoryFactory.class ); + when( repositoryFactory.createRemote( any( Repository.class ) ) ) + .thenAnswer( iom -> + { + Repository repository = iom.getArgument( 0, Repository.class ); + return repositoryFactory.createRemote( repository.getId(), repository.getUrl() ); + } ); + when( repositoryFactory.createRemote( anyString(), anyString() ) ) + .thenAnswer( iom -> + { + String id = iom.getArgument( 0, String.class ); + String url = iom.getArgument( 1, String.class ); + RemoteRepository remoteRepository = mock( RemoteRepository.class, withSettings().lenient() ); + when( remoteRepository.getId() ).thenReturn( id ); + when( remoteRepository.getUrl() ).thenReturn( url ); + when( remoteRepository.getProtocol() ).thenReturn( URI.create( url ).getScheme() ); + return remoteRepository; + } ); + + LocalRepositoryManager localRepositoryManager = mock( LocalRepositoryManager.class ); + when( localRepositoryManager.getPathForLocalArtifact( any(), any(), any() ) ) + .thenAnswer( iom -> + { + LocalRepository localRepo = iom.getArgument( 1, LocalRepository.class ); + Artifact artifact = iom.getArgument( 2, Artifact.class ); + return localRepo.getPath().resolve( getPathForArtifact( artifact, true ) ); + } ); + + ArtifactInstaller artifactInstaller = mock( ArtifactInstaller.class ); + doAnswer( iom -> + { + artifactInstaller.install( ArtifactInstallerRequest.build( + iom.getArgument( 0, Session.class ), + iom.getArgument( 1, Collection.class ) ) ); + return null; + } ) + .when( artifactInstaller ) + .install( any( Session.class ), ArgumentMatchers.>any() ); + + ArtifactDeployer artifactDeployer = mock( ArtifactDeployer.class ); + doAnswer( iom -> + { + artifactDeployer.deploy( ArtifactDeployerRequest.build( + iom.getArgument( 0, Session.class ), + iom.getArgument( 1, RemoteRepository.class ), + iom.getArgument( 2, Collection.class ) ) ); + return null; + } ) + .when( artifactDeployer ).deploy( any(), any(), any() ); + + ArtifactManager artifactManager = mock( ArtifactManager.class ); + Map paths = new HashMap<>(); + doAnswer( iom -> + { + paths.put( iom.getArgument( 0 ), iom.getArgument( 1 ) ); return null; + } ) + .when( artifactManager ).setPath( any(), any() ); + doAnswer( iom -> Optional.ofNullable( paths.get( iom.getArgument( 0, Artifact.class ) ) ) ) + .when( artifactManager ).getPath( any() ); + + ProjectManager projectManager = mock( ProjectManager.class ); + Map> attachedArtifacts = new HashMap<>(); + doAnswer( iom -> + { + Project project = iom.getArgument( 1, Project.class ); + String type = iom.getArgument( 2, String.class ); + Path path = iom.getArgument( 3, Path.class ); + Artifact artifact = session.createArtifact( + project.getGroupId(), project.getArtifactId(), project.getVersion(), + null, null, type ); + artifactManager.setPath( artifact, path ); + attachedArtifacts.computeIfAbsent( project, p -> new ArrayList<>() ) + .add( artifact ); + return null; + } ) + .when( projectManager ).attachArtifact( same( session ), any( Project.class ), any(), any() ); + doAnswer( iom -> + { + Project project = iom.getArgument( 0, Project.class ); + Artifact artifact = iom.getArgument( 1, Artifact.class ); + Path path = iom.getArgument( 2, Path.class ); + artifactManager.setPath( artifact, path ); + attachedArtifacts.computeIfAbsent( project, p -> new ArrayList<>() ) + .add( artifact ); + return null; + } ) + .when( projectManager ) + .attachArtifact( any( Project.class ), any( Artifact.class ), any( Path.class ) ); + when( projectManager.getAttachedArtifacts( any() ) ) + .then( iom -> attachedArtifacts.computeIfAbsent( + iom.getArgument( 0, Project.class ), p -> new ArrayList<>() ) ); + + ArtifactFactory artifactFactory = mock( ArtifactFactory.class ); + when( artifactFactory.create( any() ) ) + .then( iom -> + { + ArtifactFactoryRequest request = iom.getArgument( 0, ArtifactFactoryRequest.class ); + String classifier = request.getClassifier(); + String extension = request.getExtension(); + String type = request.getType(); + if ( classifier == null ) + { + classifier = ""; + } + if ( extension == null ) + { + extension = type != null ? type : ""; + } + return new ArtifactStub( request.getGroupId(), request.getArtifactId(), + classifier, request.getVersion(), extension ); + } ); + + ProjectBuilder projectBuilder = mock( ProjectBuilder.class ); + when( projectBuilder.build( any( ProjectBuilderRequest.class ) ) ).then( iom -> + { + ProjectBuilderRequest request = iom.getArgument( 0, ProjectBuilderRequest.class ); + ProjectBuilderResult result = mock( ProjectBuilderResult.class ); + Model model = new MavenXpp3Reader().read( + request.getSource().get().getInputStream() ).getDelegate(); + ProjectStub projectStub = new ProjectStub(); + projectStub.setModel( model ); + ArtifactStub artifactStub = new ArtifactStub( model.getGroupId(), model.getArtifactId(), + "", model.getVersion(), model.getPackaging() ); + projectStub.setArtifact( artifactStub ); + when( result.getProject() ).thenReturn( Optional.of( projectStub ) ); + return result; + } ); + + Properties sysProps = new Properties(); + Properties usrProps = new Properties(); + doReturn( sysProps ).when( session ).getSystemProperties(); + doReturn( usrProps ).when( session ).getUserProperties(); + + when( session.getLocalRepository() ).thenReturn( localRepository ); + when( session.getService( RepositoryFactory.class ) ).thenReturn( repositoryFactory ); + when( session.getService( ProjectBuilder.class ) ).thenReturn( projectBuilder ); + when( session.getService( LocalRepositoryManager.class ) ).thenReturn( localRepositoryManager ); + when( session.getService( ProjectManager.class ) ).thenReturn( projectManager ); + when( session.getService( ArtifactManager.class ) ).thenReturn( artifactManager ); + when( session.getService( ArtifactInstaller.class ) ).thenReturn( artifactInstaller ); + when( session.getService( ArtifactDeployer.class ) ).thenReturn( artifactDeployer ); + when( session.getService( ArtifactFactory.class ) ).thenReturn( artifactFactory ); + when( session.getService( ModelXmlFactory.class ) ).thenReturn( new DefaultModelXmlFactory() ); + + when( session.getPathForLocalArtifact( any( Artifact.class ) ) ) + .then( iom -> localRepositoryManager.getPathForLocalArtifact( session, + session.getLocalRepository(), iom.getArgument( 0, Artifact.class ) ) ); + when( session.createArtifact( any(), any(), any(), any(), any(), any() ) ) + .thenAnswer( iom -> + { + String groupId = iom.getArgument( 0, String.class ); + String artifactId = iom.getArgument( 1, String.class ); + String version = iom.getArgument( 2, String.class ); + String classifier = iom.getArgument( 3, String.class ); + String extension = iom.getArgument( 4, String.class ); + String type = iom.getArgument( 5, String.class ); + return session.getService( ArtifactFactory.class ).create( ArtifactFactoryRequest.builder() + .session( session ) + .groupId( groupId ) + .artifactId( artifactId ) + .version( version ) + .classifier( classifier ) + .extension( extension ) + .type( type ) + .build() ); + } ); + when( session.createArtifact( any(), any(), any(), any() ) ) + .thenAnswer( iom -> + { + String groupId = iom.getArgument( 0, String.class ); + String artifactId = iom.getArgument( 1, String.class ); + String version = iom.getArgument( 2, String.class ); + String extension = iom.getArgument( 3, String.class ); + return session.getService( ArtifactFactory.class ).create( ArtifactFactoryRequest.builder() + .session( session ) + .groupId( groupId ) + .artifactId( artifactId ) + .version( version ) + .extension( extension ) + .build() ); + } ); + when ( session.createRemoteRepository( anyString(), anyString() ) ) + .thenAnswer( iom -> + { + String id = iom.getArgument( 0, String.class ); + String url = iom.getArgument( 1, String.class ); + return session.getService( RepositoryFactory.class ).createRemote( id, url ); + } ); + doAnswer( iom -> artifactManager.getPath( iom.getArgument( 0, Artifact.class ) ) ) + .when( session ).getArtifactPath( any() ); + + when( session.withLocalRepository( any() ) ) + .thenAnswer( iom -> getMockSession( iom.getArgument( 0, LocalRepository.class ) ) ); + return session; + } + + static String getPathForArtifact( Artifact artifact, boolean local ) + { + StringBuilder path = new StringBuilder( 128 ); + path.append( artifact.getGroupId().replace( '.', '/' ) ).append( '/' ); + path.append( artifact.getArtifactId() ).append( '/' ); + path.append( artifact.getVersion() ).append( '/' ); + path.append( artifact.getArtifactId() ).append( '-' ); + path.append( artifact.getVersion() ); + if ( artifact.getClassifier().length() > 0 ) + { + path.append( '-' ).append( artifact.getClassifier() ); + } + if ( artifact.getExtension().length() > 0 ) + { + path.append( '.' ).append( artifact.getExtension() ); + } + return path.toString(); + } + +} 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 index fb69c6e0..acea6ec1 100644 --- 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 @@ -21,6 +21,7 @@ import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; @@ -28,7 +29,6 @@ import java.lang.reflect.Field; import java.net.MalformedURLException; import java.net.URL; -import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -39,7 +39,6 @@ import com.google.inject.Module; import org.apache.commons.io.input.XmlStreamReader; import org.apache.maven.artifact.Artifact; -import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.execution.DefaultMavenExecutionRequest; import org.apache.maven.execution.DefaultMavenExecutionResult; @@ -48,7 +47,6 @@ 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; @@ -56,8 +54,8 @@ 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.MavenRepositorySystemUtils; import org.codehaus.plexus.ContainerConfiguration; import org.codehaus.plexus.DefaultContainerConfiguration; @@ -74,7 +72,6 @@ import org.codehaus.plexus.configuration.PlexusConfiguration; import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; import org.codehaus.plexus.context.Context; -import org.codehaus.plexus.logging.LoggerManager; import org.codehaus.plexus.util.InterpolationFilterReader; import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.ReflectionUtils; @@ -153,14 +150,14 @@ protected void setUp() { PluginDescriptor pluginDescriptor = new PluginDescriptorBuilder().build( interpolationReader ); - - Artifact artifact = lookup( ArtifactFactory.class ).createBuildArtifact( pluginDescriptor.getGroupId(), + + Artifact artifact = + lookup( RepositorySystem.class ).createArtifact( pluginDescriptor.getGroupId(), pluginDescriptor.getArtifactId(), pluginDescriptor.getVersion(), ".jar" ); artifact.setFile( getPluginArtifactFile() ); pluginDescriptor.setPluginArtifact( artifact ); - //noinspection ArraysAsListWithZeroOrOneArgument pluginDescriptor.setArtifacts( Arrays.asList( artifact ) ); for ( ComponentDescriptor desc : pluginDescriptor.getComponents() ) @@ -236,7 +233,7 @@ else if ( "jar".equalsIgnoreCase( resource.getProtocol() ) ) protected InputStream getPublicDescriptorStream() throws Exception { - return Files.newInputStream( new File( getPluginDescriptorPath() ).toPath() ); + return new FileInputStream( new File( getPluginDescriptorPath() ) ); } protected String getPluginDescriptorPath() @@ -269,7 +266,6 @@ protected void setupContainer() /** * @since 3.0.0 */ - @SuppressWarnings( "EmptyMethod" ) protected void addGuiceModules( List modules ) { // no custom guice modules by default @@ -277,11 +273,15 @@ protected void addGuiceModules( List modules ) protected ContainerConfiguration setupContainerConfiguration() { - return new DefaultContainerConfiguration() - .setClassWorld( new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() ) ) + ClassWorld classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() ); + + ContainerConfiguration cc = new DefaultContainerConfiguration() + .setClassWorld( classWorld ) .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) .setAutoWiring( true ) - .setName( "maven" ); + .setName( "maven" ); + + return cc; } @Override @@ -403,12 +403,6 @@ protected T lookupMojo( String groupId, String artifactId, Stri T mojo = (T) lookup( Mojo.class, groupId + ":" + artifactId + ":" + version + ":" + goal ); - 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 @@ -494,7 +488,6 @@ protected MavenSession newMavenSession( MavenProject project ) MavenSession session = new MavenSession( container, MavenRepositorySystemUtils.newSession(), request, result ); session.setCurrentProject( project ); - //noinspection ArraysAsListWithZeroOrOneArgument session.setProjects( Arrays.asList( project ) ); return session; } @@ -525,7 +518,7 @@ private void finalizeMojoConfiguration( MojoExecution mojoExecution ) executionConfiguration = new Xpp3Dom( "configuration" ); } - Xpp3Dom defaultConfiguration = MojoDescriptorCreator.convert( mojoDescriptor ); + Xpp3Dom defaultConfiguration = new Xpp3Dom( MojoDescriptorCreator.convert( mojoDescriptor ) ); Xpp3Dom finalConfiguration = new Xpp3Dom( "configuration" ); 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 index 618d36f6..73bc8eea 100644 --- 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 @@ -316,7 +316,7 @@ public void createUnpackableFile( Artifact artifact, File destFile ) WarArchiver war = (WarArchiver) archiver; // the use of this is counter-intuitive: // http://jira.codehaus.org/browse/PLX-286 - war.setExpectWebXml( false ); + war.setIgnoreWebxml( false ); } archiver.createArchive(); } @@ -549,7 +549,7 @@ public static void setVariableValueToObject( Object object, String variable, Obj */ public static String getFormattedFileName( Artifact artifact, boolean removeVersion ) { - String destFileName; + String destFileName = null; // if there is a file and we aren't stripping the version, just get the // name directly @@ -560,7 +560,7 @@ public static String getFormattedFileName( Artifact artifact, boolean removeVers else // if offline { - String versionString; + String versionString = null; if ( !removeVersion ) { versionString = "-" + artifact.getVersion(); diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/MojoLogWrapper.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/MojoLogWrapper.java new file mode 100644 index 00000000..6fb4f247 --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/MojoLogWrapper.java @@ -0,0 +1,146 @@ +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.slf4j.Logger; + +import static java.util.Objects.requireNonNull; + +/** + * @author jdcasey + */ +public class MojoLogWrapper + implements Log +{ + private final Logger logger; + + public MojoLogWrapper( Logger logger ) + { + this.logger = requireNonNull( logger ); + } + + public void debug( CharSequence content ) + { + logger.debug( toString( content ) ); + } + + private String toString( CharSequence content ) + { + if ( content == null ) + { + return ""; + } + else + { + return content.toString(); + } + } + + @Override + public void debug( CharSequence content, Throwable error ) + { + logger.debug( toString( content ), error ); + } + + @Override + public void debug( Throwable error ) + { + logger.debug( "", error ); + } + + @Override + public void info( CharSequence content ) + { + logger.info( toString( content ) ); + } + + @Override + public void info( CharSequence content, Throwable error ) + { + logger.info( toString( content ), error ); + } + + @Override + public void info( Throwable error ) + { + logger.info( "", error ); + } + + @Override + public void warn( CharSequence content ) + { + logger.warn( toString( content ) ); + } + + @Override + public void warn( CharSequence content, Throwable error ) + { + logger.warn( toString( content ), error ); + } + + @Override + public void warn( Throwable error ) + { + logger.warn( "", error ); + } + + @Override + public void error( CharSequence content ) + { + logger.error( toString( content ) ); + } + + @Override + public void error( CharSequence content, Throwable error ) + { + logger.error( toString( content ), error ); + } + + @Override + public void error( Throwable error ) + { + logger.error( "", error ); + } + + @Override + public boolean isDebugEnabled() + { + return logger.isDebugEnabled(); + } + + @Override + public boolean isInfoEnabled() + { + return logger.isInfoEnabled(); + } + + @Override + public boolean isWarnEnabled() + { + return logger.isWarnEnabled(); + } + + @Override + public boolean isErrorEnabled() + { + return logger.isErrorEnabled(); + } +} diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/MojoRule.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/MojoRule.java index 04d25644..b430bd83 100644 --- a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/MojoRule.java +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/MojoRule.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.util.Map; +import org.apache.maven.api.Session; import org.apache.maven.execution.DefaultMavenExecutionRequest; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenSession; @@ -49,8 +50,8 @@ /** * {@link TestRule} for usage with Junit-4.10ff. This is just a wrapper for an embedded - * {@link AbstractMojoTestCase}, so all protected methods of the TestCase are - * exhibited as public in the rule. You may annotate single tests methods with + * {@link AbstractMojoTestCase}, so all {@code protected} methods of the TestCase are + * exhibited as {@code public} in the rule. You may annotate single tests methods with * {@link WithoutMojo} to prevent the rule from firing. * * @author Mirko Friedenhagen @@ -87,8 +88,7 @@ protected void before() throws Throwable /** * May be overridden in the implementation to do stuff after the current test was run. */ - @SuppressWarnings( "EmptyMethod" ) - protected void after() + protected void after() { } @@ -407,6 +407,7 @@ public void executeMojo( MavenSession session, MavenProject project, MojoExecuti { sessionScope.enter(); sessionScope.seed( MavenSession.class, session ); + sessionScope.seed( Session.class, session.getSession() ); MojoExecutionScope executionScope = lookup( MojoExecutionScope.class ); try 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 index 92172f96..3fed91fe 100644 --- 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 @@ -21,12 +21,11 @@ import java.io.File; -import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; import org.apache.maven.artifact.repository.MavenArtifactRepository; +import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; 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.layout.DefaultRepositoryLayout; /** * Stub for {@link ExpressionEvaluator} @@ -76,7 +75,7 @@ public Object evaluate( String expr ) } // Was not an expression - if ( expression.contains( "$$" ) ) + if ( expression.indexOf( "$$" ) > -1 ) { return expression.replaceAll( "\\$\\$", "\\$" ); } @@ -102,11 +101,9 @@ else if ( expression.startsWith( "basedir" ) || expression.startsWith( "project. } else if ( "localRepository".equals( expression ) ) { - return new MavenArtifactRepository( "localRepository", - "file://" + new File( PlexusTestCase.getBasedir(), "target/local-repo" ).getAbsolutePath(), - new DefaultRepositoryLayout(), - new ArtifactRepositoryPolicy( true, "release", "always" ), - new ArtifactRepositoryPolicy( true, "snapshot", "never" ) ); + File localRepo = new File( PlexusTestCase.getBasedir(), "target/local-repo" ); + return new MavenArtifactRepository( "localRepository", "file://" + localRepo.getAbsolutePath(), + new DefaultRepositoryLayout(), null, null ); } else { diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/resources/TestResources.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/resources/TestResources.java index b183c3e4..f8712923 100644 --- a/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/resources/TestResources.java +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/plugin/testing/resources/TestResources.java @@ -21,7 +21,6 @@ import java.io.File; import java.io.IOException; -import java.util.Arrays; import java.util.Collection; import java.util.Set; import java.util.TreeSet; @@ -73,7 +72,8 @@ protected void starting( Description d ) /** * Creates new clean copy of test project directory structure. The copy is named after both the test being executed * and test project name, which allows the same test project can be used by multiple tests and by different - * instances of the same parametrized tests.
+ * instances of the same parametrized tests. + *

* TODO Provide alternative working directory naming for Windows, which still limits path names to ~250 charecters */ public File getBasedir( String project ) @@ -117,7 +117,11 @@ public static void assertDirectoryContents( File dir, String... expectedPaths ) scanner.addDefaultExcludes(); scanner.scan(); - Set actual = new TreeSet<>( Arrays.asList( scanner.getIncludedFiles() ) ); + Set actual = new TreeSet<>(); + for ( String path : scanner.getIncludedFiles() ) + { + actual.add( path ); + } for ( String path : scanner.getIncludedDirectories() ) { if ( path.length() > 0 ) @@ -129,7 +133,10 @@ public static void assertDirectoryContents( File dir, String... expectedPaths ) Set expected = new TreeSet<>(); if ( expectedPaths != null ) { - expected.addAll( Arrays.asList( expectedPaths ) ); + for ( String path : expectedPaths ) + { + expected.add( path ); + } } // compare textual representation to make diff easier to understand 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 index 33b7dbae..63f15c51 100644 --- 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 @@ -185,7 +185,14 @@ public String getId() @Override public String getDependencyConflictId() { - return getGroupId() + ":" + getArtifactId() + ":" + getType() + ":" + getClassifier(); + StringBuffer buffer = new StringBuffer(); + + buffer.append( getGroupId() ); + buffer.append( ":" ).append( getArtifactId() ); + buffer.append( ":" ).append( getType() ); + buffer.append( ":" ).append( getClassifier() ); + + return buffer.toString(); } /** @@ -193,7 +200,6 @@ public String getDependencyConflictId() * * @see org.apache.maven.artifact.Artifact#addMetadata(org.apache.maven.artifact.metadata.ArtifactMetadata) */ - @SuppressWarnings( "deprecation" ) @Override public void addMetadata( ArtifactMetadata artifactMetadata ) { @@ -204,7 +210,6 @@ public void addMetadata( ArtifactMetadata artifactMetadata ) * @return null. * @see org.apache.maven.artifact.Artifact#getMetadataList() */ - @SuppressWarnings( "deprecation" ) @Override public Collection getMetadataList() { @@ -544,7 +549,6 @@ public boolean isFromAuthoritativeRepository() return true; } - @SuppressWarnings( "EmptyMethod" ) public void setFromAuthoritativeRepository( boolean fromAuthoritativeRepository ) { // nothing 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 index 4b81e857..aacb6e73 100644 --- 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 @@ -69,7 +69,6 @@ * * @author jesse */ -@SuppressWarnings( "FieldCanBeLocal" ) public class MavenProjectStub extends MavenProject { @@ -283,14 +282,19 @@ public void setRemoteArtifactRepositories( List list ) @Override public List getRemoteArtifactRepositories() { - return Collections.emptyList(); + return Collections.emptyList(); } /** {@inheritDoc} */ @Override public boolean hasParent() { - return parent != null; + if ( parent != null ) + { + return true; + } + + return false; } /** {@inheritDoc} */ @@ -333,7 +337,7 @@ public void setDependencies( List list ) @Override public List getDependencies() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -956,7 +960,7 @@ public void setMailingLists( List list ) @Override public List getMailingLists() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -989,7 +993,7 @@ public void setDevelopers( List list ) @Override public List getDevelopers() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -1022,7 +1026,7 @@ public void setContributors( List list ) @Override public List getContributors() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -1058,7 +1062,7 @@ public Build getBuild() @Override public List getResources() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -1069,7 +1073,7 @@ public List getResources() @Override public List getTestResources() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -1160,7 +1164,7 @@ public void setArtifacts( Set set ) @Override public Set getArtifacts() { - return Collections.emptySet(); + return Collections.emptySet(); } /** @@ -1171,7 +1175,7 @@ public Set getArtifacts() @Override public Map getArtifactMap() { - return Collections.emptyMap(); + return Collections.emptyMap(); } /** @@ -1193,7 +1197,7 @@ public void setPluginArtifacts( Set set ) @Override public Set getPluginArtifacts() { - return Collections.emptySet(); + return Collections.emptySet(); } /** @@ -1204,7 +1208,7 @@ public Set getPluginArtifacts() @Override public Map getPluginArtifactMap() { - return Collections.emptyMap(); + return Collections.emptyMap(); } /** @@ -1226,7 +1230,7 @@ public void setReportArtifacts( Set set ) @Override public Set getReportArtifacts() { - return Collections.emptySet(); + return Collections.emptySet(); } /** @@ -1237,7 +1241,7 @@ public Set getReportArtifacts() @Override public Map getReportArtifactMap() { - return Collections.emptyMap(); + return Collections.emptyMap(); } /** @@ -1259,7 +1263,7 @@ public void setExtensionArtifacts( Set set ) @Override public Set getExtensionArtifacts() { - return Collections.emptySet(); + return Collections.emptySet(); } /** @@ -1270,7 +1274,7 @@ public Set getExtensionArtifacts() @Override public Map getExtensionArtifactMap() { - return Collections.emptyMap(); + return Collections.emptyMap(); } /** @@ -1303,7 +1307,7 @@ public Artifact getParentArtifact() @Override public List getRepositories() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -1314,7 +1318,7 @@ public List getRepositories() @Override public List getReportPlugins() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -1325,7 +1329,7 @@ public List getReportPlugins() @Override public List getBuildPlugins() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -1336,7 +1340,7 @@ public List getBuildPlugins() @Override public List getModules() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -1353,7 +1357,6 @@ public PluginManagement getPluginManagement() /** * By default, do nothing. */ - @SuppressWarnings( "EmptyMethod" ) public void addPlugin( Plugin plugin ) { // nop @@ -1364,7 +1367,6 @@ public void addPlugin( Plugin plugin ) * * @param plugin */ - @SuppressWarnings( "EmptyMethod" ) public void injectPluginManagementInfo( Plugin plugin ) { // nop @@ -1417,7 +1419,7 @@ public ArtifactRepository getDistributionManagementArtifactRepository() @Override public List getPluginRepositories() { - return Collections.emptyList(); + return Collections.emptyList(); } /** {@inheritDoc} */ @@ -1573,7 +1575,7 @@ public Model getOriginalModel() @Override public List getBuildExtensions() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -1585,7 +1587,7 @@ public List getBuildExtensions() public Set createArtifacts( ArtifactFactory artifactFactory, String string, ArtifactFilter artifactFilter ) { - return Collections.emptySet(); + return Collections.emptySet(); } /** @@ -1629,7 +1631,7 @@ public Properties getProperties() @Override public List getFilters() { - return Collections.emptyList(); + return Collections.emptyList(); } /** @@ -1640,7 +1642,7 @@ public List getFilters() @Override public Map getProjectReferences() { - return Collections.emptyMap(); + return Collections.emptyMap(); } /** {@inheritDoc} */ 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 index 65995c83..3a5d7cb9 100644 --- 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 @@ -37,7 +37,7 @@ public class StubArtifactRepository implements ArtifactRepository { - private final String baseDir; + private String baseDir = null; /** * Default constructor @@ -274,4 +274,16 @@ public void setMirroredRepositories( List artifactRepositori { // no op } + + @Override + public boolean isBlocked() + { + return false; + } + + @Override + public void setBlocked( boolean blocked ) + { + // no op + } } 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 index cd63995b..749611f7 100644 --- a/maven-plugin-testing-harness/src/site/apt/getting-started/index.apt +++ b/maven-plugin-testing-harness/src/site/apt/getting-started/index.apt @@ -34,7 +34,7 @@ Cookbook: How To Use Maven Plugin Testing Harness? <<>> which is generated by the Maven Archetype Plugin, i.e.: +---+ -mvn archetype:generate \ +mvn archetype:create \ -DgroupId=org.apache.maven.plugin.my \ -DartifactId=maven-my-plugin \ -DarchetypeArtifactId=maven-archetype-mojo diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/api/plugin/testing/ExpressionEvaluatorTest.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/api/plugin/testing/ExpressionEvaluatorTest.java new file mode 100644 index 00000000..b86a8d07 --- /dev/null +++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/api/plugin/testing/ExpressionEvaluatorTest.java @@ -0,0 +1,111 @@ +package org.apache.maven.api.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 javax.inject.Named; + +import java.nio.file.Paths; +import java.util.Properties; + +import com.google.inject.Provides; +import org.apache.maven.api.Session; +import org.apache.maven.api.plugin.MojoException; +import org.apache.maven.api.plugin.testing.InjectMojo; +import org.apache.maven.api.plugin.testing.MojoTest; +import org.apache.maven.api.plugin.testing.stubs.SessionStub; +import org.codehaus.plexus.util.StringUtils; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; + +/** + * @author Edwin Punzalan + */ +@MojoTest +public class ExpressionEvaluatorTest +{ + + private static final String LOCAL_REPO = "target/local-repo/"; + private static final String ARTIFACT_ID = "maven-test-mojo"; + private static final String COORDINATES = "groupId:" + ARTIFACT_ID + ":version:goal"; + private static final String CONFIG = + "\n" + + " \n" + + " \n" + + " \n" + + " " + ARTIFACT_ID + "\n" + + " \n" + + " ${basedir}\n" + + " ${basedir}/workDirectory\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n"; + + @Test + @InjectMojo( goal = COORDINATES, pom = CONFIG ) + public void testInjection( ExpressionEvaluatorMojo mojo ) + { + assertDoesNotThrow( mojo::execute ); + } + + @Named( COORDINATES ) + public static class ExpressionEvaluatorMojo + implements org.apache.maven.api.plugin.Mojo + { + private String basedir; + + private String workdir; + + /** {@inheritDoc} */ + @Override + public void execute() + throws MojoException + { + if ( StringUtils.isEmpty( basedir ) ) + { + throw new MojoException( "basedir was not injected." ); + } + + if ( StringUtils.isEmpty( workdir ) ) + { + throw new MojoException( "workdir was not injected." ); + } + else if ( !workdir.startsWith( basedir ) ) + { + throw new MojoException( "workdir does not start with basedir." ); + } + } + } + + @Provides @SuppressWarnings( "unused" ) + Session session() + { + Session session = SessionStub.getMockSession( LOCAL_REPO ); + doReturn( new Properties() ).when( session ).getSystemProperties(); + doReturn( new Properties() ).when( session ).getUserProperties(); + doAnswer( iom -> Paths.get( MojoExtension.getBasedir() ) ).when( session ).getExecutionRootDirectory(); + return session; + } + +} 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 index dfbd8ab6..52070bf2 100644 --- 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 @@ -22,10 +22,14 @@ import java.io.IOException; import junit.framework.TestCase; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ArtifactStubFactoryTest - extends TestCase { + @Test public void testVersionChecks() throws IOException { ArtifactStubFactory factory = new ArtifactStubFactory(); @@ -35,7 +39,8 @@ public void testVersionChecks() throws IOException assertFalse(factory.getSnapshotArtifact().isRelease()); } - public void testCreateFiles() + @Test + 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 index 5f1f802d..2d4faa0d 100644 --- 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 @@ -22,6 +22,7 @@ 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; /** @@ -39,7 +40,7 @@ public class ExpressionEvaluatorMojo /** {@inheritDoc} */ @Override public void execute() - throws MojoExecutionException + throws MojoExecutionException, MojoFailureException { if ( StringUtils.isEmpty( 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 index e4666d59..3939bd2b 100644 --- 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 @@ -32,6 +32,7 @@ public class ExpressionEvaluatorTest extends AbstractMojoTestCase { + private Xpp3Dom pomDom; private PlexusConfiguration pluginConfiguration; @@ -42,22 +43,24 @@ protected void setUp() { super.setUp(); - String pom = "" + "\n" - + " " + "\n" - + " " + "\n" - + " " + "\n" - + " maven-test-mojo" + "\n" - + " " + "\n" - + " ${basedir}" + "\n" - + " ${basedir}/workDirectory" + "\n" - + " ${localRepository}" + "\n" - + " " + "\n" - + " " + "\n" - + " " + "\n" - + " " + "\n" - + "" + "\n"; + StringBuffer pom = new StringBuffer(); - Xpp3Dom pomDom = Xpp3DomBuilder.build( new StringReader( pom ) ); + pom.append( "" ).append( "\n" ); + pom.append( " " ).append( "\n" ); + pom.append( " " ).append( "\n" ); + pom.append( " " ).append( "\n" ); + pom.append( " maven-test-mojo" ).append( "\n" ); + pom.append( " " ).append( "\n" ); + pom.append( " ${basedir}" ).append( "\n" ); + pom.append( " ${basedir}/workDirectory" ).append( "\n" ); + pom.append( " ${localRepository}" ).append( "\n" ); + pom.append( " " ).append( "\n" ); + pom.append( " " ).append( "\n" ); + pom.append( " " ).append( "\n" ); + pom.append( " " ).append( "\n" ); + pom.append( "" ).append( "\n" ); + + pomDom = Xpp3DomBuilder.build( new StringReader( pom.toString() ) ); pluginConfiguration = extractPluginConfiguration( "maven-test-mojo", pomDom ); } diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/MojoRuleTest.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/MojoRuleTest.java index 0c7bc589..86a3902a 100644 --- a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/MojoRuleTest.java +++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/MojoRuleTest.java @@ -43,14 +43,18 @@ public class MojoRuleTest private boolean beforeWasCalled = false; @Rule - public final MojoRule rule = new MojoRule() { + public MojoRule rule = new MojoRule() { @Override - protected void before() + protected void before() throws Throwable { beforeWasCalled = true; } }; + + private String pom; + + private Xpp3Dom pomDom; private PlexusConfiguration pluginConfiguration; @@ -60,7 +64,8 @@ public void setUp() throws Exception { - String pom = "" + + pom = + "" + "" + "" + "" + @@ -74,15 +79,17 @@ public void setUp() "" + ""; - Xpp3Dom pomDom = Xpp3DomBuilder.build( new StringReader( pom ) ); + pomDom = Xpp3DomBuilder.build( new StringReader( pom ) ); pluginConfiguration = rule.extractPluginConfiguration( "maven-simple-plugin", pomDom ); } /** + * @throws Exception if any */ @Test public void testPluginConfigurationExtraction() + throws Exception { assertEquals( "valueOne", pluginConfiguration.getChild( "keyOne" ).getValue() ); @@ -159,12 +166,14 @@ public void testSettingMojoVariables() @Test @WithoutMojo public void testNoRuleWrapper() + throws Exception { assertFalse( "before executed although WithMojo annotation was added", beforeWasCalled ); } @Test public void testWithRuleWrapper() + throws Exception { assertTrue( "before executed because WithMojo annotation was not added", beforeWasCalled ); } 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 index 6858175e..8cf1f23d 100644 --- 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 @@ -19,6 +19,7 @@ * under the License. */ +import org.apache.maven.api.plugin.testing.MojoTest; import org.codehaus.plexus.configuration.PlexusConfiguration; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.codehaus.plexus.util.xml.Xpp3DomBuilder; @@ -29,9 +30,13 @@ /** * @author Jason van Zyl */ +@MojoTest public class MojoTestCaseTest extends AbstractMojoTestCase { + private String pom; + + private Xpp3Dom pomDom; private PlexusConfiguration pluginConfiguration; @@ -42,7 +47,8 @@ protected void setUp() { super.setUp(); - String pom = "" + + pom = + "" + "" + "" + "" + @@ -56,14 +62,16 @@ protected void setUp() "" + ""; - Xpp3Dom pomDom = Xpp3DomBuilder.build( new StringReader( pom ) ); + 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() ); diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/PluginArtifactFileTest.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/PluginArtifactFileTest.java index 3fb57c00..c4f32be6 100644 --- a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/PluginArtifactFileTest.java +++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/PluginArtifactFileTest.java @@ -30,6 +30,7 @@ public class PluginArtifactFileTest private static final String FS = System.getProperty( "file.separator" ); public void testArtifact() + throws Exception { MojoExecution execution = newMojoExecution( "parameters" ); // TODO dedicated test mojo 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 index 3d1bd109..85ea293b 100644 --- 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 @@ -20,6 +20,7 @@ */ import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; /** * @author Jason van Zyl @@ -43,6 +44,7 @@ public String getKeyTwo() @Override 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 index 25135ac5..4d782df0 100644 --- 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 @@ -31,7 +31,7 @@ public class TestSilentLog public void testLog() { Log log = new SilentLog(); - String text = "Text"; + String text = new String( "Text" ); Throwable e = new RuntimeException(); log.debug( text ); log.debug( text, e ); @@ -54,7 +54,7 @@ public void testLog() public void testLogger() { Logger log = new SilentLog(); - String text = "Text"; + String text = new String( "Text" ); Throwable e = new RuntimeException(); log.debug( text ); diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/resources/TestResourcesTest.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/resources/TestResourcesTest.java index 36c4b65b..c7a78e31 100644 --- a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/resources/TestResourcesTest.java +++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/resources/TestResourcesTest.java @@ -23,7 +23,7 @@ public class TestResourcesTest { - public final TestResources resources = new TestResources(); + public TestResources resources = new TestResources(); @Test( expected = IllegalStateException.class ) public void testNoRuleAnnotation() diff --git a/pom.xml b/pom.xml index 58864ee1..a09f9e24 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ under the License. org.apache.maven.plugin-testing maven-plugin-testing - 3.4.0-SNAPSHOT + 4.0.0-SNAPSHOT pom Maven Plugin Testing @@ -67,7 +67,7 @@ under the License. 3.0.0-M7 - 3.2.5 + 4.0.0-alpha-2 plugin-testing-archives/LATEST 8 2020-04-07T21:04:00Z