/*
* 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.harmony.tests.java.io;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.CountDownLatch;
public class PipedInputStreamTest extends junit.framework.TestCase {
static class PWriter implements Runnable {
PipedOutputStream pos;
public byte bytes[];
public void run() {
try {
pos.write(bytes);
synchronized (this) {
notify();
}
} catch (IOException e) {
e.printStackTrace(System.out);
System.out.println("Could not write bytes");
}
}
public PWriter(PipedOutputStream pout, int nbytes) {
pos = pout;
bytes = new byte[nbytes];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) (System.currentTimeMillis() % 9);
}
}
}
Thread t;
PWriter pw;
PipedInputStream pis;
PipedOutputStream pos;
/**
* java.io.PipedInputStream#PipedInputStream()
*/
public void test_Constructor() {
// Test for method java.io.PipedInputStream()
// Used in tests
}
/**
* java.io.PipedInputStream#PipedInputStream(java.io.PipedOutputStream)
*/
public void test_ConstructorLjava_io_PipedOutputStream() throws Exception {
// Test for method java.io.PipedInputStream(java.io.PipedOutputStream)
pis = new PipedInputStream(new PipedOutputStream());
pis.available();
}
public void test_readException() throws IOException {
pis = new PipedInputStream();
pos = new PipedOutputStream();
try {
pis.connect(pos);
t = new Thread(pw = new PWriter(pos, 1000));
t.start();
while (true) {
pis.read();
t.interrupt();
}
} catch (IOException expected) {
} finally {
try {
pis.close();
pos.close();
} catch (IOException ee) {
}
}
}
/**
* java.io.PipedInputStream#available()
*/
public void test_available() throws Exception {
pis = new PipedInputStream();
pos = new PipedOutputStream();
pis.connect(pos);
t = new Thread(pw = new PWriter(pos, 1000));
t.start();
synchronized (pw) {
pw.wait(10000);
}
assertTrue("Available returned incorrect number of bytes: "
+ pis.available(), pis.available() == 1000);
PipedInputStream pin = new PipedInputStream();
PipedOutputStream pout = new PipedOutputStream(pin);
// We know the PipedInputStream buffer size is 1024.
// Writing another byte would cause the write to wait
// for a read before returning
for (int i = 0; i < 1024; i++) {
pout.write(i);
}
assertEquals("Incorrect available count", 1024, pin.available());
}
/**
* java.io.PipedInputStream#close()
*/
public void test_close() throws IOException {
// Test for method void java.io.PipedInputStream.close()
pis = new PipedInputStream();
pos = new PipedOutputStream();
pis.connect(pos);
pis.close();
try {
pos.write((byte) 127);
fail("Failed to throw expected exception");
} catch (IOException e) {
// The spec for PipedInput saya an exception should be thrown if
// a write is attempted to a closed input. The PipedOuput spec
// indicates that an exception should be thrown only when the
// piped input thread is terminated without closing
return;
}
}
/**
* java.io.PipedInputStream#connect(java.io.PipedOutputStream)
*/
public void test_connectLjava_io_PipedOutputStream() throws Exception {
pis = new PipedInputStream();
pos = new PipedOutputStream();
assertEquals("Non-conected pipe returned non-zero available bytes", 0,
pis.available());
pis.connect(pos);
t = new Thread(pw = new PWriter(pos, 1000));
t.start();
synchronized (pw) {
pw.wait(10000);
}
assertEquals("Available returned incorrect number of bytes", 1000, pis
.available());
}
/**
* java.io.PipedInputStream#read()
*/
public void test_read() throws Exception {
pis = new PipedInputStream();
pos = new PipedOutputStream();
pis.connect(pos);
t = new Thread(pw = new PWriter(pos, 1000));
t.start();
synchronized (pw) {
pw.wait(10000);
}
assertEquals("Available returned incorrect number of bytes", 1000, pis
.available());
assertEquals("read returned incorrect byte", pw.bytes[0], (byte) pis
.read());
}
/**
* java.io.PipedInputStream#read(byte[], int, int)
*/
public void test_read$BII() throws Exception {
pis = new PipedInputStream();
pos = new PipedOutputStream();
pis.connect(pos);
t = new Thread(pw = new PWriter(pos, 1000));
t.start();
byte[] buf = new byte[400];
synchronized (pw) {
pw.wait(10000);
}
assertTrue("Available returned incorrect number of bytes: "
+ pis.available(), pis.available() == 1000);
pis.read(buf, 0, 400);
for (int i = 0; i < 400; i++) {
assertEquals("read returned incorrect byte[]", pw.bytes[i], buf[i]);
}
}
/**
* java.io.PipedInputStream#read(byte[], int, int)
* Regression for HARMONY-387
*/
public void test_read$BII_2() throws IOException {
PipedInputStream obj = new PipedInputStream();
try {
obj.read(new byte[0], 0, -1);
fail();
} catch (IndexOutOfBoundsException expected) {
}
}
/**
* java.io.PipedInputStream#read(byte[], int, int)
*/
public void test_read$BII_3() throws IOException {
PipedInputStream obj = new PipedInputStream();
try {
obj.read(new byte[0], -1, 0);
fail();
} catch (IndexOutOfBoundsException expected) {
}
}
/**
* java.io.PipedInputStream#read(byte[], int, int)
*/
public void test_read$BII_4() throws IOException {
PipedInputStream obj = new PipedInputStream();
try {
obj.read(new byte[0], -1, -1);
fail();
} catch (IndexOutOfBoundsException expected) {
}
}
/**
* java.io.PipedInputStream#receive(int)
*/
public void test_write_failsAfterReaderDead() throws Exception {
pis = new PipedInputStream();
pos = new PipedOutputStream();
// test if writer recognizes dead reader
pis.connect(pos);
class WriteRunnable implements Runnable {
final CountDownLatch readerAlive = new CountDownLatch(1);
public void run() {
try {
pos.write(1);
try {
readerAlive.await();
} catch (InterruptedException ie) {
fail();
return;
}
try {
// should throw exception since reader thread
// is now dead
pos.write(1);
fail();
} catch (IOException expected) {
}
} catch (IOException e) {
}
}
}
class ReadRunnable implements Runnable {
public void run() {
try {
pis.read();
} catch (IOException e) {
fail();
}
}
}
WriteRunnable writeRunnable = new WriteRunnable();
Thread writeThread = new Thread(writeRunnable);
ReadRunnable readRunnable = new ReadRunnable();
Thread readThread = new Thread(readRunnable);
writeThread.start();
readThread.start();
readThread.join();
writeRunnable.readerAlive.countDown();
writeThread.join();
}
static final class PipedInputStreamWithPublicReceive extends PipedInputStream {
@Override
public void receive(int oneByte) throws IOException {
super.receive(oneByte);
}
}
public void test_receive_failsIfWriterClosed() throws Exception {
// attempt to write to stream after writer closed
PipedInputStreamWithPublicReceive pis = new PipedInputStreamWithPublicReceive();
pos = new PipedOutputStream();
pos.connect(pis);
pos.close();
try {
pis.receive(1);
fail();
} catch (IOException expected) {
}
}
static class Worker extends Thread {
PipedOutputStream out;
Worker(PipedOutputStream pos) {
this.out = pos;
}
public void run() {
try {
out.write(20);
out.close();
Thread.sleep(5000);
} catch (Exception e) {
}
}
}
public void test_read_after_write_close() throws Exception {
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out);
Thread worker = new Worker(out);
worker.start();
Thread.sleep(2000);
assertEquals("Should read 20.", 20, in.read());
worker.join();
assertEquals("Write end is closed, should return -1", -1, in.read());
byte[] buf = new byte[1];
assertEquals("Write end is closed, should return -1", -1, in.read(buf, 0, 1));
assertEquals("Buf len 0 should return first", 0, in.read(buf, 0, 0));
in.close();
out.close();
}
/**
* Tears down the fixture, for example, close a network connection. This
* method is called after a test is executed.
*/
protected void tearDown() throws Exception {
try {
if (t != null) {
t.interrupt();
}
} catch (Exception ignore) {
}
super.tearDown();
}
/**
* java.io.PipedInputStream#PipedInputStream(java.io.PipedOutputStream,
*int)
* @since 1.6
*/
public void test_Constructor_LPipedOutputStream_I() throws Exception {
// Test for method java.io.PipedInputStream(java.io.PipedOutputStream,
// int)
MockPipedInputStream mpis = new MockPipedInputStream(
new PipedOutputStream(), 100);
int bufferLength = mpis.bufferLength();
assertEquals(100, bufferLength);
try {
pis = new PipedInputStream(null, -1);
fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
} catch (IllegalArgumentException e) {
// expected
}
try {
pis = new PipedInputStream(null, 0);
fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
} catch (IllegalArgumentException e) {
// expected
}
}
/**
* java.io.PipedInputStream#PipedInputStream(int)
* @since 1.6
*/
public void test_Constructor_I() throws Exception {
// Test for method java.io.PipedInputStream(int)
MockPipedInputStream mpis = new MockPipedInputStream(100);
int bufferLength = mpis.bufferLength();
assertEquals(100, bufferLength);
try {
pis = new PipedInputStream(-1);
fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
} catch (IllegalArgumentException e) {
// expected
}
try {
pis = new PipedInputStream(0);
fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
} catch (IllegalArgumentException e) {
// expected
}
}
static class MockPipedInputStream extends PipedInputStream {
public MockPipedInputStream(java.io.PipedOutputStream src,
int bufferSize) throws IOException {
super(src, bufferSize);
}
public MockPipedInputStream(int bufferSize) {
super(bufferSize);
}
public int bufferLength() {
return super.buffer.length;
}
}
}