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.checks;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck.MSG_KEY_NO_NEWLINE_EOF;
24  import static com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck.MSG_KEY_NO_NEWLINE_EOF_WITH_SEPARATOR;
25  import static com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck.MSG_KEY_UNABLE_OPEN;
26  import static com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck.MSG_KEY_WRONG_ENDING;
27  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
28  
29  import java.io.File;
30  import java.io.FileNotFoundException;
31  import java.io.RandomAccessFile;
32  import java.util.ArrayList;
33  import java.util.Iterator;
34  import java.util.List;
35  import java.util.Set;
36  
37  import org.junit.jupiter.api.Test;
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.api.FileText;
43  import com.puppycrawl.tools.checkstyle.api.Violation;
44  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
45  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
46  
47  public class NewlineAtEndOfFileCheckTest
48      extends AbstractModuleTestSupport {
49  
50      @Override
51      public String getPackageLocation() {
52          return "com/puppycrawl/tools/checkstyle/checks/newlineatendoffile";
53      }
54  
55      @Test
56      public void testNewlineLfAtEndOfFile() throws Exception {
57          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
58          verifyWithInlineConfigParser(
59                  getPath("InputNewlineAtEndOfFileLf.java"),
60              expected);
61      }
62  
63      @Test
64      public void testNewlineLfAtEndOfFileLfNotOverlapWithCrLf() throws Exception {
65          final String[] expected = {
66              "1: " + getCheckMessage(MSG_KEY_WRONG_ENDING),
67          };
68          verifyWithInlineConfigParser(
69                  getPath("InputNewlineAtEndOfFileCrlf.java"),
70              expected);
71      }
72  
73      @Test
74      public void testNewlineCrlfAtEndOfFile() throws Exception {
75          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
76          verifyWithInlineConfigParser(
77                  getPath("InputNewlineAtEndOfFileCrlf3.java"),
78              expected);
79      }
80  
81      @Test
82      public void testNewlineCrAtEndOfFile() throws Exception {
83          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
84          verifyWithInlineConfigParser(
85                  getPath("InputNewlineAtEndOfFileCr.java"),
86              expected);
87      }
88  
89      @Test
90      public void testAnyNewlineAtEndOfFile() throws Exception {
91          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
92          verifyWithInlineConfigParser(
93                  getPath("InputNewlineAtEndOfFileCrlf2.java"),
94              expected);
95          verifyWithInlineConfigParser(
96                  getPath("InputNewlineAtEndOfFileLf2.java"),
97              expected);
98          verifyWithInlineConfigParser(
99                  getPath("InputNewlineAtEndOfFileCr2.java"),
100             expected);
101     }
102 
103     @Test
104     public void testCrEndingWhenLfExpected() throws Exception {
105         final String[] expected = {
106             "1: " + getCheckMessage(MSG_KEY_NO_NEWLINE_EOF_WITH_SEPARATOR, "lf"),
107         };
108         verifyWithInlineConfigParser(
109                 getPath("InputNewlineAtEndOfFileCrWhenLfExpected.java"),
110             expected);
111     }
112 
113     @Test
114     public void testNoNewlineAtEndOfFile() throws Exception {
115         final String msgKeyNoNewlineEof = "File does not end with a newline :)";
116         final String[] expected = {
117             "1: " + msgKeyNoNewlineEof,
118         };
119         verifyWithInlineConfigParser(
120                 getPath("InputNewlineAtEndOfFileNoNewline2.java"),
121             expected);
122     }
123 
124     @Test
125     public void testNoNewlineWithLfSeparatorLogsSpecificMessage() throws Exception {
126         final String[] expected = {
127             "1: " + getCheckMessage(MSG_KEY_NO_NEWLINE_EOF_WITH_SEPARATOR, "lf"),
128         };
129         verifyWithInlineConfigParser(
130                 getPath("InputNewlineAtEndOfFileNoNewline.java"),
131             expected);
132     }
133 
134     @Test
135     public void testNoNewlineWithCrSeparatorLogsSpecificMessage() throws Exception {
136         final String[] expected = {
137             "1: " + getCheckMessage(MSG_KEY_NO_NEWLINE_EOF_WITH_SEPARATOR, "cr"),
138         };
139         verifyWithInlineConfigParser(
140                 getPath("InputNewlineAtEndOfFileNoNewlineCr.java"),
141             expected);
142     }
143 
144     @Test
145     public void testNoNewlineWithCrlfSeparatorLogsSpecificMessage() throws Exception {
146         final String[] expected = {
147             "1: " + getCheckMessage(MSG_KEY_NO_NEWLINE_EOF_WITH_SEPARATOR, "crlf"),
148         };
149         verifyWithInlineConfigParser(
150                 getPath("InputNewlineAtEndOfFileNoNewlineCrlf.java"),
151             expected);
152     }
153 
154     @Test
155     public void testNoNewlineWithLfCrCrlfSeparatorLogsGenericMessage() throws Exception {
156         final String[] expected = {
157             "1: " + getCheckMessage(MSG_KEY_NO_NEWLINE_EOF),
158         };
159         verifyWithInlineConfigParser(
160                 getPath("InputNewlineAtEndOfFileNoNewlineLfCrCrlf.java"),
161             expected);
162     }
163 
164     @Test
165     public void testSetLineSeparatorFailure() {
166         final DefaultConfiguration checkConfig =
167             createModuleConfig(NewlineAtEndOfFileCheck.class);
168         checkConfig.addProperty("lineSeparator", "ct");
169         final CheckstyleException exc = getExpectedThrowable(
170                 CheckstyleException.class,
171                 () -> createChecker(checkConfig));
172         assertWithMessage("Error message is unexpected")
173                 .that(exc.getMessage())
174                 .isEqualTo("cannot initialize module com.puppycrawl.tools.checkstyle."
175                         + "checks.NewlineAtEndOfFileCheck - "
176                         + "Cannot set property 'lineSeparator' to 'ct'");
177     }
178 
179     @Test
180     public void testEmptyFileFile() throws Exception {
181         final DefaultConfiguration checkConfig =
182             createModuleConfig(NewlineAtEndOfFileCheck.class);
183         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
184         verify(
185             checkConfig,
186             getPath("InputNewlineAtEndOfFileEmptyFile.txt"),
187             expected);
188     }
189 
190     @Test
191     public void testFileWithEmptyLineOnly() throws Exception {
192         final DefaultConfiguration checkConfig =
193                 createModuleConfig(NewlineAtEndOfFileCheck.class);
194         checkConfig.addProperty("lineSeparator", LineSeparatorOption.LF.toString());
195         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
196         verify(
197                 checkConfig,
198                 getPath("InputNewlineAtEndOfFileNewlineAtEnd.txt"),
199                 expected);
200     }
201 
202     @Test
203     public void testFileWithEmptyLineOnlyWithLfCrCrlf() throws Exception {
204         final DefaultConfiguration checkConfig =
205                 createModuleConfig(NewlineAtEndOfFileCheck.class);
206         checkConfig.addProperty("lineSeparator", LineSeparatorOption.LF_CR_CRLF.toString());
207         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
208         verify(
209                 checkConfig,
210                 getPath("InputNewlineAtEndOfFileNewlineAtEndLf.txt"),
211                 expected);
212     }
213 
214     @Test
215     public void testWrongFile() throws Exception {
216         final DefaultConfiguration checkConfig = createModuleConfig(NewlineAtEndOfFileCheck.class);
217         final NewlineAtEndOfFileCheck check = new NewlineAtEndOfFileCheck();
218         check.configure(checkConfig);
219         final List<String> lines = new ArrayList<>(1);
220         lines.add("txt");
221         final File impossibleFile = new File("");
222         final FileText fileText = new FileText(impossibleFile, lines);
223         final Set<Violation> violations = check.process(impossibleFile, fileText);
224         assertWithMessage("Amount of violations is unexpected")
225                 .that(violations)
226                 .hasSize(1);
227         final Iterator<Violation> iterator = violations.iterator();
228         assertWithMessage("Violation message differs from expected")
229                 .that(iterator.next().getViolation())
230                 .isEqualTo(getCheckMessage(MSG_KEY_UNABLE_OPEN, ""));
231     }
232 
233     @Test
234     public void testWrongSeparatorLength() throws Exception {
235         try (RandomAccessFile file =
236                      new ReadZeroRandomAccessFile(getPath("InputNewlineAtEndOfFileLf.java"), "r")) {
237             final ReflectiveOperationException exc = getExpectedThrowable(
238                 ReflectiveOperationException.class,
239                 () -> {
240                     TestUtil.invokeVoidMethod(new NewlineAtEndOfFileCheck(),
241                             "endsWithNewline", file, LineSeparatorOption.LF);
242                 });
243             assertWithMessage("Error message is unexpected")
244                 .that(exc)
245                     .hasCauseThat()
246                         .hasMessageThat()
247                         .isEqualTo("Unable to read 1 bytes, got 0");
248         }
249     }
250 
251     @Test
252     public void testTrimOptionProperty() throws Exception {
253         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
254         verifyWithInlineConfigParser(
255                 getPath("InputNewlineAtEndOfFileTestTrimProperty.java"),
256                 expected);
257     }
258 
259     private static final class ReadZeroRandomAccessFile extends RandomAccessFile {
260 
261         private ReadZeroRandomAccessFile(String name, String mode)
262                 throws FileNotFoundException {
263             super(name, mode);
264         }
265 
266         @Override
267         public int read(byte[] bytes) {
268             return 0;
269         }
270     }
271 
272 }