View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2025 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ///////////////////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.utils;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.BASE_PACKAGE;
24  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.isUtilsClassHasPrivateConstructor;
25  
26  import java.io.File;
27  import java.io.IOException;
28  import java.util.Collections;
29  import java.util.List;
30  import java.util.Set;
31  
32  import org.junit.jupiter.api.Test;
33  
34  import com.puppycrawl.tools.checkstyle.AbstractAutomaticBean;
35  import com.puppycrawl.tools.checkstyle.DefaultLogger;
36  import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent;
37  import com.puppycrawl.tools.checkstyle.TreeWalkerFilter;
38  import com.puppycrawl.tools.checkstyle.XpathFileGeneratorAstFilter;
39  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
40  import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
41  import com.puppycrawl.tools.checkstyle.api.AuditEvent;
42  import com.puppycrawl.tools.checkstyle.api.AuditListener;
43  import com.puppycrawl.tools.checkstyle.api.BeforeExecutionFileFilter;
44  import com.puppycrawl.tools.checkstyle.api.FileText;
45  import com.puppycrawl.tools.checkstyle.api.Filter;
46  import com.puppycrawl.tools.checkstyle.api.RootModule;
47  
48  public class ModuleReflectionUtilTest {
49  
50      @Test
51      public void testIsProperUtilsClass() throws ReflectiveOperationException {
52          assertWithMessage("Constructor is not private")
53                  .that(isUtilsClassHasPrivateConstructor(ModuleReflectionUtil.class))
54                  .isTrue();
55      }
56  
57      @Test
58      public void testIsCheckstyleModule() {
59          assertWithMessage("Should return true when checkstyle module is passed")
60                  .that(ModuleReflectionUtil.isCheckstyleModule(CheckClass.class))
61                  .isTrue();
62          assertWithMessage("Should return true when checkstyle module is passed")
63                  .that(ModuleReflectionUtil.isCheckstyleModule(FileSetModuleClass.class))
64                  .isTrue();
65          assertWithMessage("Should return true when checkstyle module is passed")
66                  .that(ModuleReflectionUtil.isCheckstyleModule(FilterClass.class))
67                  .isTrue();
68          assertWithMessage("Should return true when checkstyle module is passed")
69                  .that(ModuleReflectionUtil.isCheckstyleModule(TreeWalkerFilterClass.class))
70                  .isTrue();
71          assertWithMessage("Should return true when checkstyle module is passed")
72                  .that(ModuleReflectionUtil.isCheckstyleModule(FileFilterModuleClass.class))
73                  .isTrue();
74          assertWithMessage("Should return true when checkstyle module is passed")
75                  .that(ModuleReflectionUtil.isCheckstyleModule(AuditListenerClass.class))
76                  .isTrue();
77          assertWithMessage("Should return true when checkstyle module is passed")
78                  .that(ModuleReflectionUtil.isCheckstyleModule(RootModuleClass.class))
79                  .isTrue();
80      }
81  
82      /**
83       * This test case is designed to verify the behavior of getCheckstyleModules method.
84       * It is provided with a package name that does not contain any checkstyle modules.
85       * It ensures that ModuleReflectionUtil.getCheckstyleModules is returning an empty set.
86       */
87      @Test
88      public void testGetCheckStyleModules() throws IOException {
89          final ClassLoader classLoader = ClassLoader.getSystemClassLoader();
90          final Set<String> packages = Collections.singleton(BASE_PACKAGE + ".checks.javadoc.utils");
91  
92          assertWithMessage("specified package has no checkstyle modules")
93                  .that(ModuleReflectionUtil.getCheckstyleModules(packages, classLoader))
94                  .isEmpty();
95      }
96  
97      @Test
98      public void testIsValidCheckstyleClass() {
99          assertWithMessage("Should return true when valid checkstyle class is passed")
100                 .that(ModuleReflectionUtil.isCheckstyleModule(ValidCheckstyleClass.class))
101                 .isTrue();
102         assertWithMessage("Should return false when invalid class is passed")
103                 .that(
104                     ModuleReflectionUtil.isCheckstyleModule(InvalidNonAutomaticBeanClass.class))
105                 .isFalse();
106         assertWithMessage("Should return false when invalid class is passed")
107                 .that(ModuleReflectionUtil.isCheckstyleModule(AbstractInvalidClass.class))
108                 .isFalse();
109         assertWithMessage("Should return true when valid checkstyle class is passed")
110                 .that(ModuleReflectionUtil.isCheckstyleModule(ValidClass.class))
111                 .isTrue();
112         assertWithMessage("Should return false when invalid class is passed")
113                 .that(ModuleReflectionUtil
114                     .isCheckstyleModule(InvalidNonDefaultConstructorClass.class))
115                 .isFalse();
116         assertWithMessage("Should return false when forced invalid class is passed")
117                 .that(
118                     ModuleReflectionUtil.isCheckstyleModule(XpathFileGeneratorAstFilter.class))
119                 .isFalse();
120     }
121 
122     @Test
123     public void testIsCheckstyleCheck() {
124         assertWithMessage("Should return true when valid checkstyle check is passed")
125                 .that(ModuleReflectionUtil.isCheckstyleTreeWalkerCheck(CheckClass.class))
126                 .isTrue();
127         assertWithMessage("Should return false when invalid class is passed")
128                 .that(ModuleReflectionUtil.isCheckstyleTreeWalkerCheck(NotCheckstyleCheck.class))
129                 .isFalse();
130     }
131 
132     @Test
133     public void testIsFileSetModule() {
134         assertWithMessage("Should return true when valid checkstyle file set module is passed")
135                 .that(ModuleReflectionUtil.isFileSetModule(FileSetModuleClass.class))
136                 .isTrue();
137         assertWithMessage("Should return false when invalid class is passed")
138                 .that(ModuleReflectionUtil.isFileSetModule(NotCheckstyleCheck.class))
139                 .isFalse();
140     }
141 
142     @Test
143     public void testIsFilterModule() {
144         assertWithMessage("Should return true when valid checkstyle filter module is passed")
145                 .that(ModuleReflectionUtil.isFilterModule(FilterClass.class))
146                 .isTrue();
147         assertWithMessage("Should return false when invalid class is passed")
148                 .that(ModuleReflectionUtil.isFilterModule(NotCheckstyleCheck.class))
149                 .isFalse();
150     }
151 
152     @Test
153     public void testIsFileFilterModule() {
154         assertWithMessage("Should return true when valid checkstyle file filter module is passed")
155                 .that(ModuleReflectionUtil.isFileFilterModule(FileFilterModuleClass.class))
156                 .isTrue();
157         assertWithMessage("Should return false when invalid class is passed")
158                 .that(ModuleReflectionUtil.isFileFilterModule(NotCheckstyleCheck.class))
159                 .isFalse();
160     }
161 
162     @Test
163     public void testIsTreeWalkerFilterModule() {
164         assertWithMessage(
165                     "Should return true when valid checkstyle TreeWalker filter module is passed")
166                 .that(ModuleReflectionUtil.isTreeWalkerFilterModule(TreeWalkerFilterClass.class))
167                 .isTrue();
168         assertWithMessage("Should return false when invalid class is passed")
169                 .that(ModuleReflectionUtil.isTreeWalkerFilterModule(NotCheckstyleCheck.class))
170                 .isFalse();
171     }
172 
173     @Test
174     public void testIsAuditListener() {
175         assertWithMessage("Should return true when valid checkstyle AuditListener module is passed")
176                 .that(ModuleReflectionUtil.isAuditListener(DefaultLogger.class))
177                 .isTrue();
178         assertWithMessage("Should return false when invalid class is passed")
179                 .that(ModuleReflectionUtil.isAuditListener(NotCheckstyleCheck.class))
180                 .isFalse();
181     }
182 
183     @Test
184     public void testIsRootModule() {
185         assertWithMessage("Should return true when valid checkstyle root module is passed")
186                 .that(ModuleReflectionUtil.isRootModule(RootModuleClass.class))
187                 .isTrue();
188         assertWithMessage("Should return false when invalid class is passed")
189                 .that(ModuleReflectionUtil.isRootModule(NotCheckstyleCheck.class))
190                 .isFalse();
191     }
192 
193     @Test
194     public void testKeepEclipseHappy() {
195         final InvalidNonDefaultConstructorClass test = new InvalidNonDefaultConstructorClass(0);
196         assertWithMessage("should use constructor")
197             .that(test)
198             .isNotNull();
199         assertWithMessage("should use field")
200             .that(test.getField())
201             .isEqualTo(1);
202     }
203 
204     private static final class ValidCheckstyleClass extends AbstractAutomaticBean {
205 
206         // empty, use default constructor
207 
208         @Override
209         protected void finishLocalSetup() {
210             // dummy method
211         }
212 
213     }
214 
215     private static final class InvalidNonAutomaticBeanClass {
216 
217         // empty, use default constructor
218 
219     }
220 
221     /**
222      * AbstractInvalidClass.
223      */
224     private abstract static class AbstractInvalidClass extends AbstractAutomaticBean {
225 
226         public abstract void method();
227 
228     }
229 
230     private static final class ValidClass extends AbstractInvalidClass {
231 
232         @Override
233         public void method() {
234             // dummy method
235         }
236 
237         @Override
238         protected void finishLocalSetup() {
239             final AbstractInvalidClass ref = this;
240             ref.method();
241         }
242     }
243 
244     private static final class CheckClass extends AbstractCheck {
245 
246         @Override
247         public int[] getDefaultTokens() {
248             return new int[] {0};
249         }
250 
251         @Override
252         public int[] getAcceptableTokens() {
253             return getDefaultTokens();
254         }
255 
256         @Override
257         public int[] getRequiredTokens() {
258             return getDefaultTokens();
259         }
260 
261     }
262 
263     private static final class FileSetModuleClass extends AbstractFileSetCheck {
264 
265         @Override
266         protected void processFiltered(File file, FileText fileText) {
267             // dummy method
268         }
269 
270     }
271 
272     private static final class FilterClass extends AbstractAutomaticBean implements Filter {
273 
274         @Override
275         protected void finishLocalSetup() {
276             // dummy method
277         }
278 
279         @Override
280         public boolean accept(AuditEvent event) {
281             return false;
282         }
283 
284     }
285 
286     private static final class FileFilterModuleClass extends AbstractAutomaticBean
287             implements BeforeExecutionFileFilter {
288 
289         @Override
290         protected void finishLocalSetup() {
291             // dummy method
292         }
293 
294         @Override
295         public boolean accept(String uri) {
296             return false;
297         }
298 
299     }
300 
301     private static final class RootModuleClass extends AbstractAutomaticBean implements RootModule {
302 
303         @Override
304         protected void finishLocalSetup() {
305             // dummy method
306         }
307 
308         @Override
309         public void addListener(AuditListener listener) {
310             // dummy method
311         }
312 
313         @Override
314         public int process(List<File> files) {
315             return 0;
316         }
317 
318         @Override
319         public void destroy() {
320             // dummy method
321         }
322 
323         @Override
324         public void setModuleClassLoader(ClassLoader moduleClassLoader) {
325             // dummy method
326         }
327 
328     }
329 
330     private static final class TreeWalkerFilterClass
331             extends AbstractAutomaticBean implements TreeWalkerFilter {
332 
333         @Override
334         protected void finishLocalSetup() {
335             // dummy method
336         }
337 
338         @Override
339         public boolean accept(TreeWalkerAuditEvent treeWalkerAuditEvent) {
340             return false;
341         }
342 
343     }
344 
345     private static final class AuditListenerClass
346             extends AbstractAutomaticBean implements AuditListener {
347 
348         @Override
349         protected void finishLocalSetup() {
350             // dummy method
351         }
352 
353         @Override
354         public void auditStarted(AuditEvent event) {
355             // dummy method
356         }
357 
358         @Override
359         public void auditFinished(AuditEvent event) {
360             // dummy method
361         }
362 
363         @Override
364         public void fileStarted(AuditEvent event) {
365             // dummy method
366         }
367 
368         @Override
369         public void fileFinished(AuditEvent event) {
370             // dummy method
371         }
372 
373         @Override
374         public void addError(AuditEvent event) {
375             // dummy method
376         }
377 
378         @Override
379         public void addException(AuditEvent event, Throwable throwable) {
380             // dummy method
381         }
382 
383     }
384 
385     private static final class NotCheckstyleCheck {
386 
387         // empty, use default constructor
388 
389     }
390 
391     private static final class InvalidNonDefaultConstructorClass extends AbstractAutomaticBean {
392 
393         private int field;
394 
395         private InvalidNonDefaultConstructorClass(int data) {
396             // keep pmd calm and happy
397             field = 0;
398             method(data);
399         }
400 
401         /**
402          * Increments the field.
403          *
404          * @param data of int type.
405          */
406         private void method(int data) {
407             field = data + 1;
408         }
409 
410         private int getField() {
411             return field;
412         }
413 
414         @Override
415         protected void finishLocalSetup() {
416             // dummy method
417         }
418 
419     }
420 
421 }