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