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.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      protected 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.first().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 ex) {
123             // exception is expected
124             assertWithMessage("Invalid exception message")
125                     .that(ex.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 ex) {
144             // exception is expected
145             assertWithMessage("Invalid exception message")
146                     .that(ex.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.iterator().next();
200         assertWithMessage("expected line")
201                 .that(violation.getLineNo())
202                 .isEqualTo(1);
203         assertWithMessage("expected column")
204                 .that(violation.getColumnNo())
205                 .isEqualTo(1);
206     }
207 
208     @Test
209     public void testGetMessageDispatcher() {
210         final DummyFileSetCheck check = new DummyFileSetCheck();
211         final Checker checker = new Checker();
212         check.setMessageDispatcher(checker);
213 
214         assertWithMessage("Invalid message dispatcher")
215                 .that(check.getMessageDispatcher())
216                 .isSameInstanceAs(checker);
217     }
218 
219     @Test
220     public void testCheck() throws Exception {
221         final String[] expected = {
222             "1:1: Violation.",
223         };
224         verifyWithInlineConfigParser(getPath("InputAbstractFileSetLineColumn.java"), expected);
225     }
226 
227     @Test
228     public void testMultiFileFireErrors() throws Exception {
229         final MultiFileViolationFileSetCheck check = new MultiFileViolationFileSetCheck();
230         check.configure(new DefaultConfiguration("filesetcheck"));
231         final ViolationDispatcher dispatcher = new ViolationDispatcher();
232         check.setMessageDispatcher(dispatcher);
233 
234         check.finishProcessing();
235 
236         assertWithMessage("Invalid fileName reported")
237                 .that(dispatcher.name)
238                 .isEqualTo("fileName");
239 
240         assertWithMessage("errors should only have 1")
241                 .that(dispatcher.errorList)
242                 .hasSize(1);
243 
244         final Violation violation = dispatcher.errorList.iterator().next();
245         assertWithMessage("expected line")
246                 .that(violation.getLineNo())
247                 .isEqualTo(1);
248         assertWithMessage("expected column")
249                 .that(violation.getColumnNo())
250                 .isEqualTo(0);
251 
252         // re-running erases previous errors
253 
254         check.finishProcessing();
255 
256         assertWithMessage("errors should still have 1 after re-run")
257                 .that(dispatcher.errorList)
258                 .hasSize(1);
259         assertWithMessage("finishProcessing was called twice")
260                 .that(check.finishProcessingCount)
261                 .isEqualTo(2);
262     }
263 
264     /**
265      * S2384 - Mutable members should not be stored or returned directly.
266      * Inspection is valid, a pure unit test is required as this condition can't be recreated in
267      * a test with checks and input file as none of the checks try to modify the fileExtensions.
268      */
269     @Test
270     public void testCopiedArrayIsReturned() {
271         final DummyFileSetCheck check = new DummyFileSetCheck();
272         check.setFileExtensions(".tmp");
273         assertWithMessage("Extensions should be copied")
274             .that(check.getFileExtensions())
275             .isNotSameInstanceAs(check.getFileExtensions());
276     }
277 
278     public static class DummyFileSetCheck extends AbstractFileSetCheck {
279 
280         private static final String MSG_KEY = "File should not be empty.";
281 
282         @Override
283         protected void processFiltered(File file, FileText fileText) {
284             if (fileText.size() == 0) {
285                 log(1, MSG_KEY);
286             }
287         }
288 
289     }
290 
291     public static class ViolationFileSetCheck extends AbstractFileSetCheck {
292 
293         private static final String MSG_KEY = "Violation.";
294 
295         @Override
296         protected void processFiltered(File file, FileText fileText) {
297             log(1, 0, MSG_KEY);
298         }
299 
300     }
301 
302     public static class MultiFileViolationFileSetCheck extends AbstractFileSetCheck {
303 
304         private static final String MSG_KEY = "Violation.";
305         private int finishProcessingCount;
306 
307         @Override
308         protected void processFiltered(File file, FileText fileText) {
309             // no code needed
310         }
311 
312         @Override
313         public void finishProcessing() {
314             final String fileName = "fileName";
315 
316             log(1, MSG_KEY + finishProcessingCount);
317             fireErrors(fileName);
318 
319             finishProcessingCount++;
320         }
321 
322     }
323 
324     public static class ExceptionFileSetCheck extends AbstractFileSetCheck {
325 
326         private static final String MSG_KEY = "Test.";
327         private int count = 1;
328 
329         @Override
330         protected void processFiltered(File file, FileText fileText) {
331             log(count, MSG_KEY);
332             count++;
333             throw new IllegalArgumentException("Test");
334         }
335 
336     }
337 
338     public static class ViolationDispatcher implements MessageDispatcher {
339         private String name;
340         private SortedSet<Violation> errorList;
341 
342         @Override
343         public void fireFileStarted(String fileName) {
344             // no code needed
345         }
346 
347         @Override
348         public void fireFileFinished(String fileName) {
349             // no code needed
350         }
351 
352         @Override
353         public void fireErrors(String fileName, SortedSet<Violation> errors) {
354             name = fileName;
355             errorList = new TreeSet<>(errors);
356         }
357 
358     }
359 
360 }