/* * Copyright (c) 2016, PostgreSQL Global Development Group * See the LICENSE file in the project root for more information. */ package org.postgresql.util; import static org.junit.Assert.assertEquals; import org.junit.Test; import java.io.ByteArrayInputStream; import java.io.CharArrayReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.nio.charset.MalformedInputException; import java.util.Arrays; public class ReaderInputStreamTest { // 132878 = U+2070E - chosen because it is the first supplementary character // in the International Ideographic Core (IICore) // see http://www.i18nguy.com/unicode/supplementary-test.html for further explanation // Character.highSurrogate(132878) = 0xd841 static final private char LEADING_SURROGATE = 0xd841; // Character.lowSurrogate(132878) = 0xdf0e static final private char TRAILING_SURROGATE = 0xdf0e; @Test(expected = IllegalArgumentException.class) public void NullReaderTest() { new ReaderInputStream(null); } @Test(expected = IllegalArgumentException.class) public void cbufTooSmallReaderTest() { new ReaderInputStream(new StringReader("abc"), 1); } static private void read(InputStream is, int... expected) throws IOException { byte[] actual = new byte[4]; Arrays.fill(actual, (byte) 0x00); int nActual = is.read(actual); int[] actualInts = new int[4]; for (int i = 0; i < actual.length; i++) { actualInts[i] = actual[i] & 0xff; } if (expected.length > 0) { // Ensure "expected" has 4 bytes expected = Arrays.copyOf(expected, 4); assertEquals(Arrays.toString(expected), Arrays.toString(actualInts)); } else { assertEquals("should be end-of-stream", -1, nActual); is.close(); } } @Test public void SimpleTest() throws IOException { char[] chars = new char[]{'a', 'b', 'c'}; Reader reader = new CharArrayReader(chars); InputStream is = new ReaderInputStream(reader); read(is, 0x61, 0x62, 0x63); read(is); } @Test public void inputSmallerThanCbufsizeTest() throws IOException { char[] chars = new char[]{'a'}; Reader reader = new CharArrayReader(chars); InputStream is = new ReaderInputStream(reader, 2); read(is, 0x61); read(is); } @Test public void tooManyReadsTest() throws IOException { char[] chars = new char[]{'a'}; Reader reader = new CharArrayReader(chars); InputStream is = new ReaderInputStream(reader, 2); read(is, 0x61); assertEquals("should be end-of-stream", -1, is.read()); assertEquals("should be end-of-stream", -1, is.read()); assertEquals("should be end-of-stream", -1, is.read()); is.close(); } @Test public void surrogatePairSpansCharBufBoundaryTest() throws IOException { char[] chars = new char[]{'a', LEADING_SURROGATE, TRAILING_SURROGATE}; Reader reader = new CharArrayReader(chars); InputStream is = new ReaderInputStream(reader, 2); read(is, 0x61, 0xF0, 0xA0, 0x9C); read(is, 0x8E); read(is); } @Test(expected = MalformedInputException.class) public void invalidInputTest() throws IOException { char[] chars = new char[]{'a', LEADING_SURROGATE, LEADING_SURROGATE}; Reader reader = new CharArrayReader(chars); InputStream is = new ReaderInputStream(reader, 2); read(is); } @Test(expected = MalformedInputException.class) public void unmatchedLeadingSurrogateInputTest() throws IOException { char[] chars = new char[]{LEADING_SURROGATE}; Reader reader = new CharArrayReader(chars); InputStream is = new ReaderInputStream(reader, 2); read(is, 0x00); } @Test(expected = MalformedInputException.class) public void unmatchedTrailingSurrogateInputTest() throws IOException { char[] chars = new char[]{TRAILING_SURROGATE}; Reader reader = new CharArrayReader(chars); InputStream is = new ReaderInputStream(reader, 2); read(is); } @Test(expected = NullPointerException.class) public void nullArrayReadTest() throws IOException { Reader reader = new StringReader("abc"); InputStream is = new ReaderInputStream(reader); is.read(null, 0, 4); } @Test(expected = IndexOutOfBoundsException.class) public void invalidOffsetArrayReadTest() throws IOException { Reader reader = new StringReader("abc"); InputStream is = new ReaderInputStream(reader); byte[] bytes = new byte[4]; is.read(bytes, 5, 4); } @Test(expected = IndexOutOfBoundsException.class) public void negativeOffsetArrayReadTest() throws IOException { Reader reader = new StringReader("abc"); InputStream is = new ReaderInputStream(reader); byte[] bytes = new byte[4]; is.read(bytes, -1, 4); } @Test(expected = IndexOutOfBoundsException.class) public void invalidLengthArrayReadTest() throws IOException { Reader reader = new StringReader("abc"); InputStream is = new ReaderInputStream(reader); byte[] bytes = new byte[4]; is.read(bytes, 1, 4); } @Test(expected = IndexOutOfBoundsException.class) public void negativeLengthArrayReadTest() throws IOException { Reader reader = new StringReader("abc"); InputStream is = new ReaderInputStream(reader); byte[] bytes = new byte[4]; is.read(bytes, 1, -2); } @Test public void zeroLengthArrayReadTest() throws IOException { Reader reader = new StringReader("abc"); InputStream is = new ReaderInputStream(reader); byte[] bytes = new byte[4]; assertEquals("requested 0 byte read", 0, is.read(bytes, 1, 0)); } @Test public void singleCharArrayReadTest() throws IOException { Reader reader = new SingleCharPerReadReader(LEADING_SURROGATE, TRAILING_SURROGATE); InputStream is = new ReaderInputStream(reader); read(is, 0xF0, 0xA0, 0x9C, 0x8E); read(is); } @Test(expected = MalformedInputException.class) public void malformedSingleCharArrayReadTest() throws IOException { Reader reader = new SingleCharPerReadReader(LEADING_SURROGATE, LEADING_SURROGATE); InputStream is = new ReaderInputStream(reader); read(is, 0xF0, 0xA0, 0x9C, 0x8E); } @Test public void readsEqualToBlockSizeTest() throws Exception { final int blockSize = 8 * 1024; final int dataSize = blockSize + 57; final byte[] data = new byte[dataSize]; final byte[] buffer = new byte[blockSize]; InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(data), "UTF-8"); ReaderInputStream r = new ReaderInputStream(isr, blockSize); int total = 0; total += r.read(buffer, 0, blockSize); total += r.read(buffer, 0, blockSize); assertEquals("Data not read completely: missing " + (dataSize - total) + " bytes", dataSize, total); } private static class SingleCharPerReadReader extends Reader { private final char[] data; private int i; private SingleCharPerReadReader(char... data) { this.data = data; } @Override public int read(char[] cbuf, int off, int len) throws IOException { if (i < data.length) { cbuf[off] = data[i++]; return 1; } return -1; } @Override public void close() throws IOException { } } }