View Javadoc
1   package org.apache.maven.model.inheritance;
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.io.IOException;
24  import java.nio.file.Path;
25  
26  import org.apache.maven.api.model.Model;
27  import org.apache.maven.model.building.AbstractModelSourceTransformer;
28  import org.apache.maven.model.building.SimpleProblemCollector;
29  import org.apache.maven.model.building.TransformerContext;
30  import org.apache.maven.model.building.TransformerException;
31  import org.apache.maven.model.io.DefaultModelReader;
32  import org.apache.maven.model.io.DefaultModelWriter;
33  import org.apache.maven.model.io.ModelWriter;
34  import org.codehaus.plexus.util.xml.pull.XmlPullParser;
35  import org.junit.jupiter.api.BeforeEach;
36  import org.junit.jupiter.api.Test;
37  import org.xmlunit.matchers.CompareMatcher;
38  
39  import static org.hamcrest.MatcherAssert.assertThat;
40  import static org.junit.jupiter.api.Assertions.assertThrows;
41  import static org.junit.jupiter.api.Assertions.assertTrue;
42  
43  /**
44   * @author Hervé Boutemy
45   */
46  public class DefaultInheritanceAssemblerTest
47  {
48      private DefaultModelReader reader;
49  
50      private ModelWriter writer;
51  
52      private InheritanceAssembler assembler;
53  
54      @BeforeEach
55      public void setUp()
56          throws Exception
57      {
58          reader = new DefaultModelReader( new AbstractModelSourceTransformer()
59          {
60              @Override
61              public XmlPullParser transform( XmlPullParser parser, Path pomFile, TransformerContext context )
62                      throws IOException, TransformerException
63              {
64                  return null;
65              }
66          } );
67          writer = new DefaultModelWriter();
68          assembler = new DefaultInheritanceAssembler();
69      }
70  
71      private File getPom( String name )
72      {
73          return new File( "src/test/resources/poms/inheritance/" + name + ".xml" );
74      }
75  
76      private Model getModel( String name )
77          throws IOException
78      {
79          return reader.read( getPom( name ), null );
80      }
81  
82      @Test
83      public void testPluginConfiguration()
84          throws Exception
85      {
86          testInheritance( "plugin-configuration" );
87      }
88  
89      /**
90       * Check most classical urls inheritance: directory structure where parent POM in parent directory
91       * and child directory == artifactId
92       * @throws IOException Model read problem
93       */
94      @Test
95      public void testUrls()
96          throws Exception
97      {
98          testInheritance( "urls" );
99      }
100 
101     /**
102      * Flat directory structure: parent & child POMs in sibling directories, child directory == artifactId.
103      * @throws IOException Model read problem
104      */
105     @Test
106     public void testFlatUrls()
107         throws IOException
108     {
109         testInheritance( "flat-urls" );
110     }
111 
112     /**
113      * MNG-5951 MNG-6059 child.x.y.inherit.append.path="false" test
114      * @throws Exception
115      */
116     @Test
117     public void testNoAppendUrls()
118         throws Exception
119     {
120         testInheritance( "no-append-urls" );
121     }
122 
123     /**
124      * MNG-5951 special case test: inherit with partial override
125      * @throws Exception
126      */
127     @Test
128     public void testNoAppendUrls2()
129         throws Exception
130     {
131         testInheritance( "no-append-urls2" );
132     }
133 
134     /**
135      * MNG-5951 special case test: child.x.y.inherit.append.path="true" in child should not reset content
136      * @throws Exception
137      */
138     @Test
139     public void testNoAppendUrls3()
140         throws Exception
141     {
142         testInheritance( "no-append-urls3" );
143     }
144 
145     /**
146      * Tricky case: flat directory structure, but child directory != artifactId.
147      * Model interpolation does not give same result when calculated from build or from repo...
148      * This is why MNG-5000 fix in code is marked as bad practice (uses file names)
149      * @throws IOException Model read problem
150      */
151     @Test
152     public void testFlatTrickyUrls()
153         throws IOException
154     {
155         // parent references child with artifactId (which is not directory name)
156         // then relative path calculation will fail during build from disk but success when calculated from repo
157         try
158         {
159             // build from disk expected to fail
160             testInheritance( "tricky-flat-artifactId-urls", false );
161             //fail( "should have failed since module reference == artifactId != directory name" );
162         }
163         catch ( AssertionError afe )
164         {
165             // expected failure: wrong relative path calculation
166             assertTrue( afe.getMessage().contains(
167                                 "Expected text value 'http://www.apache.org/path/to/parent/child-artifact-id/' but was " +
168                                         "'http://www.apache.org/path/to/parent/../child-artifact-id/'" ),
169                         afe.getMessage() );
170         }
171         // but ok from repo: local disk is ignored
172         testInheritance( "tricky-flat-artifactId-urls", true );
173 
174         // parent references child with directory name (which is not artifact id)
175         // then relative path calculation will success during build from disk but fail when calculated from repo
176         testInheritance( "tricky-flat-directory-urls", false );
177 
178         AssertionError afe = assertThrows(
179                 AssertionError.class,
180                 () -> testInheritance( "tricky-flat-directory-urls", true ),
181                 "should have failed since module reference == directory name != artifactId" );
182         // expected failure
183         assertTrue( afe.getMessage().contains(
184                                 "Expected text value 'http://www.apache.org/path/to/parent/../child-artifact-id/' but was " +
185                                         "'http://www.apache.org/path/to/parent/child-artifact-id/'" ),
186                     afe.getMessage() );
187     }
188 
189     @Test
190     public void testWithEmptyUrl()
191         throws IOException
192     {
193             testInheritance( "empty-urls", false );
194     }
195 
196     public void testInheritance( String baseName )
197         throws IOException
198     {
199         testInheritance( baseName, false );
200         testInheritance( baseName, true );
201     }
202 
203     public void testInheritance( String baseName, boolean fromRepo )
204         throws IOException
205     {
206         Model parent = getModel( baseName + "-parent" );
207 
208         Model child = getModel( baseName + "-child" );
209 
210         if ( fromRepo )
211         {
212             // when model is read from repo, a stream is used, then pomFile == null
213             // (has consequences in inheritance algorithm since getProjectDirectory() returns null)
214             parent = Model.newBuilder( parent, true ).pomFile( null ).build();
215             child = Model.newBuilder( child, true ).pomFile( null ).build();
216         }
217 
218         SimpleProblemCollector problems = new SimpleProblemCollector();
219 
220         Model assembled = assembler.assembleModelInheritance( child, parent, null, problems );
221 
222         // write baseName + "-actual"
223         File actual = new File( "target/test-classes/poms/inheritance/" + baseName
224             + ( fromRepo ? "-build" : "-repo" ) + "-actual.xml" );
225         writer.write( actual, null, assembled );
226 
227         // check with getPom( baseName + "-expected" )
228         File expected = getPom( baseName + "-expected" );
229 
230         assertThat( actual, CompareMatcher.isIdenticalTo( expected ).ignoreComments().ignoreWhitespace() );
231     }
232 
233     @Test
234     public void testModulePathNotArtifactId()
235         throws IOException
236     {
237         Model parent = getModel( "module-path-not-artifactId-parent" );
238 
239         Model child = getModel( "module-path-not-artifactId-child" );
240 
241         SimpleProblemCollector problems = new SimpleProblemCollector();
242 
243         Model model = assembler.assembleModelInheritance( child, parent, null, problems );
244 
245         File actual = new File( "target/test-classes/poms/inheritance/module-path-not-artifactId-actual.xml" );
246 
247         writer.write( actual, null, model );
248 
249         // check with getPom( "module-path-not-artifactId-effective" )
250         File expected = getPom( "module-path-not-artifactId-expected" );
251 
252         assertThat( actual, CompareMatcher.isIdenticalTo(expected).ignoreComments().ignoreWhitespace() );
253     }
254 }