View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2026 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.api;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  
24  import java.io.File;
25  import java.nio.charset.StandardCharsets;
26  import java.util.Arrays;
27  import java.util.Collections;
28  import java.util.List;
29  import java.util.SortedSet;
30  import java.util.TreeSet;
31  
32  import org.junit.jupiter.api.Test;
33  
34  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
35  import com.puppycrawl.tools.checkstyle.Checker;
36  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
37  
38  public class AbstractFileSetCheckTest extends AbstractModuleTestSupport {
39  
40      @Override
41      public String getPackageLocation() {
42          return "com/puppycrawl/tools/checkstyle/api/abstractfileset";
43      }
44  
45      @Test
46      public void testTabWidth() {
47          final DummyFileSetCheck check = new DummyFileSetCheck();
48          check.setTabWidth(12345);
49          assertWithMessage("expected tab width")
50                  .that(check.getTabWidth())
51                  .isEqualTo(12345);
52      }
53  
54      @Test
55      public void testFileContents() {
56          final FileContents contents = new FileContents(
57                  new FileText(new File("inputAbstractFileSetCheck.tmp"), Collections.emptyList()));
58          final DummyFileSetCheck check = new DummyFileSetCheck();
59          check.setFileContents(contents);
60          assertWithMessage("expected file contents")
61                  .that(check.getFileContents())
62                  .isSameInstanceAs(contents);
63      }
64  
65      @Test
66      public void testProcessSequential() throws Exception {
67          final DummyFileSetCheck check = new DummyFileSetCheck();
68          check.configure(new DefaultConfiguration("filesetcheck"));
69          check.setFileExtensions("tmp");
70          final File firstFile = new File("inputAbstractFileSetCheck.tmp");
71          final SortedSet<Violation> firstFileMessages =
72              check.process(firstFile, new FileText(firstFile, Collections.emptyList()));
73  
74          assertWithMessage("Invalid message")
75                  .that(firstFileMessages.getFirst().getViolation())
76                  .isEqualTo("File should not be empty.");
77  
78          final SortedSet<Violation> internalMessages =
79                  check.getViolations();
80          assertWithMessage("Internal message should be empty, but was not")
81                  .that(internalMessages)
82                  .isEmpty();
83  
84          final File secondFile = new File("inputAbstractFileSetCheck.txt");
85          final List<String> lines = Arrays.asList("key=value", "ext=tmp");
86          final SortedSet<Violation> secondFileMessages =
87              check.process(secondFile, new FileText(secondFile, lines));
88  
89          assertWithMessage("Message should be empty, but was not")
90                  .that(secondFileMessages)
91                  .isEmpty();
92      }
93  
94      @Test
95      public void testNotProcessed() throws Exception {
96          final ExceptionFileSetCheck check = new ExceptionFileSetCheck();
97          check.setFileExtensions("java");
98          final File firstFile = new File("inputAbstractFileSetCheck.tmp");
99  
100         check.process(firstFile, new FileText(firstFile, Collections.emptyList()));
101 
102         final SortedSet<Violation> internalMessages =
103                 check.getViolations();
104         assertWithMessage("Internal message should be empty")
105                 .that(internalMessages)
106                 .isEmpty();
107     }
108 
109     @Test
110     public void testProcessException() throws Exception {
111         final ExceptionFileSetCheck check = new ExceptionFileSetCheck();
112         check.configure(new DefaultConfiguration("filesetcheck"));
113         check.setFileExtensions("tmp");
114         final File firstFile = new File("inputAbstractFileSetCheck.tmp");
115 
116         final FileText fileText = new FileText(firstFile, Collections.emptyList());
117         try {
118             check.process(firstFile, fileText);
119             assertWithMessage("Exception is expected")
120                     .fail();
121         }
122         catch (IllegalArgumentException exc) {
123             // exception is expected
124             assertWithMessage("Invalid exception message")
125                     .that(exc.getMessage())
126                     .isEqualTo("Test");
127         }
128 
129         final SortedSet<Violation> internalViolations =
130                 check.getViolations();
131         assertWithMessage("Internal violation should only have 1")
132                 .that(internalViolations)
133                 .hasSize(1);
134 
135         // again to prove only 1 violation exists
136         final File secondFile = new File("inputAbstractFileSetCheck.tmp");
137         final FileText fileText2 = new FileText(secondFile, Collections.emptyList());
138         try {
139             check.process(secondFile, fileText2);
140             assertWithMessage("Exception is expected")
141                 .fail();
142         }
143         catch (IllegalArgumentException exc) {
144             // exception is expected
145             assertWithMessage("Invalid exception message")
146                     .that(exc.getMessage())
147                     .isEqualTo("Test");
148         }
149 
150         final SortedSet<Violation> internalViolations2 =
151             check.getViolations();
152         assertWithMessage("Internal violation should only have 1 again")
153                 .that(internalViolations2)
154                 .hasSize(1);
155     }
156 
157     @Test
158     public void testGetFileExtension() {
159         final DummyFileSetCheck check = new DummyFileSetCheck();
160         check.setFileExtensions("tmp", ".java");
161         final String[] expectedExtensions = {".tmp", ".java"};
162 
163         assertWithMessage("Invalid extensions")
164                 .that(check.getFileExtensions())
165                 .isEqualTo(expectedExtensions);
166     }
167 
168     /**
169      * This javadoc exists only to suppress IntelliJ IDEA inspection.
170      */
171     @Test
172     public void testSetExtensionThrowsExceptionWhenTheyAreNull() {
173         final DummyFileSetCheck check = new DummyFileSetCheck();
174         try {
175             check.setFileExtensions((String[]) null);
176             assertWithMessage("Expected exception.")
177                 .fail();
178         }
179         catch (IllegalArgumentException exception) {
180             assertWithMessage("Invalid exception message")
181                     .that(exception.getMessage())
182                     .isEqualTo("Extensions array can not be null");
183         }
184     }
185 
186     @Test
187     public void testLineColumnLog() throws Exception {
188         final ViolationFileSetCheck check = new ViolationFileSetCheck();
189         check.configure(new DefaultConfiguration("filesetcheck"));
190         final File file = new File(getPath("InputAbstractFileSetLineColumn.java"));
191         final FileText theText = new FileText(file.getAbsoluteFile(),
192                 StandardCharsets.UTF_8.name());
193         final SortedSet<Violation> internalViolations = check.process(file, theText);
194 
195         assertWithMessage("Internal violation should only have 1")
196                 .that(internalViolations)
197                 .hasSize(1);
198 
199         final Violation violation = internalViolations.getFirst();
200         assertWithMessage("expected line")
201                 .that(violation.getLineNo())
202                 .isEqualTo(1);
203         assertWithMessage("expected column")
204                 .that(violation.getColumnNo())
205                 .isEqualTo(1);
206         assertWithMessage("expected severity")
207                 .that(violation.getSeverityLevel())
208                 .isEqualTo(SeverityLevel.ERROR);
209     }
210 
211     @Test
212     public void testGetMessageDispatcher() {
213         final DummyFileSetCheck check = new DummyFileSetCheck();
214         final Checker checker = new Checker();
215         check.setMessageDispatcher(checker);
216 
217         assertWithMessage("Invalid message dispatcher")
218                 .that(check.getMessageDispatcher())
219                 .isSameInstanceAs(checker);
220     }
221 
222     @Test
223     public void testCheck() throws Exception {
224         final String[] expected = {
225             "1:1: Violation.",
226         };
227         verifyWithInlineConfigParser(getPath("InputAbstractFileSetLineColumn.java"), expected);
228     }
229 
230     @Test
231     public void testMultiFileFireErrors() throws Exception {
232         final MultiFileViolationFileSetCheck check = new MultiFileViolationFileSetCheck();
233         check.configure(new DefaultConfiguration("filesetcheck"));
234         final ViolationDispatcher dispatcher = new ViolationDispatcher();
235         check.setMessageDispatcher(dispatcher);
236 
237         check.finishProcessing();
238 
239         assertWithMessage("Invalid fileName reported")
240                 .that(dispatcher.name)
241                 .isEqualTo("fileName");
242 
243         assertWithMessage("errors should only have 1")
244                 .that(dispatcher.errorList)
245                 .hasSize(1);
246 
247         final Violation violation = dispatcher.errorList.getFirst();
248         assertWithMessage("expected line")
249                 .that(violation.getLineNo())
250                 .isEqualTo(1);
251         assertWithMessage("expected column")
252                 .that(violation.getColumnNo())
253                 .isEqualTo(0);
254         assertWithMessage("expected severity")
255                 .that(violation.getSeverityLevel())
256                 .isEqualTo(SeverityLevel.ERROR);
257 
258         // re-running erases previous errors
259 
260         check.finishProcessing();
261 
262         assertWithMessage("errors should still have 1 after re-run")
263                 .that(dispatcher.errorList)
264                 .hasSize(1);
265         assertWithMessage("finishProcessing was called twice")
266                 .that(check.finishProcessingCount)
267                 .isEqualTo(2);
268     }
269 
270     /**
271      * S2384 - Mutable members should not be stored or returned directly.
272      * Inspection is valid, a pure unit test is required as this condition can't be recreated in
273      * a test with checks and input file as none of the checks try to modify the fileExtensions.
274      */
275     @Test
276     public void testCopiedArrayIsReturned() {
277         final DummyFileSetCheck check = new DummyFileSetCheck();
278         check.setFileExtensions(".tmp");
279         assertWithMessage("Extensions should be copied")
280             .that(check.getFileExtensions())
281             .isNotSameInstanceAs(check.getFileExtensions());
282     }
283 
284     public static class DummyFileSetCheck extends AbstractFileSetCheck {
285 
286         private static final String MSG_KEY = "File should not be empty.";
287 
288         @Override
289         protected void processFiltered(File file, FileText fileText) {
290             if (fileText.size() == 0) {
291                 log(1, MSG_KEY);
292             }
293         }
294 
295     }
296 
297     public static class ViolationFileSetCheck extends AbstractFileSetCheck {
298 
299         private static final String MSG_KEY = "Violation.";
300 
301         @Override
302         protected void processFiltered(File file, FileText fileText) {
303             log(1, 0, MSG_KEY);
304         }
305 
306     }
307 
308     public static class MultiFileViolationFileSetCheck extends AbstractFileSetCheck {
309 
310         private static final String MSG_KEY = "Violation.";
311         private int finishProcessingCount;
312 
313         @Override
314         protected void processFiltered(File file, FileText fileText) {
315             // no code needed
316         }
317 
318         @Override
319         public void finishProcessing() {
320             final String fileName = "fileName";
321 
322             log(1, MSG_KEY + finishProcessingCount);
323             fireErrors(fileName);
324 
325             finishProcessingCount++;
326         }
327 
328     }
329 
330     public static class ExceptionFileSetCheck extends AbstractFileSetCheck {
331 
332         private static final String MSG_KEY = "Test.";
333         private int count = 1;
334 
335         @Override
336         protected void processFiltered(File file, FileText fileText) {
337             log(count, MSG_KEY);
338             count++;
339             throw new IllegalArgumentException("Test");
340         }
341 
342     }
343 
344     public static class ViolationDispatcher implements MessageDispatcher {
345         private String name;
346         private SortedSet<Violation> errorList;
347 
348         @Override
349         public void fireFileStarted(String fileName) {
350             // no code needed
351         }
352 
353         @Override
354         public void fireFileFinished(String fileName) {
355             // no code needed
356         }
357 
358         @Override
359         public void fireErrors(String fileName, SortedSet<Violation> errors) {
360             name = fileName;
361             errorList = new TreeSet<>(errors);
362         }
363 
364     }
365 
366 }