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