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(Paths.get(getBasedir(), "src", "main", "resource").toString());
350 build.setResources(Arrays.asList(resource));
351
352 Resource testResource = spy(new Resource());
353 testResource.setDirectory(
354 Paths.get(getBasedir(), "src", "test", "resource").toString());
355 build.setTestResources(Arrays.asList(resource));
356
357 mavenProject.setBuild(build);
358 mavenProject.addCompileSourceRoot(build.getSourceDirectory());
359 mavenProject.addTestCompileSourceRoot(build.getTestSourceDirectory());
360
361 try {
362
363 setVariableValueToObject(
364 mavenProject, "basedir", Paths.get(getBasedir()).toFile());
365 } catch (IllegalAccessException e) {
366
367 throw new RuntimeException(e);
368 }
369
370 return mavenProject;
371 }
372
373 protected String getPluginDescriptorLocation() {
374 return "META-INF/maven/plugin.xml";
375 }
376
377 private Mojo lookupMojo(
378 ExtensionContext extensionContext,
379 Class<?> holder,
380 InjectMojo injectMojo,
381 Collection<MojoParameter> mojoParameters,
382 PluginDescriptor descriptor)
383 throws Exception {
384 String goal = injectMojo.goal();
385 String pom = injectMojo.pom();
386 Path basedir = Paths.get(getTestBasedir(extensionContext));
387 String[] coord = mojoCoordinates(goal, descriptor);
388 Xpp3Dom pomDom = null;
389 Path pomPath = null;
390 if (pom.startsWith("file:")) {
391 pomPath = basedir.resolve(pom.substring("file:".length()));
392 } else if (pom.startsWith("classpath:")) {
393 URL url = holder.getResource(pom.substring("classpath:".length()));
394 if (url == null) {
395 throw new IllegalStateException("Unable to find pom on classpath: " + pom);
396 }
397 pomPath = Paths.get(url.toURI());
398 } else if (pom.contains("<project>")) {
399 pomDom = Xpp3DomBuilder.build(new StringReader(pom));
400 } else if (!pom.isEmpty()) {
401 pomPath = basedir.resolve(pom);
402 } else if (isBasedirSet(extensionContext)) {
403
404 pomPath = basedir.resolve("pom.xml");
405 }
406
407 if (pomDom == null) {
408 if (pomPath != null && Files.exists(pomPath)) {
409 pomDom = Xpp3DomBuilder.build(new XmlStreamReader(pomPath.toFile()));
410 } else {
411 pomDom = new Xpp3Dom("");
412 }
413 }
414
415 Xpp3Dom pluginConfiguration = extractPluginConfiguration(coord[1], pomDom);
416 if (!mojoParameters.isEmpty()) {
417 List<Xpp3Dom> children = mojoParameters.stream()
418 .map(mp -> {
419 Xpp3Dom c = new Xpp3Dom(mp.name());
420 c.setValue(mp.value());
421 return c;
422 })
423 .collect(Collectors.toList());
424 Xpp3Dom config = new Xpp3Dom("configuration");
425 children.forEach(config::addChild);
426 pluginConfiguration = Xpp3Dom.mergeXpp3Dom(config, pluginConfiguration);
427 }
428 return lookupMojo(extensionContext, coord, pluginConfiguration, descriptor, pomPath);
429 }
430
431 private boolean isBasedirSet(ExtensionContext extensionContext) {
432 return extensionContext.getStore(MOJO_EXTENSION).getOrDefault(BASEDIR_IS_SET_KEY, Boolean.class, Boolean.FALSE);
433 }
434
435 protected String[] mojoCoordinates(String goal, PluginDescriptor pluginDescriptor) throws Exception {
436 if (goal.matches(".*:.*:.*:.*")) {
437 return goal.split(":");
438 } else {
439 String artifactId = pluginDescriptor.getArtifactId();
440 String groupId = pluginDescriptor.getGroupId();
441 String version = pluginDescriptor.getVersion();
442 return new String[] {groupId, artifactId, version, goal};
443 }
444 }
445
446
447
448
449 protected Mojo lookupMojo(
450 ExtensionContext extensionContext,
451 String[] coord,
452 Xpp3Dom pluginConfiguration,
453 PluginDescriptor descriptor,
454 Path pomPath)
455 throws Exception {
456 PlexusContainer plexusContainer = getContainer(extensionContext);
457
458 MavenExecutionRequest request = setupMavenExecutionRequest(extensionContext);
459 plexusContainer.lookup(MavenExecutionRequestPopulator.class).populateDefaults(request);
460 setupRepositorySession(extensionContext, request);
461
462
463 Mojo mojo = plexusContainer.lookup(Mojo.class, coord[0] + ":" + coord[1] + ":" + coord[2] + ":" + coord[3]);
464
465 Optional<MojoDescriptor> mojoDescriptor = descriptor.getMojos().stream()
466 .filter(md ->
467 Objects.equals(md.getImplementation(), mojo.getClass().getName()))
468 .findFirst();
469
470 if (mojoDescriptor.isPresent()) {
471 pluginConfiguration = finalizeConfig(pluginConfiguration, mojoDescriptor.get());
472 }
473
474 MavenSession session = plexusContainer.lookup(MavenSession.class);
475 MavenProject mavenProject = plexusContainer.lookup(MavenProject.class);
476 MojoExecution mojoExecution = plexusContainer.lookup(MojoExecution.class);
477
478 if (mockingDetails(session).isMock()) {
479 lenient().doReturn(mavenProject).when(session).getCurrentProject();
480 lenient().doReturn(request.getLocalRepository()).when(session).getLocalRepository();
481 }
482
483 if (mockingDetails(mavenProject).isMock()) {
484 File pomFile = Optional.ofNullable(pomPath).map(Path::toFile).orElse(null);
485 if (mockingDetails(mavenProject).isSpy()) {
486
487
488 mavenProject.setPomFile(pomFile);
489 } else {
490 lenient().doReturn(pomFile).when(mavenProject).getFile();
491 }
492 }
493
494 if (mojoDescriptor.isPresent() && mockingDetails(mojoExecution).isMock()) {
495 if (mockingDetails(mojoExecution).isSpy()) {
496 mojoExecution.setMojoDescriptor(mojoDescriptor.get());
497 } else {
498 lenient().doReturn(mojoDescriptor.get()).when(mojoExecution).getMojoDescriptor();
499 }
500 }
501
502 if (pluginConfiguration != null) {
503 ExpressionEvaluator evaluator =
504 new WrapEvaluator(plexusContainer, new PluginParameterExpressionEvaluator(session, mojoExecution));
505 ComponentConfigurator configurator = new BasicComponentConfigurator();
506 configurator.configureComponent(
507 mojo,
508 new XmlPlexusConfiguration(pluginConfiguration),
509 evaluator,
510 plexusContainer.getContainerRealm());
511 }
512
513 mojo.setLog(plexusContainer.lookup(Log.class));
514
515
516 if (mockingDetails(session).isMock()) {
517 clearInvocations(session);
518 }
519
520 if (mockingDetails(mavenProject).isMock()) {
521 clearInvocations(mavenProject);
522 }
523
524 if (mockingDetails(mojoExecution).isMock()) {
525 clearInvocations(mojoExecution);
526 }
527
528 return mojo;
529 }
530
531 private boolean isRealRepositorySessionNotRequired(ExtensionContext context) {
532 return !AnnotationSupport.findAnnotation(
533 context.getRequiredTestClass(), MojoTest.class, context.getEnclosingTestClasses())
534 .map(MojoTest::realRepositorySession)
535 .orElse(false);
536 }
537
538
539
540
541 private void createMavenExecutionRequest(ExtensionContext context) throws ComponentLookupException {
542 PlexusContainer container = getContainer(context);
543 MavenSession session = container.lookup(MavenSession.class);
544 MavenExecutionRequest request = session.getRequest();
545
546 if (request == null && mockingDetails(session).isMock()) {
547 lenient()
548 .doReturn(spy(new DefaultMavenExecutionRequest()))
549 .when(session)
550 .getRequest();
551 }
552 }
553
554 private MavenExecutionRequest setupMavenExecutionRequest(ExtensionContext context) throws ComponentLookupException {
555 PlexusContainer container = getContainer(context);
556 MavenSession session = container.lookup(MavenSession.class);
557 MavenExecutionRequest request = session.getRequest();
558
559 if (request == null) {
560
561 request = new DefaultMavenExecutionRequest();
562 }
563
564 if (request.getStartTime() == null) {
565 request.setStartTime(new Date());
566 }
567
568 if (request.getUserProperties().isEmpty()) {
569 request.setUserProperties(session.getUserProperties());
570 }
571
572 if (request.getSystemProperties().isEmpty()) {
573 request.setSystemProperties(session.getSystemProperties());
574 }
575
576
577 if (request.getLocalRepositoryPath() == null && request.getLocalRepository() == null) {
578 request.setLocalRepositoryPath(getTestBasedir(context) + "/target/local-repo");
579 }
580
581 if (request.getBaseDirectory() == null) {
582 request.setBaseDirectory(new File(getTestBasedir(context)));
583 }
584
585 return request;
586 }
587
588 private void setupRepositorySession(ExtensionContext context, MavenExecutionRequest request)
589 throws ComponentLookupException {
590
591 if (isRealRepositorySessionNotRequired(context)) {
592 return;
593 }
594
595 PlexusContainer container = getContainer(context);
596
597 MavenProject mavenProject = container.lookup(MavenProject.class);
598 if (mockingDetails(mavenProject).isMock()) {
599 lenient()
600 .doReturn(request.getRemoteRepositories())
601 .when(mavenProject)
602 .getRemoteArtifactRepositories();
603 lenient()
604 .doReturn(request.getPluginArtifactRepositories())
605 .when(mavenProject)
606 .getPluginArtifactRepositories();
607 lenient()
608 .doReturn(RepositoryUtils.toRepos(request.getRemoteRepositories()))
609 .when(mavenProject)
610 .getRemoteProjectRepositories();
611 lenient()
612 .doReturn(RepositoryUtils.toRepos(request.getPluginArtifactRepositories()))
613 .when(mavenProject)
614 .getRemotePluginRepositories();
615 }
616
617 RepositorySystemSession repositorySystemSession =
618 container.lookup(DefaultRepositorySystemSessionFactory.class).newRepositorySession(request);
619
620 MavenSession session = container.lookup(MavenSession.class);
621 if (mockingDetails(session).isMock()) {
622 lenient().doReturn(repositorySystemSession).when(session).getRepositorySession();
623 }
624 }
625
626 private Xpp3Dom finalizeConfig(Xpp3Dom config, MojoDescriptor mojoDescriptor) {
627 List<Xpp3Dom> children = new ArrayList<>();
628 if (mojoDescriptor != null && mojoDescriptor.getParameters() != null) {
629 Xpp3Dom defaultConfiguration = MojoDescriptorCreator.convert(mojoDescriptor);
630 for (Parameter parameter : mojoDescriptor.getParameters()) {
631 Xpp3Dom parameterConfiguration = config.getChild(parameter.getName());
632 if (parameterConfiguration == null) {
633 parameterConfiguration = config.getChild(parameter.getAlias());
634 }
635 Xpp3Dom parameterDefaults = defaultConfiguration.getChild(parameter.getName());
636 parameterConfiguration = Xpp3Dom.mergeXpp3Dom(parameterConfiguration, parameterDefaults, Boolean.TRUE);
637 if (parameterConfiguration != null) {
638 if (isEmpty(parameterConfiguration.getAttribute("implementation"))
639 && !isEmpty(parameter.getImplementation())) {
640 parameterConfiguration.setAttribute("implementation", parameter.getImplementation());
641 }
642 children.add(parameterConfiguration);
643 }
644 }
645 }
646 Xpp3Dom c = new Xpp3Dom("configuration");
647 children.forEach(c::addChild);
648 return c;
649 }
650
651 private boolean isEmpty(String str) {
652 return str == null || str.isEmpty();
653 }
654
655 private static Optional<Xpp3Dom> child(Xpp3Dom element, String name) {
656 return Optional.ofNullable(element.getChild(name));
657 }
658
659 private static Stream<Xpp3Dom> children(Xpp3Dom element) {
660 return Stream.of(element.getChildren());
661 }
662
663 public static Xpp3Dom extractPluginConfiguration(String artifactId, Xpp3Dom pomDom) throws Exception {
664 Xpp3Dom pluginConfigurationElement = child(pomDom, "build")
665 .flatMap(buildElement -> child(buildElement, "plugins"))
666 .map(MojoExtension::children)
667 .orElseGet(Stream::empty)
668 .filter(e -> e.getChild("artifactId").getValue().equals(artifactId))
669 .findFirst()
670 .flatMap(buildElement -> child(buildElement, "configuration"))
671 .orElse(Xpp3DomBuilder.build(new StringReader("<configuration/>")));
672 return pluginConfigurationElement;
673 }
674
675
676
677
678
679
680 @SuppressWarnings("unchecked")
681 public static <T> T getVariableValueFromObject(Object object, String variable) throws IllegalAccessException {
682 Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(variable, object.getClass());
683 field.setAccessible(true);
684 return (T) field.get(object);
685 }
686
687
688
689
690
691
692 public static Map<String, Object> getVariablesAndValuesFromObject(Object object) throws IllegalAccessException {
693 return getVariablesAndValuesFromObject(object.getClass(), object);
694 }
695
696
697
698
699
700
701
702
703 public static Map<String, Object> getVariablesAndValuesFromObject(Class<?> clazz, Object object)
704 throws IllegalAccessException {
705 Map<String, Object> map = new HashMap<>();
706 Field[] fields = clazz.getDeclaredFields();
707 AccessibleObject.setAccessible(fields, true);
708 for (Field field : fields) {
709 map.put(field.getName(), field.get(object));
710 }
711 Class<?> superclass = clazz.getSuperclass();
712 if (!Object.class.equals(superclass)) {
713 map.putAll(getVariablesAndValuesFromObject(superclass, object));
714 }
715 return map;
716 }
717
718
719
720
721
722 public static String getBasedir() {
723 return PlexusExtension.getBasedir();
724 }
725
726
727
728
729 public static File getTestFile(String path) {
730 return PlexusExtension.getTestFile(path);
731 }
732
733
734
735
736 public static String getTestPath(String path) {
737 return PlexusExtension.getTestPath(path);
738 }
739
740
741
742
743 public static void setVariableValueToObject(Object object, String variable, Object value)
744 throws IllegalAccessException {
745 Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(variable, object.getClass());
746 Objects.requireNonNull(field, "Field " + variable + " not found");
747 field.setAccessible(true);
748 field.set(object, value);
749 }
750
751 private static class WrapEvaluator implements TypeAwareExpressionEvaluator {
752
753 private final PlexusContainer container;
754
755 private final TypeAwareExpressionEvaluator evaluator;
756
757 WrapEvaluator(PlexusContainer container, TypeAwareExpressionEvaluator evaluator) {
758 this.container = container;
759 this.evaluator = evaluator;
760 }
761
762 @Override
763 public Object evaluate(String expression) throws ExpressionEvaluationException {
764 return evaluate(expression, null);
765 }
766
767 @Override
768 public Object evaluate(String expression, Class<?> type) throws ExpressionEvaluationException {
769 Object value = evaluator.evaluate(expression, type);
770 if (value == null) {
771 String expr = stripTokens(expression);
772 if (expr != null) {
773 try {
774 value = container.lookup(type, expr);
775 } catch (ComponentLookupException e) {
776
777 }
778 }
779 }
780 return value;
781 }
782
783 private String stripTokens(String expr) {
784 if (expr.startsWith("${") && expr.endsWith("}")) {
785 return expr.substring(2, expr.length() - 1);
786 }
787 return null;
788 }
789
790 @Override
791 public File alignToBaseDirectory(File path) {
792 return evaluator.alignToBaseDirectory(path);
793 }
794 }
795
796 private static class MavenProvidesModule implements Module {
797 private final Object testInstance;
798
799 MavenProvidesModule(Object testInstance) {
800 this.testInstance = testInstance;
801 }
802
803 @Override
804 @SuppressWarnings("unchecked")
805 public void configure(Binder binder) {
806 List<Method> providesMethods = AnnotationSupport.findAnnotatedMethods(
807 testInstance.getClass(), Provides.class, HierarchyTraversalMode.BOTTOM_UP);
808
809 for (Method method : providesMethods) {
810 if (method.getParameterCount() > 0) {
811 throw new IllegalArgumentException("Parameterized method are not supported " + method);
812 }
813 try {
814 method.setAccessible(true);
815 Object value = method.invoke(testInstance);
816 if (value == null) {
817 throw new IllegalArgumentException("Provides method returned null: " + method);
818 }
819 binder.bind((Class<Object>) method.getReturnType()).toInstance(value);
820 } catch (IllegalAccessException | InvocationTargetException e) {
821 throw new IllegalArgumentException(e);
822 }
823 }
824 }
825 }
826 }