View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 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 false when invalid class is passed")
110                 .that(ModuleReflectionUtil
111                     .isCheckstyleModule(InvalidNonDefaultConstructorClass.class))
112                 .isFalse();
113         assertWithMessage("Should return false when forced invalid class is passed")
114                 .that(
115                     ModuleReflectionUtil.isCheckstyleModule(XpathFileGeneratorAstFilter.class))
116                 .isFalse();
117     }
118 
119     @Test
120     public void testIsCheckstyleCheck() {
121         assertWithMessage("Should return true when valid checkstyle check is passed")
122                 .that(ModuleReflectionUtil.isCheckstyleTreeWalkerCheck(CheckClass.class))
123                 .isTrue();
124         assertWithMessage("Should return false when invalid class is passed")
125                 .that(ModuleReflectionUtil.isCheckstyleTreeWalkerCheck(NotCheckstyleCheck.class))
126                 .isFalse();
127     }
128 
129     @Test
130     public void testIsFileSetModule() {
131         assertWithMessage("Should return true when valid checkstyle file set module is passed")
132                 .that(ModuleReflectionUtil.isFileSetModule(FileSetModuleClass.class))
133                 .isTrue();
134         assertWithMessage("Should return false when invalid class is passed")
135                 .that(ModuleReflectionUtil.isFileSetModule(NotCheckstyleCheck.class))
136                 .isFalse();
137     }
138 
139     @Test
140     public void testIsFilterModule() {
141         assertWithMessage("Should return true when valid checkstyle filter module is passed")
142                 .that(ModuleReflectionUtil.isFilterModule(FilterClass.class))
143                 .isTrue();
144         assertWithMessage("Should return false when invalid class is passed")
145                 .that(ModuleReflectionUtil.isFilterModule(NotCheckstyleCheck.class))
146                 .isFalse();
147     }
148 
149     @Test
150     public void testIsFileFilterModule() {
151         assertWithMessage("Should return true when valid checkstyle file filter module is passed")
152                 .that(ModuleReflectionUtil.isFileFilterModule(FileFilterModuleClass.class))
153                 .isTrue();
154         assertWithMessage("Should return false when invalid class is passed")
155                 .that(ModuleReflectionUtil.isFileFilterModule(NotCheckstyleCheck.class))
156                 .isFalse();
157     }
158 
159     @Test
160     public void testIsTreeWalkerFilterModule() {
161         assertWithMessage(
162                     "Should return true when valid checkstyle TreeWalker filter module is passed")
163                 .that(ModuleReflectionUtil.isTreeWalkerFilterModule(TreeWalkerFilterClass.class))
164                 .isTrue();
165         assertWithMessage("Should return false when invalid class is passed")
166                 .that(ModuleReflectionUtil.isTreeWalkerFilterModule(NotCheckstyleCheck.class))
167                 .isFalse();
168     }
169 
170     @Test
171     public void testIsAuditListener() {
172         assertWithMessage("Should return true when valid checkstyle AuditListener module is passed")
173                 .that(ModuleReflectionUtil.isAuditListener(DefaultLogger.class))
174                 .isTrue();
175         assertWithMessage("Should return false when invalid class is passed")
176                 .that(ModuleReflectionUtil.isAuditListener(NotCheckstyleCheck.class))
177                 .isFalse();
178     }
179 
180     @Test
181     public void testIsRootModule() {
182         assertWithMessage("Should return true when valid checkstyle root module is passed")
183                 .that(ModuleReflectionUtil.isRootModule(RootModuleClass.class))
184                 .isTrue();
185         assertWithMessage("Should return false when invalid class is passed")
186                 .that(ModuleReflectionUtil.isRootModule(NotCheckstyleCheck.class))
187                 .isFalse();
188     }
189 
190     @Test
191     public void testKeepEclipseHappy() {
192         final InvalidNonDefaultConstructorClass test = new InvalidNonDefaultConstructorClass(0);
193         assertWithMessage("should use constructor")
194             .that(test)
195             .isNotNull();
196         assertWithMessage("should use field")
197             .that(test.getField())
198             .isEqualTo(1);
199     }
200 
201     private static final class ValidCheckstyleClass extends AbstractAutomaticBean {
202 
203         // empty, use default constructor
204 
205         @Override
206         protected void finishLocalSetup() {
207             // dummy method
208         }
209 
210     }
211 
212     private static final class InvalidNonAutomaticBeanClass {
213 
214         // empty, use default constructor
215 
216     }
217 
218     /**
219      * AbstractInvalidClass.
220      *
221      * @noinspection AbstractClassNeverImplemented
222      * @noinspectionreason AbstractClassNeverImplemented - class is only used in testing
223      */
224     private abstract static class AbstractInvalidClass extends AbstractAutomaticBean {
225 
226         public abstract void method();
227 
228     }
229 
230     private static final class CheckClass extends AbstractCheck {
231 
232         @Override
233         public int[] getDefaultTokens() {
234             return new int[] {0};
235         }
236 
237         @Override
238         public int[] getAcceptableTokens() {
239             return getDefaultTokens();
240         }
241 
242         @Override
243         public int[] getRequiredTokens() {
244             return getDefaultTokens();
245         }
246 
247     }
248 
249     private static final class FileSetModuleClass extends AbstractFileSetCheck {
250 
251         @Override
252         protected void processFiltered(File file, FileText fileText) {
253             // dummy method
254         }
255 
256     }
257 
258     private static final class FilterClass extends AbstractAutomaticBean implements Filter {
259 
260         @Override
261         protected void finishLocalSetup() {
262             // dummy method
263         }
264 
265         @Override
266         public boolean accept(AuditEvent event) {
267             return false;
268         }
269 
270     }
271 
272     private static final class FileFilterModuleClass extends AbstractAutomaticBean
273             implements BeforeExecutionFileFilter {
274 
275         @Override
276         protected void finishLocalSetup() {
277             // dummy method
278         }
279 
280         @Override
281         public boolean accept(String uri) {
282             return false;
283         }
284 
285     }
286 
287     private static final class RootModuleClass extends AbstractAutomaticBean implements RootModule {
288 
289         @Override
290         protected void finishLocalSetup() {
291             // dummy method
292         }
293 
294         @Override
295         public void addListener(AuditListener listener) {
296             // dummy method
297         }
298 
299         @Override
300         public int process(List<File> files) {
301             return 0;
302         }
303 
304         @Override
305         public void destroy() {
306             // dummy method
307         }
308 
309         @Override
310         public void setModuleClassLoader(ClassLoader moduleClassLoader) {
311             // dummy method
312         }
313 
314     }
315 
316     private static final class TreeWalkerFilterClass
317             extends AbstractAutomaticBean implements TreeWalkerFilter {
318 
319         @Override
320         protected void finishLocalSetup() {
321             // dummy method
322         }
323 
324         @Override
325         public boolean accept(TreeWalkerAuditEvent treeWalkerAuditEvent) {
326             return false;
327         }
328 
329     }
330 
331     private static final class AuditListenerClass
332             extends AbstractAutomaticBean implements AuditListener {
333 
334         @Override
335         protected void finishLocalSetup() {
336             // dummy method
337         }
338 
339         @Override
340         public void auditStarted(AuditEvent event) {
341             // dummy method
342         }
343 
344         @Override
345         public void auditFinished(AuditEvent event) {
346             // dummy method
347         }
348 
349         @Override
350         public void fileStarted(AuditEvent event) {
351             // dummy method
352         }
353 
354         @Override
355         public void fileFinished(AuditEvent event) {
356             // dummy method
357         }
358 
359         @Override
360         public void addError(AuditEvent event) {
361             // dummy method
362         }
363 
364         @Override
365         public void addException(AuditEvent event, Throwable throwable) {
366             // dummy method
367         }
368 
369     }
370 
371     private static final class NotCheckstyleCheck {
372 
373         // empty, use default constructor
374 
375     }
376 
377     private static class InvalidNonDefaultConstructorClass extends AbstractAutomaticBean {
378 
379         private int field;
380 
381         protected InvalidNonDefaultConstructorClass(int data) {
382             // keep pmd calm and happy
383             field = 0;
384             method(data);
385         }
386 
387         /**
388          * Method has tail recursive call.
389          *
390          * @param data of int type.
391          * @noinspection TailRecursion
392          * @noinspectionreason TailRecursion - until issue #14814
393          */
394         public final void method(int data) {
395             field++;
396             if (data > 0) {
397                 method(data - 1);
398             }
399         }
400 
401         public int getField() {
402             return field;
403         }
404 
405         @Override
406         protected void finishLocalSetup() {
407             // dummy method
408         }
409 
410     }
411 
412 }