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