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.ArrayList;
28  import java.util.Collections;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Objects;
32  import java.util.Properties;
33  
34  import org.apache.maven.AbstractCoreMavenComponentTestCase;
35  import org.apache.maven.artifact.Artifact;
36  import org.apache.maven.artifact.ArtifactUtils;
37  import org.apache.maven.artifact.repository.ArtifactRepository;
38  import org.apache.maven.bridge.MavenRepositorySystem;
39  import org.apache.maven.configuration.internal.EnhancedComponentConfigurator;
40  import org.apache.maven.execution.DefaultMavenExecutionRequest;
41  import org.apache.maven.execution.DefaultMavenExecutionResult;
42  import org.apache.maven.execution.MavenExecutionRequest;
43  import org.apache.maven.execution.MavenSession;
44  import org.apache.maven.model.Build;
45  import org.apache.maven.model.Dependency;
46  import org.apache.maven.model.Model;
47  import org.apache.maven.model.building.DefaultModelBuildingRequest;
48  import org.apache.maven.model.interpolation.reflection.IntrospectionException;
49  import org.apache.maven.model.root.RootLocator;
50  import org.apache.maven.plugin.descriptor.MojoDescriptor;
51  import org.apache.maven.plugin.descriptor.PluginDescriptor;
52  import org.apache.maven.project.CycleDetectedException;
53  import org.apache.maven.project.DuplicateProjectException;
54  import org.apache.maven.project.MavenProject;
55  import org.codehaus.plexus.MutablePlexusContainer;
56  import org.codehaus.plexus.PlexusContainer;
57  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
58  import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
59  import org.codehaus.plexus.util.Os;
60  import org.junit.jupiter.api.Test;
61  
62  import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
63  import static org.junit.jupiter.api.Assertions.assertEquals;
64  import static org.junit.jupiter.api.Assertions.assertInstanceOf;
65  import static org.junit.jupiter.api.Assertions.assertNotNull;
66  import static org.junit.jupiter.api.Assertions.assertNull;
67  import static org.junit.jupiter.api.Assertions.assertSame;
68  import static org.junit.jupiter.api.Assertions.assertThrows;
69  import static org.junit.jupiter.api.Assertions.assertTrue;
70  
71  /**
72   */
73  class PluginParameterExpressionEvaluatorTest extends AbstractCoreMavenComponentTestCase {
74      private static final String FS = File.separator;
75  
76      @Inject
77      private MavenRepositorySystem factory;
78  
79      private Path rootDirectory;
80  
81      @Test
82      void testPluginDescriptorExpressionReference() throws Exception {
83          MojoExecution exec = newMojoExecution();
84  
85          MavenSession session = newMavenSession();
86  
87          Object result = new PluginParameterExpressionEvaluator(session, exec).evaluate("${plugin}");
88  
89          System.out.println("Result: " + result);
90  
91          assertSame(
92                  exec.getMojoDescriptor().getPluginDescriptor(),
93                  result,
94                  "${plugin} expression does not return plugin descriptor.");
95      }
96  
97      @Test
98      void testPluginArtifactsExpressionReference() throws Exception {
99          MojoExecution exec = newMojoExecution();
100 
101         Artifact depArtifact = createArtifact("group", "artifact", "1");
102 
103         List<Artifact> deps = new ArrayList<>();
104         deps.add(depArtifact);
105 
106         exec.getMojoDescriptor().getPluginDescriptor().setArtifacts(deps);
107 
108         MavenSession session = newMavenSession();
109 
110         @SuppressWarnings("unchecked")
111         List<Artifact> depResults =
112                 (List<Artifact>) new PluginParameterExpressionEvaluator(session, exec).evaluate("${plugin.artifacts}");
113 
114         System.out.println("Result: " + depResults);
115 
116         assertNotNull(depResults);
117         assertEquals(1, depResults.size());
118         assertSame(depArtifact, depResults.get(0), "dependency artifact is wrong.");
119     }
120 
121     @Test
122     void testPluginArtifactMapExpressionReference() throws Exception {
123         MojoExecution exec = newMojoExecution();
124 
125         Artifact depArtifact = createArtifact("group", "artifact", "1");
126 
127         List<Artifact> deps = new ArrayList<>();
128         deps.add(depArtifact);
129 
130         exec.getMojoDescriptor().getPluginDescriptor().setArtifacts(deps);
131 
132         MavenSession session = newMavenSession();
133 
134         @SuppressWarnings("unchecked")
135         Map<String, Artifact> depResults = (Map<String, Artifact>)
136                 new PluginParameterExpressionEvaluator(session, exec).evaluate("${plugin.artifactMap}");
137 
138         System.out.println("Result: " + depResults);
139 
140         assertNotNull(depResults);
141         assertEquals(1, depResults.size());
142         assertSame(
143                 depArtifact,
144                 depResults.get(ArtifactUtils.versionlessKey(depArtifact)),
145                 "dependency artifact is wrong.");
146     }
147 
148     @Test
149     void testPluginArtifactIdExpressionReference() throws Exception {
150         MojoExecution exec = newMojoExecution();
151 
152         MavenSession session = newMavenSession();
153 
154         Object result = new PluginParameterExpressionEvaluator(session, exec).evaluate("${plugin.artifactId}");
155 
156         System.out.println("Result: " + result);
157 
158         assertSame(
159                 exec.getMojoDescriptor().getPluginDescriptor().getArtifactId(),
160                 result,
161                 "${plugin.artifactId} expression does not return plugin descriptor's artifactId.");
162     }
163 
164     @Test
165     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, null, 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     void testEscapedVariablePassthrough() throws Exception {
187         String var = "${var}";
188 
189         Model model = new Model();
190         model.setVersion("1");
191 
192         MavenProject project = new MavenProject(model);
193 
194         ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
195 
196         Object value = ee.evaluate("$" + var);
197 
198         assertEquals(var, value);
199     }
200 
201     @Test
202     void testEscapedVariablePassthroughInLargerExpression() throws Exception {
203         String var = "${var}";
204         String key = var + " with version: ${project.version}";
205 
206         Model model = new Model();
207         model.setVersion("1");
208 
209         MavenProject project = new MavenProject(model);
210 
211         ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
212 
213         Object value = ee.evaluate("$" + key);
214 
215         assertEquals("${var} with version: 1", value);
216     }
217 
218     @Test
219     void testMultipleSubExpressionsInLargerExpression() throws Exception {
220         String key = "${project.artifactId} with version: ${project.version}";
221 
222         Model model = new Model();
223         model.setArtifactId("test");
224         model.setVersion("1");
225 
226         MavenProject project = new MavenProject(model);
227 
228         ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
229 
230         Object value = ee.evaluate(key);
231 
232         assertEquals("test with version: 1", value);
233     }
234 
235     @Test
236     void testMissingPOMPropertyRefInLargerExpression() throws Exception {
237         String expr = "/path/to/someproject-${baseVersion}";
238 
239         MavenProject project = new MavenProject(new Model());
240 
241         ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
242 
243         Object value = ee.evaluate(expr);
244 
245         assertEquals(expr, value);
246     }
247 
248     @Test
249     void testPOMPropertyExtractionWithMissingProject_WithDotNotation() throws Exception {
250         String key = "m2.name";
251         String checkValue = "value";
252 
253         Properties properties = new Properties();
254         properties.setProperty(key, checkValue);
255 
256         Model model = new Model();
257         model.setProperties(properties);
258 
259         MavenProject project = new MavenProject(model);
260 
261         ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
262 
263         Object value = ee.evaluate("${" + key + "}");
264 
265         assertEquals(checkValue, value);
266     }
267 
268     @Test
269     void testBasedirExtractionWithMissingProject() throws Exception {
270         ExpressionEvaluator ee = createExpressionEvaluator(null, null, new Properties());
271 
272         Object value = ee.evaluate("${basedir}");
273 
274         assertEquals(System.getProperty("user.dir"), value);
275     }
276 
277     @Test
278     void testValueExtractionFromSystemPropertiesWithMissingProject() throws Exception {
279         String sysprop = "PPEET_sysprop1";
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, null, executionProperties);
288 
289         Object value = ee.evaluate("${" + sysprop + "}");
290 
291         assertEquals("value", value);
292     }
293 
294     @Test
295     void testValueExtractionFromSystemPropertiesWithMissingProject_WithDotNotation() throws Exception {
296         String sysprop = "PPEET.sysprop2";
297 
298         Properties executionProperties = new Properties();
299 
300         if (executionProperties.getProperty(sysprop) == null) {
301             executionProperties.setProperty(sysprop, "value");
302         }
303 
304         ExpressionEvaluator ee = createExpressionEvaluator(null, null, executionProperties);
305 
306         Object value = ee.evaluate("${" + sysprop + "}");
307 
308         assertEquals("value", value);
309     }
310 
311     @SuppressWarnings("deprecation")
312     private static MavenSession createSession(PlexusContainer container, ArtifactRepository repo, Properties properties)
313             throws CycleDetectedException, DuplicateProjectException {
314         MavenExecutionRequest request = new DefaultMavenExecutionRequest()
315                 .setSystemProperties(properties)
316                 .setGoals(Collections.<String>emptyList())
317                 .setBaseDirectory(new File(""))
318                 .setLocalRepository(repo);
319 
320         return new MavenSession(
321                 container, request, new DefaultMavenExecutionResult(), Collections.<MavenProject>emptyList());
322     }
323 
324     @Test
325     void testLocalRepositoryExtraction() throws Exception {
326         ExpressionEvaluator expressionEvaluator =
327                 createExpressionEvaluator(createDefaultProject(), null, new Properties());
328         Object value = expressionEvaluator.evaluate("${localRepository}");
329 
330         assertEquals("local", ((ArtifactRepository) value).getId());
331     }
332 
333     @Test
334     void testTwoExpressions() throws Exception {
335         Build build = new Build();
336         build.setDirectory("expected-directory");
337         build.setFinalName("expected-finalName");
338 
339         Model model = new Model();
340         model.setBuild(build);
341 
342         ExpressionEvaluator expressionEvaluator =
343                 createExpressionEvaluator(new MavenProject(model), null, new Properties());
344 
345         Object value = expressionEvaluator.evaluate("${project.build.directory}" + FS + "${project.build.finalName}");
346 
347         assertEquals("expected-directory" + File.separatorChar + "expected-finalName", value);
348     }
349 
350     @Test
351     void testShouldExtractPluginArtifacts() throws Exception {
352         PluginDescriptor pd = new PluginDescriptor();
353 
354         Artifact artifact = createArtifact("testGroup", "testArtifact", "1.0");
355 
356         pd.setArtifacts(Collections.singletonList(artifact));
357 
358         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), pd, new Properties());
359 
360         Object value = ee.evaluate("${plugin.artifacts}");
361 
362         assertTrue(value instanceof List);
363 
364         @SuppressWarnings("unchecked")
365         List<Artifact> artifacts = (List<Artifact>) value;
366 
367         assertEquals(1, artifacts.size());
368 
369         Artifact result = artifacts.get(0);
370 
371         assertEquals("testGroup", result.getGroupId());
372     }
373 
374     @Test
375     void testRootDirectoryNotPrefixed() throws Exception {
376         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
377         assertNull(ee.evaluate("${rootDirectory}"));
378     }
379 
380     @Test
381     void testRootDirectoryWithNull() throws Exception {
382         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
383         Exception e = assertThrows(Exception.class, () -> ee.evaluate("${session.rootDirectory}"));
384         e = assertInstanceOf(IntrospectionException.class, e.getCause());
385         e = assertInstanceOf(IllegalStateException.class, e.getCause());
386         assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
387     }
388 
389     @Test
390     void testRootDirectory() throws Exception {
391         this.rootDirectory = Paths.get("myRootDirectory");
392         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
393         assertInstanceOf(Path.class, ee.evaluate("${session.rootDirectory}"));
394     }
395 
396     @Test
397     public void testUri() throws Exception {
398         Path path = Paths.get("").toAbsolutePath();
399 
400         MavenSession mavenSession = createMavenSession(null);
401         mavenSession.getRequest().setTopDirectory(path);
402         mavenSession.getRequest().setRootDirectory(path);
403 
404         Object result = new PluginParameterExpressionEvaluator(mavenSession, new MojoExecution(null))
405                 .evaluate("${session.rootDirectory.uri}");
406         assertEquals(path.toUri(), result);
407     }
408 
409     @Test
410     public void testPath() throws Exception {
411         Path path = Paths.get("").toAbsolutePath();
412 
413         MavenSession mavenSession = createMavenSession(null);
414         mavenSession.getRequest().setTopDirectory(path);
415         mavenSession.getRequest().setRootDirectory(path);
416 
417         Object result = new PluginParameterExpressionEvaluator(mavenSession, new MojoExecution(null))
418                 .evaluate("${session.rootDirectory/target}");
419         assertEquals(path.resolve("target"), result);
420     }
421 
422     @Test
423     public void testPluginInjection() throws Exception {
424         Path path = Paths.get("rép➜α").toAbsolutePath();
425 
426         MavenSession mavenSession = createMavenSession(null);
427         mavenSession.getRequest().setTopDirectory(path);
428         mavenSession.getRequest().setRootDirectory(path);
429         DefaultModelBuildingRequest mbr = new DefaultModelBuildingRequest();
430 
431         PluginParameterExpressionEvaluator evaluator =
432                 new PluginParameterExpressionEvaluator(mavenSession, new MojoExecution(null));
433 
434         DefaultPlexusConfiguration configuration = new DefaultPlexusConfiguration("config");
435         configuration.addChild("uri", "${session.rootDirectory.uri}");
436         configuration.addChild("path", "${session.rootDirectory}");
437         configuration.addChild("uriString", "${session.rootDirectory.uri.string}");
438         configuration.addChild("uriAsciiString", "${session.rootDirectory.uri.ASCIIString}");
439         configuration.addChild("pathString", "${session.rootDirectory.string}");
440 
441         Mojo mojo = new Mojo();
442         new EnhancedComponentConfigurator().configureComponent(mojo, configuration, evaluator, null);
443 
444         assertEquals(
445                 Objects.equals(path.toUri().toString(), path.toUri().toASCIIString()), !Os.isFamily(Os.FAMILY_WINDOWS));
446         assertEquals(mojo.uri, path.toUri());
447         assertEquals(mojo.path, path);
448         assertEquals(mojo.uriString, path.toUri().toString());
449         assertEquals(mojo.uriAsciiString, path.toUri().toASCIIString());
450         assertEquals(mojo.pathString, path.toString());
451     }
452 
453     private MavenProject createDefaultProject() {
454         return new MavenProject(new Model());
455     }
456 
457     private ExpressionEvaluator createExpressionEvaluator(
458             MavenProject project, PluginDescriptor pluginDescriptor, Properties executionProperties) throws Exception {
459         ArtifactRepository repo = getLocalRepository();
460 
461         MutablePlexusContainer container = (MutablePlexusContainer) getContainer();
462         MavenSession session = createSession(container, repo, executionProperties);
463         session.setCurrentProject(project);
464         session.getRequest().setRootDirectory(rootDirectory);
465 
466         MojoDescriptor mojo = new MojoDescriptor();
467         mojo.setPluginDescriptor(pluginDescriptor);
468         mojo.setGoal("goal");
469 
470         MojoExecution mojoExecution = new MojoExecution(mojo);
471 
472         return new PluginParameterExpressionEvaluator(session, mojoExecution);
473     }
474 
475     protected Artifact createArtifact(String groupId, String artifactId, String version) throws Exception {
476         Dependency dependency = new Dependency();
477         dependency.setGroupId(groupId);
478         dependency.setArtifactId(artifactId);
479         dependency.setVersion(version);
480         dependency.setType("jar");
481         dependency.setScope("compile");
482 
483         return factory.createDependencyArtifact(dependency);
484     }
485 
486     private MojoExecution newMojoExecution() {
487         PluginDescriptor pd = new PluginDescriptor();
488         pd.setArtifactId("my-plugin");
489         pd.setGroupId("org.myco.plugins");
490         pd.setVersion("1");
491 
492         MojoDescriptor md = new MojoDescriptor();
493         md.setPluginDescriptor(pd);
494 
495         pd.addComponentDescriptor(md);
496 
497         return new MojoExecution(md);
498     }
499 
500     private MavenSession newMavenSession() throws Exception {
501         return createMavenSession(null);
502     }
503 
504     @Override
505     protected String getProjectsDirectory() {
506         // TODO Auto-generated method stub
507         return null;
508     }
509 
510     public static class Mojo {
511         URI uri;
512         Path path;
513         String uriString;
514         String uriAsciiString;
515         String pathString;
516     }
517 }