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