package org.netbeans.gradle.project.output; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.nio.charset.Charset; import org.junit.Test; import org.netbeans.gradle.project.util.StringUtils; import static org.junit.Assert.*; public class ReaderInputStreamTest { private static final Charset[] UNIVERSAL_CHARSETS = new Charset[] { Charset.forName("UTF-16"), StringUtils.UTF8, Charset.forName("UTF-16LE"), }; private static final Charset[] CHARSETS = new Charset[] { StringUtils.UTF8, Charset.forName("UTF-16LE"), Charset.forName("ISO-8859-1"), Charset.forName("ISO-8859-2"), }; private static byte[] readAllBytesWithOffsets(InputStream input, int expected) throws IOException { byte[] buffer = new byte[1024]; ByteArrayOutputStream result = new ByteArrayOutputStream(4096); boolean oddCycle = true; int sumReadCount = 0; while (true) { int readCount; int offset = oddCycle ? 0 : 1; int expectedRemaining = expected - sumReadCount; if (expectedRemaining > 0 && expectedRemaining < buffer.length) { offset = buffer.length - expectedRemaining; } readCount = input.read(buffer, offset, buffer.length - offset); if (readCount <= 0) { break; } sumReadCount += readCount; result.write(buffer, offset, readCount); oddCycle = !oddCycle; } return result.toByteArray(); } private static byte[] readAllBytes(InputStream input, int copyBatchSize) throws IOException { byte[] buffer = new byte[copyBatchSize]; ByteArrayOutputStream result = new ByteArrayOutputStream(4096); while (true) { int readCount = input.read(buffer); if (readCount <= 0) { break; } result.write(buffer, 0, readCount); } return result.toByteArray(); } private static void doTest(Charset charset, String text, int copyBatchSize) throws IOException { try { ReaderInputStream reader = new ReaderInputStream(new StringReader(text), charset); byte[] bytes = readAllBytes(reader, copyBatchSize); assertEquals(text, new String(bytes, charset)); } catch (Throwable ex) { throw new AssertionError("Test failed for charset: " + charset.name() + ", copyBatchSize: " + copyBatchSize + ", text: " + text, ex); } } private static void doTestForAllCharsets(String text) throws IOException { for (Charset charset: CHARSETS) { doTest(charset, text); } } private static void doTestForUniversalCharsets(String text) throws IOException { for (Charset charset: UNIVERSAL_CHARSETS) { doTest(charset, text); } } private static void doTest(Charset charset, String text) throws IOException { for (int copyBatchSize: new int[]{1, 2, 1024, 4096, 4 * text.length()}) { doTest(charset, text, copyBatchSize); } } @Test public void testEmpty() throws IOException { doTestForAllCharsets(""); } @Test public void test1AsciiChar() throws IOException { doTestForAllCharsets("a"); } @Test public void test2AsciiChars() throws IOException { doTestForAllCharsets("ab"); } @Test public void test10AsciiChars() throws IOException { doTestForAllCharsets("abcdefghij"); } private static boolean isValidSingleCodePoint(int value) { return value != 0xFFFE && (value < 0xD800 || value > 0xDFFF); } @Test public void testSingleChar() throws IOException { int lastTested = -1; try { int[] codePoint = new int[1]; for (int i = 0; i < 100_000; i++) { if (isValidSingleCodePoint(i)) { lastTested = i; codePoint[0] = i; doTestForUniversalCharsets(new String(codePoint, 0, 1)); } } } catch (Throwable ex) { throw new AssertionError("Test failed for codepoint: " + lastTested, ex); } } @Test public void testForLongString() throws IOException { int charCount = 100_000; StringBuilder str = new StringBuilder(charCount); for (int i = 0; i < charCount; i++) { if (isValidSingleCodePoint(i)) { str.appendCodePoint(i); } } doTestForUniversalCharsets(str.toString()); } @Test public void testForAsciiLongString() throws IOException { int charCount = 100_000; StringBuilder str = new StringBuilder(charCount); char currentChar = 'a'; for (int i = 0; i < 100000; i++) { str.append(currentChar); currentChar = (char)(currentChar + 1); if (currentChar > 'z') { currentChar = 'a'; } } doTestForAllCharsets(str.toString()); } @Test public void testForAsciiLongString2() throws IOException { int charCount = 20_000; StringBuilder str = new StringBuilder(charCount); for (int i = 0; i < 100000; i++) { char ch; if (i % 16 == 15) { ch = '\n'; } else { ch = (char)((i % ('z' - 'a')) + 'a'); } str.append(ch); } String text = str.toString(); Charset charset = Charset.forName("ISO-8859-1"); ReaderInputStream reader = new ReaderInputStream(new StringReader(text), charset); byte[] bytes = readAllBytesWithOffsets(reader, charCount); assertEquals(text, new String(bytes, charset)); } }