Add BufferedWriter

This commit is contained in:
Alexey Andreev 2017-11-16 13:43:31 +03:00
parent c9281b700b
commit 30da395304
2 changed files with 516 additions and 0 deletions

View File

@ -0,0 +1,193 @@
/*
* Copyright 2017 Alexey Andreev.
*
* Licensed 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.teavm.classlib.java.io;
import java.io.IOException;
import java.io.Writer;
import java.util.Objects;
public class TBufferedWriter extends Writer {
private Writer out;
private char[] buf;
private int pos;
private final String lineSeparator = "\n";
public TBufferedWriter(Writer out) {
super(out);
this.out = out;
buf = new char[8192];
}
public TBufferedWriter(Writer out, int size) {
super(out);
if (size <= 0) {
throw new IllegalArgumentException();
}
this.out = out;
this.buf = new char[size];
}
@Override
public void close() throws IOException {
if (isClosed()) {
return;
}
Throwable thrown = null;
try {
flushInternal();
} catch (Throwable e) {
thrown = e;
}
buf = null;
try {
out.close();
} catch (Throwable e) {
if (thrown == null) {
thrown = e;
}
}
out = null;
if (thrown != null) {
if (thrown instanceof IOException) {
throw (IOException) thrown;
} else if (thrown instanceof RuntimeException) {
throw (RuntimeException) thrown;
} else {
throw new IOException(thrown);
}
}
}
@Override
public void flush() throws IOException {
if (isClosed()) {
throw new IOException();
}
flushInternal();
out.flush();
}
private void flushInternal() throws IOException {
if (pos > 0) {
out.write(buf, 0, pos);
}
pos = 0;
}
private boolean isClosed() {
return out == null;
}
public void newLine() throws IOException {
write(lineSeparator, 0, lineSeparator.length());
}
@Override
public void write(char[] cbuf, int offset, int count) throws IOException {
if (isClosed()) {
throw new IOException();
}
if (offset < 0 || offset > Objects.requireNonNull(cbuf).length - count || count < 0) {
throw new IndexOutOfBoundsException();
}
if (pos == 0 && count >= this.buf.length) {
out.write(cbuf, offset, count);
return;
}
int available = this.buf.length - pos;
if (count < available) {
available = count;
}
if (available > 0) {
System.arraycopy(cbuf, offset, this.buf, pos, available);
pos += available;
}
if (pos == this.buf.length) {
out.write(this.buf, 0, this.buf.length);
pos = 0;
if (count > available) {
offset += available;
available = count - available;
if (available >= this.buf.length) {
out.write(cbuf, offset, available);
return;
}
System.arraycopy(cbuf, offset, this.buf, pos, available);
pos += available;
}
}
}
@Override
public void write(int oneChar) throws IOException {
if (isClosed()) {
throw new IOException();
}
if (pos >= buf.length) {
out.write(buf, 0, buf.length);
pos = 0;
}
buf[pos++] = (char) oneChar;
}
@Override
public void write(String str, int offset, int count) throws IOException {
if (isClosed()) {
throw new IOException();
}
if (count <= 0) {
return;
}
if (offset > Objects.requireNonNull(str).length() - count || offset < 0) {
throw new StringIndexOutOfBoundsException();
}
if (pos == 0 && count >= buf.length) {
char[] chars = new char[count];
str.getChars(offset, offset + count, chars, 0);
out.write(chars, 0, count);
return;
}
int available = buf.length - pos;
if (count < available) {
available = count;
}
if (available > 0) {
str.getChars(offset, offset + available, buf, pos);
pos += available;
}
if (pos == buf.length) {
out.write(this.buf, 0, this.buf.length);
pos = 0;
if (count > available) {
offset += available;
available = count - available;
if (available >= buf.length) {
char[] chars = new char[count];
str.getChars(offset, offset + available, chars, 0);
out.write(chars, 0, available);
return;
}
str.getChars(offset, offset + available, buf, pos);
pos += available;
}
}
}
}

View File

@ -0,0 +1,323 @@
/*
* Copyright 2017 Alexey Andreev.
*
* Licensed 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.teavm.classlib.java.io;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.teavm.junit.TeaVMTestRunner;
@RunWith(TeaVMTestRunner.class)
public class BufferedWriterTest {
private BufferedWriter bw;
private StringWriter sw;
private String testString = ""
+ "Test_All_Tests\n" + "Test_java_io_BufferedInputStream\n" + "Test_java_io_BufferedOutputStream\n"
+ "Test_java_io_ByteArrayInputStream\n" + "Test_java_io_ByteArrayOutputStream\n"
+ "Test_java_io_DataInputStream\n" + "Test_java_io_File\n" + "Test_java_io_FileDescriptor\n"
+ "Test_java_io_FileInputStream\n" + "Test_java_io_FileNotFoundException\n"
+ "Test_java_io_FileOutputStream\n" + "Test_java_io_FilterInputStream\n"
+ "Test_java_io_FilterOutputStream\n" + "Test_java_io_InputStream\n" + "Test_java_io_IOException\n"
+ "Test_java_io_OutputStream\n" + "Test_java_io_PrintStream\n" + "Test_java_io_RandomAccessFile\n"
+ "Test_java_io_SyncFailedException\n" + "Test_java_lang_AbstractMethodError\n"
+ "Test_java_lang_ArithmeticException\n" + "Test_java_lang_ArrayIndexOutOfBoundsException\n"
+ "Test_java_lang_ArrayStoreException\n" + "Test_java_lang_Boolean\n" + "Test_java_lang_Byte\n"
+ "Test_java_lang_Character\n" + "Test_java_lang_Class\n" + "Test_java_lang_ClassCastException\n"
+ "Test_java_lang_ClassCircularityError\n" + "Test_java_lang_ClassFormatError\n"
+ "Test_java_lang_ClassLoader\n" + "Test_java_lang_ClassNotFoundException\n"
+ "Test_java_lang_CloneNotSupportedException\n" + "Test_java_lang_Double\n"
+ "Test_java_lang_Error\n" + "Test_java_lang_Exception\n"
+ "Test_java_lang_ExceptionInInitializerError\n" + "Test_java_lang_Float\n"
+ "Test_java_lang_IllegalAccessError\n" + "Test_java_lang_IllegalAccessException\n"
+ "Test_java_lang_IllegalArgumentException\n" + "Test_java_lang_IllegalMonitorStateException\n"
+ "Test_java_lang_IllegalThreadStateException\n" + "Test_java_lang_IncompatibleClassChangeError\n"
+ "Test_java_lang_IndexOutOfBoundsException\n" + "Test_java_lang_InstantiationError\n"
+ "Test_java_lang_InstantiationException\n" + "Test_java_lang_Integer\n"
+ "Test_java_lang_InternalError\n" + "Test_java_lang_InterruptedException\n"
+ "Test_java_lang_LinkageError\n" + "Test_java_lang_Long\n" + "Test_java_lang_Math\n"
+ "Test_java_lang_NegativeArraySizeException\n" + "Test_java_lang_NoClassDefFoundError\n"
+ "Test_java_lang_NoSuchFieldError\n" + "Test_java_lang_NoSuchMethodError\n"
+ "Test_java_lang_NullPointerException\n" + "Test_java_lang_Number\n"
+ "Test_java_lang_NumberFormatException\n" + "Test_java_lang_Object\n"
+ "Test_java_lang_OutOfMemoryError\n" + "Test_java_lang_RuntimeException\n"
+ "Test_java_lang_SecurityManager\n" + "Test_java_lang_Short\n"
+ "Test_java_lang_StackOverflowError\n" + "Test_java_lang_String\n"
+ "Test_java_lang_StringBuffer\n" + "Test_java_lang_StringIndexOutOfBoundsException\n"
+ "Test_java_lang_System\n" + "Test_java_lang_Thread\n" + "Test_java_lang_ThreadDeath\n"
+ "Test_java_lang_ThreadGroup\n" + "Test_java_lang_Throwable\n" + "Test_java_lang_UnknownError\n"
+ "Test_java_lang_UnsatisfiedLinkError\n" + "Test_java_lang_VerifyError\n"
+ "Test_java_lang_VirtualMachineError\n" + "Test_java_lang_vm_Image\n"
+ "Test_java_lang_vm_MemorySegment\n" + "Test_java_lang_vm_ROMStoreException\n"
+ "Test_java_lang_vm_VM\n" + "Test_java_lang_Void\n" + "Test_java_net_BindException\n"
+ "Test_java_net_ConnectException\n" + "Test_java_net_DatagramPacket\n"
+ "Test_java_net_DatagramSocket\n" + "Test_java_net_DatagramSocketImpl\n"
+ "Test_java_net_InetAddress\n" + "Test_java_net_NoRouteToHostException\n"
+ "Test_java_net_PlainDatagramSocketImpl\n" + "Test_java_net_PlainSocketImpl\n"
+ "Test_java_net_Socket\n" + "Test_java_net_SocketException\n" + "Test_java_net_SocketImpl\n"
+ "Test_java_net_SocketInputStream\n" + "Test_java_net_SocketOutputStream\n"
+ "Test_java_net_UnknownHostException\n" + "Test_java_util_ArrayEnumerator\n"
+ "Test_java_util_Date\n" + "Test_java_util_EventObject\n" + "Test_java_util_HashEnumerator\n"
+ "Test_java_util_Hashtable\n" + "Test_java_util_Properties\n" + "Test_java_util_ResourceBundle\n"
+ "Test_java_util_tm\n" + "Test_java_util_Vector\n";
public BufferedWriterTest() {
sw = new StringWriter();
bw = new BufferedWriter(sw, 500);
}
@Test
public void constructorLjava_io_Writer() {
sw = new StringWriter();
bw = new BufferedWriter(sw);
sw.write("Hi");
assertEquals("Constructor failed", "Hi", sw.toString());
}
@Test
public void constructorLjava_io_WriterI() {
assertTrue("Used in tests", true);
}
static class MockWriter extends Writer {
StringBuffer sb = new StringBuffer();
boolean flushCalled;
@Override
public void write(char[] buf, int off, int len) {
for (int i = off; i < off + len; i++) {
sb.append(buf[i]);
}
}
@Override
public void close() {
// Empty
}
@Override
public void flush() {
flushCalled = true;
}
String getWritten() {
return sb.toString();
}
boolean isFlushCalled() {
return flushCalled;
}
}
@Test
public void close() throws IOException {
try {
bw.close();
bw.write(testString);
fail("Writing to a closed stream should throw IOException");
} catch (IOException e) {
// Expected
}
assertTrue("Write after close", !sw.toString().equals(testString));
// Regression test for HARMONY-4178
MockWriter mw = new MockWriter();
BufferedWriter bw = new BufferedWriter(mw);
bw.write('a');
bw.close();
// flush should not be called on underlying stream
assertFalse("Flush was called in the underlying stream", mw.isFlushCalled());
// on the other hand the BufferedWriter itself should flush the
// buffer
assertEquals("BufferdWriter do not flush itself before close", "a", mw.getWritten());
}
@Test
public void close2() throws IOException {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new ByteArrayOutputStream()));
bw.close();
}
@Test
public void flush() throws Exception {
bw.write("This should not cause a flush");
assertTrue("Bytes written without flush", sw.toString().equals(""));
bw.flush();
assertEquals("Bytes not flushed", "This should not cause a flush", sw.toString());
}
@Test
public void newLine() throws Exception {
String separator = System.getProperty("line.separator");
bw.write("Hello");
bw.newLine();
bw.write("World");
bw.flush();
assertTrue("Incorrect string written: " + sw.toString(), sw.toString().equals("Hello" + separator + "World"));
}
@Test
public void write$CII() throws Exception {
char[] testCharArray = testString.toCharArray();
bw.write(testCharArray, 500, 1000);
bw.flush();
assertTrue("Incorrect string written", sw.toString().equals(testString.substring(500, 1500)));
}
@Test
public void write_$CII_Exception() throws IOException {
BufferedWriter bWriter = new BufferedWriter(sw);
char[] nullCharArray = null;
try {
bWriter.write(nullCharArray, -1, -1);
fail("should throw IndexOutOfBoundsException");
} catch (IndexOutOfBoundsException e) {
// expected
}
try {
bWriter.write(nullCharArray, -1, 0);
fail("should throw IndexOutOfBoundsException");
} catch (IndexOutOfBoundsException e) {
// expected
}
try {
bWriter.write(nullCharArray, 0, -1);
fail("should throw NullPointerException");
} catch (NullPointerException e) {
// expected
}
try {
bWriter.write(nullCharArray, 0, 0);
fail("should throw NullPointerException");
} catch (NullPointerException e) {
// expected
}
char[] testCharArray = testString.toCharArray();
bWriter.write(testCharArray, 0, 0);
bWriter.write(testCharArray, testCharArray.length, 0);
try {
bWriter.write(testCharArray, testCharArray.length + 1, 0);
fail("should throw IndexOutOfBoundsException");
} catch (IndexOutOfBoundsException e) {
// expected
}
bWriter.close();
try {
bWriter.write(nullCharArray, -1, -1);
fail("should throw IOException");
} catch (IOException e) {
// expected
}
}
@Test
public void writeI() throws Exception {
bw.write('T');
assertTrue("Char written without flush", sw.toString().equals(""));
bw.flush();
assertEquals("Incorrect char written", "T", sw.toString());
}
@Test
public void writeLjava_lang_StringII() throws Exception {
bw.write(testString);
bw.flush();
assertTrue("Incorrect string written", sw.toString().equals(testString));
}
@Test
public void write_LStringII_Exception() throws IOException {
BufferedWriter bWriter = new BufferedWriter(sw);
bWriter.write((String) null, -1, -1);
bWriter.write((String) null, -1, 0);
bWriter.write((String) null, 0, -1);
bWriter.write((String) null, 0, 0);
try {
bWriter.write((String) null, -1, 1);
fail("should throw NullPointerException");
} catch (NullPointerException e) {
// expected
}
bWriter.write(testString, 0, 0);
bWriter.write(testString, testString.length(), 0);
bWriter.write(testString, testString.length() + 1, 0);
try {
bWriter.write(testString, testString.length() + 1, 1);
fail("should throw StringIndexOutOfBoundsException");
} catch (StringIndexOutOfBoundsException e) {
// expected
}
bWriter.close();
try {
bWriter.write((String) null, -1, -1);
fail("should throw IOException");
} catch (IOException e) {
// expected
}
try {
bWriter.write((String) null, -1, 1);
fail("should throw IOException");
} catch (IOException e) {
// expected
}
try {
bWriter.write(testString, -1, -1);
fail("should throw IOException");
} catch (IOException e) {
// expected
}
}
@After
public void tearDown() {
try {
bw.close();
} catch (Exception e) {
// Do nothing
}
}
}