commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject svn commit: r1202500 - in /commons/proper/io/trunk/src: main/java/org/apache/commons/io/ test/java/org/apache/commons/io/ test/resources/
Date Wed, 16 Nov 2011 01:30:47 GMT
Author: sebb
Date: Wed Nov 16 01:30:46 2011
New Revision: 1202500

URL: http://svn.apache.org/viewvc?rev=1202500&view=rev
Log:
IO-288 Supply a ReversedLinesFileReader
N.B. Renamed test .txt files to .bin and made them application/octet-stream
as it's important not to change the EOL setting

Added:
    commons/proper/io/trunk/src/main/java/org/apache/commons/io/ReversedLinesFileReader.java
  (with props)
    commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamBlockSize.java
  (with props)
    commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamFile.java
  (with props)
    commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestSimple.java
  (with props)
    commons/proper/io/trunk/src/test/resources/test-file-20byteslength.bin   (with props)
    commons/proper/io/trunk/src/test/resources/test-file-empty.bin   (with props)
    commons/proper/io/trunk/src/test/resources/test-file-iso8859-1-shortlines-win-linebr.bin
  (with props)
    commons/proper/io/trunk/src/test/resources/test-file-iso8859-1.bin   (with props)
    commons/proper/io/trunk/src/test/resources/test-file-shiftjis.bin   (with props)
    commons/proper/io/trunk/src/test/resources/test-file-utf16be.bin   (with props)
    commons/proper/io/trunk/src/test/resources/test-file-utf16le.bin   (with props)
    commons/proper/io/trunk/src/test/resources/test-file-utf8-cr-only.bin   (with props)
    commons/proper/io/trunk/src/test/resources/test-file-utf8-win-linebr.bin   (with props)
    commons/proper/io/trunk/src/test/resources/test-file-utf8.bin   (with props)

Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/ReversedLinesFileReader.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/ReversedLinesFileReader.java?rev=1202500&view=auto
==============================================================================
--- commons/proper/io/trunk/src/main/java/org/apache/commons/io/ReversedLinesFileReader.java
(added)
+++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/ReversedLinesFileReader.java
Wed Nov 16 01:30:46 2011
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.io;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+
+/**
+ * Reads lines in a file reversely (similar to a BufferedReader, but starting at
+ * the last line). Useful for e.g. searching in log files.
+ *
+ */
+public class ReversedLinesFileReader implements Closeable {
+
+	private final int blockSize;
+	private final String encoding;
+
+	private final RandomAccessFile randomAccessFile;
+
+	private final long totalByteLength;
+	private final long totalBlockCount;
+
+	private final byte[][] newLineSequences;
+	private final int avoidNewlineSplitBufferSize;
+	private final int byteDecrement;
+	
+    private FilePart currentFilePart;
+
+	private boolean trailingNewlineOfFileSkipped = false;
+
+	/**
+	 * Creates a ReversedLinesFileReader with default block size of 4KB and the
+	 * platform's default encoding.
+	 *
+	 * @param file
+	 *            the file to be read
+	 * @throws IOException
+	 */
+	public ReversedLinesFileReader(final File file) throws IOException {
+		this(file, 4096, Charset.defaultCharset().toString());
+	}
+
+	/**
+	 * Creates a ReversedLinesFileReader with the given block size and encoding.
+	 *
+	 * @param file
+	 *            the file to be read
+	 * @param blockSize
+	 *            size of the internal buffer (for ideal performance this should
+	 *            match with the block size of the underlying file system).
+	 * @param encoding
+	 *            the encoding of the file
+	 * @throws IOException
+	 */
+	public ReversedLinesFileReader(final File file, final int blockSize, final String encoding)
throws IOException {
+		this.blockSize = blockSize;
+		this.encoding = encoding;
+		
+		randomAccessFile = new RandomAccessFile(file, "r");
+		totalByteLength = randomAccessFile.length();
+		int lastBlockLength = (int) (totalByteLength % blockSize);
+		if (lastBlockLength > 0) {
+	        totalBlockCount = totalByteLength / blockSize + 1;
+		} else {
+            totalBlockCount = totalByteLength / blockSize;
+			if (totalByteLength > 0) {
+				lastBlockLength = blockSize;
+			}
+		}
+		currentFilePart = new FilePart(totalBlockCount, lastBlockLength, null);
+
+		// --- check & prepare encoding ---
+		Charset charset = Charset.forName(encoding);
+		CharsetEncoder charsetEncoder = charset.newEncoder();
+		float maxBytesPerChar = charsetEncoder.maxBytesPerChar();
+		if(maxBytesPerChar==1f) {
+			// all one byte encodings are no problem
+			byteDecrement = 1;
+		} else if(charset == Charset.forName("UTF-8")) {
+			// UTF-8 works fine out of the box, for multibyte sequences a second UTF-8 byte can never
be a newline byte
+			// http://en.wikipedia.org/wiki/UTF-8
+			byteDecrement = 1;
+		} else if(charset == Charset.forName("Shift_JIS")) {
+			// Same as for UTF-8
+			// http://www.herongyang.com/Unicode/JIS-Shift-JIS-Encoding.html
+			byteDecrement = 1;
+		} else if(charset == Charset.forName("UTF-16BE") || charset == Charset.forName("UTF-16LE"))
{
+			// UTF-16 new line sequences are not allowed as second tuple of four byte sequences, however
byte order has to be specified
+			byteDecrement = 2;
+		} else if(charset == Charset.forName("UTF-16")) {
+			throw new UnsupportedEncodingException("For UTF-16, you need to specify the byte order
(use UTF-16BE or UTF-16LE)");
+		} else {
+			throw new UnsupportedEncodingException("Encoding "+encoding+" is not supported yet (feel
free to submit a patch)");
+		}
+		// NOTE: The new line sequences are matched in the order given, so it is important that
\r\n is BEFORE \n
+		newLineSequences = new byte[][] { "\r\n".getBytes(encoding), "\n".getBytes(encoding), "\r".getBytes(encoding)
};
+		
+		avoidNewlineSplitBufferSize = newLineSequences[0].length;
+
+	}
+
+	/**
+	 * Returns the lines of the file from bottom to top.
+	 *
+	 * @return the next line or null if the start of the file is reached
+	 * @throws IOException
+	 */
+	public String readLine() throws IOException {
+
+		String line = currentFilePart.readLine();
+		while (line == null) {
+			currentFilePart = currentFilePart.rollOver();
+			if (currentFilePart != null) {
+				line = currentFilePart.readLine();
+			} else {
+				// no more fileparts: we're done, leave line set to null
+				break;
+			}
+		}
+		
+		// aligned behaviour wiht BufferedReader that doesn't return a last, emtpy line
+		if("".equals(line) && !trailingNewlineOfFileSkipped) {
+			trailingNewlineOfFileSkipped = true;
+			line = readLine();
+		}
+		
+		return line;
+	}
+
+	/**
+	 * Closes underlying resources.
+	 */
+	public void close() throws IOException {
+		randomAccessFile.close();
+	}
+
+	private class FilePart {
+		private final long no;
+		private final byte[] data;
+
+		private byte[] leftOver;
+
+		private int currentLastBytePos;
+
+		private FilePart(final long no, final int length, final byte[] leftOverOfLastFilePart)
throws IOException {
+			this.no = no;
+			int dataLength = length + (leftOverOfLastFilePart != null ? leftOverOfLastFilePart.length
: 0);
+			this.data = new byte[dataLength];
+			final long off = (no - 1) * blockSize;
+
+			// read data
+			if (no > 0 /* file not empty */) {
+				randomAccessFile.seek(off);
+				final int countRead = randomAccessFile.read(data, 0, length);
+				if (countRead != length) {
+					throw new IllegalStateException("Count of requested bytes and actually read bytes don't
match");
+				}
+			}
+			// copy left over part into data arr
+			if (leftOverOfLastFilePart != null) {
+				System.arraycopy(leftOverOfLastFilePart, 0, data, length, leftOverOfLastFilePart.length);
+			}
+			this.currentLastBytePos = data.length - 1;
+			this.leftOver = null;
+		}
+
+		private FilePart rollOver() throws IOException {
+
+			if (currentLastBytePos > -1) {
+				throw new IllegalStateException("Current currentLastCharPos unexpectedly positive...
"
+						+ "last readLine() should have returned something! currentLastCharPos=" + currentLastBytePos);
+			}
+
+			if (no > 1) {
+				return new FilePart(no - 1, blockSize, leftOver);
+			} else {
+				// NO 1 was the last FilePart, we're finished
+				if (leftOver != null) {
+					throw new IllegalStateException("Unexpected leftover of the last block: leftOverOfThisFilePart="
+							+ new String(leftOver, encoding));
+				}
+				return null;
+			}
+		}
+
+		private String readLine() throws IOException {
+
+			String line = null;
+			int newLineMatchByteCount;
+			
+			boolean isLastFilePart = (no == 1);			
+
+			int i = currentLastBytePos;
+			while (i > -1) {
+				
+				if (!isLastFilePart && i < avoidNewlineSplitBufferSize) {
+					// avoidNewlineSplitBuffer: for all except the last file part we
+					// take a few bytes to the next file part to avoid splitting of newlines
+					createLeftOver();
+					break; // skip last few bytes and leave it to the next file part
+				}
+				
+				// --- check for newline ---
+				if ((newLineMatchByteCount = getNewLineMatchByteCount(data, i)) > 0 /* found newline
*/) {
+					final int lineStart = i + 1;
+					int lineLengthBytes = currentLastBytePos - lineStart + 1;
+
+					if (lineLengthBytes < 0) {
+						throw new IllegalStateException("Unexpected negative line length="+lineLengthBytes);
+					}
+					byte[] lineData = new byte[lineLengthBytes];
+					System.arraycopy(data, lineStart, lineData, 0, lineLengthBytes);
+
+					line = new String(lineData, encoding);
+					
+					currentLastBytePos = i - newLineMatchByteCount;
+					break; // found line
+				}
+
+				// --- move cursor ---
+				i -= byteDecrement;
+
+				// --- end of file part handling ---
+				if (i < 0) {
+					createLeftOver();
+					break; // end of file part
+				}
+			}
+			
+			// --- last file part handling ---
+			if (isLastFilePart && leftOver != null) {
+				// there will be no line break anymore, this is the first line of the file
+				line = new String(leftOver, encoding);
+				leftOver = null;
+			}			
+
+			return line;
+		}
+
+		private void createLeftOver() {
+			int lineLengthBytes = currentLastBytePos + 1;
+			if (lineLengthBytes > 0) {
+				// create left over for next block
+				leftOver = new byte[lineLengthBytes];
+				System.arraycopy(data, 0, leftOver, 0, lineLengthBytes);
+			} else {
+				leftOver = null;
+			}
+			currentLastBytePos = -1;
+		}
+
+		private int getNewLineMatchByteCount(byte[] data, int i) {
+			for (byte[] newLineSequence : newLineSequences) {
+				boolean match = true;
+				for (int j = newLineSequence.length - 1; j >= 0; j--) {
+					int k = i + j - (newLineSequence.length - 1);
+					match &= k >= 0 && data[k] == newLineSequence[j];
+				}
+				if (match) {
+					return newLineSequence.length;
+				}
+			}
+			return 0;
+		}
+	}
+
+}
\ No newline at end of file

Propchange: commons/proper/io/trunk/src/main/java/org/apache/commons/io/ReversedLinesFileReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/io/trunk/src/main/java/org/apache/commons/io/ReversedLinesFileReader.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamBlockSize.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamBlockSize.java?rev=1202500&view=auto
==============================================================================
--- commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamBlockSize.java
(added)
+++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamBlockSize.java
Wed Nov 16 01:30:46 2011
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.io;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ReversedLinesFileReaderTestParamBlockSize {
+
+	private static final String UTF_8 = "UTF-8";
+	private static final String ISO_8859_1 = "ISO-8859-1";
+	
+    @SuppressWarnings("boxing")
+    @Parameters // small and uneven block sizes are not used in reality but are good to show
that the algorithm is solid
+    public static Collection<Integer[]> blockSizes() {
+            return Arrays.asList(new Integer[][] { {1}, {3}, {8}, {256}, {4096} });
+    }
+	
+    private ReversedLinesFileReader reversedLinesFileReader;
+    private int testParamBlockSize;
+
+    public ReversedLinesFileReaderTestParamBlockSize(Integer testWithBlockSize) {
+    	testParamBlockSize = testWithBlockSize.intValue();
+    }
+
+	// Strings are escaped in constants to avoid java source encoding issues (source file enc
is UTF-8):
+	
+	// "A Test Line. Special chars: ÄäÜüÖöß
Ãáéíïçñ ©µ¥£±²®"
+	private static final String TEST_LINE = "A Test Line. Special chars: \u00C4\u00E4\u00DC\u00FC\u00D6\u00F6\u00DF
\u00C3\u00E1\u00E9\u00ED\u00EF\u00E7\u00F1\u00C2 \u00A9\u00B5\u00A5\u00A3\u00B1\u00B2\u00AE";
+	// Hiragana letters: �����
+	private static final String TEST_LINE_SHIFT_JIS1 = "Hiragana letters: \u3041\u3042\u3043\u3044\u3045";
+	// Kanji letters: 明輸�京
+	private static final String TEST_LINE_SHIFT_JIS2 = "Kanji letters: \u660E\u8F38\u5B50\u4EAC";
+	
+	@After
+	public void closeReader() {
+		try {
+			reversedLinesFileReader.close();
+		} catch(Exception e) {
+			// ignore
+		}
+	}
+	
+	@Test
+	public void testIsoFileDefaults() throws URISyntaxException, IOException {
+		File testFileIso = new File(this.getClass().getResource("/test-file-iso8859-1.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileIso, testParamBlockSize,
ISO_8859_1);
+		assertFileWithShrinkingTestLines(reversedLinesFileReader);
+	}	
+
+	@Test
+	public void testUTF8FileWindowsBreaks() throws URISyntaxException, IOException {
+		File testFileIso = new File(this.getClass().getResource("/test-file-utf8-win-linebr.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileIso, testParamBlockSize,
UTF_8);
+		assertFileWithShrinkingTestLines(reversedLinesFileReader);
+	}
+	@Test
+	public void testUTF8FileCRBreaks() throws URISyntaxException, IOException {
+		File testFileIso = new File(this.getClass().getResource("/test-file-utf8-cr-only.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileIso, testParamBlockSize,
UTF_8);
+		assertFileWithShrinkingTestLines(reversedLinesFileReader);
+	}	
+
+	@Test
+	public void testUTF8File() throws URISyntaxException, IOException {
+		File testFileIso = new File(this.getClass().getResource("/test-file-utf8.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileIso, testParamBlockSize,
UTF_8);
+		assertFileWithShrinkingTestLines(reversedLinesFileReader);
+	}
+
+	@Test
+	public void testEmptyFile() throws URISyntaxException, IOException {
+		File testFileEmpty = new File(this.getClass().getResource("/test-file-empty.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileEmpty, testParamBlockSize,
UTF_8);
+		assertNull(reversedLinesFileReader.readLine());
+	}	
+	
+	@Test
+	public void testUTF16BEFile() throws URISyntaxException, IOException {
+		File testFileUTF16BE = new File(this.getClass().getResource("/test-file-utf16be.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileUTF16BE, testParamBlockSize,
"UTF-16BE");
+		assertFileWithShrinkingTestLines(reversedLinesFileReader);
+	}
+	
+	@Test
+	public void testUTF16LEFile() throws URISyntaxException, IOException {
+		File testFileUTF16LE = new File(this.getClass().getResource("/test-file-utf16le.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileUTF16LE, testParamBlockSize,
"UTF-16LE");
+		assertFileWithShrinkingTestLines(reversedLinesFileReader);
+	}	
+	
+	@Test
+	public void testShiftJISFile() throws URISyntaxException, IOException {
+		File testFileShiftJIS = new File(this.getClass().getResource("/test-file-shiftjis.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileShiftJIS, testParamBlockSize,
"Shift_JIS");
+		assertEqualsAndNoLineBreaks(TEST_LINE_SHIFT_JIS2, reversedLinesFileReader.readLine());
+		assertEqualsAndNoLineBreaks(TEST_LINE_SHIFT_JIS1, reversedLinesFileReader.readLine());
+	}	
+	
+	@Test // this test is run 3x for same block size as we want to test with 10
+	public void testFileSizeIsExactMultipleOfBlockSize() throws URISyntaxException, IOException
{
+		int blockSize = 10;
+		File testFile20Bytes = new File(this.getClass().getResource("/test-file-20byteslength.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFile20Bytes, blockSize, ISO_8859_1);
+		String testLine = "123456789";
+		assertEqualsAndNoLineBreaks(testLine, reversedLinesFileReader.readLine());
+		assertEqualsAndNoLineBreaks(testLine, reversedLinesFileReader.readLine());
+	}	
+
+	@Test
+	public void testUTF8FileWindowsBreaksSmallBlockSize2VerifyBlockSpanningNewLines() throws
URISyntaxException, IOException {
+		File testFileUtf8 = new File(this.getClass().getResource("/test-file-utf8-win-linebr.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileUtf8, testParamBlockSize,
UTF_8);
+		assertFileWithShrinkingTestLines(reversedLinesFileReader);
+	}
+	
+	@Test
+	public void testIsoFileManyWindowsBreaksSmallBlockSize2VerifyBlockSpanningNewLines() throws
URISyntaxException, IOException {
+		File testFileIso = new File(this.getClass().getResource("/test-file-iso8859-1-shortlines-win-linebr.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileIso, testParamBlockSize,
ISO_8859_1);
+		
+		for(int i=3;i>0;i--) {
+			for(int j=1;j<=3;j++) {
+				assertEqualsAndNoLineBreaks("", reversedLinesFileReader.readLine());
+			}	
+			assertEqualsAndNoLineBreaks(""+i, reversedLinesFileReader.readLine());
+		}
+	}	
+	
+	@Test(expected=UnsupportedEncodingException.class)
+	public void testUnsupportedEncodingUTF16() throws URISyntaxException, IOException {
+		File testFileEmpty = new File(this.getClass().getResource("/test-file-empty.bin").toURI());
+		new ReversedLinesFileReader(testFileEmpty, testParamBlockSize, "UTF-16");
+	}
+	
+	@Test(expected=UnsupportedEncodingException.class)
+	public void testUnsupportedEncodingBig5() throws URISyntaxException, IOException {
+		File testFileEncodingBig5 = new File(this.getClass().getResource("/test-file-empty.bin").toURI());
+		new ReversedLinesFileReader(testFileEncodingBig5, testParamBlockSize, "Big5");
+	}	
+	
+	private void assertFileWithShrinkingTestLines(ReversedLinesFileReader reversedLinesFileReader)
throws IOException {
+		String line = null;
+		int lineCount = 0;
+		while ((line = reversedLinesFileReader.readLine()) != null) {
+			lineCount++;
+			assertEqualsAndNoLineBreaks("Line "+lineCount+" is not matching", TEST_LINE.substring(0,
lineCount), line);
+		}
+	}
+	
+	static void assertEqualsAndNoLineBreaks(String msg, String expected, String actual) {
+		if(actual!=null) {
+			assertFalse("Line contains \\n: line="+actual, actual.contains("\n"));
+			assertFalse("Line contains \\r: line="+actual, actual.contains("\r"));
+		}
+		assertEquals(msg, expected, actual);
+	}
+	static void assertEqualsAndNoLineBreaks(String expected, String actual) {
+		assertEqualsAndNoLineBreaks(null, expected, actual);
+	}
+}

Propchange: commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamBlockSize.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamBlockSize.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamFile.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamFile.java?rev=1202500&view=auto
==============================================================================
--- commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamFile.java
(added)
+++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamFile.java
Wed Nov 16 01:30:46 2011
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.io;
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Stack;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Test checks symmetric behaviour with  BufferedReader
+ *
+ */
+@RunWith(Parameterized.class)
+public class ReversedLinesFileReaderTestParamFile {
+
+    @Parameters
+    public static Collection<Object[]> blockSizes() {
+            return Arrays.asList(new Object[][] {
+            		{"test-file-20byteslength.bin", "ISO_8859_1", null},
+            		{"test-file-iso8859-1-shortlines-win-linebr.bin", "ISO_8859_1", null},
+            		{"test-file-iso8859-1.bin", "ISO_8859_1", null},
+            		{"test-file-shiftjis.bin", "Shift_JIS", null},
+            		{"test-file-utf16be.bin", "UTF-16BE", null},
+            		{"test-file-utf16le.bin", "UTF-16LE", null},
+            		{"test-file-utf8-cr-only.bin", "UTF-8", null},
+            		{"test-file-utf8-win-linebr.bin", "UTF-8", null},
+                    {"test-file-utf8-win-linebr.bin", "UTF-8", Integer.valueOf(1)},
+                    {"test-file-utf8-win-linebr.bin", "UTF-8", Integer.valueOf(2)},
+                    {"test-file-utf8-win-linebr.bin", "UTF-8", Integer.valueOf(3)},
+                    {"test-file-utf8-win-linebr.bin", "UTF-8", Integer.valueOf(4)},
+            		{"test-file-utf8.bin", "UTF-8", null},
+            });
+    }
+	
+    private ReversedLinesFileReader reversedLinesFileReader;
+    private BufferedReader bufferedReader;
+
+    private final String fileName;
+    private final String encoding;
+    private final int buffSize;
+
+    public ReversedLinesFileReaderTestParamFile(String fileName, String encoding, Integer
buffsize) {
+    	this.fileName = fileName;
+    	this.encoding = encoding;
+    	this.buffSize = buffsize == null ? 4096 : buffsize.intValue();
+    }
+
+	@Test
+	public void testDataIntegrityWithBufferedReader() throws URISyntaxException, IOException
{
+		File testFileIso = new File(this.getClass().getResource("/"+fileName).toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFileIso, buffSize, encoding);
+		
+		Stack<String> lineStack = new Stack<String>();
+		
+		bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(testFileIso),
encoding));
+		String line = null;
+		
+		// read all lines in normal order
+		while((line = bufferedReader.readLine())!=null) {
+			lineStack.push(line);
+		}
+		
+		// read in reverse order and compare with lines from stack
+		while((line = reversedLinesFileReader.readLine())!=null) {
+			String lineFromBufferedReader = lineStack.pop();
+			assertEquals(lineFromBufferedReader, line);
+		}		
+		
+	}	
+
+	@After
+	public void closeReader() {
+		try {
+			bufferedReader.close();
+		} catch(Exception e) {
+			// ignore
+		}		
+		try {
+			reversedLinesFileReader.close();
+		} catch(Exception e) {
+			// ignore
+		}
+	}
+	
+
+
+}

Propchange: commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamFile.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestParamFile.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestSimple.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestSimple.java?rev=1202500&view=auto
==============================================================================
--- commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestSimple.java
(added)
+++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestSimple.java
Wed Nov 16 01:30:46 2011
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.io;
+
+import static org.apache.commons.io.ReversedLinesFileReaderTestParamBlockSize.assertEqualsAndNoLineBreaks;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+
+import org.junit.After;
+import org.junit.Test;
+
+
+public class ReversedLinesFileReaderTestSimple {
+	
+    private ReversedLinesFileReader reversedLinesFileReader;
+
+	@After
+	public void closeReader() {
+		try {
+			reversedLinesFileReader.close();
+		} catch(Exception e) {
+			// ignore
+		}
+	}
+	
+	@Test
+	public void testFileSizeIsExactMultipleOfBlockSize() throws URISyntaxException, IOException
{
+		int blockSize = 10;
+		File testFile20Bytes = new File(this.getClass().getResource("/test-file-20byteslength.bin").toURI());
+		reversedLinesFileReader = new ReversedLinesFileReader(testFile20Bytes, blockSize, "ISO-8859-1");
+		String testLine = "123456789";
+		assertEqualsAndNoLineBreaks(testLine, reversedLinesFileReader.readLine());
+		assertEqualsAndNoLineBreaks(testLine, reversedLinesFileReader.readLine());
+	}	
+	
+	@Test(expected=UnsupportedEncodingException.class)
+	public void testUnsupportedEncodingUTF16() throws URISyntaxException, IOException {
+		File testFileEmpty = new File(this.getClass().getResource("/test-file-empty.bin").toURI());
+		new ReversedLinesFileReader(testFileEmpty, 4096, "UTF-16");
+	}
+	
+	@Test(expected=UnsupportedEncodingException.class)
+	public void testUnsupportedEncodingBig5() throws URISyntaxException, IOException {
+		File testFileEncodingBig5 = new File(this.getClass().getResource("/test-file-empty.bin").toURI());
+		new ReversedLinesFileReader(testFileEncodingBig5, 4096, "Big5");
+	}	
+	
+
+
+}

Propchange: commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestSimple.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/io/trunk/src/test/java/org/apache/commons/io/ReversedLinesFileReaderTestSimple.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/io/trunk/src/test/resources/test-file-20byteslength.bin
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/resources/test-file-20byteslength.bin?rev=1202500&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/io/trunk/src/test/resources/test-file-20byteslength.bin
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: commons/proper/io/trunk/src/test/resources/test-file-empty.bin
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/resources/test-file-empty.bin?rev=1202500&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/io/trunk/src/test/resources/test-file-empty.bin
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: commons/proper/io/trunk/src/test/resources/test-file-iso8859-1-shortlines-win-linebr.bin
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/resources/test-file-iso8859-1-shortlines-win-linebr.bin?rev=1202500&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/io/trunk/src/test/resources/test-file-iso8859-1-shortlines-win-linebr.bin
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: commons/proper/io/trunk/src/test/resources/test-file-iso8859-1.bin
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/resources/test-file-iso8859-1.bin?rev=1202500&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/io/trunk/src/test/resources/test-file-iso8859-1.bin
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: commons/proper/io/trunk/src/test/resources/test-file-shiftjis.bin
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/resources/test-file-shiftjis.bin?rev=1202500&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/io/trunk/src/test/resources/test-file-shiftjis.bin
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: commons/proper/io/trunk/src/test/resources/test-file-utf16be.bin
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/resources/test-file-utf16be.bin?rev=1202500&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/io/trunk/src/test/resources/test-file-utf16be.bin
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: commons/proper/io/trunk/src/test/resources/test-file-utf16le.bin
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/resources/test-file-utf16le.bin?rev=1202500&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/io/trunk/src/test/resources/test-file-utf16le.bin
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: commons/proper/io/trunk/src/test/resources/test-file-utf8-cr-only.bin
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/resources/test-file-utf8-cr-only.bin?rev=1202500&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/io/trunk/src/test/resources/test-file-utf8-cr-only.bin
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: commons/proper/io/trunk/src/test/resources/test-file-utf8-win-linebr.bin
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/resources/test-file-utf8-win-linebr.bin?rev=1202500&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/io/trunk/src/test/resources/test-file-utf8-win-linebr.bin
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: commons/proper/io/trunk/src/test/resources/test-file-utf8.bin
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/resources/test-file-utf8.bin?rev=1202500&view=auto
==============================================================================
Binary file - no diff available.

Propchange: commons/proper/io/trunk/src/test/resources/test-file-utf8.bin
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream



Mime
View raw message