View Javadoc
1   package org.apache.maven.model.interpolation;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.text.SimpleDateFormat;
24  import java.util.Arrays;
25  import java.util.Calendar;
26  import java.util.Collections;
27  import java.util.Date;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Properties;
33  import java.util.TimeZone;
34  
35  import org.apache.maven.api.model.Build;
36  import org.apache.maven.api.model.Dependency;
37  import org.apache.maven.api.model.Model;
38  import org.apache.maven.api.model.Organization;
39  import org.apache.maven.api.model.Repository;
40  import org.apache.maven.api.model.Resource;
41  import org.apache.maven.api.model.Scm;
42  import org.apache.maven.model.building.DefaultModelBuildingRequest;
43  import org.apache.maven.model.building.ModelBuildingRequest;
44  import org.apache.maven.model.building.SimpleProblemCollector;
45  import org.junit.jupiter.api.BeforeEach;
46  import org.junit.jupiter.api.Test;
47  
48  import static org.junit.jupiter.api.Assertions.assertEquals;
49  import static org.junit.jupiter.api.Assertions.assertNotNull;
50  import static org.junit.jupiter.api.Assertions.assertTrue;
51  
52  /**
53   * @author jdcasey
54   */
55  public abstract class AbstractModelInterpolatorTest
56  {
57      private Properties context;
58  
59      @BeforeEach
60      public void setUp()
61      {
62          context = new Properties();
63          context.put( "basedir", "myBasedir" );
64          context.put( "project.baseUri", "myBaseUri" );
65      }
66  
67  
68      protected void assertProblemFree( SimpleProblemCollector collector )
69      {
70          assertEquals( 0, collector.getErrors().size(), "Expected no errors" );
71          assertEquals( 0, collector.getWarnings().size(), "Expected no warnings" );
72          assertEquals( 0, collector.getFatals().size(), "Expected no fatals" );
73      }
74  
75      protected void assertCollectorState( int numFatals, int numErrors, int numWarnings, SimpleProblemCollector collector )
76      {
77          assertEquals( numErrors, collector.getErrors().size(), "Errors" );
78          assertEquals( numWarnings, collector.getWarnings().size(), "Warnings" );
79          assertEquals( numFatals, collector.getFatals().size(), "Fatals" );
80      }
81  
82      private ModelBuildingRequest createModelBuildingRequest( Properties p )
83      {
84          ModelBuildingRequest config = new DefaultModelBuildingRequest();
85          if ( p != null )
86          {
87              config.setSystemProperties( p );
88          }
89          return config;
90      }
91  
92      @Test
93      public void testDefaultBuildTimestampFormatShouldFormatTimeIn24HourFormat()
94      {
95          Calendar cal = Calendar.getInstance();
96          cal.setTimeZone( MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE );
97          cal.set( Calendar.HOUR, 12 );
98          cal.set( Calendar.AM_PM, Calendar.AM );
99  
100         // just to make sure all the bases are covered...
101         cal.set( Calendar.HOUR_OF_DAY, 0 );
102         cal.set( Calendar.MINUTE, 16 );
103         cal.set( Calendar.SECOND, 0 );
104         cal.set( Calendar.YEAR, 1976 );
105         cal.set( Calendar.MONTH, Calendar.NOVEMBER );
106         cal.set( Calendar.DATE, 11 );
107 
108         Date firstTestDate = cal.getTime();
109 
110         cal.set( Calendar.HOUR, 11 );
111         cal.set( Calendar.AM_PM, Calendar.PM );
112 
113         // just to make sure all the bases are covered...
114         cal.set( Calendar.HOUR_OF_DAY, 23 );
115 
116         Date secondTestDate = cal.getTime();
117 
118         SimpleDateFormat format = new SimpleDateFormat( MavenBuildTimestamp.DEFAULT_BUILD_TIMESTAMP_FORMAT );
119         format.setTimeZone( MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE );
120         assertEquals( "1976-11-11T00:16:00Z", format.format( firstTestDate ) );
121         assertEquals( "1976-11-11T23:16:00Z", format.format( secondTestDate ) );
122     }
123 
124     @Test
125     public void testDefaultBuildTimestampFormatWithLocalTimeZoneMidnightRollover()
126     {
127         Calendar cal = Calendar.getInstance();
128         cal.setTimeZone( TimeZone.getTimeZone( "Europe/Berlin" ) );
129 
130         cal.set( Calendar.HOUR_OF_DAY, 1 );
131         cal.set( Calendar.MINUTE, 16 );
132         cal.set( Calendar.SECOND, 0 );
133         cal.set( Calendar.YEAR, 2014 );
134         cal.set( Calendar.MONTH, Calendar.JUNE );
135         cal.set( Calendar.DATE, 16 );
136 
137         Date firstTestDate = cal.getTime();
138 
139         cal.set( Calendar.MONTH, Calendar.NOVEMBER );
140 
141         Date secondTestDate = cal.getTime();
142 
143         SimpleDateFormat format = new SimpleDateFormat( MavenBuildTimestamp.DEFAULT_BUILD_TIMESTAMP_FORMAT );
144         format.setTimeZone( MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE );
145         assertEquals( "2014-06-15T23:16:00Z", format.format( firstTestDate ) );
146         assertEquals( "2014-11-16T00:16:00Z", format.format( secondTestDate ) );
147     }
148 
149     @Test
150     public void testShouldNotThrowExceptionOnReferenceToNonExistentValue() throws Exception
151     {
152         Scm scm = Scm.newBuilder().connection( "${test}/somepath" ).build();
153         Model model = Model.newBuilder().scm( scm ).build();
154 
155         ModelInterpolator interpolator = createInterpolator();
156 
157         final SimpleProblemCollector collector = new SimpleProblemCollector();
158         Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
159                 collector );
160 
161         assertProblemFree( collector );
162         assertEquals( "${test}/somepath", out.getScm().getConnection() );
163     }
164 
165     @Test
166     public void testShouldThrowExceptionOnRecursiveScmConnectionReference() throws Exception
167     {
168         Scm scm = Scm.newBuilder().connection( "${project.scm.connection}/somepath" ).build();
169         Model model = Model.newBuilder().scm( scm ).build();
170 
171         ModelInterpolator interpolator = createInterpolator();
172 
173         final SimpleProblemCollector collector = new SimpleProblemCollector();
174         interpolator.interpolateModel( model, null, createModelBuildingRequest( context ), collector );
175         assertCollectorState( 0, 1, 0, collector );
176     }
177 
178     @Test
179     public void testShouldNotThrowExceptionOnReferenceToValueContainingNakedExpression() throws Exception
180     {
181         Scm scm = Scm.newBuilder().connection( "${test}/somepath" ).build();
182         Map<String, String> props = new HashMap<>();
183         props.put( "test", "test" );
184         Model model = Model.newBuilder().scm( scm ).properties( props ).build();
185 
186         ModelInterpolator interpolator = createInterpolator();
187 
188         final SimpleProblemCollector collector = new SimpleProblemCollector();
189         Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
190                 collector );
191 
192         assertProblemFree( collector );
193 
194         assertEquals( "test/somepath", out.getScm().getConnection() );
195     }
196 
197     @Test
198     public void shouldInterpolateOrganizationNameCorrectly() throws Exception
199     {
200         String orgName = "MyCo";
201 
202         Model model = Model.newBuilder().name( "${project.organization.name} Tools" )
203                 .organization( Organization.newBuilder().name( orgName ).build() )
204                 .build();
205 
206         ModelInterpolator interpolator = createInterpolator();
207 
208         Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
209                 new SimpleProblemCollector() );
210 
211         assertEquals( orgName + " Tools", out.getName() );
212     }
213 
214     @Test
215     public void shouldInterpolateDependencyVersionToSetSameAsProjectVersion() throws Exception
216     {
217         Model model = Model.newBuilder().version(  "3.8.1" )
218                 .dependencies( Collections.singletonList( Dependency.newBuilder().version( "${project.version}" ).build() ) )
219                 .build();
220 
221         ModelInterpolator interpolator = createInterpolator();
222 
223         final SimpleProblemCollector collector = new SimpleProblemCollector();
224         Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
225                 collector );
226         assertCollectorState( 0, 0, 0, collector );
227 
228         assertEquals( "3.8.1", ( out.getDependencies().get( 0 ) ).getVersion() );
229     }
230 
231     @Test
232     public void testShouldNotInterpolateDependencyVersionWithInvalidReference() throws Exception
233     {
234         Model model = Model.newBuilder().version(  "3.8.1" )
235                 .dependencies( Collections.singletonList( Dependency.newBuilder().version( "${something}" ).build() ) )
236                 .build();
237 
238         /*
239          // This is the desired behaviour, however there are too many crappy poms in the repo and an issue with the
240          // timing of executing the interpolation
241 
242          try
243          {
244          new RegexBasedModelInterpolator().interpolate( model, context );
245          fail( "Should have failed to interpolate with invalid reference" );
246          }
247          catch ( ModelInterpolationException expected )
248          {
249          assertTrue( true );
250          }
251          */
252 
253         ModelInterpolator interpolator = createInterpolator();
254 
255         final SimpleProblemCollector collector = new SimpleProblemCollector();
256         Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
257                 collector );
258         assertProblemFree( collector );
259 
260         assertEquals( "${something}", ( out.getDependencies().get( 0 ) ).getVersion() );
261     }
262 
263     @Test
264     public void testTwoReferences() throws Exception
265     {
266         Model model = Model.newBuilder().version(  "3.8.1" ).artifactId( "foo" )
267                 .dependencies( Collections.singletonList(
268                         Dependency.newBuilder().version( "${project.artifactId}-${project.version}" ).build() ) )
269                 .build();
270 
271         ModelInterpolator interpolator = createInterpolator();
272 
273         final SimpleProblemCollector collector = new SimpleProblemCollector();
274         Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
275                 collector );
276         assertCollectorState( 0, 0, 0, collector );
277 
278         assertEquals( "foo-3.8.1", ( out.getDependencies().get( 0 ) ).getVersion() );
279     }
280 
281     @Test
282     public void testBasedir() throws Exception
283     {
284         Model model = Model.newBuilder().version(  "3.8.1" ).artifactId( "foo" )
285                 .repositories( Collections.singletonList(
286                         Repository.newBuilder().url( "file://localhost/${basedir}/temp-repo" ).build() ) )
287                 .build();
288 
289         ModelInterpolator interpolator = createInterpolator();
290 
291         final SimpleProblemCollector collector = new SimpleProblemCollector();
292         Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest( context ), collector );
293         assertProblemFree( collector );
294 
295         assertEquals( "file://localhost/myBasedir/temp-repo", ( out.getRepositories().get( 0 ) ).getUrl() );
296     }
297 
298     @Test
299     public void testBaseUri() throws Exception
300     {
301         Model model = Model.newBuilder().version(  "3.8.1" ).artifactId( "foo" )
302                 .repositories( Collections.singletonList(
303                         Repository.newBuilder().url( "${project.baseUri}/temp-repo" ).build() ) )
304                 .build();
305 
306         ModelInterpolator interpolator = createInterpolator();
307 
308         final SimpleProblemCollector collector = new SimpleProblemCollector();
309         Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest( context ), collector );
310         assertProblemFree( collector );
311 
312         assertEquals( "myBaseUri/temp-repo", ( out.getRepositories().get( 0 ) ).getUrl() );
313     }
314 
315     @Test
316     public void testEnvars() throws Exception
317     {
318         Properties context = new Properties();
319         context.put( "env.HOME", "/path/to/home" );
320 
321         Map<String, String> modelProperties = new HashMap<>();
322         modelProperties.put( "outputDirectory", "${env.HOME}" );
323 
324         Model model = Model.newBuilder().properties( modelProperties ).build();
325 
326         ModelInterpolator interpolator = createInterpolator();
327 
328         final SimpleProblemCollector collector = new SimpleProblemCollector();
329         Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
330                 collector );
331         assertProblemFree( collector );
332 
333         assertEquals( "/path/to/home", out.getProperties().get( "outputDirectory" ) );
334     }
335 
336     @Test
337     public void envarExpressionThatEvaluatesToNullReturnsTheLiteralString() throws Exception
338     {
339 
340         Map<String, String> modelProperties = new HashMap<>();
341         modelProperties.put( "outputDirectory", "${env.DOES_NOT_EXIST}" );
342 
343         Model model = Model.newBuilder().properties( modelProperties ).build();
344 
345         ModelInterpolator interpolator = createInterpolator();
346 
347         final SimpleProblemCollector collector = new SimpleProblemCollector();
348         Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
349                 collector );
350         assertProblemFree( collector );
351 
352         assertEquals( out.getProperties().get( "outputDirectory" ), "${env.DOES_NOT_EXIST}" );
353     }
354 
355     @Test
356     public void expressionThatEvaluatesToNullReturnsTheLiteralString() throws Exception
357     {
358         Map<String, String> modelProperties = new HashMap<>();
359         modelProperties.put( "outputDirectory", "${DOES_NOT_EXIST}" );
360 
361         Model model = Model.newBuilder().properties( modelProperties ).build();
362 
363         ModelInterpolator interpolator = createInterpolator();
364 
365         final SimpleProblemCollector collector = new SimpleProblemCollector();
366         Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
367                 collector );
368         assertProblemFree( collector );
369 
370         assertEquals( out.getProperties().get( "outputDirectory" ), "${DOES_NOT_EXIST}" );
371     }
372 
373     @Test
374     public void shouldInterpolateSourceDirectoryReferencedFromResourceDirectoryCorrectly() throws Exception
375     {
376         Model model = Model.newBuilder()
377                 .build( Build.newBuilder()
378                         .sourceDirectory( "correct" )
379                         .resources( Arrays.asList(
380                                 Resource.newBuilder().directory( "${project.build.sourceDirectory}" ).build()
381                         ) )
382                         .build() )
383                 .build();
384 
385         ModelInterpolator interpolator = createInterpolator();
386 
387         final SimpleProblemCollector collector = new SimpleProblemCollector();
388         Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest( context ), collector );
389         assertCollectorState( 0, 0, 0, collector );
390 
391 
392         List<Resource> outResources = out.getBuild().getResources();
393         Iterator<Resource> resIt = outResources.iterator();
394 
395         assertEquals( model.getBuild().getSourceDirectory(), resIt.next().getDirectory() );
396     }
397 
398     @Test
399     public void shouldInterpolateUnprefixedBasedirExpression() throws Exception
400     {
401         File basedir = new File( "/test/path" );
402         Model model = Model.newBuilder()
403                 .dependencies( Collections.singletonList(
404                         Dependency.newBuilder().systemPath( "${basedir}/artifact.jar" ).build()
405                 ) ).build();
406 
407         ModelInterpolator interpolator = createInterpolator();
408 
409         final SimpleProblemCollector collector = new SimpleProblemCollector();
410         Model result = interpolator.interpolateModel( model, basedir, createModelBuildingRequest( context ),
411                 collector );
412         assertProblemFree( collector );
413 
414 
415         List<Dependency> rDeps = result.getDependencies();
416         assertNotNull( rDeps );
417         assertEquals( 1, rDeps.size() );
418         assertEquals( new File( basedir, "artifact.jar" ).getAbsolutePath(),
419                 new File( rDeps.get( 0 ).getSystemPath() ).getAbsolutePath() );
420     }
421 
422     @Test
423     public void testRecursiveExpressionCycleNPE() throws Exception
424     {
425         Map<String, String> props = new HashMap<>();
426         props.put( "aa", "${bb}" );
427         props.put( "bb", "${aa}" );
428         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
429 
430         Model model = Model.newBuilder().properties( props ).build();
431 
432         SimpleProblemCollector collector = new SimpleProblemCollector();
433         ModelInterpolator interpolator = createInterpolator();
434         interpolator.interpolateModel( model, null, request, collector );
435 
436         assertCollectorState( 0, 2, 0, collector );
437         assertTrue( collector.getErrors().get( 0 ).contains( "Detected the following recursive expression cycle" ) );
438     }
439 
440     @Test
441     public void testRecursiveExpressionCycleBaseDir() throws Exception
442     {
443         Map<String, String> props = new HashMap<>();
444         props.put( "basedir", "${basedir}" );
445         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
446 
447         Model model = Model.newBuilder().properties( props ).build();
448 
449         SimpleProblemCollector collector = new SimpleProblemCollector();
450         ModelInterpolator interpolator = createInterpolator();
451         interpolator.interpolateModel( model, null, request, collector );
452 
453         assertCollectorState( 0, 1, 0, collector );
454         assertEquals(
455                 "Resolving expression: '${basedir}': Detected the following recursive expression cycle in 'basedir': [basedir]",
456                 collector.getErrors().get( 0 ) );
457     }
458 
459     @Test
460     public void shouldIgnorePropertiesWithPomPrefix() throws Exception
461     {
462         final String orgName = "MyCo";
463         final String expectedName = "${pom.organization.name} Tools";
464 
465         Model model = Model.newBuilder()
466                 .name( expectedName )
467                 .organization( Organization.newBuilder().name( orgName ).build() )
468                 .build();
469 
470         ModelInterpolator interpolator = createInterpolator();
471         SimpleProblemCollector collector = new SimpleProblemCollector();
472         Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest( context ),
473                 collector );
474 
475         assertCollectorState( 0, 0, 0, collector );
476         assertEquals( out.getName(), expectedName );
477     }
478 
479     protected abstract ModelInterpolator createInterpolator() throws Exception;
480 
481 }