PipedInputStreamTest.java revision 561ee011997c6c2f1befbfaa9d5f0a99771c1d63
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17package org.apache.harmony.luni.tests.java.io;
18
19import java.io.IOException;
20import java.io.PipedInputStream;
21import java.io.PipedOutputStream;
22
23public class PipedInputStreamTest extends junit.framework.TestCase {
24
25	static class PWriter implements Runnable {
26		PipedOutputStream pos;
27
28		public byte bytes[];
29
30		public void run() {
31			try {
32				pos.write(bytes);
33				synchronized (this) {
34					notify();
35				}
36			} catch (IOException e) {
37				e.printStackTrace(System.out);
38				System.out.println("Could not write bytes");
39			}
40		}
41
42		public PWriter(PipedOutputStream pout, int nbytes) {
43			pos = pout;
44			bytes = new byte[nbytes];
45			for (int i = 0; i < bytes.length; i++) {
46				bytes[i] = (byte) (System.currentTimeMillis() % 9);
47		    }
48		}
49	}
50
51	Thread t;
52
53	PWriter pw;
54
55	PipedInputStream pis;
56
57	PipedOutputStream pos;
58
59	/**
60	 * @tests java.io.PipedInputStream#PipedInputStream()
61	 */
62	public void test_Constructor() {
63		// Test for method java.io.PipedInputStream()
64		// Used in tests
65	}
66
67	/**
68	 * @tests java.io.PipedInputStream#PipedInputStream(java.io.PipedOutputStream)
69	 */
70	public void test_ConstructorLjava_io_PipedOutputStream() throws Exception {
71        // Test for method java.io.PipedInputStream(java.io.PipedOutputStream)
72        pis = new PipedInputStream(new PipedOutputStream());
73        pis.available();
74    }
75
76
77    /**
78     * @test java.io.PipedInputStream#read()
79     */
80    public void test_readException() throws IOException {
81        pis = new PipedInputStream();
82        pos = new PipedOutputStream();
83
84        try {
85            pis.connect(pos);
86            t = new Thread(pw = new PWriter(pos, 1000));
87            t.start();
88            assertTrue(t.isAlive());
89            while (true) {
90                pis.read();
91                t.interrupt();
92            }
93        } catch (IOException e) {
94            if (!e.getMessage().contains("Write end dead")) {
95                throw e;
96            }
97        } finally {
98            try {
99                pis.close();
100                pos.close();
101            } catch (IOException ee) {}
102        }
103    }
104
105    /**
106     * @tests java.io.PipedInputStream#available()
107     */
108    public void test_available() throws Exception {
109        pis = new PipedInputStream();
110        pos = new PipedOutputStream();
111
112        pis.connect(pos);
113        t = new Thread(pw = new PWriter(pos, 1000));
114        t.start();
115
116        synchronized (pw) {
117            pw.wait(10000);
118        }
119        assertTrue("Available returned incorrect number of bytes: "
120                + pis.available(), pis.available() == 1000);
121
122        PipedInputStream pin = new PipedInputStream();
123        PipedOutputStream pout = new PipedOutputStream(pin);
124        // We know the PipedInputStream buffer size is 1024.
125        // Writing another byte would cause the write to wait
126        // for a read before returning
127        for (int i = 0; i < 1024; i++) {
128            pout.write(i);
129        }
130        assertEquals("Incorrect available count", 1024 , pin.available());
131    }
132
133	/**
134	 * @tests java.io.PipedInputStream#close()
135	 */
136	public void test_close() throws IOException {
137		// Test for method void java.io.PipedInputStream.close()
138		pis = new PipedInputStream();
139		pos = new PipedOutputStream();
140        pis.connect(pos);
141        pis.close();
142		try {
143			pos.write((byte) 127);
144            fail("Failed to throw expected exception");
145		} catch (IOException e) {
146			// The spec for PipedInput saya an exception should be thrown if
147			// a write is attempted to a closed input. The PipedOuput spec
148			// indicates that an exception should be thrown only when the
149			// piped input thread is terminated without closing
150			return;
151		}
152	}
153
154	/**
155	 * @tests java.io.PipedInputStream#connect(java.io.PipedOutputStream)
156	 */
157	public void test_connectLjava_io_PipedOutputStream() throws Exception {
158        pis = new PipedInputStream();
159        pos = new PipedOutputStream();
160        assertEquals("Non-conected pipe returned non-zero available bytes", 0,
161                pis.available());
162
163        pis.connect(pos);
164        t = new Thread(pw = new PWriter(pos, 1000));
165        t.start();
166
167        synchronized (pw) {
168            pw.wait(10000);
169        }
170        assertEquals("Available returned incorrect number of bytes", 1000, pis
171                .available());
172    }
173
174	/**
175	 * @tests java.io.PipedInputStream#read()
176	 */
177	public void test_read() throws Exception {
178        pis = new PipedInputStream();
179        pos = new PipedOutputStream();
180
181        pis.connect(pos);
182        t = new Thread(pw = new PWriter(pos, 1000));
183        t.start();
184
185        synchronized (pw) {
186            pw.wait(10000);
187        }
188        assertEquals("Available returned incorrect number of bytes", 1000, pis
189                .available());
190        assertEquals("read returned incorrect byte", pw.bytes[0], (byte) pis
191                .read());
192    }
193
194	/**
195	 * @tests java.io.PipedInputStream#read(byte[], int, int)
196	 */
197	public void test_read$BII() throws Exception {
198        pis = new PipedInputStream();
199        pos = new PipedOutputStream();
200
201        pis.connect(pos);
202        t = new Thread(pw = new PWriter(pos, 1000));
203        t.start();
204
205        byte[] buf = new byte[400];
206        synchronized (pw) {
207            pw.wait(10000);
208        }
209        assertTrue("Available returned incorrect number of bytes: "
210                + pis.available(), pis.available() == 1000);
211        pis.read(buf, 0, 400);
212        for (int i = 0; i < 400; i++) {
213            assertEquals("read returned incorrect byte[]", pw.bytes[i], buf[i]);
214        }
215    }
216
217    /**
218     * @tests java.io.PipedInputStream#read(byte[], int, int)
219     * Regression for HARMONY-387
220     */
221    public void test_read$BII_2() throws IOException {
222        PipedInputStream obj = new PipedInputStream();
223        try {
224            obj.read(new byte[0], 0, -1);
225            fail("IndexOutOfBoundsException expected");
226        } catch (IndexOutOfBoundsException t) {
227            assertEquals(
228                    "IndexOutOfBoundsException rather than a subclass expected",
229                    IndexOutOfBoundsException.class, t.getClass());
230        }
231    }
232
233    /**
234     * @tests java.io.PipedInputStream#read(byte[], int, int)
235     */
236    public void test_read$BII_3() throws IOException {
237        PipedInputStream obj = new PipedInputStream();
238        try {
239            obj.read(new byte[0], -1, 0);
240            fail("IndexOutOfBoundsException expected");
241        } catch (ArrayIndexOutOfBoundsException t) {
242            fail("IndexOutOfBoundsException expected");
243        } catch (IndexOutOfBoundsException t) {
244        }
245    }
246
247    /**
248     * @tests java.io.PipedInputStream#read(byte[], int, int)
249     */
250    public void test_read$BII_4() throws IOException {
251        PipedInputStream obj = new PipedInputStream();
252        try {
253            obj.read(new byte[0], -1, -1);
254            fail("IndexOutOfBoundsException expected");
255        } catch (ArrayIndexOutOfBoundsException t) {
256            fail("IndexOutOfBoundsException expected");
257        } catch (IndexOutOfBoundsException t) {
258        }
259    }
260
261    /**
262     * @tests java.io.PipedInputStream#receive(int)
263     */
264    public void test_receive() throws IOException {
265        pis = new PipedInputStream();
266        pos = new PipedOutputStream();
267
268        // test if writer recognizes dead reader
269        pis.connect(pos);
270        class WriteRunnable implements Runnable {
271
272            boolean pass = false;
273
274            volatile boolean readerAlive = true;
275
276            public void run() {
277                try {
278                    pos.write(1);
279                    while (readerAlive) {
280                        ;
281                    }
282                    try {
283                        // should throw exception since reader thread
284                        // is now dead
285                        pos.write(1);
286                    } catch (IOException e) {
287                        pass = true;
288                    }
289                } catch (IOException e) {
290                }
291            }
292        }
293        WriteRunnable writeRunnable = new WriteRunnable();
294        Thread writeThread = new Thread(writeRunnable);
295        class ReadRunnable implements Runnable {
296
297            boolean pass;
298
299            public void run() {
300                try {
301                    pis.read();
302                    pass = true;
303                } catch (IOException e) {
304                }
305            }
306        }
307        ;
308        ReadRunnable readRunnable = new ReadRunnable();
309        Thread readThread = new Thread(readRunnable);
310        writeThread.start();
311        readThread.start();
312        while (readThread.isAlive()) {
313            ;
314        }
315        writeRunnable.readerAlive = false;
316        assertTrue("reader thread failed to read", readRunnable.pass);
317        while (writeThread.isAlive()) {
318            ;
319        }
320        assertTrue("writer thread failed to recognize dead reader",
321                writeRunnable.pass);
322
323        // attempt to write to stream after writer closed
324        pis = new PipedInputStream();
325        pos = new PipedOutputStream();
326
327        pis.connect(pos);
328        class MyRunnable implements Runnable {
329
330            boolean pass;
331
332            public void run() {
333                try {
334                    pos.write(1);
335                } catch (IOException e) {
336                    pass = true;
337                }
338            }
339        }
340        MyRunnable myRun = new MyRunnable();
341        synchronized (pis) {
342            t = new Thread(myRun);
343            // thread t will be blocked inside pos.write(1)
344            // when it tries to call the synchronized method pis.receive
345            // because we hold the monitor for object pis
346            t.start();
347            try {
348                // wait for thread t to get to the call to pis.receive
349                Thread.sleep(100);
350            } catch (InterruptedException e) {
351            }
352            // now we close
353            pos.close();
354        }
355        // we have exited the synchronized block, so now thread t will make
356        // a call to pis.receive AFTER the output stream was closed,
357        // in which case an IOException should be thrown
358        while (t.isAlive()) {
359            ;
360        }
361        assertTrue(
362                "write failed to throw IOException on closed PipedOutputStream",
363                myRun.pass);
364    }
365
366    static class Worker extends Thread {
367        PipedOutputStream out;
368
369        Worker(PipedOutputStream pos) {
370            this.out = pos;
371        }
372
373        public void run() {
374            try {
375                out.write(20);
376                out.close();
377                Thread.sleep(5000);
378            } catch (Exception e) {
379            }
380        }
381    }
382
383    public void test_read_after_write_close() throws Exception{
384        PipedInputStream in = new PipedInputStream();
385        PipedOutputStream out = new PipedOutputStream();
386        in.connect(out);
387        Thread worker = new Worker(out);
388        worker.start();
389        Thread.sleep(2000);
390        assertEquals("Should read 20.", 20, in.read());
391        worker.join();
392        assertEquals("Write end is closed, should return -1", -1, in.read());
393        byte[] buf = new byte[1];
394        assertEquals("Write end is closed, should return -1", -1, in.read(buf, 0, 1));
395        assertEquals("Buf len 0 should return first", 0, in.read(buf, 0, 0));
396        in.close();
397        out.close();
398    }
399
400	/**
401	 * Tears down the fixture, for example, close a network connection. This
402	 * method is called after a test is executed.
403	 */
404	protected void tearDown() throws Exception {
405		try {
406			if (t != null) {
407				t.interrupt();
408            }
409		} catch (Exception ignore) {
410		}
411        super.tearDown();
412	}
413
414
415     /**
416     * @tests java.io.PipedInputStream#PipedInputStream(java.io.PipedOutputStream,
417     *        int)
418     * @since 1.6
419     */
420    public void test_Constructor_LPipedOutputStream_I() throws Exception {
421        // Test for method java.io.PipedInputStream(java.io.PipedOutputStream,
422        // int)
423        MockPipedInputStream mpis = new MockPipedInputStream(
424                new PipedOutputStream(), 100);
425        int bufferLength = mpis.bufferLength();
426        assertEquals(100, bufferLength);
427
428        try {
429            pis = new PipedInputStream(null, -1);
430            fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
431        } catch (IllegalArgumentException e) {
432            // expected
433        }
434
435        try {
436            pis = new PipedInputStream(null, 0);
437            fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
438        } catch (IllegalArgumentException e) {
439            // expected
440        }
441    }
442
443    /**
444     * @tests java.io.PipedInputStream#PipedInputStream(int)
445     * @since 1.6
446     */
447    public void test_Constructor_I() throws Exception {
448        // Test for method java.io.PipedInputStream(int)
449        MockPipedInputStream mpis = new MockPipedInputStream(100);
450        int bufferLength = mpis.bufferLength();
451        assertEquals(100, bufferLength);
452
453        try {
454            pis = new PipedInputStream(-1);
455            fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
456        } catch (IllegalArgumentException e) {
457            // expected
458        }
459
460        try {
461            pis = new PipedInputStream(0);
462            fail("Should throw IllegalArgumentException"); //$NON-NLS-1$
463        } catch (IllegalArgumentException e) {
464            // expected
465        }
466    }
467
468    static class MockPipedInputStream extends PipedInputStream {
469
470        public MockPipedInputStream(java.io.PipedOutputStream src,
471                int bufferSize) throws IOException {
472            super(src, bufferSize);
473        }
474
475        public MockPipedInputStream(int bufferSize) {
476            super(bufferSize);
477        }
478
479        public int bufferLength() {
480            return super.buffer.length;
481        }
482    }
483}
484