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.checks.header;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck.MSG_MISMATCH;
24  import static com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck.MSG_MISSING;
25  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
26  import static org.mockito.Mockito.mockConstruction;
27  import static org.mockito.Mockito.when;
28  
29  import java.io.File;
30  import java.io.IOException;
31  import java.io.LineNumberReader;
32  import java.net.URI;
33  import java.util.Set;
34  
35  import org.junit.jupiter.api.Test;
36  import org.junit.jupiter.api.io.TempDir;
37  import org.mockito.MockedConstruction;
38  
39  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
40  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
41  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
42  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
43  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
44  
45  public class HeaderCheckTest extends AbstractModuleTestSupport {
46  
47      @TempDir
48      public File temporaryFolder;
49  
50      @Override
51      protected String getPackageLocation() {
52          return "com/puppycrawl/tools/checkstyle/checks/header/header";
53      }
54  
55      @Test
56      public void testStaticHeader() throws Exception {
57          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
58          checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
59          checkConfig.addProperty("ignoreLines", "");
60          final String[] expected = {
61              "1: " + getCheckMessage(MSG_MISSING),
62          };
63          verify(checkConfig, getPath("InputHeader.java"), expected);
64      }
65  
66      @Test
67      public void testNoHeader() throws Exception {
68          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
69  
70          createChecker(checkConfig);
71          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
72          verify(checkConfig, getPath("InputHeaderRegexp.java"), expected);
73      }
74  
75      @Test
76      public void testWhitespaceHeader() throws Exception {
77          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
78          checkConfig.addProperty("header", "\n    \n");
79  
80          createChecker(checkConfig);
81          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
82          verify(checkConfig, getPath("InputHeaderRegexp.java"), expected);
83      }
84  
85      @Test
86      public void testNonExistentHeaderFile() throws Exception {
87          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
88          checkConfig.addProperty("headerFile", getPath("nonExistent.file"));
89          final CheckstyleException ex = getExpectedThrowable(CheckstyleException.class,
90                  () -> createChecker(checkConfig));
91          assertWithMessage("Invalid exception message")
92                  .that(ex)
93                  .hasMessageThat()
94                          .startsWith("cannot initialize module"
95                              + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
96                              + " - illegal value ");
97          assertWithMessage("Invalid cause exception message")
98                  .that(ex)
99                  .hasCauseThat()
100                 .hasCauseThat()
101                 .hasCauseThat()
102                 .hasMessageThat()
103                         .startsWith("Unable to find: ");
104     }
105 
106     @Test
107     public void testInvalidCharset() throws Exception {
108         final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
109         checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
110         checkConfig.addProperty("charset", "XSO-8859-1");
111         final CheckstyleException ex = getExpectedThrowable(CheckstyleException.class,
112                 () -> createChecker(checkConfig));
113         assertWithMessage("Invalid exception message")
114                 .that(ex)
115                 .hasMessageThat()
116                         .isEqualTo("cannot initialize module"
117                                 + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
118                                 + " - Cannot set property 'charset' to 'XSO-8859-1'");
119         assertWithMessage("Invalid cause exception message")
120                 .that(ex)
121                 .hasCauseThat()
122                 .hasCauseThat()
123                 .hasCauseThat()
124                 .hasMessageThat()
125                         .startsWith("unsupported charset: 'XSO-8859-1'");
126     }
127 
128     @Test
129     public void testEmptyFilename() {
130         final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
131         checkConfig.addProperty("headerFile", "");
132         final CheckstyleException ex = getExpectedThrowable(CheckstyleException.class,
133                 () -> createChecker(checkConfig));
134         assertWithMessage("Invalid exception message")
135                 .that(ex)
136                 .hasMessageThat()
137                         .isEqualTo("cannot initialize module"
138                                 + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
139                                 + " - Cannot set property 'headerFile' to ''");
140         assertWithMessage("Invalid cause exception message")
141                 .that(ex)
142                 .hasCauseThat()
143                 .hasCauseThat()
144                 .hasCauseThat()
145                 .hasMessageThat()
146                         .isEqualTo("property 'headerFile' is missing or invalid in module"
147                                 + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck");
148     }
149 
150     @Test
151     public void testNullFilename() {
152         final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
153         checkConfig.addProperty("headerFile", null);
154         final CheckstyleException ex = getExpectedThrowable(CheckstyleException.class,
155                 () -> createChecker(checkConfig));
156         assertWithMessage("Invalid exception message")
157                 .that(ex)
158                 .hasMessageThat()
159                         .isEqualTo("cannot initialize module"
160                                 + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
161                                 + " - Cannot set property 'headerFile' to 'null'");
162     }
163 
164     @Test
165     public void testNotMatch() throws Exception {
166         final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
167         checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
168         checkConfig.addProperty("ignoreLines", "");
169         final String[] expected = {
170             "2: " + getCheckMessage(MSG_MISMATCH,
171                     "// checkstyle: Checks Java source code and other text files for adherence to a"
172                         + " set of rules."),
173         };
174         verify(checkConfig, getPath("InputHeaderjava2.header"), expected);
175     }
176 
177     @Test
178     public void testIgnore() throws Exception {
179         final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
180         checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
181         checkConfig.addProperty("ignoreLines", "2");
182         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
183         verify(checkConfig, getPath("InputHeaderjava2.header"), expected);
184     }
185 
186     @Test
187     public void testSetHeaderTwice() {
188         final HeaderCheck check = new HeaderCheck();
189         check.setHeader("Header");
190         final IllegalArgumentException ex =
191                 getExpectedThrowable(IllegalArgumentException.class,
192                         () -> check.setHeader("Header2"));
193         assertWithMessage("Invalid exception message")
194                 .that(ex)
195                 .hasMessageThat()
196                         .isEqualTo("header has already been set - "
197                                 + "set either header or headerFile, not both");
198     }
199 
200     @Test
201     public void testIoExceptionWhenLoadingHeaderFile() throws Exception {
202         final HeaderCheck check = new HeaderCheck();
203         check.setHeaderFile(new URI("test://bad"));
204 
205         final ReflectiveOperationException ex =
206                 getExpectedThrowable(ReflectiveOperationException.class,
207                         () -> TestUtil.invokeMethod(check, "loadHeaderFile"));
208         assertWithMessage("Invalid exception cause message")
209             .that(ex)
210                 .hasCauseThat()
211                     .hasMessageThat()
212                     .startsWith("unable to load header file ");
213     }
214 
215     @Test
216     public void testCacheHeaderFile() throws Exception {
217         final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
218         checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
219 
220         final DefaultConfiguration checkerConfig = createRootConfig(checkConfig);
221         final File cacheFile = File.createTempFile("junit", null, temporaryFolder);
222         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
223 
224         final String[] expected = {
225             "1: " + getCheckMessage(MSG_MISSING),
226         };
227 
228         verify(checkerConfig, getPath("InputHeader.java"), expected);
229         // One more time to use cache.
230         verify(checkerConfig, getPath("InputHeader.java"), expected);
231     }
232 
233     @Test
234     public void testCacheHeaderWithoutFile() throws Exception {
235         final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
236         checkConfig.addProperty("header", "Test");
237 
238         final DefaultConfiguration checkerConfig = createRootConfig(checkConfig);
239         final File cacheFile = File.createTempFile("junit", null, temporaryFolder);
240         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
241 
242         final String[] expected = {
243             "1: " + getCheckMessage(MSG_MISMATCH, "Test"),
244         };
245 
246         verify(checkerConfig, getPath("InputHeader.java"), expected);
247     }
248 
249     @Test
250     public void testIgnoreLinesSorted() throws Exception {
251         final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
252         checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
253         checkConfig.addProperty("ignoreLines", "4,2,3");
254         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
255         verify(checkConfig, getPath("InputHeaderjava3.header"), expected);
256     }
257 
258     @Test
259     public void testLoadHeaderFileTwice() {
260         final HeaderCheck check = new HeaderCheck();
261         check.setHeader("Header");
262         final ReflectiveOperationException ex =
263                 getExpectedThrowable(ReflectiveOperationException.class,
264                         () -> TestUtil.invokeMethod(check, "loadHeaderFile"));
265         assertWithMessage("Invalid exception cause message")
266                 .that(ex)
267                 .hasCauseThat()
268                         .hasMessageThat()
269                                 .isEqualTo("header has already been set - "
270                                     + "set either header or headerFile, not both");
271     }
272 
273     @Test
274     public void testHeaderIsValidWithBlankLines() throws Exception {
275         final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
276         checkConfig.addProperty("headerFile", getPath("InputHeaderjava.blank-lines.header"));
277         verify(checkConfig, getPath("InputHeaderBlankLines.java"));
278     }
279 
280     @Test
281     public void testHeaderIsValidWithBlankLinesBlockStyle() throws Exception {
282         final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
283         checkConfig.addProperty("headerFile", getPath("InputHeaderjava.blank-lines2.header"));
284         verify(checkConfig, getPath("InputHeaderBlankLines2.java"));
285     }
286 
287     @Test
288     public void testExternalResource() throws Exception {
289         final HeaderCheck check = new HeaderCheck();
290         final URI uri = CommonUtil.getUriByFilename(getPath("InputHeaderjava.header"));
291         check.setHeaderFile(uri);
292         final Set<String> results = check.getExternalResourceLocations();
293         assertWithMessage("Invalid result size")
294             .that(results.size())
295             .isEqualTo(1);
296         assertWithMessage("Invalid resource location")
297             .that(results.iterator().next())
298             .isEqualTo(uri.toASCIIString());
299     }
300 
301     @Test
302     public void testIoExceptionWhenLoadingHeader() {
303         final HeaderCheck check = new HeaderCheck();
304         try (MockedConstruction<LineNumberReader> mocked = mockConstruction(
305                 LineNumberReader.class, (mock, context) -> {
306                     when(mock.readLine()).thenThrow(IOException.class);
307                 })) {
308             final IllegalArgumentException ex =
309                     getExpectedThrowable(IllegalArgumentException.class,
310                             () -> check.setHeader("header"));
311             assertWithMessage("Invalid exception cause")
312                     .that(ex)
313                     .hasCauseThat()
314                             .isInstanceOf(IOException.class);
315             assertWithMessage("Invalid exception message")
316                     .that(ex)
317                     .hasMessageThat()
318                             .isEqualTo("unable to load header");
319         }
320     }
321 
322 }