Author: niallp
Date: Fri Dec  5 14:42:34 2008
New Revision: 723912

URL: http://svn.apache.org/viewvc?rev=723912&view=rev
Log:
IO-158 New ReaderInputStream and WriterOutputStream implementations - thanks to 
Andreas Veithen for the patch

Added:
    
commons/proper/io/trunk/src/java/org/apache/commons/io/input/ReaderInputStream.java
   (with props)
    
commons/proper/io/trunk/src/java/org/apache/commons/io/output/WriterOutputStream.java
   (with props)
    
commons/proper/io/trunk/src/test/org/apache/commons/io/input/ReaderInputStreamTest.java
   (with props)
    
commons/proper/io/trunk/src/test/org/apache/commons/io/output/WriterOutputStreamTest.java
   (with props)

Added: 
commons/proper/io/trunk/src/java/org/apache/commons/io/input/ReaderInputStream.java
URL: 
http://svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/apache/commons/io/input/ReaderInputStream.java?rev=723912&view=auto
==============================================================================
--- 
commons/proper/io/trunk/src/java/org/apache/commons/io/input/ReaderInputStream.java
 (added)
+++ 
commons/proper/io/trunk/src/java/org/apache/commons/io/input/ReaderInputStream.java
 Fri Dec  5 14:42:34 2008
@@ -0,0 +1,237 @@
+/*
+ * 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.input;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+
+/**
+ * [EMAIL PROTECTED] InputStream} implementation that reads a character stream 
from a [EMAIL PROTECTED] Reader}
+ * and transforms it to a byte stream using a specified charset encoding. The 
stream
+ * is transformed using a [EMAIL PROTECTED] CharsetEncoder} object, 
guaranteeing that all charset
+ * encodings supported by the JRE are handled correctly. In particular for 
charsets such as
+ * UTF-16, the implementation ensures that one and only one byte order marker
+ * is produced.
+ * <p>
+ * Since in general it is not possible to predict the number of characters to 
be read from the
+ * [EMAIL PROTECTED] Reader} to satisfy a read request on the [EMAIL 
PROTECTED] ReaderInputStream}, all reads from
+ * the [EMAIL PROTECTED] Reader} are buffered. There is therefore no well 
defined correlation
+ * between the current position of the [EMAIL PROTECTED] Reader} and that of 
the [EMAIL PROTECTED] ReaderInputStream}.
+ * This also implies that in general there is no need to wrap the underlying 
[EMAIL PROTECTED] Reader}
+ * in a [EMAIL PROTECTED] java.io.BufferedReader}.
+ * <p>
+ * [EMAIL PROTECTED] ReaderInputStream} implements the inverse transformation 
of [EMAIL PROTECTED] java.io.InputStreamReader};
+ * in the following example, reading from <tt>in2</tt> would return the same 
byte
+ * sequence as reading from <tt>in</tt> (provided that the initial byte 
sequence is legal
+ * with respect to the charset encoding):
+ * <pre>
+ * InputStream in = ...
+ * Charset cs = ...
+ * InputStreamReader reader = new InputStreamReader(in, cs);
+ * ReaderInputStream in2 = new ReaderInputStream(reader, cs);</pre>
+ * [EMAIL PROTECTED] ReaderInputStream} implements the same transformation as 
[EMAIL PROTECTED] java.io.OutputStreamWriter},
+ * except that the control flow is reversed: both classes transform a 
character stream
+ * into a byte stream, but [EMAIL PROTECTED] java.io.OutputStreamWriter} 
pushes data to the underlying stream,
+ * while [EMAIL PROTECTED] ReaderInputStream} pulls it from the underlying 
stream.
+ * <p>
+ * Note that while there are use cases where there is no alternative to using
+ * this class, very often the need to use this class is an indication of a flaw
+ * in the design of the code. This class is typically used in situations where 
an existing
+ * API only accepts an [EMAIL PROTECTED] InputStream}, but where the most 
natural way to produce the data
+ * is as a character stream, i.e. by providing a [EMAIL PROTECTED] Reader} 
instance. An example of a situation
+ * where this problem may appear is when implementing the [EMAIL PROTECTED] 
javax.activation.DataSource}
+ * interface from the Java Activation Framework.
+ * <p>
+ * Given the fact that the [EMAIL PROTECTED] Reader} class doesn't provide any 
way to predict whether the next
+ * read operation will block or not, it is not possible to provide a meaningful
+ * implementation of the [EMAIL PROTECTED] InputStream#available()} method. A 
call to this method
+ * will always return 0. Also, this class doesn't support [EMAIL PROTECTED] 
InputStream#mark(int)}.
+ * <p>
+ * Instances of [EMAIL PROTECTED] ReaderInputStream} are not thread safe.
+ * 
+ * @see org.apache.commons.io.output.WriterOutputStream
+ * 
+ * @author <a href="mailto:[EMAIL PROTECTED]">Andreas Veithen</a>
+ * @since Commons IO 2.0
+ */
+public class ReaderInputStream extends InputStream {
+    private static final int DEFAULT_BUFFER_SIZE = 1024;
+
+    private final Reader reader;
+    private final CharsetEncoder encoder;
+
+    /**
+     * CharBuffer used as input for the decoder. It should be reasonably
+     * large as we read data from the underlying Reader into this buffer.
+     */
+    private final CharBuffer encoderIn;
+
+    /**
+     * ByteBuffer used as output for the decoder. This buffer can be small
+     * as it is only used to transfer data from the decoder to the
+     * buffer provided by the caller.
+     */
+    private final ByteBuffer encoderOut = ByteBuffer.allocate(128);
+
+    private CoderResult lastCoderResult;
+    private boolean endOfInput;
+
+    /**
+     * Construct a new [EMAIL PROTECTED] ReaderInputStream}.
+     * 
+     * @param reader the target [EMAIL PROTECTED] Reader}
+     * @param charset the charset encoding
+     * @param bufferSize the size of the input buffer in number of characters
+     */
+    public ReaderInputStream(Reader reader, Charset charset, int bufferSize) {
+        this.reader = reader;
+        encoder = charset.newEncoder();
+        encoderIn = CharBuffer.allocate(bufferSize);
+        encoderIn.flip();
+    }
+
+    /**
+     * Construct a new [EMAIL PROTECTED] ReaderInputStream} with a default 
input buffer size of
+     * 1024 characters.
+     * 
+     * @param reader the target [EMAIL PROTECTED] Reader}
+     * @param charset the charset encoding
+     */
+    public ReaderInputStream(Reader reader, Charset charset) {
+        this(reader, charset, DEFAULT_BUFFER_SIZE);
+    }
+
+    /**
+     * Construct a new [EMAIL PROTECTED] ReaderInputStream}.
+     * 
+     * @param reader the target [EMAIL PROTECTED] Reader}
+     * @param charsetName the name of the charset encoding
+     * @param bufferSize the size of the input buffer in number of characters
+     */
+    public ReaderInputStream(Reader reader, String charsetName, int 
bufferSize) {
+        this(reader, Charset.forName(charsetName), bufferSize);
+    }
+
+    /**
+     * Construct a new [EMAIL PROTECTED] ReaderInputStream} with a default 
input buffer size of
+     * 1024 characters.
+     * 
+     * @param reader the target [EMAIL PROTECTED] Reader}
+     * @param charsetName the name of the charset encoding
+     */
+    public ReaderInputStream(Reader reader, String charsetName) {
+        this(reader, charsetName, DEFAULT_BUFFER_SIZE);
+    }
+
+    /**
+     * Construct a new [EMAIL PROTECTED] ReaderInputStream} that uses the 
default character encoding
+     * with a default input buffer size of 1024 characters.
+     * 
+     * @param reader the target [EMAIL PROTECTED] Reader}
+     */
+    public ReaderInputStream(Reader reader) {
+        this(reader, Charset.defaultCharset());
+    }
+
+    /**
+     * Read the specified number of bytes into an array.
+     * 
+     * @param b the byte array to read into
+     * @param off the offset to start reading bytes into
+     * @param len the number of bytes to read
+     * @return the number of bytes read or <code>-1</code>
+     *         if the end of the stream has been reached
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        int read = 0;
+        while (len > 0) {
+            if (encoderOut.position() > 0) {
+                encoderOut.flip();
+                int c = Math.min(encoderOut.remaining(), len);
+                encoderOut.get(b, off, c);
+                off += c;
+                len -= c;
+                read += c;
+                encoderOut.compact();
+            } else {
+                if (!endOfInput && (lastCoderResult == null || 
lastCoderResult.isUnderflow())) {
+                    encoderIn.compact();
+                    int position = encoderIn.position();
+                    // We don't use Reader#read(CharBuffer) here because it is 
more efficient
+                    // to write directly to the underlying char array (the 
default implementation
+                    // copies data to a temporary char array).
+                    int c = reader.read(encoderIn.array(), position, 
encoderIn.remaining());
+                    if (c == -1) {
+                        endOfInput = true;
+                    } else {
+                        encoderIn.position(position+c);
+                    }
+                    encoderIn.flip();
+                }
+                lastCoderResult = encoder.encode(encoderIn, encoderOut, 
endOfInput);
+                if (endOfInput && encoderOut.position() == 0) {
+                    break;
+                }
+            }
+        }
+        return read == 0 && endOfInput ? -1 : read;
+    }
+
+    /**
+     * Read the specified number of bytes into an array.
+     * 
+     * @param b the byte array to read into
+     * @return the number of bytes read or <code>-1</code>
+     *         if the end of the stream has been reached
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public int read(byte[] b) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    /**
+     * Read a single byte.
+     *
+     * @return either the byte read or <code>-1</code> if the end of the stream
+     *         has been reached
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public int read() throws IOException {
+        byte[] b = new byte[1];
+        return read(b) == -1 ? -1 : b[0] & 0xFF;
+    }
+
+    /**
+     * Close the stream. This method will cause the underlying [EMAIL 
PROTECTED] Reader}
+     * to be closed.
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public void close() throws IOException {
+        reader.close();
+    }
+}

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

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

Added: 
commons/proper/io/trunk/src/java/org/apache/commons/io/output/WriterOutputStream.java
URL: 
http://svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/apache/commons/io/output/WriterOutputStream.java?rev=723912&view=auto
==============================================================================
--- 
commons/proper/io/trunk/src/java/org/apache/commons/io/output/WriterOutputStream.java
 (added)
+++ 
commons/proper/io/trunk/src/java/org/apache/commons/io/output/WriterOutputStream.java
 Fri Dec  5 14:42:34 2008
@@ -0,0 +1,274 @@
+/*
+ * 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.output;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * [EMAIL PROTECTED] OutputStream} implementation that transforms a byte 
stream to a
+ * character stream using a specified charset encoding and writes the resulting
+ * stream to a [EMAIL PROTECTED] Writer}. The stream is transformed using a
+ * [EMAIL PROTECTED] CharsetDecoder} object, guaranteeing that all charset
+ * encodings supported by the JRE are handled correctly.
+ * <p>
+ * The output of the [EMAIL PROTECTED] CharsetDecoder} is buffered using a 
fixed size buffer.
+ * This implies that the data is written to the underlying [EMAIL PROTECTED] 
Writer} in chunks
+ * that are no larger than the size of this buffer. By default, the buffer is
+ * flushed only when it overflows or when [EMAIL PROTECTED] #flush()} or 
[EMAIL PROTECTED] #close()}
+ * is called. In general there is therefore no need to wrap the underlying 
[EMAIL PROTECTED] Writer}
+ * in a [EMAIL PROTECTED] java.io.BufferedWriter}. [EMAIL PROTECTED] 
WriterOutputStream} can also
+ * be instructed to flush the buffer after each write operation. In this case, 
all
+ * available data is written immediately to the underlying [EMAIL PROTECTED] 
Writer}, implying that
+ * the current position of the [EMAIL PROTECTED] Writer} is correlated to the 
current position
+ * of the [EMAIL PROTECTED] WriterOutputStream}.
+ * <p>
+ * [EMAIL PROTECTED] WriterOutputStream} implements the inverse transformation 
of [EMAIL PROTECTED] java.io.OutputStreamWriter};
+ * in the following example, writing to <tt>out2</tt> would have the same 
result as writing to
+ * <tt>out</tt> directly (provided that the byte sequence is legal with 
respect to the
+ * charset encoding):
+ * <pre>
+ * OutputStream out = ...
+ * Charset cs = ...
+ * OutputStreamWriter writer = new OutputStreamWriter(out, cs);
+ * WriterOutputStream out2 = new WriterOutputStream(writer, cs);</pre>
+ * [EMAIL PROTECTED] WriterOutputStream} implements the same transformation as 
[EMAIL PROTECTED] java.io.InputStreamReader},
+ * except that the control flow is reversed: both classes transform a byte 
stream
+ * into a character stream, but [EMAIL PROTECTED] java.io.InputStreamReader} 
pulls data from the underlying stream,
+ * while [EMAIL PROTECTED] WriterOutputStream} pushes it to the underlying 
stream.
+ * <p>
+ * Note that while there are use cases where there is no alternative to using
+ * this class, very often the need to use this class is an indication of a flaw
+ * in the design of the code. This class is typically used in situations where 
an existing
+ * API only accepts an [EMAIL PROTECTED] OutputStream} object, but where the 
stream is known to represent
+ * character data that must be decoded for further use.
+ * <p>
+ * Instances of [EMAIL PROTECTED] WriterOutputStream} are not thread safe.
+ * 
+ * @see org.apache.commons.io.input.ReaderInputStream
+ * 
+ * @author <a href="mailto:[EMAIL PROTECTED]">Andreas Veithen</a>
+ * @since Commons IO 2.0
+ */
+public class WriterOutputStream extends OutputStream {
+    private static final int DEFAULT_BUFFER_SIZE = 1024;
+
+    private final Writer writer;
+    private final CharsetDecoder decoder;
+    private final boolean writeImmediately;
+
+    /**
+     * ByteBuffer used as input for the decoder. This buffer can be small
+     * as it is used only to transfer the received data to the
+     * decoder.
+     */
+    private final ByteBuffer decoderIn = ByteBuffer.allocate(128);
+
+    /**
+     * CharBuffer used as output for the decoder. It should be
+     * somewhat larger as we write from this buffer to the
+     * underlying Writer.
+     */
+    private final CharBuffer decoderOut;
+
+    /**
+     * Constructs a new [EMAIL PROTECTED] WriterOutputStream}.
+     * 
+     * @param writer the target [EMAIL PROTECTED] Writer}
+     * @param charset the charset encoding
+     * @param bufferSize the size of the output buffer in number of characters
+     * @param writeImmediately If <tt>true</tt> the output buffer will be 
flushed after each
+     *                         write operation, i.e. all available data will 
be written to the
+     *                         underlying [EMAIL PROTECTED] Writer} 
immediately. If <tt>false</tt>, the
+     *                         output buffer will only be flushed when it 
overflows or when
+     *                         [EMAIL PROTECTED] #flush()} or [EMAIL 
PROTECTED] #close()} is called.
+     */
+    public WriterOutputStream(Writer writer, Charset charset, int bufferSize, 
boolean writeImmediately) {
+        this.writer = writer;
+        decoder = charset.newDecoder();
+        decoder.onMalformedInput(CodingErrorAction.REPLACE);
+        decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
+        decoder.replaceWith("?");
+        this.writeImmediately = writeImmediately;
+        decoderOut = CharBuffer.allocate(bufferSize);
+    }
+
+    /**
+     * Constructs a new [EMAIL PROTECTED] WriterOutputStream} with a default 
output buffer size of
+     * 1024 characters. The output buffer will only be flushed when it 
overflows or when
+     * [EMAIL PROTECTED] #flush()} or [EMAIL PROTECTED] #close()} is called.
+     * 
+     * @param writer the target [EMAIL PROTECTED] Writer}
+     * @param charset the charset encoding
+     */
+    public WriterOutputStream(Writer writer, Charset charset) {
+        this(writer, charset, DEFAULT_BUFFER_SIZE, false);
+    }
+
+    /**
+     * Constructs a new [EMAIL PROTECTED] WriterOutputStream}.
+     * 
+     * @param writer the target [EMAIL PROTECTED] Writer}
+     * @param charsetName the name of the charset encoding
+     * @param bufferSize the size of the output buffer in number of characters
+     * @param writeImmediately If <tt>true</tt> the output buffer will be 
flushed after each
+     *                         write operation, i.e. all available data will 
be written to the
+     *                         underlying [EMAIL PROTECTED] Writer} 
immediately. If <tt>false</tt>, the
+     *                         output buffer will only be flushed when it 
overflows or when
+     *                         [EMAIL PROTECTED] #flush()} or [EMAIL 
PROTECTED] #close()} is called.
+     */
+    public WriterOutputStream(Writer writer, String charsetName, int 
bufferSize, boolean writeImmediately) {
+        this(writer, Charset.forName(charsetName), bufferSize, 
writeImmediately);
+    }
+
+    /**
+     * Constructs a new [EMAIL PROTECTED] WriterOutputStream} with a default 
output buffer size of
+     * 1024 characters. The output buffer will only be flushed when it 
overflows or when
+     * [EMAIL PROTECTED] #flush()} or [EMAIL PROTECTED] #close()} is called.
+     * 
+     * @param writer the target [EMAIL PROTECTED] Writer}
+     * @param charsetName the name of the charset encoding
+     */
+    public WriterOutputStream(Writer writer, String charsetName) {
+        this(writer, charsetName, DEFAULT_BUFFER_SIZE, false);
+    }
+
+    /**
+     * Constructs a new [EMAIL PROTECTED] WriterOutputStream} that uses the 
default character encoding
+     * and with a default output buffer size of 1024 characters. The output 
buffer will only
+     * be flushed when it overflows or when [EMAIL PROTECTED] #flush()} or 
[EMAIL PROTECTED] #close()} is called.
+     * 
+     * @param writer the target [EMAIL PROTECTED] Writer}
+     */
+    public WriterOutputStream(Writer writer) {
+        this(writer, Charset.defaultCharset(), DEFAULT_BUFFER_SIZE, false);
+    }
+
+    /**
+     * Write bytes from the specified byte array to the stream.
+     * 
+     * @param b the byte array containing the bytes to write
+     * @param off the start offset in the byte array
+     * @param len the number of bytes to write
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public void write(byte[] b, int off, int len) throws IOException {
+        while (len > 0) {
+            int c = Math.min(len, decoderIn.remaining());
+            decoderIn.put(b, off, c);
+            processInput(false);
+            len -= c;
+            off += c;
+        }
+        if (writeImmediately) {
+            flushOutput();
+        }
+    }
+
+    /**
+     * Write bytes from the specified byte array to the stream.
+     * 
+     * @param b the byte array containing the bytes to write
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public void write(byte[] b) throws IOException {
+        write(b, 0, b.length);
+    }
+
+    /**
+     * Write a single byte to the stream.
+     * 
+     * @param b the byte to write
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public void write(int b) throws IOException {
+        write(new byte[] { (byte)b }, 0, 1);
+    }
+
+    /**
+     * Flush the stream. Any remaining content accumulated in the output buffer
+     * will be written to the underlying [EMAIL PROTECTED] Writer}. After that
+     * [EMAIL PROTECTED] Writer#flush()} will be called. 
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public void flush() throws IOException {
+        flushOutput();
+        writer.flush();
+    }
+
+    /**
+     * Close the stream. Any remaining content accumulated in the output buffer
+     * will be written to the underlying [EMAIL PROTECTED] Writer}. After that
+     * [EMAIL PROTECTED] Writer#close()} will be called. 
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public void close() throws IOException {
+        processInput(true);
+        flushOutput();
+        writer.close();
+    }
+
+    /**
+     * Decode the contents of the input ByteBuffer into a CharBuffer.
+     * 
+     * @param endOfInput indicates end of input
+     * @throws IOException if an I/O error occurs
+     */
+    private void processInput(boolean endOfInput) throws IOException {
+        // Prepare decoderIn for reading
+        decoderIn.flip();
+        CoderResult coderResult;
+        while (true) {
+            coderResult = decoder.decode(decoderIn, decoderOut, endOfInput);
+            if (coderResult.isOverflow()) {
+                flushOutput();
+            } else if (coderResult.isUnderflow()) {
+                break;
+            } else {
+                // The decoder is configured to replace malformed input and 
unmappable characters,
+                // so we should not get here.
+                throw new IOException("Unexpected coder result");
+            }
+        }
+        // Discard the bytes that have been read
+        decoderIn.compact();
+    }
+
+    /**
+     * Flush the output.
+     * 
+     * @throws IOException if an I/O error occurs
+     */
+    private void flushOutput() throws IOException {
+        if (decoderOut.position() > 0) {
+            writer.write(decoderOut.array(), 0, decoderOut.position());
+            decoderOut.rewind();
+        }
+    }
+}

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

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

Added: 
commons/proper/io/trunk/src/test/org/apache/commons/io/input/ReaderInputStreamTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/org/apache/commons/io/input/ReaderInputStreamTest.java?rev=723912&view=auto
==============================================================================
--- 
commons/proper/io/trunk/src/test/org/apache/commons/io/input/ReaderInputStreamTest.java
 (added)
+++ 
commons/proper/io/trunk/src/test/org/apache/commons/io/input/ReaderInputStreamTest.java
 Fri Dec  5 14:42:34 2008
@@ -0,0 +1,101 @@
+/*
+ * 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.input;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Random;
+
+import junit.framework.TestCase;
+
+public class ReaderInputStreamTest extends TestCase {
+    private static final String TEST_STRING = "\u00e0 peine arriv\u00e9s nous 
entr\u00e2mes dans sa chambre";
+    private static final String LARGE_TEST_STRING;
+    
+    static {
+        StringBuilder buffer = new StringBuilder();
+        for (int i=0; i<100; i++) {
+            buffer.append(TEST_STRING);
+        }
+        LARGE_TEST_STRING = buffer.toString();
+    }
+    
+    private Random random = new Random();
+    
+    private void testWithSingleByteRead(String testString, String charsetName) 
throws IOException {
+        byte[] bytes = testString.getBytes(charsetName);
+        ReaderInputStream in = new ReaderInputStream(new 
StringReader(testString), charsetName);
+        for (int i=0; i<bytes.length; i++) {
+            int read = in.read();
+            assertTrue(read >= 0);
+            assertTrue(read <= 255);
+            assertEquals(bytes[i], (byte)read);
+        }
+        assertEquals(-1, in.read());
+    }
+    
+    private void testWithBufferedRead(String testString, String charsetName) 
throws IOException {
+        byte[] expected = testString.getBytes(charsetName);
+        ReaderInputStream in = new ReaderInputStream(new 
StringReader(testString), charsetName);
+        byte[] buffer = new byte[128];
+        int offset = 0;
+        while (true) {
+            int bufferOffset = random.nextInt(64);
+            int bufferLength = random.nextInt(64);
+            int read = in.read(buffer, bufferOffset, bufferLength);
+            if (read == -1) {
+                assertEquals(offset, expected.length);
+                break;
+            } else {
+                assertTrue(read <= bufferLength);
+                while (read > 0) {
+                    assertTrue(offset < expected.length);
+                    assertEquals(expected[offset], buffer[bufferOffset]);
+                    offset++;
+                    bufferOffset++;
+                    read--;
+                }
+            }
+        }
+    }
+    
+    public void testUTF8WithSingleByteRead() throws IOException {
+        testWithSingleByteRead(TEST_STRING, "UTF-8");
+    }
+    
+    public void testLargeUTF8WithSingleByteRead() throws IOException {
+        testWithSingleByteRead(LARGE_TEST_STRING, "UTF-8");
+    }
+    
+    public void testUTF8WithBufferedRead() throws IOException {
+        testWithBufferedRead(TEST_STRING, "UTF-8");
+    }
+    
+    public void testLargeUTF8WithBufferedRead() throws IOException {
+        testWithBufferedRead(LARGE_TEST_STRING, "UTF-8");
+    }
+    
+    public void testUTF16WithSingleByteRead() throws IOException {
+        testWithSingleByteRead(TEST_STRING, "UTF-16");
+    }
+    
+    public void testReadZero() throws Exception {
+        ReaderInputStream r = new ReaderInputStream(new StringReader("test"));
+        byte[] bytes = new byte[30];
+        assertEquals(0, r.read(bytes, 0, 0));
+    }
+}

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

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

Added: 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/WriterOutputStreamTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/org/apache/commons/io/output/WriterOutputStreamTest.java?rev=723912&view=auto
==============================================================================
--- 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/WriterOutputStreamTest.java
 (added)
+++ 
commons/proper/io/trunk/src/test/org/apache/commons/io/output/WriterOutputStreamTest.java
 Fri Dec  5 14:42:34 2008
@@ -0,0 +1,99 @@
+/*
+ * 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.output;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Random;
+
+import junit.framework.TestCase;
+
+public class WriterOutputStreamTest extends TestCase {
+    private static final String TEST_STRING = "\u00e0 peine arriv\u00e9s nous 
entr\u00e2mes dans sa chambre";
+    private static final String LARGE_TEST_STRING;
+    
+    static {
+        StringBuilder buffer = new StringBuilder();
+        for (int i=0; i<100; i++) {
+            buffer.append(TEST_STRING);
+        }
+        LARGE_TEST_STRING = buffer.toString();
+    }
+    
+    private Random random = new Random();
+    
+    private void testWithSingleByteWrite(String testString, String 
charsetName) throws IOException {
+        byte[] bytes = testString.getBytes(charsetName);
+        StringWriter writer = new StringWriter();
+        WriterOutputStream out = new WriterOutputStream(writer, charsetName);
+        for (int i=0; i<bytes.length; i++) {
+            out.write(bytes[i]);
+        }
+        out.close();
+        assertEquals(testString, writer.toString());
+    }
+    
+    private void testWithBufferedWrite(String testString, String charsetName) 
throws IOException {
+        byte[] expected = testString.getBytes(charsetName);
+        StringWriter writer = new StringWriter();
+        WriterOutputStream out = new WriterOutputStream(writer, charsetName);
+        int offset = 0;
+        while (offset < expected.length) {
+            int length = Math.min(random.nextInt(128), expected.length-offset);
+            out.write(expected, offset, length);
+            offset += length;
+        }
+        out.close();
+        assertEquals(testString, writer.toString());
+    }
+    
+    public void testUTF8WithSingleByteWrite() throws IOException {
+        testWithSingleByteWrite(TEST_STRING, "UTF-8");
+    }
+    
+    public void testLargeUTF8WithSingleByteWrite() throws IOException {
+        testWithSingleByteWrite(LARGE_TEST_STRING, "UTF-8");
+    }
+    
+    public void testUTF8WithBufferedWrite() throws IOException {
+        testWithBufferedWrite(TEST_STRING, "UTF-8");
+    }
+    
+    public void testLargeUTF8WithBufferedWrite() throws IOException {
+        testWithBufferedWrite(LARGE_TEST_STRING, "UTF-8");
+    }
+    
+    public void testUTF16WithSingleByteWrite() throws IOException {
+        testWithSingleByteWrite(TEST_STRING, "UTF-16");
+    }
+    
+    public void testFlush() throws IOException {
+        StringWriter writer = new StringWriter();
+        WriterOutputStream out = new WriterOutputStream(writer, "us-ascii", 
1024, false);
+        out.write("abc".getBytes("us-ascii"));
+        assertEquals(0, writer.getBuffer().length());
+        out.flush();
+        assertEquals("abc", writer.toString());
+    }
+    
+    public void testWriteImmediately() throws IOException {
+        StringWriter writer = new StringWriter();
+        WriterOutputStream out = new WriterOutputStream(writer, "us-ascii", 
1024, true);
+        out.write("abc".getBytes("us-ascii"));
+        assertEquals("abc", writer.toString());
+    }
+}

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

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


Reply via email to