You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2024/09/15 13:37:20 UTC
(commons-io) branch master updated: Add UnsynchronizedBufferedReader.peek()
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-io.git
The following commit(s) were added to refs/heads/master by this push:
new e9d28f723 Add UnsynchronizedBufferedReader.peek()
e9d28f723 is described below
commit e9d28f723a60991f0601b076be67b1354d6836c8
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Sep 15 09:37:14 2024 -0400
Add UnsynchronizedBufferedReader.peek()
---
.../io/input/UnsynchronizedBufferedReader.java | 30 +++
.../io/input/UnsynchronizedBufferedReaderTest.java | 223 ++++++++++++++++-----
2 files changed, 208 insertions(+), 45 deletions(-)
diff --git a/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedReader.java b/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedReader.java
index c0ded3212..f19b102c3 100644
--- a/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedReader.java
+++ b/src/main/java/org/apache/commons/io/input/UnsynchronizedBufferedReader.java
@@ -209,6 +209,35 @@ public class UnsynchronizedBufferedReader extends UnsynchronizedReader {
return true;
}
+ /**
+ * Returns the next character in the current reader without consuming it. So the next call to {@link #read()} will still return this value.
+ *
+ * @return the next character
+ * @throws IOException If an I/O error occurs
+ */
+ public int peek() throws IOException {
+ mark(1);
+ final int c = read();
+ reset();
+ return c;
+ }
+
+ /**
+ * Populates the buffer with the next {@code buf.length} characters in the current reader without consuming them. The next call to {@link #read()} will
+ * still return the next value.
+ *
+ * @param buf the buffer to fill for the look ahead.
+ * @return the buffer itself
+ * @throws IOException If an I/O error occurs
+ */
+ public int peek(final char[] buf) throws IOException {
+ final int n = buf.length;
+ mark(n);
+ final int c = read(buf, 0, n);
+ reset();
+ return c;
+ }
+
/**
* Reads a single character from this reader and returns it with the two higher-order bytes set to 0. If possible, BufferedReader returns a character from
* the buffer. If there are no characters available in the buffer, it fills the buffer and then returns a character. It returns -1 if there are no more
@@ -445,4 +474,5 @@ public class UnsynchronizedBufferedReader extends UnsynchronizedReader {
}
return amount;
}
+
}
diff --git a/src/test/java/org/apache/commons/io/input/UnsynchronizedBufferedReaderTest.java b/src/test/java/org/apache/commons/io/input/UnsynchronizedBufferedReaderTest.java
index 909a20cc0..de1cc2297 100644
--- a/src/test/java/org/apache/commons/io/input/UnsynchronizedBufferedReaderTest.java
+++ b/src/test/java/org/apache/commons/io/input/UnsynchronizedBufferedReaderTest.java
@@ -17,6 +17,8 @@
package org.apache.commons.io.input;
+import static org.apache.commons.io.IOUtils.EOF;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -29,6 +31,7 @@ import java.io.InputStreamReader;
import java.io.PipedReader;
import java.io.Reader;
import java.io.StringReader;
+import java.util.function.Supplier;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.AfterEach;
@@ -79,8 +82,45 @@ public class UnsynchronizedBufferedReaderTest {
IOUtils.closeQuietly(br);
}
- private void assertLines(final String in, final String... lines) throws IOException {
- try (UnsynchronizedBufferedReader bufferedReader = new UnsynchronizedBufferedReader(new StringReader(in))) {
+ private void assertLines(final String input, final String... lines) throws IOException {
+ assertReadLines(input, lines);
+ assertPeek(input, lines);
+ }
+
+ private void assertPeek(final String input, final String... lines) throws IOException {
+ try (UnsynchronizedBufferedReader bufferedReader = new UnsynchronizedBufferedReader(new StringReader(input))) {
+ for (final String line : lines) {
+ // all
+ final char[] bufAFull = new char[line.length()];
+ assertEquals(bufAFull.length, bufferedReader.peek(bufAFull));
+ assertArrayEquals(line.toCharArray(), bufAFull);
+ if (!line.isEmpty()) {
+ // one
+ assertEquals(line.charAt(0), bufferedReader.peek());
+ // array
+ for (int peekLen = 0; peekLen < line.length(); peekLen++) {
+ assertPeekArray(bufferedReader, peekLen, line);
+ }
+ }
+ // move test to the next fixture
+ assertEquals(line, bufferedReader.readLine());
+ }
+ assertNull(bufferedReader.readLine());
+ }
+ }
+
+ private void assertPeekArray(final UnsynchronizedBufferedReader bufferedReader, final int peekLen, final String line) throws IOException {
+ final char[] expectedBuf = new char[peekLen];
+ final int srcPeekLen = Math.min(peekLen, line.length());
+ line.getChars(0, srcPeekLen, expectedBuf, 0);
+ final char[] actualBuf = new char[peekLen];
+ final Supplier<String> msg = () -> String.format("len=%,d, line='%s'", peekLen, line);
+ assertEquals(actualBuf.length, bufferedReader.peek(actualBuf), msg);
+ assertArrayEquals(expectedBuf, actualBuf, msg);
+ }
+
+ private void assertReadLines(final String input, final String... lines) throws IOException {
+ try (UnsynchronizedBufferedReader bufferedReader = new UnsynchronizedBufferedReader(new StringReader(input))) {
for (final String line : lines) {
assertEquals(line, bufferedReader.readLine());
}
@@ -94,20 +134,30 @@ public class UnsynchronizedBufferedReaderTest {
* @throws IOException test failure.
*/
@Test
- public void test_close() throws IOException {
+ public void testClose() throws IOException {
// Test for method void UnsynchronizedBufferedReader.close()
br = new UnsynchronizedBufferedReader(new StringReader(testString));
br.close();
assertThrows(IOException.class, br::read);
}
+ @Test
+ public void testEmptyInput() throws Exception {
+ try (final UnsynchronizedBufferedReader br = new UnsynchronizedBufferedReader(new StringReader(""))) {
+ assertEquals(EOF, br.read());
+ assertEquals(EOF, br.peek());
+ assertNull(br.readLine());
+ assertEquals(0, br.read(new char[10], 0, 0));
+ }
+ }
+
/**
* Tests {@link UnsynchronizedBufferedReader#mark(int)}.
*
* @throws IOException test failure.
*/
@Test
- public void test_markI() throws IOException {
+ public void testMark() throws IOException {
// Test for method void UnsynchronizedBufferedReader.mark(int)
char[] buf = null;
br = new UnsynchronizedBufferedReader(new StringReader(testString));
@@ -176,7 +226,7 @@ public class UnsynchronizedBufferedReaderTest {
* Tests {@link UnsynchronizedBufferedReader#markSupported()}.
*/
@Test
- public void test_markSupported() {
+ public void testMarkSupported() {
// Test for method boolean UnsynchronizedBufferedReader.markSupported()
br = new UnsynchronizedBufferedReader(new StringReader(testString));
assertTrue(br.markSupported());
@@ -188,21 +238,20 @@ public class UnsynchronizedBufferedReaderTest {
* @throws IOException test failure.
*/
@Test
- public void test_read() throws IOException {
+ public void testRead() throws IOException {
// Test for method int UnsynchronizedBufferedReader.read()
br = new UnsynchronizedBufferedReader(new StringReader(testString));
final int r = br.read();
- assertTrue(testString.charAt(0) == r);
+ assertEquals(testString.charAt(0), r);
br = new UnsynchronizedBufferedReader(new StringReader(new String(new char[] { '\u8765' })));
- assertTrue(br.read() == '\u8765');
+ assertEquals(br.read(), '\u8765');
//
final char[] chars = new char[256];
for (int i = 0; i < 256; i++) {
chars[i] = (char) i;
}
try (Reader in = new UnsynchronizedBufferedReader(new StringReader(new String(chars)), 12)) {
- assertEquals(0, in.read()); // Fill the
- // buffer
+ assertEquals(0, in.read()); // Fill the buffer
final char[] buf = new char[14];
in.read(buf, 0, 14); // Read greater than the buffer
assertTrue(new String(buf).equals(new String(chars, 1, 14)));
@@ -211,40 +260,91 @@ public class UnsynchronizedBufferedReaderTest {
//
// regression test for HARMONY-841
try (Reader reader = new UnsynchronizedBufferedReader(new CharArrayReader(new char[5], 1, 0), 2)) {
- assertTrue(reader.read() == -1);
+ assertEquals(reader.read(), -1);
}
}
/**
- * Tests {@link UnsynchronizedBufferedReader#read(char[], int, int)}.
+ * Tests {@link UnsynchronizedBufferedReader#peek()}.
*
* @throws IOException test failure.
*/
@Test
- public void test_read_$CII_Exception() throws IOException {
+ public void testPeek() throws IOException {
+ // Test for method int UnsynchronizedBufferedReader.read()
br = new UnsynchronizedBufferedReader(new StringReader(testString));
- final char[] nullCharArray = null;
- final char[] charArray = testString.toCharArray();
- assertThrows(IndexOutOfBoundsException.class, () -> br.read(nullCharArray, -1, -1));
- assertThrows(IndexOutOfBoundsException.class, () -> br.read(nullCharArray, -1, 0));
- assertThrows(NullPointerException.class, () -> br.read(nullCharArray, 0, -1));
- assertThrows(NullPointerException.class, () -> br.read(nullCharArray, 0, 0));
- assertThrows(NullPointerException.class, () -> br.read(nullCharArray, 0, 1));
- assertThrows(IndexOutOfBoundsException.class, () -> br.read(charArray, -1, -1));
- assertThrows(IndexOutOfBoundsException.class, () -> br.read(charArray, -1, 0));
-
- br.read(charArray, 0, 0);
- br.read(charArray, 0, charArray.length);
- br.read(charArray, charArray.length, 0);
-
- assertThrows(IndexOutOfBoundsException.class, () -> br.read(charArray, charArray.length + 1, 0));
- assertThrows(IndexOutOfBoundsException.class, () -> br.read(charArray, charArray.length + 1, 1));
-
- br.close();
+ final int p = br.peek();
+ assertEquals(testString.charAt(0), p);
+ final int r = br.read();
+ assertEquals(testString.charAt(0), r);
+ br = new UnsynchronizedBufferedReader(new StringReader(new String(new char[] { '\u8765' })));
+ assertEquals(br.peek(), '\u8765');
+ assertEquals(br.read(), '\u8765');
+ // chars '\0'...'\255'
+ final char[] chars = new char[256];
+ for (int i = 0; i < 256; i++) {
+ chars[i] = (char) i;
+ }
+ try (UnsynchronizedBufferedReader in = new UnsynchronizedBufferedReader(new StringReader(new String(chars)), 12)) {
+ assertEquals(0, in.peek()); // Fill the buffer
+ assertEquals(0, in.read()); // Fill the buffer
+ final char[] buf = new char[14];
+ in.read(buf, 0, 14); // Read greater than the buffer
+ assertTrue(new String(buf).equals(new String(chars, 1, 14)));
+ assertEquals(15, in.peek()); // Check next byte
+ assertEquals(15, in.read()); // Check next byte
+ }
+ //
+ // regression test for HARMONY-841
+ try (UnsynchronizedBufferedReader reader = new UnsynchronizedBufferedReader(new CharArrayReader(new char[5], 1, 0), 2)) {
+ assertEquals(reader.peek(), -1);
+ assertEquals(reader.read(), -1);
+ }
+ }
- assertThrows(IOException.class, () -> br.read(nullCharArray, -1, -1));
- assertThrows(IOException.class, () -> br.read(charArray, -1, 0));
- assertThrows(IOException.class, () -> br.read(charArray, 0, -1));
+ /**
+ * Tests {@link UnsynchronizedBufferedReader#peek()}.
+ *
+ * @throws IOException test failure.
+ */
+ @Test
+ public void testPeekArray() throws IOException {
+ // Test for method int UnsynchronizedBufferedReader.read()
+ final char[] peekBuf1 = new char[1];
+ br = new UnsynchronizedBufferedReader(new StringReader(testString));
+ assertEquals(peekBuf1.length, br.peek(peekBuf1));
+ assertEquals(testString.charAt(0), peekBuf1[0]);
+ final int r = br.read();
+ assertEquals(testString.charAt(0), r);
+ br = new UnsynchronizedBufferedReader(new StringReader(new String(new char[] { '\u8765' })));
+ assertEquals(peekBuf1.length, br.peek(peekBuf1));
+ assertEquals(peekBuf1[0], '\u8765');
+ assertEquals(br.read(), '\u8765');
+ // chars '\0'...'\255'
+ final char[] chars = new char[256];
+ for (int i = 0; i < 256; i++) {
+ chars[i] = (char) i;
+ }
+ try (UnsynchronizedBufferedReader in = new UnsynchronizedBufferedReader(new StringReader(new String(chars)), 12)) {
+ assertEquals(peekBuf1.length, in.peek(peekBuf1)); // Fill the buffer
+ assertEquals(peekBuf1[0], 0);
+ assertEquals(0, in.read()); // Fill the buffer
+ final char[] peekBuf14 = new char[14];
+ assertEquals(peekBuf14.length, in.peek(peekBuf14)); // Peek greater than the buffer
+ assertTrue(new String(peekBuf14).equals(new String(chars, 1, 14)));
+ final char[] buf = new char[14];
+ in.read(buf, 0, 14); // Read greater than the buffer
+ assertTrue(new String(buf).equals(new String(chars, 1, 14)));
+ assertEquals(peekBuf1.length, in.peek(peekBuf1)); // Check next byte
+ assertEquals(15, peekBuf1[0]);
+ assertEquals(15, in.read()); // Check next byte
+ }
+ //
+ // regression test for HARMONY-841
+ try (UnsynchronizedBufferedReader reader = new UnsynchronizedBufferedReader(new CharArrayReader(new char[5], 1, 0), 2)) {
+ assertEquals(reader.peek(), -1);
+ assertEquals(reader.read(), -1);
+ }
}
/**
@@ -253,7 +353,7 @@ public class UnsynchronizedBufferedReaderTest {
* @throws IOException test failure.
*/
@Test
- public void test_read$CII() throws IOException {
+ public void testReadArray() throws IOException {
final char[] ca = new char[2];
try (UnsynchronizedBufferedReader toRet = new UnsynchronizedBufferedReader(new InputStreamReader(new ByteArrayInputStream(new byte[0])))) {
/* Null buffer should throw NPE even when len == 0 */
@@ -289,6 +389,7 @@ public class UnsynchronizedBufferedReaderTest {
@Override
public void close() throws IOException {
+ // Empty
}
@Override
@@ -320,7 +421,7 @@ public class UnsynchronizedBufferedReaderTest {
})) {
bufin.read();
final int result = bufin.read(new char[2], 0, 2);
- assertTrue(result == 1);
+ assertEquals(result, 1);
}
// regression for HARMONY-831
try (Reader reader = new UnsynchronizedBufferedReader(new PipedReader(), 9)) {
@@ -344,13 +445,45 @@ public class UnsynchronizedBufferedReaderTest {
assertThrows(IOException.class, () -> reader.read(ch, 0, 42));
}
+ /**
+ * Tests {@link UnsynchronizedBufferedReader#read(char[], int, int)}.
+ *
+ * @throws IOException test failure.
+ */
+ @Test
+ public void testReadArrayException() throws IOException {
+ br = new UnsynchronizedBufferedReader(new StringReader(testString));
+ final char[] nullCharArray = null;
+ final char[] charArray = testString.toCharArray();
+ assertThrows(IndexOutOfBoundsException.class, () -> br.read(nullCharArray, -1, -1));
+ assertThrows(IndexOutOfBoundsException.class, () -> br.read(nullCharArray, -1, 0));
+ assertThrows(NullPointerException.class, () -> br.read(nullCharArray, 0, -1));
+ assertThrows(NullPointerException.class, () -> br.read(nullCharArray, 0, 0));
+ assertThrows(NullPointerException.class, () -> br.read(nullCharArray, 0, 1));
+ assertThrows(IndexOutOfBoundsException.class, () -> br.read(charArray, -1, -1));
+ assertThrows(IndexOutOfBoundsException.class, () -> br.read(charArray, -1, 0));
+
+ br.read(charArray, 0, 0);
+ br.read(charArray, 0, charArray.length);
+ br.read(charArray, charArray.length, 0);
+
+ assertThrows(IndexOutOfBoundsException.class, () -> br.read(charArray, charArray.length + 1, 0));
+ assertThrows(IndexOutOfBoundsException.class, () -> br.read(charArray, charArray.length + 1, 1));
+
+ br.close();
+
+ assertThrows(IOException.class, () -> br.read(nullCharArray, -1, -1));
+ assertThrows(IOException.class, () -> br.read(charArray, -1, 0));
+ assertThrows(IOException.class, () -> br.read(charArray, 0, -1));
+ }
+
/**
* Tests {@link UnsynchronizedBufferedReader#readLine()}.
*
* @throws IOException test failure.
*/
@Test
- public void test_readLine() throws IOException {
+ public void testReadLine() throws IOException {
// Test for method java.lang.String UnsynchronizedBufferedReader.readLine()
br = new UnsynchronizedBufferedReader(new StringReader(testString));
final String r = br.readLine();
@@ -364,12 +497,12 @@ public class UnsynchronizedBufferedReaderTest {
* @throws IOException test failure.
*/
@Test
- public void test_readLine_IgnoresEbcdic85Characters() throws IOException {
+ public void testReadLineIgnoresEbcdic85Characters() throws IOException {
assertLines("A\u0085B", "A\u0085B");
}
@Test
- public void test_readLine_Separators() throws IOException {
+ public void testReadLineSeparators() throws IOException {
assertLines("A\nB\nC", "A", "B", "C");
assertLines("A\rB\rC", "A", "B", "C");
assertLines("A\r\nB\r\nC", "A", "B", "C");
@@ -389,7 +522,7 @@ public class UnsynchronizedBufferedReaderTest {
* @throws IOException test failure.
*/
@Test
- public void test_ready() throws IOException {
+ public void testReady() throws IOException {
// Test for method boolean UnsynchronizedBufferedReader.ready()
br = new UnsynchronizedBufferedReader(new StringReader(testString));
assertTrue(br.ready());
@@ -398,10 +531,10 @@ public class UnsynchronizedBufferedReaderTest {
/**
* Tests {@link UnsynchronizedBufferedReader#reset()}.
*
- * @throws IOException
+ * @throws IOException test failure.
*/
@Test
- public void test_reset() throws IOException {
+ public void testReset() throws IOException {
// Test for method void UnsynchronizedBufferedReader.reset()
br = new UnsynchronizedBufferedReader(new StringReader(testString));
br.skip(500);
@@ -417,7 +550,7 @@ public class UnsynchronizedBufferedReaderTest {
}
@Test
- public void test_reset_IOException() throws Exception {
+ public void testReset_IOException() throws Exception {
final int[] expected = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', -1 };
br = new UnsynchronizedBufferedReader(new StringReader("1234567890"), 9);
br.mark(9);
@@ -443,10 +576,10 @@ public class UnsynchronizedBufferedReaderTest {
/**
* Tests {@link UnsynchronizedBufferedReader#skip(long)}.
*
- * @throws IOException
+ * @throws IOException test failure.
*/
@Test
- public void test_skipJ() throws IOException {
+ public void testSkip() throws IOException {
// Test for method long UnsynchronizedBufferedReader.skip(long)
br = new UnsynchronizedBufferedReader(new StringReader(testString));
br.skip(500);