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 f9caf4f..bed529e 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 @@ -86,7 +86,9 @@ import org.mockito.Mockito; import org.slf4j.LoggerFactory; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mockingDetails; /** * JUnit's extension to help testing Mojos. The extension should be automatically registered @@ -151,6 +153,7 @@ public void beforeEach(ExtensionContext context) throws Exception { binder.install(new MavenProvidesModule(context.getRequiredTestInstance())); binder.requestInjection(context.getRequiredTestInstance()); binder.bind(Log.class).toInstance(new MojoLogWrapper(LoggerFactory.getLogger("anonymous"))); + binder.bind(MavenProject.class).toInstance(mockMavenProject()); binder.bind(MavenSession.class).toInstance(mockMavenSession()); binder.bind(MojoExecution.class).toInstance(mockMojoExecution()); }); @@ -180,9 +183,7 @@ public void beforeEach(ExtensionContext context) throws Exception { * @return a MojoExecution mock */ private MojoExecution mockMojoExecution() { - MojoExecution mockExecution = Mockito.mock(MojoExecution.class); - lenient().when(mockExecution.getMojoDescriptor()).thenReturn(new MojoDescriptor()); - return mockExecution; + return Mockito.mock(MojoExecution.class); } /** @@ -197,6 +198,17 @@ private MavenSession mockMavenSession() { return session; } + /** + * Default MavenProject mock + * + * @return a MavenProject mock + */ + private MavenProject mockMavenProject() { + MavenProject mavenProject = Mockito.mock(MavenProject.class); + lenient().when(mavenProject.getProperties()).thenReturn(new Properties()); + return mavenProject; + } + protected String getPluginDescriptorLocation() { return "META-INF/maven/plugin.xml"; } @@ -266,27 +278,33 @@ protected Mojo lookupMojo( PlexusContainer plexusContainer = getContainer(extensionContext); // pluginkey = groupId : artifactId : version : goal Mojo mojo = plexusContainer.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); - } - } + + Optional mojoDescriptor = descriptor.getMojos().stream() + .filter(md -> + Objects.equals(md.getImplementation(), mojo.getClass().getName())) + .findFirst(); + + if (mojoDescriptor.isPresent()) { + pluginConfiguration = finalizeConfig(pluginConfiguration, mojoDescriptor.get()); + } + + MavenSession session = plexusContainer.lookup(MavenSession.class); + MavenProject mavenProject = plexusContainer.lookup(MavenProject.class); + MojoExecution mojoExecution = plexusContainer.lookup(MojoExecution.class); + + if (mockingDetails(session).isMock()) { + lenient().when(session.getCurrentProject()).thenReturn(mavenProject); + } + + if (mockingDetails(mavenProject).isMock()) { + lenient().when(mavenProject.getBasedir()).thenReturn(new File(getTestBasedir(extensionContext))); + } + + if (mojoDescriptor.isPresent() && mockingDetails(mojoExecution).isMock()) { + lenient().when(mojoExecution.getMojoDescriptor()).thenReturn(mojoDescriptor.get()); } + if (pluginConfiguration != null) { - MavenSession session = plexusContainer.lookup(MavenSession.class); - try { - plexusContainer.lookup(MavenProject.class); - } catch (ComponentLookupException ignore) { - // nothing - } - MojoExecution mojoExecution; - try { - mojoExecution = plexusContainer.lookup(MojoExecution.class); - } catch (ComponentLookupException e) { - mojoExecution = null; - } ExpressionEvaluator evaluator = new WrapEvaluator(plexusContainer, new PluginParameterExpressionEvaluator(session, mojoExecution)); ComponentConfigurator configurator = new BasicComponentConfigurator(); @@ -299,6 +317,19 @@ protected Mojo lookupMojo( mojo.setLog(plexusContainer.lookup(Log.class)); + // clear invocations on mocks to avoid test interference + if (mockingDetails(session).isMock()) { + clearInvocations(session); + } + + if (mockingDetails(mavenProject).isMock()) { + clearInvocations(mavenProject); + } + + if (mockingDetails(mojoExecution).isMock()) { + clearInvocations(mojoExecution); + } + return mojo; } @@ -351,19 +382,6 @@ public static Xpp3Dom extractPluginConfiguration(String artifactId, Xpp3Dom pomD return pluginConfigurationElement; } - /** - * 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. *
@@ -425,7 +443,7 @@ public static void setVariableValueToObject(Object object, String variable, Obje field.set(object, value); } - static class WrapEvaluator implements TypeAwareExpressionEvaluator { + private static class WrapEvaluator implements TypeAwareExpressionEvaluator { private final PlexusContainer container; @@ -473,6 +491,10 @@ public File alignToBaseDirectory(File path) { private static class MavenProvidesModule implements Module { private final Object testInstance; + MavenProvidesModule(Object testInstance) { + this.testInstance = testInstance; + } + @Override @SuppressWarnings("unchecked") public void configure(Binder binder) { @@ -486,15 +508,14 @@ public void configure(Binder binder) { try { method.setAccessible(true); Object value = method.invoke(testInstance); + if (value == null) { + throw new IllegalArgumentException("Provides method returned null: " + method); + } binder.bind((Class) method.getReturnType()).toInstance(value); } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException(e); + throw new IllegalArgumentException(e); } } } - - MavenProvidesModule(Object testInstance) { - this.testInstance = testInstance; - } } }