View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin;
20  
21  import javax.inject.Inject;
22  
23  import java.io.File;
24  import java.net.URI;
25  import java.nio.file.Path;
26  import java.nio.file.Paths;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.Map;
30  import java.util.Objects;
31  import java.util.Properties;
32  
33  import org.apache.maven.AbstractCoreMavenComponentTestCase;
34  import org.apache.maven.RepositoryUtils;
35  import org.apache.maven.api.Artifact;
36  import org.apache.maven.api.MojoExecution;
37  import org.apache.maven.api.Session;
38  import org.apache.maven.artifact.DefaultArtifact;
39  import org.apache.maven.artifact.handler.DefaultArtifactHandler;
40  import org.apache.maven.artifact.repository.ArtifactRepository;
41  import org.apache.maven.configuration.internal.EnhancedComponentConfigurator;
42  import org.apache.maven.execution.DefaultMavenExecutionRequest;
43  import org.apache.maven.execution.DefaultMavenExecutionResult;
44  import org.apache.maven.execution.MavenExecutionRequest;
45  import org.apache.maven.execution.MavenSession;
46  import org.apache.maven.internal.impl.*;
47  import org.apache.maven.model.Build;
48  import org.apache.maven.model.Model;
49  import org.apache.maven.model.building.DefaultModelBuildingRequest;
50  import org.apache.maven.model.interpolation.reflection.IntrospectionException;
51  import org.apache.maven.model.root.RootLocator;
52  import org.apache.maven.plugin.descriptor.MojoDescriptor;
53  import org.apache.maven.plugin.descriptor.PluginDescriptor;
54  import org.apache.maven.project.CycleDetectedException;
55  import org.apache.maven.project.DuplicateProjectException;
56  import org.apache.maven.project.MavenProject;
57  import org.codehaus.plexus.MutablePlexusContainer;
58  import org.codehaus.plexus.PlexusContainer;
59  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
60  import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
61  import org.codehaus.plexus.util.Os;
62  import org.eclipse.aether.DefaultRepositorySystemSession;
63  import org.eclipse.aether.RepositorySystem;
64  import org.eclipse.aether.graph.DefaultDependencyNode;
65  import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
66  import org.eclipse.aether.repository.LocalRepository;
67  import org.eclipse.aether.repository.NoLocalRepositoryManagerException;
68  import org.junit.jupiter.api.Test;
69  
70  import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
71  import static org.junit.jupiter.api.Assertions.assertEquals;
72  import static org.junit.jupiter.api.Assertions.assertInstanceOf;
73  import static org.junit.jupiter.api.Assertions.assertNotNull;
74  import static org.junit.jupiter.api.Assertions.assertNull;
75  import static org.junit.jupiter.api.Assertions.assertSame;
76  import static org.junit.jupiter.api.Assertions.assertThrows;
77  import static org.junit.jupiter.api.Assertions.assertTrue;
78  import static org.mockito.Mockito.mock;
79  
80  /**
81   */
82  public class PluginParameterExpressionEvaluatorV4Test extends AbstractCoreMavenComponentTestCase {
83      private static final String FS = File.separator;
84  
85      @Inject
86      PlexusContainer container;
87  
88      private Path rootDirectory;
89  
90      @Test
91      public void testPluginDescriptorExpressionReference() throws Exception {
92          Session session = newSession();
93          MojoExecution exec = newMojoExecution(session);
94  
95          Object result =
96                  new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${mojo.plugin.descriptor}");
97  
98          System.out.println("Result: " + result);
99  
100         assertSame(
101                 exec.getPlugin().getDescriptor(),
102                 result,
103                 "${mojo.plugin.descriptor} expression does not return plugin descriptor.");
104     }
105 
106     @Test
107     public void testPluginArtifactsExpressionReference() throws Exception {
108         Session session = newSession();
109         MojoExecution exec = newMojoExecution(session);
110 
111         @SuppressWarnings("unchecked")
112         Collection<Artifact> depResults = (Collection<Artifact>)
113                 new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${mojo.plugin.dependencies}");
114 
115         System.out.println("Result: " + depResults);
116 
117         assertNotNull(depResults);
118         assertEquals(1, depResults.size());
119         assertEquals(
120                 exec.getPlugin().getArtifact().key(),
121                 depResults.iterator().next().key(),
122                 "dependency artifact is wrong.");
123     }
124 
125     @Test
126     public void testPluginArtifactMapExpressionReference() throws Exception {
127         Session session = newSession();
128 
129         MojoExecution exec = newMojoExecution(session);
130 
131         @SuppressWarnings("unchecked")
132         Map<String, org.apache.maven.api.Dependency> depResults = (Map<String, org.apache.maven.api.Dependency>)
133                 new PluginParameterExpressionEvaluatorV4(session, null, exec)
134                         .evaluate("${mojo.plugin.dependenciesMap}");
135 
136         System.out.println("Result: " + depResults);
137 
138         assertNotNull(depResults);
139         assertEquals(1, depResults.size());
140         assertTrue(depResults.containsKey("org.myco.plugins:my-plugin"));
141         assertEquals(
142                 exec.getPlugin().getArtifact().key(),
143                 depResults.get("org.myco.plugins:my-plugin").key(),
144                 "dependency artifact is wrong.");
145     }
146 
147     @Test
148     public void testPluginArtifactIdExpressionReference() throws Exception {
149         Session session = newSession();
150 
151         MojoExecution exec = newMojoExecution(session);
152 
153         Object result = new PluginParameterExpressionEvaluatorV4(session, null, exec)
154                 .evaluate("${mojo.plugin.artifact.artifactId}");
155 
156         System.out.println("Result: " + result);
157 
158         assertSame(
159                 exec.getPlugin().getArtifact().getArtifactId(),
160                 result,
161                 "${plugin.artifactId} expression does not return plugin descriptor's artifactId.");
162     }
163 
164     @Test
165     public void testValueExtractionWithAPomValueContainingAPath() throws Exception {
166         String expected = getTestFile("target/test-classes/target/classes").getCanonicalPath();
167 
168         Build build = new Build();
169         build.setDirectory(expected.substring(0, expected.length() - "/classes".length()));
170 
171         Model model = new Model();
172         model.setBuild(build);
173 
174         MavenProject project = new MavenProject(model);
175         project.setFile(new File("pom.xml").getCanonicalFile());
176 
177         ExpressionEvaluator expressionEvaluator = createExpressionEvaluator(project, new Properties());
178 
179         Object value = expressionEvaluator.evaluate("${project.build.directory}/classes");
180         String actual = new File(value.toString()).getCanonicalPath();
181 
182         assertEquals(expected, actual);
183     }
184 
185     @Test
186     public void testEscapedVariablePassthrough() throws Exception {
187         String var = "${var}";
188 
189         MavenProject project = createDefaultProject();
190         project.setVersion("1");
191 
192         ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
193 
194         Object value = ee.evaluate("$" + var);
195 
196         assertEquals(var, value);
197     }
198 
199     @Test
200     public void testEscapedVariablePassthroughInLargerExpression() throws Exception {
201         String var = "${var}";
202         String key = var + " with version: ${project.version}";
203 
204         MavenProject project = createDefaultProject();
205         project.setVersion("1");
206 
207         ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
208 
209         Object value = ee.evaluate("$" + key);
210 
211         assertEquals("${var} with version: 1", value);
212     }
213 
214     @Test
215     public void testMultipleSubExpressionsInLargerExpression() throws Exception {
216         String key = "${project.artifactId} with version: ${project.version}";
217 
218         MavenProject project = createDefaultProject();
219         project.setArtifactId("test");
220         project.setVersion("1");
221 
222         ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
223 
224         Object value = ee.evaluate(key);
225 
226         assertEquals("test with version: 1", value);
227     }
228 
229     @Test
230     public void testMissingPOMPropertyRefInLargerExpression() throws Exception {
231         String expr = "/path/to/someproject-${baseVersion}";
232 
233         MavenProject project = createDefaultProject();
234 
235         ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
236 
237         Object value = ee.evaluate(expr);
238 
239         assertEquals(expr, value);
240     }
241 
242     @Test
243     public void testPOMPropertyExtractionWithMissingProject_WithDotNotation() throws Exception {
244         String key = "m2.name";
245         String checkValue = "value";
246 
247         MavenProject project = createDefaultProject();
248         project.getModel().getProperties().setProperty(key, checkValue);
249 
250         ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
251 
252         Object value = ee.evaluate("${" + key + "}");
253 
254         assertEquals(checkValue, value);
255     }
256 
257     @Test
258     public void testValueExtractionFromSystemPropertiesWithMissingProject() throws Exception {
259         String sysprop = "PPEET_sysprop1";
260 
261         Properties executionProperties = new Properties();
262 
263         if (executionProperties.getProperty(sysprop) == null) {
264             executionProperties.setProperty(sysprop, "value");
265         }
266 
267         ExpressionEvaluator ee = createExpressionEvaluator(null, executionProperties);
268 
269         Object value = ee.evaluate("${" + sysprop + "}");
270 
271         assertEquals("value", value);
272     }
273 
274     @Test
275     public void testValueExtractionFromSystemPropertiesWithMissingProject_WithDotNotation() throws Exception {
276         String sysprop = "PPEET.sysprop2";
277 
278         Properties executionProperties = new Properties();
279 
280         if (executionProperties.getProperty(sysprop) == null) {
281             executionProperties.setProperty(sysprop, "value");
282         }
283 
284         ExpressionEvaluator ee = createExpressionEvaluator(null, executionProperties);
285 
286         Object value = ee.evaluate("${" + sysprop + "}");
287 
288         assertEquals("value", value);
289     }
290 
291     @SuppressWarnings("deprecation")
292     private static MavenSession createSession(PlexusContainer container, ArtifactRepository repo, Properties properties)
293             throws CycleDetectedException, DuplicateProjectException, NoLocalRepositoryManagerException {
294         MavenExecutionRequest request = new DefaultMavenExecutionRequest()
295                 .setSystemProperties(properties)
296                 .setGoals(Collections.<String>emptyList())
297                 .setBaseDirectory(new File(""))
298                 .setLocalRepository(repo);
299 
300         DefaultRepositorySystemSession repositorySession =
301                 new DefaultRepositorySystemSession(h -> false); // no close handle
302         repositorySession.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory()
303                 .newInstance(repositorySession, new LocalRepository(repo.getUrl())));
304         MavenSession session =
305                 new MavenSession(container, repositorySession, request, new DefaultMavenExecutionResult());
306         session.setProjects(Collections.<MavenProject>emptyList());
307         return session;
308     }
309 
310     @Test
311     public void testTwoExpressions() throws Exception {
312         MavenProject project = createDefaultProject();
313         Build build = project.getBuild();
314         build.setDirectory("expected-directory");
315         build.setFinalName("expected-finalName");
316 
317         ExpressionEvaluator expressionEvaluator = createExpressionEvaluator(project, new Properties());
318 
319         Object value = expressionEvaluator.evaluate("${project.build.directory}" + FS + "${project.build.finalName}");
320 
321         assertEquals("expected-directory" + File.separatorChar + "expected-finalName", value);
322     }
323 
324     @Test
325     public void testShouldExtractPluginArtifacts() throws Exception {
326         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
327 
328         Object value = ee.evaluate("${mojo.plugin.dependencies}");
329 
330         assertTrue(value instanceof Collection);
331 
332         @SuppressWarnings("unchecked")
333         Collection<Artifact> artifacts = (Collection<Artifact>) value;
334 
335         assertEquals(1, artifacts.size());
336 
337         Artifact result = artifacts.iterator().next();
338 
339         assertEquals("org.myco.plugins", result.getGroupId());
340     }
341 
342     @Test
343     void testRootDirectoryNotPrefixed() throws Exception {
344         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
345         assertNull(ee.evaluate("${rootDirectory}"));
346     }
347 
348     @Test
349     void testRootDirectoryWithNull() throws Exception {
350         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
351         Exception e = assertThrows(Exception.class, () -> ee.evaluate("${session.rootDirectory}"));
352         e = assertInstanceOf(IntrospectionException.class, e.getCause());
353         e = assertInstanceOf(IllegalStateException.class, e.getCause());
354         assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
355     }
356 
357     @Test
358     void testRootDirectory() throws Exception {
359         this.rootDirectory = Paths.get("myRootDirectory");
360         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
361         assertInstanceOf(Path.class, ee.evaluate("${session.rootDirectory}"));
362     }
363 
364     private MavenProject createDefaultProject() {
365         MavenProject project = new MavenProject(new Model());
366         project.setFile(new File("pom.xml").getAbsoluteFile());
367         return project;
368     }
369 
370     private ExpressionEvaluator createExpressionEvaluator(MavenProject project, Properties executionProperties)
371             throws Exception {
372         ArtifactRepository repo = getLocalRepository();
373 
374         MutablePlexusContainer container = (MutablePlexusContainer) getContainer();
375         MavenSession mavenSession = createSession(container, repo, executionProperties);
376         mavenSession.setCurrentProject(project);
377         mavenSession.getRequest().setRootDirectory(rootDirectory);
378         mavenSession.getRequest().setTopDirectory(rootDirectory);
379 
380         DefaultSession session = new DefaultSession(
381                 mavenSession, mock(RepositorySystem.class), null, null, new DefaultLookup(container), null);
382 
383         MojoExecution mojoExecution = newMojoExecution(session);
384 
385         return new PluginParameterExpressionEvaluatorV4(
386                 session, project != null ? new DefaultProject(session, project) : null, mojoExecution);
387     }
388 
389     private MojoExecution newMojoExecution(Session session) {
390         PluginDescriptor pd = new PluginDescriptor();
391         pd.setArtifactId("my-plugin");
392         pd.setGroupId("org.myco.plugins");
393         pd.setVersion("1");
394 
395         DefaultArtifact artifact = new DefaultArtifact(
396                 pd.getGroupId(),
397                 pd.getArtifactId(),
398                 pd.getVersion(),
399                 "compile",
400                 "maven-plugin",
401                 "",
402                 new DefaultArtifactHandler("maven-plugin"));
403         pd.setPluginArtifact(artifact);
404 
405         pd.setArtifacts(Collections.singletonList(artifact));
406         DefaultDependencyNode node = new DefaultDependencyNode(
407                 new org.eclipse.aether.graph.Dependency(RepositoryUtils.toArtifact(artifact), "compile"));
408         pd.setDependencyNode(node);
409 
410         MojoDescriptor md = new MojoDescriptor();
411         md.setGoal("my-goal");
412         md.setPluginDescriptor(pd);
413 
414         pd.addComponentDescriptor(md);
415 
416         return new DefaultMojoExecution(
417                 InternalMavenSession.from(session), new org.apache.maven.plugin.MojoExecution(md));
418     }
419 
420     private DefaultSession newSession() throws Exception {
421         DefaultSession session = new DefaultSession(
422                 newMavenSession(), mock(RepositorySystem.class), null, null, new DefaultLookup(container), null);
423         return session;
424     }
425 
426     private MavenSession newMavenSession() throws Exception {
427         return createMavenSession(null);
428     }
429 
430     @Test
431     public void testUri() throws Exception {
432         Path path = Paths.get("").toAbsolutePath();
433 
434         MavenSession mavenSession = createMavenSession(null);
435         mavenSession.getRequest().setTopDirectory(path);
436         mavenSession.getRequest().setRootDirectory(path);
437 
438         Object result = new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null)
439                 .evaluate("${session.rootDirectory.uri}");
440         assertEquals(path.toUri(), result);
441     }
442 
443     @Test
444     public void testPath() throws Exception {
445         Path path = Paths.get("").toAbsolutePath();
446 
447         MavenSession mavenSession = createMavenSession(null);
448         mavenSession.getRequest().setTopDirectory(path);
449         mavenSession.getRequest().setRootDirectory(path);
450 
451         Object result = new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null)
452                 .evaluate("${session.rootDirectory/target}");
453         assertEquals(path.resolve("target"), result);
454     }
455 
456     @Test
457     public void testPluginInjection() throws Exception {
458         Path path = Paths.get("rép➜α").toAbsolutePath();
459 
460         MavenSession mavenSession = createMavenSession(null);
461         mavenSession.getRequest().setTopDirectory(path);
462         mavenSession.getRequest().setRootDirectory(path);
463         DefaultModelBuildingRequest mbr = new DefaultModelBuildingRequest();
464 
465         PluginParameterExpressionEvaluatorV4 evaluator =
466                 new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null);
467 
468         DefaultPlexusConfiguration configuration = new DefaultPlexusConfiguration("config");
469         configuration.addChild("uri", "${session.rootDirectory.uri}");
470         configuration.addChild("path", "${session.rootDirectory}");
471         configuration.addChild("uriString", "${session.rootDirectory.uri.string}");
472         configuration.addChild("uriAsciiString", "${session.rootDirectory.uri.ASCIIString}");
473         configuration.addChild("pathString", "${session.rootDirectory.string}");
474 
475         Mojo mojo = new Mojo();
476         new EnhancedComponentConfigurator().configureComponent(mojo, configuration, evaluator, null);
477 
478         assertEquals(
479                 Objects.equals(path.toUri().toString(), path.toUri().toASCIIString()), !Os.isFamily(Os.FAMILY_WINDOWS));
480         assertEquals(mojo.uri, path.toUri());
481         assertEquals(mojo.path, path);
482         assertEquals(mojo.uriString, path.toUri().toString());
483         assertEquals(mojo.uriAsciiString, path.toUri().toASCIIString());
484         assertEquals(mojo.pathString, path.toString());
485     }
486 
487     @Override
488     protected String getProjectsDirectory() {
489         // TODO Auto-generated method stub
490         return null;
491     }
492 
493     public static class Mojo {
494         URI uri;
495         Path path;
496         String uriString;
497         String uriAsciiString;
498         String pathString;
499     }
500 }