Coverage Report - com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck
 
Classes in this File Line Coverage Branch Coverage Complexity
NewlineAtEndOfFileCheck
100%
32/32
100%
6/6
2.75
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2017 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 java.io.File;
 23  
 import java.io.IOException;
 24  
 import java.io.RandomAccessFile;
 25  
 import java.util.Locale;
 26  
 
 27  
 import com.google.common.io.Closeables;
 28  
 import com.puppycrawl.tools.checkstyle.StatelessCheck;
 29  
 import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
 30  
 import com.puppycrawl.tools.checkstyle.api.FileText;
 31  
 
 32  
 /**
 33  
  * <p>
 34  
  * Checks that there is a newline at the end of each file.
 35  
  * </p>
 36  
  * <p>
 37  
  * An example of how to configure the check is:
 38  
  * </p>
 39  
  * <pre>
 40  
  * &lt;module name="NewlineAtEndOfFile"/&gt;</pre>
 41  
  * <p>
 42  
  * This will check against the platform-specific default line separator.
 43  
  * </p>
 44  
  * <p>
 45  
  * It is also possible to enforce the use of a specific line-separator across
 46  
  * platforms, with the 'lineSeparator' property:
 47  
  * </p>
 48  
  * <pre>
 49  
  * &lt;module name="NewlineAtEndOfFile"&gt;
 50  
  *   &lt;property name="lineSeparator" value="lf"/&gt;
 51  
  * &lt;/module&gt;</pre>
 52  
  * <p>
 53  
  * Valid values for the 'lineSeparator' property are 'system' (system default),
 54  
  * 'crlf' (windows), 'cr' (mac), 'lf' (unix) and 'lf_cr_crlf' (lf, cr or crlf).
 55  
  * </p>
 56  
  *
 57  
  * @author Christopher Lenz
 58  
  * @author lkuehne
 59  
  */
 60  
 @StatelessCheck
 61  22
 public class NewlineAtEndOfFileCheck
 62  
     extends AbstractFileSetCheck {
 63  
 
 64  
     /**
 65  
      * A key is pointing to the warning message text in "messages.properties"
 66  
      * file.
 67  
      */
 68  
     public static final String MSG_KEY_UNABLE_OPEN = "unable.open";
 69  
 
 70  
     /**
 71  
      * A key is pointing to the warning message text in "messages.properties"
 72  
      * file.
 73  
      */
 74  
     public static final String MSG_KEY_NO_NEWLINE_EOF = "noNewlineAtEOF";
 75  
 
 76  
     /** The line separator to check against. */
 77  22
     private LineSeparatorOption lineSeparator = LineSeparatorOption.SYSTEM;
 78  
 
 79  
     @Override
 80  
     protected void processFiltered(File file, FileText fileText) {
 81  
         try {
 82  15
             readAndCheckFile(file);
 83  
         }
 84  1
         catch (final IOException ignored) {
 85  1
             log(0, MSG_KEY_UNABLE_OPEN, file.getPath());
 86  14
         }
 87  15
     }
 88  
 
 89  
     /**
 90  
      * Sets the line separator to one of 'crlf', 'lf','cr', 'lf_cr_crlf' or 'system'.
 91  
      *
 92  
      * @param lineSeparatorParam The line separator to set
 93  
      * @throws IllegalArgumentException If the specified line separator is not
 94  
      *         one of 'crlf', 'lf', 'cr', 'lf_cr_crlf' or 'system'
 95  
      */
 96  
     public void setLineSeparator(String lineSeparatorParam) {
 97  
         try {
 98  13
             lineSeparator =
 99  26
                 Enum.valueOf(LineSeparatorOption.class, lineSeparatorParam.trim()
 100  13
                     .toUpperCase(Locale.ENGLISH));
 101  
         }
 102  1
         catch (IllegalArgumentException iae) {
 103  1
             throw new IllegalArgumentException("unable to parse " + lineSeparatorParam, iae);
 104  12
         }
 105  12
     }
 106  
 
 107  
     /**
 108  
      * Reads the file provided and checks line separators.
 109  
      * @param file the file to be processed
 110  
      * @throws IOException When an IO error occurred while reading from the
 111  
      *         file provided
 112  
      */
 113  
     private void readAndCheckFile(File file) throws IOException {
 114  
         // Cannot use lines as the line separators have been removed!
 115  15
         final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
 116  14
         boolean threw = true;
 117  
         try {
 118  14
             if (!endsWithNewline(randomAccessFile)) {
 119  5
                 log(0, MSG_KEY_NO_NEWLINE_EOF, file.getPath());
 120  
             }
 121  14
             threw = false;
 122  
         }
 123  
         finally {
 124  14
             Closeables.close(randomAccessFile, threw);
 125  14
         }
 126  14
     }
 127  
 
 128  
     /**
 129  
      * Checks whether the content provided by the Reader ends with the platform
 130  
      * specific line separator.
 131  
      * @param randomAccessFile The reader for the content to check
 132  
      * @return boolean Whether the content ends with a line separator
 133  
      * @throws IOException When an IO error occurred while reading from the
 134  
      *         provided reader
 135  
      */
 136  
     private boolean endsWithNewline(RandomAccessFile randomAccessFile)
 137  
             throws IOException {
 138  
         final boolean result;
 139  15
         final int len = lineSeparator.length();
 140  15
         if (randomAccessFile.length() < len) {
 141  3
             result = false;
 142  
         }
 143  
         else {
 144  12
             randomAccessFile.seek(randomAccessFile.length() - len);
 145  12
             final byte[] lastBytes = new byte[len];
 146  12
             final int readBytes = randomAccessFile.read(lastBytes);
 147  12
             if (readBytes != len) {
 148  1
                 throw new IOException("Unable to read " + len + " bytes, got "
 149  
                         + readBytes);
 150  
             }
 151  11
             result = lineSeparator.matches(lastBytes);
 152  
         }
 153  14
         return result;
 154  
     }
 155  
 }