diff --git a/maven-plugin-testing-harness/pom.xml b/maven-plugin-testing-harness/pom.xml index fbf9c526..c09b4842 100644 --- a/maven-plugin-testing-harness/pom.xml +++ b/maven-plugin-testing-harness/pom.xml @@ -152,6 +152,12 @@ under the License. mockito-core 4.11.0 + + org.mockito + mockito-junit-jupiter + 4.11.0 + test + org.slf4j slf4j-simple diff --git a/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/di/Provides.java b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/di/Provides.java new file mode 100644 index 00000000..70fd0dde --- /dev/null +++ b/maven-plugin-testing-harness/src/main/java/org/apache/maven/api/di/Provides.java @@ -0,0 +1,34 @@ +/* + * 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. + */ +package org.apache.maven.api.di; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Marks a method as a provider of beans for dependency injection. + */ +@Target(METHOD) +@Retention(RUNTIME) +@Documented +public @interface Provides {} 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 index 3ea09b8f..4bc86a73 100644 --- 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 @@ -25,6 +25,8 @@ import java.io.StringReader; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; @@ -43,7 +45,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.google.inject.Binder; +import com.google.inject.Module; import com.google.inject.internal.ProviderMethodsModule; +import org.apache.maven.api.di.Provides; import org.apache.maven.execution.MavenSession; import org.apache.maven.lifecycle.internal.MojoDescriptorCreator; import org.apache.maven.plugin.Mojo; @@ -77,6 +82,7 @@ import org.junit.jupiter.api.extension.ParameterResolutionException; import org.junit.jupiter.api.extension.ParameterResolver; import org.junit.platform.commons.support.AnnotationSupport; +import org.junit.platform.commons.support.HierarchyTraversalMode; import org.mockito.Mockito; import org.slf4j.LoggerFactory; @@ -142,6 +148,7 @@ public void beforeEach(ExtensionContext context) throws Exception { ((DefaultPlexusContainer) getContainer()).addPlexusInjector(Collections.emptyList(), binder -> { binder.install(ProviderMethodsModule.forObject(context.getRequiredTestInstance())); + binder.install(new MavenProvidesModule(context.getRequiredTestInstance())); binder.requestInjection(context.getRequiredTestInstance()); binder.bind(Log.class).toInstance(new MojoLogWrapper(LoggerFactory.getLogger("anonymous"))); binder.bind(MavenSession.class).toInstance(mockMavenSession()); @@ -190,8 +197,8 @@ private MojoExecution mockMojoExecution() { */ private MavenSession mockMavenSession() { MavenSession session = Mockito.mock(MavenSession.class); - Mockito.when(session.getUserProperties()).thenReturn(new Properties()); - Mockito.when(session.getSystemProperties()).thenReturn(new Properties()); + Mockito.lenient().when(session.getUserProperties()).thenReturn(new Properties()); + Mockito.lenient().when(session.getSystemProperties()).thenReturn(new Properties()); return session; } @@ -455,4 +462,32 @@ public File alignToBaseDirectory(File path) { return evaluator.alignToBaseDirectory(path); } } + + private static class MavenProvidesModule implements Module { + private final Object testInstance; + + @Override + @SuppressWarnings("unchecked") + public void configure(Binder binder) { + List providesMethods = AnnotationSupport.findAnnotatedMethods( + testInstance.getClass(), Provides.class, HierarchyTraversalMode.BOTTOM_UP); + + for (Method method : providesMethods) { + if (method.getParameterCount() > 0) { + throw new IllegalArgumentException("Parameterized method are not supported " + method); + } + try { + method.setAccessible(true); + Object value = method.invoke(testInstance); + binder.bind((Class) method.getReturnType()).toInstance(value); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException(e); + } + } + } + + MavenProvidesModule(Object testInstance) { + this.testInstance = testInstance; + } + } } diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ProvidesInjectMojo.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ProvidesInjectMojo.java new file mode 100644 index 00000000..887e6c64 --- /dev/null +++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ProvidesInjectMojo.java @@ -0,0 +1,48 @@ +/* + * 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. + */ +package org.apache.maven.plugin.testing; + +import javax.inject.Inject; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.project.MavenProject; + +public class ProvidesInjectMojo extends AbstractMojo { + + private final MavenSession session; + private final MavenProject project; + + @Inject + public ProvidesInjectMojo(MavenSession session, MavenProject project) { + this.session = session; + this.project = project; + } + + @Override + public void execute() {} + + public MavenSession getSession() { + return session; + } + + public MavenProject getProject() { + return project; + } +} diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ProvidesInjectMojoTest.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ProvidesInjectMojoTest.java new file mode 100644 index 00000000..b5c1b24e --- /dev/null +++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ProvidesInjectMojoTest.java @@ -0,0 +1,54 @@ +/* + * 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. + */ +package org.apache.maven.plugin.testing; + +import org.apache.maven.api.di.Provides; +import org.apache.maven.api.plugin.testing.InjectMojo; +import org.apache.maven.api.plugin.testing.MojoTest; +import org.apache.maven.project.MavenProject; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +@ExtendWith(MockitoExtension.class) +@MojoTest +public class ProvidesInjectMojoTest { + + private static final String POM = "" + ""; + + @Mock + private MavenProject project; + + @Provides + public MavenProject mockMavenProject() { + return project; + } + + @Test + @InjectMojo(pom = POM, goal = "test:test-plugin:0.0.1-SNAPSHOT:provides") + public void bennShouldBeInjected(ProvidesInjectMojo mojo) { + assertNotNull(mojo); + assertNotNull(mojo.getSession()); + assertSame(project, mojo.getProject()); + } +} diff --git a/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ProvidesInjectOverrideMojoTest.java b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ProvidesInjectOverrideMojoTest.java new file mode 100644 index 00000000..a10c7b21 --- /dev/null +++ b/maven-plugin-testing-harness/src/test/java/org/apache/maven/plugin/testing/ProvidesInjectOverrideMojoTest.java @@ -0,0 +1,74 @@ +/* + * 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. + */ +package org.apache.maven.plugin.testing; + +import java.util.Properties; + +import org.apache.maven.api.di.Provides; +import org.apache.maven.api.plugin.testing.InjectMojo; +import org.apache.maven.api.plugin.testing.MojoTest; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +@MojoTest +class ProvidesInjectOverrideMojoTest { + + private static final String POM = ""; + + @Mock + private MavenProject project; + + @Mock + private MavenSession session; + + @BeforeEach + void setup() { + when(session.getUserProperties()).thenReturn(new Properties()); + when(session.getSystemProperties()).thenReturn(new Properties()); + } + + @Provides + public MavenProject mockMavenProject() { + return project; + } + + @Provides + public MavenSession mockMavenSession() { + return session; + } + + @Test + @InjectMojo(pom = POM, goal = "test:test-plugin:0.0.1-SNAPSHOT:provides") + public void bennShouldBeInjected(ProvidesInjectMojo mojo) { + assertNotNull(mojo); + // session provided by the @Provides method should be used + assertSame(session, mojo.getSession()); + assertSame(project, mojo.getProject()); + } +} diff --git a/maven-plugin-testing-harness/src/test/resources/META-INF/maven/plugin.xml b/maven-plugin-testing-harness/src/test/resources/META-INF/maven/plugin.xml index d442272a..7a17964c 100644 --- a/maven-plugin-testing-harness/src/test/resources/META-INF/maven/plugin.xml +++ b/maven-plugin-testing-harness/src/test/resources/META-INF/maven/plugin.xml @@ -79,6 +79,20 @@ under the License. ${property} + + provides + false + true + false + false + false + true + org.apache.maven.plugin.testing.ProvidesInjectMojo + java + per-lookup + once-per-session + false + \ No newline at end of file