View Javadoc
1   /*
2    * Copyright (c) 2011-2025 Yegor Bugayenko
3    *
4    * All rights reserved.
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions
8    * are met: 1) Redistributions of source code must retain the above
9    * copyright notice, this list of conditions and the following
10   * disclaimer. 2) Redistributions in binary form must reproduce the above
11   * copyright notice, this list of conditions and the following
12   * disclaimer in the documentation and/or other materials provided
13   * with the distribution. 3) Neither the name of the Qulice.com nor
14   * the names of its contributors may be used to endorse or promote
15   * products derived from this software without specific prior written
16   * permission.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
20   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29   * OF THE POSSIBILITY OF SUCH DAMAGE.
30   */
31  package com.qulice.maven;
32  
33  import com.google.common.base.Joiner;
34  import com.qulice.spi.Environment;
35  import com.qulice.spi.ValidationException;
36  import java.util.HashSet;
37  import java.util.Set;
38  import org.apache.maven.artifact.Artifact;
39  import org.apache.maven.plugin.testing.stubs.ArtifactStub;
40  import org.apache.maven.project.MavenProject;
41  import org.apache.maven.shared.dependency.analyzer.ProjectDependencyAnalysis;
42  import org.apache.maven.shared.dependency.analyzer.ProjectDependencyAnalyzer;
43  import org.junit.jupiter.api.Assertions;
44  import org.junit.jupiter.api.Test;
45  import org.mockito.Mockito;
46  
47  /**
48   * Test case for {@link DependenciesValidator} class.
49   * @since 0.3
50   */
51  final class DependenciesValidatorTest {
52  
53      /**
54       * Plexus role.
55       */
56      private static final String ROLE = ProjectDependencyAnalyzer.class.getName();
57  
58      /**
59       * Plexus hint.
60       */
61      private static final String HINT = "default";
62  
63      /**
64       * Compile scope.
65       */
66      private static final String SCOPE = "compile";
67  
68      /**
69       * Jar type.
70       */
71      private static final String TYPE = "jar";
72  
73      /**
74       * DependencyValidator can pass on when no violations are found.
75       * @throws Exception If something wrong happens inside
76       */
77      @Test
78      void passesIfNoDependencyProblemsFound() throws Exception {
79          final ProjectDependencyAnalysis analysis =
80              Mockito.mock(ProjectDependencyAnalysis.class);
81          final ProjectDependencyAnalyzer analyzer = this.analyzer(analysis);
82          final MavenEnvironment env = new MavenEnvironmentMocker().inPlexus(
83              DependenciesValidatorTest.ROLE,
84              DependenciesValidatorTest.HINT,
85              analyzer
86          ).mock();
87          new DependenciesValidator().validate(env);
88      }
89  
90      /**
91       * DependencyValidator can catch dependency problems.
92       * @throws Exception If something wrong happens inside
93       */
94      @Test
95      void catchesDependencyProblemsAndThrowsException() throws Exception {
96          final ProjectDependencyAnalysis analysis =
97              Mockito.mock(ProjectDependencyAnalysis.class);
98          final Set<Artifact> unused = new HashSet<>();
99          unused.add(Mockito.mock(Artifact.class));
100         Mockito.doReturn(unused).when(analysis).getUsedUndeclaredArtifacts();
101         final ProjectDependencyAnalyzer analyzer = this.analyzer(analysis);
102         final MavenEnvironment env = new MavenEnvironmentMocker().inPlexus(
103             DependenciesValidatorTest.ROLE,
104             DependenciesValidatorTest.HINT,
105             analyzer
106         ).mock();
107         Assertions.assertThrows(
108             ValidationException.class,
109             () -> new DependenciesValidator().validate(env)
110         );
111     }
112 
113     /**
114      * DependencyValidator can ignore runtime scope dependencies.
115      * @throws Exception If something wrong happens inside
116      */
117     @Test
118     void ignoresRuntimeScope() throws Exception {
119         final ProjectDependencyAnalysis analysis =
120             Mockito.mock(ProjectDependencyAnalysis.class);
121         final Artifact artifact = Mockito.mock(Artifact.class);
122         final Set<Artifact> unused = new HashSet<>();
123         unused.add(artifact);
124         Mockito.doReturn(unused).when(analysis).getUnusedDeclaredArtifacts();
125         Mockito.doReturn(Artifact.SCOPE_RUNTIME).when(artifact).getScope();
126         final ProjectDependencyAnalyzer analyzer = this.analyzer(analysis);
127         final MavenEnvironment env = new MavenEnvironmentMocker().inPlexus(
128             DependenciesValidatorTest.ROLE,
129             DependenciesValidatorTest.HINT,
130             analyzer
131         ).mock();
132         new DependenciesValidator().validate(env);
133     }
134 
135     /**
136      * DependencyValidator can exclude used undeclared dependencies.
137      * @throws Exception If something wrong happens inside
138      */
139     @Test
140     void excludesUsedUndeclaredDependencies() throws Exception {
141         final ProjectDependencyAnalysis analysis =
142             Mockito.mock(ProjectDependencyAnalysis.class);
143         final Set<Artifact> used = new HashSet<>();
144         final ArtifactStub artifact = new ArtifactStub();
145         artifact.setGroupId("group");
146         artifact.setArtifactId("artifact");
147         artifact.setScope(DependenciesValidatorTest.SCOPE);
148         artifact.setVersion("2.3.4");
149         artifact.setType(DependenciesValidatorTest.TYPE);
150         used.add(artifact);
151         Mockito.doReturn(used).when(analysis).getUsedUndeclaredArtifacts();
152         final ProjectDependencyAnalyzer analyzer = this.analyzer(analysis);
153         final MavenEnvironment env = new MavenEnvironmentMocker().inPlexus(
154             DependenciesValidatorTest.ROLE,
155             DependenciesValidatorTest.HINT,
156             analyzer
157         ).mock();
158         new DependenciesValidator().validate(
159             new MavenEnvironment.Wrap(
160                 new Environment.Mock().withExcludes(
161                     Joiner.on(':').join(
162                         artifact.getGroupId(), artifact.getArtifactId()
163                     )
164                 ), env
165             )
166         );
167     }
168 
169     /**
170      * DependencyValidator can exclude unused declared dependencies.
171      * @throws Exception If something wrong happens inside
172      */
173     @Test
174     void excludesUnusedDeclaredDependencies() throws Exception {
175         final ProjectDependencyAnalysis analysis =
176             Mockito.mock(ProjectDependencyAnalysis.class);
177         final Set<Artifact> unused = new HashSet<>();
178         final ArtifactStub artifact = new ArtifactStub();
179         artifact.setGroupId("othergroup");
180         artifact.setArtifactId("otherartifact");
181         artifact.setScope(DependenciesValidatorTest.SCOPE);
182         artifact.setVersion("1.2.3");
183         artifact.setType(DependenciesValidatorTest.TYPE);
184         unused.add(artifact);
185         Mockito.doReturn(unused).when(analysis).getUnusedDeclaredArtifacts();
186         final ProjectDependencyAnalyzer analyzer = this.analyzer(analysis);
187         final MavenEnvironment env = new MavenEnvironmentMocker().inPlexus(
188             DependenciesValidatorTest.ROLE,
189             DependenciesValidatorTest.HINT,
190             analyzer
191         ).mock();
192         new DependenciesValidator().validate(
193             new MavenEnvironment.Wrap(
194                 new Environment.Mock().withExcludes(
195                     Joiner.on(':').join(
196                         artifact.getGroupId(), artifact.getArtifactId()
197                     )
198                 ), env
199             )
200         );
201     }
202 
203     /**
204      * Create analyzer object.
205      * @param analysis The analysis object
206      * @return The object
207      * @throws Exception If something wrong happens inside
208      */
209     private ProjectDependencyAnalyzer analyzer(
210         final ProjectDependencyAnalysis analysis) throws Exception {
211         final ProjectDependencyAnalyzer analyzer =
212             Mockito.mock(ProjectDependencyAnalyzer.class);
213         Mockito.doReturn(analysis).when(analyzer)
214             .analyze(Mockito.any(MavenProject.class));
215         return analyzer;
216     }
217 
218 }