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