1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.api.plugin.testing;
20
21 import java.io.BufferedReader;
22 import java.io.File;
23 import java.io.InputStream;
24 import java.io.Reader;
25 import java.io.StringReader;
26 import java.lang.reflect.AccessibleObject;
27 import java.lang.reflect.Field;
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import java.net.URL;
31 import java.nio.file.Files;
32 import java.nio.file.Path;
33 import java.nio.file.Paths;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.Date;
39 import java.util.HashMap;
40 import java.util.LinkedHashSet;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.Objects;
44 import java.util.Optional;
45 import java.util.Properties;
46 import java.util.Set;
47 import java.util.function.Supplier;
48 import java.util.stream.Collectors;
49 import java.util.stream.Stream;
50
51 import com.google.inject.Binder;
52 import com.google.inject.Module;
53 import com.google.inject.internal.ProviderMethodsModule;
54 import org.apache.maven.RepositoryUtils;
55 import org.apache.maven.api.di.Provides;
56 import org.apache.maven.execution.DefaultMavenExecutionRequest;
57 import org.apache.maven.execution.MavenExecutionRequest;
58 import org.apache.maven.execution.MavenExecutionRequestPopulator;
59 import org.apache.maven.execution.MavenSession;
60 import org.apache.maven.execution.scope.internal.MojoExecutionScope;
61 import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
62 import org.apache.maven.lifecycle.internal.MojoDescriptorCreator;
63 import org.apache.maven.model.Build;
64 import org.apache.maven.model.Plugin;
65 import org.apache.maven.model.Resource;
66 import org.apache.maven.plugin.Mojo;
67 import org.apache.maven.plugin.MojoExecution;
68 import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
69 import org.apache.maven.plugin.descriptor.MojoDescriptor;
70 import org.apache.maven.plugin.descriptor.Parameter;
71 import org.apache.maven.plugin.descriptor.PluginDescriptor;
72 import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
73 import org.apache.maven.plugin.logging.Log;
74 import org.apache.maven.plugin.testing.MojoLogWrapper;
75 import org.apache.maven.project.MavenProject;
76 import org.apache.maven.session.scope.internal.SessionScope;
77 import org.codehaus.plexus.DefaultPlexusContainer;
78 import org.codehaus.plexus.PlexusContainer;
79 import org.codehaus.plexus.component.configurator.BasicComponentConfigurator;
80 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
81 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
82 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
83 import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator;
84 import org.codehaus.plexus.component.repository.ComponentDescriptor;
85 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
86 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
87 import org.codehaus.plexus.testing.PlexusExtension;
88 import org.codehaus.plexus.util.InterpolationFilterReader;
89 import org.codehaus.plexus.util.ReflectionUtils;
90 import org.codehaus.plexus.util.xml.XmlStreamReader;
91 import org.codehaus.plexus.util.xml.Xpp3Dom;
92 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
93 import org.eclipse.aether.RepositorySystemSession;
94 import org.junit.jupiter.api.extension.ExtensionContext;
95 import org.junit.jupiter.api.extension.ParameterContext;
96 import org.junit.jupiter.api.extension.ParameterResolutionException;
97 import org.junit.jupiter.api.extension.ParameterResolver;
98 import org.junit.platform.commons.support.AnnotationSupport;
99 import org.junit.platform.commons.support.HierarchyTraversalMode;
100 import org.mockito.Mockito;
101 import org.slf4j.LoggerFactory;
102
103 import static org.mockito.Mockito.clearInvocations;
104 import static org.mockito.Mockito.lenient;
105 import static org.mockito.Mockito.mockingDetails;
106 import static org.mockito.Mockito.spy;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 public class MojoExtension extends PlexusExtension implements ParameterResolver {
153
154
155 private static final ExtensionContext.Namespace MOJO_EXTENSION = ExtensionContext.Namespace.create("MojoExtension");
156
157 public static final String BASEDIR_IS_SET_KEY = "basedirIsSet";
158
159 @Override
160 public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
161 throws ParameterResolutionException {
162 return Mojo.class.isAssignableFrom(parameterContext.getParameter().getType())
163 && (parameterContext.isAnnotated(InjectMojo.class)
164 || parameterContext.getDeclaringExecutable().isAnnotationPresent(InjectMojo.class));
165 }
166
167 @Override
168 public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
169 throws ParameterResolutionException {
170 try {
171 InjectMojo injectMojo = parameterContext
172 .findAnnotation(InjectMojo.class)
173 .orElseGet(() -> parameterContext.getDeclaringExecutable().getAnnotation(InjectMojo.class));
174
175 Set<MojoParameter> mojoParameters = new LinkedHashSet<>();
176
177 extensionContext.getEnclosingTestClasses().forEach(testClass -> {
178 mojoParameters.addAll(Arrays.asList(testClass.getAnnotationsByType(MojoParameter.class)));
179 });
180
181 extensionContext
182 .getTestClass()
183 .map(c -> c.getAnnotationsByType(MojoParameter.class))
184 .map(Arrays::asList)
185 .ifPresent(mojoParameters::addAll);
186
187 Optional.ofNullable(parameterContext.getDeclaringExecutable().getAnnotation(MojoParameter.class))
188 .ifPresent(mojoParameters::add);
189
190 Optional.ofNullable(parameterContext.getDeclaringExecutable().getAnnotation(MojoParameters.class))
191 .map(MojoParameters::value)
192 .map(Arrays::asList)
193 .ifPresent(mojoParameters::addAll);
194
195 mojoParameters.addAll(parameterContext.findRepeatableAnnotations(MojoParameter.class));
196
197 Class<?> holder = parameterContext.getTarget().get().getClass();
198 PluginDescriptor descriptor =
199 extensionContext.getStore(MOJO_EXTENSION).get(PluginDescriptor.class, PluginDescriptor.class);
200 return lookupMojo(extensionContext, holder, injectMojo, mojoParameters, descriptor);
201 } catch (Exception e) {
202 throw new ParameterResolutionException("Unable to resolve parameter", e);
203 }
204 }
205
206 @Override
207 public void beforeEach(ExtensionContext context) throws Exception {
208 String basedir = AnnotationSupport.findAnnotation(context.getElement().get(), Basedir.class)
209 .map(Basedir::value)
210 .orElseGet(() -> {
211 return AnnotationSupport.findAnnotation(
212 context.getRequiredTestClass(), Basedir.class, context.getEnclosingTestClasses())
213 .map(Basedir::value)
214 .orElse(null);
215 });
216
217 if (basedir == null) {
218 basedir = getBasedir();
219 } else {
220 context.getStore(MOJO_EXTENSION).put(BASEDIR_IS_SET_KEY, Boolean.TRUE);
221 }
222
223 URL resource = context.getRequiredTestClass().getResource(basedir);
224 if (resource != null) {
225 basedir = Paths.get(resource.toURI()).toString();
226 }
227
228
229 basedir = new File(basedir).getAbsolutePath();
230
231 setTestBasedir(basedir, context);
232
233 PlexusContainer plexusContainer = getContainer(context);
234
235 context.getRequiredTestInstances().getAllInstances().forEach(testInstance -> ((DefaultPlexusContainer)
236 plexusContainer)
237 .addPlexusInjector(Collections.emptyList(), binder -> {
238 binder.install(ProviderMethodsModule.forObject(testInstance));
239 binder.install(new MavenProvidesModule(testInstance));
240 }));
241
242 addMock(plexusContainer, Log.class, () -> spy(new MojoLogWrapper(LoggerFactory.getLogger("anonymous"))));
243 MavenProject mavenProject = addMock(plexusContainer, MavenProject.class, this::mockMavenProject);
244 MojoExecution mojoExecution = addMock(plexusContainer, MojoExecution.class, this::mockMojoExecution);
245 MavenSession mavenSession = addMock(plexusContainer, MavenSession.class, this::mockMavenSession);
246
247
248 createMavenExecutionRequest(context);
249
250 SessionScope sessionScope = plexusContainer.lookup(SessionScope.class);
251 sessionScope.enter();
252 sessionScope.seed(MavenSession.class, mavenSession);
253
254 MojoExecutionScope executionScope = plexusContainer.lookup(MojoExecutionScope.class);
255 executionScope.enter();
256 executionScope.seed(MavenProject.class, mavenProject);
257 executionScope.seed(MojoExecution.class, mojoExecution);
258
259 context.getRequiredTestInstances().getAllInstances().forEach(testInstance -> ((DefaultPlexusContainer)
260 plexusContainer)
261 .addPlexusInjector(Collections.emptyList(), binder -> {
262 binder.requestInjection(testInstance);
263 }));
264
265 Map<Object, Object> map = plexusContainer.getContext().getContextData();
266
267 ClassLoader classLoader = context.getRequiredTestClass().getClassLoader();
268 try (InputStream is = Objects.requireNonNull(
269 classLoader.getResourceAsStream(getPluginDescriptorLocation()),
270 "Unable to find plugin descriptor: " + getPluginDescriptorLocation());
271 Reader reader = new BufferedReader(new XmlStreamReader(is));
272 InterpolationFilterReader interpolationReader = new InterpolationFilterReader(reader, map, "${", "}")) {
273
274 PluginDescriptor pluginDescriptor = new PluginDescriptorBuilder().build(interpolationReader);
275 Plugin plugin = new Plugin();
276 plugin.setGroupId(pluginDescriptor.getGroupId());
277 plugin.setArtifactId(pluginDescriptor.getArtifactId());
278 plugin.setVersion(pluginDescriptor.getVersion());
279 pluginDescriptor.setPlugin(plugin);
280 context.getStore(MOJO_EXTENSION).put(PluginDescriptor.class, pluginDescriptor);
281
282 for (ComponentDescriptor<?> desc : pluginDescriptor.getComponents()) {
283 plexusContainer.addComponentDescriptor(desc);
284 }
285 }
286 }
287
288 private <T> T addMock(PlexusContainer container, Class<T> role, Supplier<T> supplier)
289 throws ComponentLookupException {
290 if (!container.hasComponent(role)) {
291 T mock = supplier.get();
292 container.addComponent(mock, role, "default");
293 return mock;
294 } else {
295 return container.lookup(role);
296 }
297 }
298
299 @Override
300 public void afterEach(ExtensionContext context) throws Exception {
301 SessionScope sessionScope = getContainer(context).lookup(SessionScope.class);
302 sessionScope.exit();
303
304 MojoExecutionScope executionScope = getContainer(context).lookup(MojoExecutionScope.class);
305 executionScope.exit();
306
307 super.afterEach(context);
308 }
309
310
311
312
313
314
315 private MojoExecution mockMojoExecution() {
316 return spy(new MojoExecution(null));
317 }
318
319
320
321
322
323
324 private MavenSession mockMavenSession() {
325 MavenSession session = Mockito.mock(MavenSession.class);
326 lenient().when(session.getUserProperties()).thenReturn(new Properties());
327 lenient().when(session.getSystemProperties()).thenReturn(new Properties());
328 return session;
329 }
330
331
332
333
334
335
336 private MavenProject mockMavenProject() {
337 MavenProject mavenProject = spy(new MavenProject());
338 Build build = spy(new Build());
339
340 build.setDirectory(Paths.get(getBasedir(), "target").toString());
341 build.setOutputDirectory(Paths.get(getBasedir(), "target", "classes").toString());
342 build.setTestOutputDirectory(
343 Paths.get(getBasedir(), "target", "test-classes").toString());
344 build.setSourceDirectory(Paths.get(getBasedir(), "src", "main", "java").toString());
345 build.setTestSourceDirectory(
346 Paths.get(getBasedir(), "src", "test", "java").toString());
347
348 Resource resource = spy(new Resource());
349 resource.setDirectory(
350 Paths.get(getBasedir(), "src", "main", "resources").toString());
351 build.setResources(Arrays.asList(resource));
352
353 Resource testResource = spy(new Resource());
354 testResource.setDirectory(
355 Paths.get(getBasedir(), "src", "test", "resources").toString());
356 build.setTestResources(Arrays.asList(resource));
357
358 mavenProject.setBuild(build);
359 mavenProject.addCompileSourceRoot(build.getSourceDirectory());
360 mavenProject.addTestCompileSourceRoot(build.getTestSourceDirectory());
361
362 try {
363
364 setVariableValueToObject(
365 mavenProject, "basedir", Paths.get(getBasedir()).toFile());
366 } catch (IllegalAccessException e) {
367
368 throw new RuntimeException(e);
369 }
370
371 return mavenProject;
372 }
373
374 protected String getPluginDescriptorLocation() {
375 return "META-INF/maven/plugin.xml";
376 }
377
378 private Mojo lookupMojo(
379 ExtensionContext extensionContext,
380 Class<?> holder,
381 InjectMojo injectMojo,
382 Collection<MojoParameter> mojoParameters,
383 PluginDescriptor descriptor)
384 throws Exception {
385 String goal = injectMojo.goal();
386 String pom = injectMojo.pom();
387 Path basedir = Paths.get(getTestBasedir(extensionContext));
388 String[] coord = mojoCoordinates(goal, descriptor);
389 Xpp3Dom pomDom = null;
390 Path pomPath = null;
391 if (pom.startsWith("file:")) {
392 pomPath = basedir.resolve(pom.substring("file:".length()));
393 } else if (pom.startsWith("classpath:")) {
394 URL url = holder.getResource(pom.substring("classpath:".length()));
395 if (url == null) {
396 throw new IllegalStateException("Unable to find pom on classpath: " + pom);
397 }
398 pomPath = Paths.get(url.toURI());
399 } else if (pom.contains("<project>")) {
400 pomDom = Xpp3DomBuilder.build(new StringReader(pom));
401 } else if (!pom.isEmpty()) {
402 pomPath = basedir.resolve(pom);
403 } else if (isBasedirSet(extensionContext)) {
404
405 pomPath = basedir.resolve("pom.xml");
406 }
407
408 if (pomDom == null) {
409 if (pomPath != null && Files.exists(pomPath)) {
410 pomDom = Xpp3DomBuilder.build(new XmlStreamReader(pomPath.toFile()));
411 } else {
412 pomDom = new Xpp3Dom("");
413 }
414 }
415
416 Xpp3Dom pluginConfiguration = extractPluginConfiguration(coord[1], pomDom);
417 if (!mojoParameters.isEmpty()) {
418 List<Xpp3Dom> children = mojoParameters.stream()
419 .map(mp -> {
420 Xpp3Dom c = new Xpp3Dom(mp.name());
421 c.setValue(mp.value());
422 return c;
423 })
424 .collect(Collectors.toList());
425 Xpp3Dom config = new Xpp3Dom("configuration");
426 children.forEach(config::addChild);
427 pluginConfiguration = Xpp3Dom.mergeXpp3Dom(config, pluginConfiguration);
428 }
429 return lookupMojo(extensionContext, coord, pluginConfiguration, descriptor, pomPath);
430 }
431
432 private boolean isBasedirSet(ExtensionContext extensionContext) {
433 return extensionContext.getStore(MOJO_EXTENSION).getOrDefault(BASEDIR_IS_SET_KEY, Boolean.class, Boolean.FALSE);
434 }
435
436 protected String[] mojoCoordinates(String goal, PluginDescriptor pluginDescriptor) throws Exception {
437 if (goal.matches(".*:.*:.*:.*")) {
438 return goal.split(":");
439 } else {
440 String artifactId = pluginDescriptor.getArtifactId();
441 String groupId = pluginDescriptor.getGroupId();
442 String version = pluginDescriptor.getVersion();
443 return new String[] {groupId, artifactId, version, goal};
444 }
445 }
446
447
448
449
450 protected Mojo lookupMojo(
451 ExtensionContext extensionContext,
452 String[] coord,
453 Xpp3Dom pluginConfiguration,
454 PluginDescriptor descriptor,
455 Path pomPath)
456 throws Exception {
457 PlexusContainer plexusContainer = getContainer(extensionContext);
458
459 MavenExecutionRequest request = setupMavenExecutionRequest(extensionContext);
460 plexusContainer.lookup(MavenExecutionRequestPopulator.class).populateDefaults(request);
461 setupRepositorySession(extensionContext, request);
462
463
464 Mojo mojo = plexusContainer.lookup(Mojo.class, coord[0] + ":" + coord[1] + ":" + coord[2] + ":" + coord[3]);
465
466 Optional<MojoDescriptor> mojoDescriptor = descriptor.getMojos().stream()
467 .filter(md ->
468 Objects.equals(md.getImplementation(), mojo.getClass().getName()))
469 .findFirst();
470
471 if (mojoDescriptor.isPresent()) {
472 pluginConfiguration = finalizeConfig(pluginConfiguration, mojoDescriptor.get());
473 }
474
475 MavenSession session = plexusContainer.lookup(MavenSession.class);
476 MavenProject mavenProject = plexusContainer.lookup(MavenProject.class);
477 MojoExecution mojoExecution = plexusContainer.lookup(MojoExecution.class);
478
479 if (mockingDetails(session).isMock()) {
480 lenient().doReturn(mavenProject).when(session).getCurrentProject();
481 lenient().doReturn(request.getLocalRepository()).when(session).getLocalRepository();
482 }
483
484 if (mockingDetails(mavenProject).isMock()) {
485 File pomFile = Optional.ofNullable(pomPath).map(Path::toFile).orElse(null);
486 if (mockingDetails(mavenProject).isSpy()) {
487
488
489 mavenProject.setPomFile(pomFile);
490 } else {
491 lenient().doReturn(pomFile).when(mavenProject).getFile();
492 }
493 }
494
495 if (mojoDescriptor.isPresent() && mockingDetails(mojoExecution).isMock()) {
496 if (mockingDetails(mojoExecution).isSpy()) {
497 mojoExecution.setMojoDescriptor(mojoDescriptor.get());
498 } else {
499 lenient().doReturn(mojoDescriptor.get()).when(mojoExecution).getMojoDescriptor();
500 }
501 }
502
503 if (pluginConfiguration != null) {
504 ExpressionEvaluator evaluator =
505 new WrapEvaluator(plexusContainer, new PluginParameterExpressionEvaluator(session, mojoExecution));
506 ComponentConfigurator configurator = new BasicComponentConfigurator();
507 configurator.configureComponent(
508 mojo,
509 new XmlPlexusConfiguration(pluginConfiguration),
510 evaluator,
511 plexusContainer.getContainerRealm());
512 }
513
514 mojo.setLog(plexusContainer.lookup(Log.class));
515
516
517 if (mockingDetails(session).isMock()) {
518 clearInvocations(session);
519 }
520
521 if (mockingDetails(mavenProject).isMock()) {
522 clearInvocations(mavenProject);
523 }
524
525 if (mockingDetails(mojoExecution).isMock()) {
526 clearInvocations(mojoExecution);
527 }
528
529 return mojo;
530 }
531
532 private boolean isRealRepositorySessionNotRequired(ExtensionContext context) {
533 return !AnnotationSupport.findAnnotation(
534 context.getRequiredTestClass(), MojoTest.class, context.getEnclosingTestClasses())
535 .map(MojoTest::realRepositorySession)
536 .orElse(false);
537 }
538
539
540
541
542 private void createMavenExecutionRequest(ExtensionContext context) throws ComponentLookupException {
543 PlexusContainer container = getContainer(context);
544 MavenSession session = container.lookup(MavenSession.class);
545 MavenExecutionRequest request = session.getRequest();
546
547 if (request == null && mockingDetails(session).isMock()) {
548 lenient()
549 .doReturn(spy(new DefaultMavenExecutionRequest()))
550 .when(session)
551 .getRequest();
552 }
553 }
554
555 private MavenExecutionRequest setupMavenExecutionRequest(ExtensionContext context) throws ComponentLookupException {
556 PlexusContainer container = getContainer(context);
557 MavenSession session = container.lookup(MavenSession.class);
558 MavenExecutionRequest request = session.getRequest();
559
560 if (request == null) {
561
562 request = new DefaultMavenExecutionRequest();
563 }
564
565 if (request.getStartTime() == null) {
566 request.setStartTime(new Date());
567 }
568
569 if (request.getUserProperties().isEmpty()) {
570 request.setUserProperties(session.getUserProperties());
571 }
572
573 if (request.getSystemProperties().isEmpty()) {
574 request.setSystemProperties(session.getSystemProperties());
575 }
576
577
578 if (request.getLocalRepositoryPath() == null && request.getLocalRepository() == null) {
579 request.setLocalRepositoryPath(getTestBasedir(context) + "/target/local-repo");
580 }
581
582 if (request.getBaseDirectory() == null) {
583 request.setBaseDirectory(new File(getTestBasedir(context)));
584 }
585
586 return request;
587 }
588
589 private void setupRepositorySession(ExtensionContext context, MavenExecutionRequest request)
590 throws ComponentLookupException {
591
592 if (isRealRepositorySessionNotRequired(context)) {
593 return;
594 }
595
596 PlexusContainer container = getContainer(context);
597
598 MavenProject mavenProject = container.lookup(MavenProject.class);
599 if (mockingDetails(mavenProject).isMock()) {
600 lenient()
601 .doReturn(request.getRemoteRepositories())
602 .when(mavenProject)
603 .getRemoteArtifactRepositories();
604 lenient()
605 .doReturn(request.getPluginArtifactRepositories())
606 .when(mavenProject)
607 .getPluginArtifactRepositories();
608 lenient()
609 .doReturn(RepositoryUtils.toRepos(request.getRemoteRepositories()))
610 .when(mavenProject)
611 .getRemoteProjectRepositories();
612 lenient()
613 .doReturn(RepositoryUtils.toRepos(request.getPluginArtifactRepositories()))
614 .when(mavenProject)
615 .getRemotePluginRepositories();
616 }
617
618 RepositorySystemSession repositorySystemSession =
619 container.lookup(DefaultRepositorySystemSessionFactory.class).newRepositorySession(request);
620
621 MavenSession session = container.lookup(MavenSession.class);
622 if (mockingDetails(session).isMock()) {
623 lenient().doReturn(repositorySystemSession).when(session).getRepositorySession();
624 }
625 }
626
627 private Xpp3Dom finalizeConfig(Xpp3Dom config, MojoDescriptor mojoDescriptor) {
628 List<Xpp3Dom> children = new ArrayList<>();
629 if (mojoDescriptor != null && mojoDescriptor.getParameters() != null) {
630 Xpp3Dom defaultConfiguration = MojoDescriptorCreator.convert(mojoDescriptor);
631 for (Parameter parameter : mojoDescriptor.getParameters()) {
632 Xpp3Dom parameterConfiguration = config.getChild(parameter.getName());
633 if (parameterConfiguration == null) {
634 parameterConfiguration = config.getChild(parameter.getAlias());
635 }
636 Xpp3Dom parameterDefaults = defaultConfiguration.getChild(parameter.getName());
637 parameterConfiguration = Xpp3Dom.mergeXpp3Dom(parameterConfiguration, parameterDefaults, Boolean.TRUE);
638 if (parameterConfiguration != null) {
639 if (isEmpty(parameterConfiguration.getAttribute("implementation"))
640 && !isEmpty(parameter.getImplementation())) {
641 parameterConfiguration.setAttribute("implementation", parameter.getImplementation());
642 }
643 children.add(parameterConfiguration);
644 }
645 }
646 }
647 Xpp3Dom c = new Xpp3Dom("configuration");
648 children.forEach(c::addChild);
649 return c;
650 }
651
652 private boolean isEmpty(String str) {
653 return str == null || str.isEmpty();
654 }
655
656 private static Optional<Xpp3Dom> child(Xpp3Dom element, String name) {
657 return Optional.ofNullable(element.getChild(name));
658 }
659
660 private static Stream<Xpp3Dom> children(Xpp3Dom element) {
661 return Stream.of(element.getChildren());
662 }
663
664 public static Xpp3Dom extractPluginConfiguration(String artifactId, Xpp3Dom pomDom) throws Exception {
665 Xpp3Dom pluginConfigurationElement = child(pomDom, "build")
666 .flatMap(buildElement -> child(buildElement, "plugins"))
667 .map(MojoExtension::children)
668 .orElseGet(Stream::empty)
669 .filter(e -> e.getChild("artifactId").getValue().equals(artifactId))
670 .findFirst()
671 .flatMap(buildElement -> child(buildElement, "configuration"))
672 .orElse(Xpp3DomBuilder.build(new StringReader("<configuration/>")));
673 return pluginConfigurationElement;
674 }
675
676
677
678
679
680
681 @SuppressWarnings("unchecked")
682 public static <T> T getVariableValueFromObject(Object object, String variable) throws IllegalAccessException {
683 Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(variable, object.getClass());
684 field.setAccessible(true);
685 return (T) field.get(object);
686 }
687
688
689
690
691
692
693 public static Map<String, Object> getVariablesAndValuesFromObject(Object object) throws IllegalAccessException {
694 return getVariablesAndValuesFromObject(object.getClass(), object);
695 }
696
697
698
699
700
701
702
703
704 public static Map<String, Object> getVariablesAndValuesFromObject(Class<?> clazz, Object object)
705 throws IllegalAccessException {
706 Map<String, Object> map = new HashMap<>();
707 Field[] fields = clazz.getDeclaredFields();
708 AccessibleObject.setAccessible(fields, true);
709 for (Field field : fields) {
710 map.put(field.getName(), field.get(object));
711 }
712 Class<?> superclass = clazz.getSuperclass();
713 if (!Object.class.equals(superclass)) {
714 map.putAll(getVariablesAndValuesFromObject(superclass, object));
715 }
716 return map;
717 }
718
719
720
721
722
723 public static String getBasedir() {
724 return PlexusExtension.getBasedir();
725 }
726
727
728
729
730 public static File getTestFile(String path) {
731 return PlexusExtension.getTestFile(path);
732 }
733
734
735
736
737 public static String getTestPath(String path) {
738 return PlexusExtension.getTestPath(path);
739 }
740
741
742
743
744 public static void setVariableValueToObject(Object object, String variable, Object value)
745 throws IllegalAccessException {
746 Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(variable, object.getClass());
747 Objects.requireNonNull(field, "Field " + variable + " not found");
748 field.setAccessible(true);
749 field.set(object, value);
750 }
751
752 private static class WrapEvaluator implements TypeAwareExpressionEvaluator {
753
754 private final PlexusContainer container;
755
756 private final TypeAwareExpressionEvaluator evaluator;
757
758 WrapEvaluator(PlexusContainer container, TypeAwareExpressionEvaluator evaluator) {
759 this.container = container;
760 this.evaluator = evaluator;
761 }
762
763 @Override
764 public Object evaluate(String expression) throws ExpressionEvaluationException {
765 return evaluate(expression, null);
766 }
767
768 @Override
769 public Object evaluate(String expression, Class<?> type) throws ExpressionEvaluationException {
770 Object value = evaluator.evaluate(expression, type);
771 if (value == null) {
772 String expr = stripTokens(expression);
773 if (expr != null) {
774 try {
775 value = container.lookup(type, expr);
776 } catch (ComponentLookupException e) {
777
778 }
779 }
780 }
781 return value;
782 }
783
784 private String stripTokens(String expr) {
785 if (expr.startsWith("${") && expr.endsWith("}")) {
786 return expr.substring(2, expr.length() - 1);
787 }
788 return null;
789 }
790
791 @Override
792 public File alignToBaseDirectory(File path) {
793 return evaluator.alignToBaseDirectory(path);
794 }
795 }
796
797 private static class MavenProvidesModule implements Module {
798 private final Object testInstance;
799
800 MavenProvidesModule(Object testInstance) {
801 this.testInstance = testInstance;
802 }
803
804 @Override
805 @SuppressWarnings("unchecked")
806 public void configure(Binder binder) {
807 List<Method> providesMethods = AnnotationSupport.findAnnotatedMethods(
808 testInstance.getClass(), Provides.class, HierarchyTraversalMode.BOTTOM_UP);
809
810 for (Method method : providesMethods) {
811 if (method.getParameterCount() > 0) {
812 throw new IllegalArgumentException("Parameterized method are not supported " + method);
813 }
814 try {
815 method.setAccessible(true);
816 Object value = method.invoke(testInstance);
817 if (value == null) {
818 throw new IllegalArgumentException("Provides method returned null: " + method);
819 }
820 binder.bind((Class<Object>) method.getReturnType()).toInstance(value);
821 } catch (IllegalAccessException | InvocationTargetException e) {
822 throw new IllegalArgumentException(e);
823 }
824 }
825 }
826 }
827 }