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 */ 17 18 package tests.api.java.io; 19 20 import java.io.ByteArrayInputStream; 21 import java.io.ByteArrayOutputStream; 22 import java.io.EOFException; 23 import java.io.IOException; 24 import java.io.InputStream; 25 import java.io.ObjectInputStream; 26 import java.io.ObjectOutputStream; 27 import java.io.ObjectStreamClass; 28 import java.io.OutputStream; 29 import java.io.Serializable; 30 import java.io.StreamCorruptedException; 31 import java.util.Arrays; 32 import java.util.Hashtable; 33 import java.util.Vector; 34 import org.apache.harmony.testframework.serialization.SerializationTest; 35 import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert; 36 import tests.support.Support_ASimpleInputStream; 37 38 public class ObjectInputStreamTest extends junit.framework.TestCase implements 39 Serializable { 40 41 static final long serialVersionUID = 1L; 42 43 ObjectInputStream ois; 44 45 ObjectOutputStream oos; 46 47 ByteArrayOutputStream bao; 48 49 boolean readStreamHeaderCalled; 50 51 private final String testString = "Lorem ipsum..."; 52 53 private final int testLength = testString.length(); 54 55 public void test_ConstructorLjava_io_InputStream_IOException() throws IOException { 56 oos.writeObject(testString); 57 oos.close(); 58 59 Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray()); 60 sis.throwExceptionOnNextUse = true; 61 try { 62 ois = new ObjectInputStream(sis); 63 fail("Test 1: IOException expected."); 64 } catch (IOException e) { 65 // Expected. 66 } 67 sis.throwExceptionOnNextUse = false; 68 } 69 70 public void test_ClassDescriptor() throws IOException, 71 ClassNotFoundException { 72 73 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 74 ObjectOutputStreamWithWriteDesc oos = new ObjectOutputStreamWithWriteDesc( 75 baos); 76 oos.writeObject(String.class); 77 oos.close(); 78 Class<?> cls = TestClassForSerialization.class; 79 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 80 ObjectInputStreamWithReadDesc ois = new ObjectInputStreamWithReadDesc( 81 bais, cls); 82 Object obj = ois.readObject(); 83 ois.close(); 84 assertEquals(cls, obj); 85 } 86 87 public void test_available() throws IOException { 88 // Test for method int java.io.ObjectInputStream.available() 89 oos.writeBytes(testString); 90 oos.close(); 91 92 Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray()); 93 ois = new ObjectInputStream(sis); 94 assertEquals("Test 1: Incorrect number of bytes;", testLength, ois.available()); 95 ois.close(); 96 } 97 98 public void test_available_IOException() throws IOException { 99 oos.writeObject(testString); 100 oos.close(); 101 102 Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray()); 103 ois = new ObjectInputStream(sis); 104 sis.throwExceptionOnNextUse = true; 105 try { 106 ois.available(); 107 fail("Test 1: IOException expected."); 108 } catch (IOException e) { 109 // Expected. 110 } 111 sis.throwExceptionOnNextUse = false; 112 ois.close(); 113 } 114 115 public void test_close() throws Exception { 116 // Test for method void java.io.ObjectInputStream.close() 117 oos.writeObject(testString); 118 oos.close(); 119 120 Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray()); 121 ois = new ObjectInputStream(sis); 122 sis.throwExceptionOnNextUse = true; 123 try { 124 ois.close(); 125 fail("Test 1: IOException expected."); 126 } catch (IOException e) { 127 // Expected. 128 } 129 sis.throwExceptionOnNextUse = false; 130 ois.close(); 131 } 132 133 public void test_enableResolveObjectB() throws IOException { 134 // Start testing without a SecurityManager. 135 BasicObjectInputStream bois = new BasicObjectInputStream(); 136 assertFalse("Test 1: Object resolving must be disabled by default.", 137 bois.enableResolveObject(true)); 138 139 assertTrue("Test 2: enableResolveObject did not return the previous value.", 140 bois.enableResolveObject(false)); 141 } 142 143 public void test_read_IOException() throws IOException { 144 oos.writeObject(testString); 145 oos.close(); 146 147 Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray()); 148 ois = new ObjectInputStream(sis); 149 sis.throwExceptionOnNextUse = true; 150 try { 151 ois.read(); 152 fail("Test 1: IOException expected."); 153 } catch (IOException e) { 154 // Expected. 155 } 156 sis.throwExceptionOnNextUse = false; 157 ois.close(); 158 } 159 160 public void test_read$BII() throws IOException { 161 // Test for method int java.io.ObjectInputStream.read(byte [], int, int) 162 byte[] buf = new byte[testLength]; 163 oos.writeBytes(testString); 164 oos.close(); 165 ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray())); 166 ois.read(buf, 0, testLength); 167 ois.close(); 168 assertEquals("Read incorrect bytes", testString, new String(buf)); 169 } 170 171 public void test_read$BII_Exception() throws IOException { 172 byte[] buf = new byte[testLength]; 173 oos.writeObject(testString); 174 oos.close(); 175 176 ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray())); 177 try { 178 ois.read(buf, 0, -1); 179 fail("IndexOutOfBoundsException was not thrown."); 180 } catch (IndexOutOfBoundsException e) { 181 // Expected 182 } 183 try { 184 ois.read(buf, -1,1); 185 fail("IndexOutOfBoundsException was not thrown."); 186 } catch (IndexOutOfBoundsException e) { 187 // Expected 188 } 189 try { 190 ois.read(buf, testLength, 1); 191 fail("IndexOutOfBoundsException was not thrown."); 192 } catch (IndexOutOfBoundsException e) { 193 // Expected 194 } 195 ois.close(); 196 197 198 Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray()); 199 ois = new ObjectInputStream(sis); 200 sis.throwExceptionOnNextUse = true; 201 try { 202 ois.read(buf, 0, testLength); 203 fail("Test 1: IOException expected."); 204 } catch (IOException e) { 205 // Expected. 206 } 207 sis.throwExceptionOnNextUse = false; 208 ois.close(); 209 } 210 211 public void test_readFully$B() throws IOException { 212 byte[] buf = new byte[testLength]; 213 oos.writeBytes(testString); 214 oos.close(); 215 ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray())); 216 ois.readFully(buf); 217 assertEquals("Test 1: Incorrect bytes read;", 218 testString, new String(buf)); 219 ois.close(); 220 221 ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray())); 222 ois.read(); 223 try { 224 ois.readFully(buf); 225 fail("Test 2: EOFException expected."); 226 } catch (EOFException e) { 227 // Expected. 228 } 229 } 230 231 public void test_readFully$B_Exception() throws IOException { 232 byte[] buf = new byte[testLength]; 233 oos.writeObject(testString); 234 oos.close(); 235 236 Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray()); 237 ois = new ObjectInputStream(sis); 238 sis.throwExceptionOnNextUse = true; 239 try { 240 ois.readFully(buf); 241 fail("Test 1: IOException expected."); 242 } catch (IOException e) { 243 // Expected. 244 } 245 sis.throwExceptionOnNextUse = false; 246 ois.close(); 247 } 248 249 public void test_readFully$BII() throws IOException { 250 // Test for method void java.io.ObjectInputStream.readFully(byte [], 251 // int, int) 252 byte[] buf = new byte[testLength]; 253 oos.writeBytes(testString); 254 oos.close(); 255 ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray())); 256 ois.readFully(buf, 0, testLength); 257 assertEquals("Read incorrect bytes", testString, new String(buf)); 258 ois.close(); 259 260 ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray())); 261 ois.read(); 262 try { 263 ois.readFully(buf); 264 fail("Test 2: EOFException expected."); 265 } catch (EOFException e) { 266 // Expected. 267 } 268 } 269 270 public void test_readFully$BII_Exception() throws IOException { 271 byte[] buf = new byte[testLength]; 272 oos.writeObject(testString); 273 oos.close(); 274 275 ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray())); 276 try { 277 ois.readFully(buf, 0, -1); 278 fail("IndexOutOfBoundsException was not thrown."); 279 } catch (IndexOutOfBoundsException e) { 280 // Expected 281 } 282 try { 283 ois.readFully(buf, -1,1); 284 fail("IndexOutOfBoundsException was not thrown."); 285 } catch (IndexOutOfBoundsException e) { 286 // Expected 287 } 288 try { 289 ois.readFully(buf, testLength, 1); 290 fail("IndexOutOfBoundsException was not thrown."); 291 } catch (IndexOutOfBoundsException e) { 292 // Expected 293 } 294 ois.close(); 295 296 Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray()); 297 ois = new ObjectInputStream(sis); 298 sis.throwExceptionOnNextUse = true; 299 try { 300 ois.readFully(buf, 0, 1); 301 fail("Test 1: IOException expected."); 302 } catch (IOException e) { 303 // Expected. 304 } 305 sis.throwExceptionOnNextUse = false; 306 ois.close(); 307 } 308 309 @SuppressWarnings("deprecation") 310 public void test_readLine() throws IOException { 311 String line; 312 oos.writeBytes("Lorem\nipsum\rdolor sit amet..."); 313 oos.close(); 314 315 ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray())); 316 line = ois.readLine(); 317 assertTrue("Test 1: Incorrect line written or read: " + line, 318 line.equals("Lorem")); 319 line = ois.readLine(); 320 assertTrue("Test 2: Incorrect line written or read: " + line, 321 line.equals("ipsum")); 322 line = ois.readLine(); 323 assertTrue("Test 3: Incorrect line written or read: " + line, 324 line.equals("dolor sit amet...")); 325 ois.close(); 326 } 327 328 public void test_readLine_IOException() throws IOException { 329 oos.writeObject(testString); 330 oos.close(); 331 332 Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray()); 333 ois = new ObjectInputStream(sis); 334 sis.throwExceptionOnNextUse = true; 335 try { 336 ois.readLine(); 337 fail("Test 1: IOException expected."); 338 } catch (IOException e) { 339 // Expected. 340 } 341 sis.throwExceptionOnNextUse = false; 342 ois.close(); 343 } 344 345 private void fillStreamHeader(byte[] buffer) { 346 short magic = java.io.ObjectStreamConstants.STREAM_MAGIC; 347 short version = java.io.ObjectStreamConstants.STREAM_VERSION; 348 349 if (buffer.length < 4) { 350 throw new IllegalArgumentException("The buffer's minimal length must be 4."); 351 } 352 353 // Initialize the buffer with the correct header for object streams 354 buffer[0] = (byte) (magic >> 8); 355 buffer[1] = (byte) magic; 356 buffer[2] = (byte) (version >> 8); 357 buffer[3] = (byte) (version); 358 } 359 360 public void test_readObjectOverride() throws Exception { 361 byte[] buffer = new byte[4]; 362 363 // Initialize the buffer with the correct header for object streams 364 fillStreamHeader(buffer); 365 366 // Test 1: Check that readObjectOverride() returns null if there 367 // is no input stream. 368 BasicObjectInputStream bois = new BasicObjectInputStream(); 369 assertNull("Test 1:", bois.readObjectOverride()); 370 371 // Test 2: Check that readObjectOverride() throws an IOException 372 // if there is an input stream. 373 bois = new BasicObjectInputStream(new ByteArrayInputStream(buffer)); 374 try { 375 bois.readObjectOverride(); 376 fail("Test 2: IOException expected."); 377 } catch (IOException e) {} 378 379 bois.close(); 380 } 381 382 public void test_readObjectMissingClasses() throws Exception { 383 SerializationTest.verifySelf(new A1(), new SerializableAssert() { 384 public void assertDeserialized(Serializable initial, 385 Serializable deserialized) { 386 assertEquals(5, ((A1) deserialized).b1.i); 387 } 388 }); 389 } 390 391 public void test_readObjectCorrupt() { 392 byte[] bytes = { 00, 00, 00, 0x64, 0x43, 0x48, (byte) 0xFD, 0x71, 00, 393 00, 0x0B, (byte) 0xB8, 0x4D, 0x65 }; 394 ByteArrayInputStream bin = new ByteArrayInputStream(bytes); 395 boolean exception = false; 396 try { 397 ObjectInputStream in = new ObjectInputStream(bin); 398 in.readObject(); 399 fail("Unexpected read of corrupted stream"); 400 } catch (StreamCorruptedException e) { 401 exception = true; 402 } catch (IOException e) { 403 fail("Unexpected: " + e); 404 } catch (ClassNotFoundException e) { 405 fail("Unexpected: " + e); 406 } 407 assertTrue("Expected StreamCorruptedException", exception); 408 } 409 410 public void test_readStreamHeader() throws IOException { 411 String testString = "Lorem ipsum"; 412 BasicObjectInputStream bois; 413 short magic = java.io.ObjectStreamConstants.STREAM_MAGIC; 414 short version = java.io.ObjectStreamConstants.STREAM_VERSION; 415 byte[] buffer = new byte[20]; 416 417 // Initialize the buffer with the correct header for object streams 418 fillStreamHeader(buffer); 419 System.arraycopy(testString.getBytes(), 0, buffer, 4, testString.length()); 420 421 // Test 1: readStreamHeader should not throw a StreamCorruptedException. 422 // It should get called by the ObjectInputStream constructor. 423 try { 424 readStreamHeaderCalled = false; 425 bois = new BasicObjectInputStream(new ByteArrayInputStream(buffer)); 426 bois.close(); 427 } catch (StreamCorruptedException e) { 428 fail("Test 1: Unexpected StreamCorruptedException."); 429 } 430 assertTrue("Test 1: readStreamHeader() has not been called.", 431 readStreamHeaderCalled); 432 433 // Test 2: Make the stream magic number invalid and check that 434 // readStreamHeader() throws an exception. 435 buffer[0] = (byte)magic; 436 buffer[1] = (byte)(magic >> 8); 437 try { 438 readStreamHeaderCalled = false; 439 bois = new BasicObjectInputStream(new ByteArrayInputStream(buffer)); 440 fail("Test 2: StreamCorruptedException expected."); 441 bois.close(); 442 } catch (StreamCorruptedException e) { 443 } 444 assertTrue("Test 2: readStreamHeader() has not been called.", 445 readStreamHeaderCalled); 446 447 // Test 3: Make the stream version invalid and check that 448 // readStreamHeader() throws an exception. 449 buffer[0] = (byte)(magic >> 8); 450 buffer[1] = (byte)magic; 451 buffer[2] = (byte)(version); 452 buffer[3] = (byte)(version >> 8); 453 try { 454 readStreamHeaderCalled = false; 455 bois = new BasicObjectInputStream(new ByteArrayInputStream(buffer)); 456 fail("Test 3: StreamCorruptedException expected."); 457 bois.close(); 458 } catch (StreamCorruptedException e) { 459 } 460 assertTrue("Test 3: readStreamHeader() has not been called.", 461 readStreamHeaderCalled); 462 } 463 464 public void test_readUnsignedByte() throws IOException { 465 oos.writeByte(-1); 466 oos.close(); 467 468 ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray())); 469 assertEquals("Test 1: Incorrect unsigned byte written or read.", 470 255, ois.readUnsignedByte()); 471 472 try { 473 ois.readUnsignedByte(); 474 fail("Test 2: EOFException expected."); 475 } catch (EOFException e) { 476 // Expected. 477 } 478 479 ois.close(); 480 try { 481 ois.readUnsignedByte(); 482 fail("Test 3: IOException expected."); 483 } catch (IOException e) { 484 // Expected. 485 } 486 } 487 488 public void test_readUnsignedShort() throws IOException { 489 // Test for method int java.io.ObjectInputStream.readUnsignedShort() 490 oos.writeShort(-1); 491 oos.close(); 492 493 ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray())); 494 assertEquals("Test 1: Incorrect unsigned short written or read.", 495 65535, ois.readUnsignedShort()); 496 497 try { 498 ois.readUnsignedShort(); 499 fail("Test 2: EOFException expected."); 500 } catch (EOFException e) { 501 // Expected. 502 } 503 504 ois.close(); 505 try { 506 ois.readUnsignedShort(); 507 fail("Test 3: IOException expected."); 508 } catch (IOException e) { 509 // Expected. 510 } 511 } 512 513 public void test_resolveProxyClass() throws IOException { 514 BasicObjectInputStream bois; 515 byte[] buffer = new byte[10]; 516 517 // Initialize the buffer with the header for object streams 518 fillStreamHeader(buffer); 519 bois = new BasicObjectInputStream(new ByteArrayInputStream(buffer)); 520 521 // Test 1: Check that a NullPointerException is thrown 522 // if null is passed to the method. 523 try { 524 bois.resolveProxyClass(null); 525 fail("Test 1: NullPointerException expected."); 526 } 527 catch (NullPointerException npe) { 528 } 529 catch (ClassNotFoundException cnfe) { 530 fail("Test 1: Unexpected ClassNotFoundException."); 531 } 532 533 // Test 2: Check that visible interfaces are found. 534 try { 535 String[] interfaces = { "java.io.Closeable", 536 "java.lang.Cloneable" }; 537 bois.resolveProxyClass(interfaces); 538 } 539 catch (ClassNotFoundException cnfe) { 540 fail("Test 2: Unexpected ClassNotFoundException."); 541 } 542 543 // Test 3: Check that a ClassNotFoundException is thrown if the 544 // array of interfaces is not valid. 545 try { 546 String[] interfaces = { "java.io.Closeable", 547 "java.io.Closeable" }; 548 bois.resolveProxyClass(interfaces); 549 fail ("Test 3: ClassNotFoundException expected."); 550 } 551 catch (ClassNotFoundException cnfe) { 552 } 553 554 bois.close(); 555 } 556 557 public void test_skipBytesI_IOException() throws IOException { 558 oos.writeObject(testString); 559 oos.close(); 560 561 Support_ASimpleInputStream sis = new Support_ASimpleInputStream(bao.toByteArray()); 562 ois = new ObjectInputStream(sis); 563 sis.throwExceptionOnNextUse = true; 564 try { 565 ois.skipBytes(5); 566 fail("Test 1: IOException expected."); 567 } catch (IOException e) { 568 // Expected. 569 } 570 sis.throwExceptionOnNextUse = false; 571 ois.close(); 572 } 573 574 public static class A implements Serializable { 575 576 private static final long serialVersionUID = 11L; 577 578 public String name = "name"; 579 } 580 581 public static class B extends A {} 582 583 public static class C extends B { 584 585 private static final long serialVersionUID = 33L; 586 } 587 588 public static class A1 implements Serializable { 589 590 static final long serialVersionUID = 5942584913446079661L; 591 592 B1 b1 = new B1(); 593 594 B1 b2 = b1; 595 596 Vector v = new Vector(); 597 } 598 599 public static class B1 implements Serializable { 600 601 int i = 5; 602 603 Hashtable h = new Hashtable(); 604 } 605 606 class BasicObjectInputStream extends ObjectInputStream { 607 public BasicObjectInputStream() throws IOException, SecurityException { 608 super(); 609 } 610 611 public BasicObjectInputStream(InputStream input) throws IOException { 612 super(input); 613 } 614 615 public boolean enableResolveObject(boolean enable) 616 throws SecurityException { 617 return super.enableResolveObject(enable); 618 } 619 620 public Object readObjectOverride() throws ClassNotFoundException, IOException { 621 return super.readObjectOverride(); 622 } 623 624 public void readStreamHeader() throws IOException { 625 readStreamHeaderCalled = true; 626 super.readStreamHeader(); 627 } 628 629 public Class<?> resolveProxyClass(String[] interfaceNames) 630 throws IOException, ClassNotFoundException { 631 return super.resolveProxyClass(interfaceNames); 632 } 633 } 634 635 //Regression Test for JIRA-2249 636 public static class ObjectOutputStreamWithWriteDesc extends 637 ObjectOutputStream { 638 public ObjectOutputStreamWithWriteDesc(OutputStream os) 639 throws IOException { 640 super(os); 641 } 642 643 public void writeClassDescriptor(ObjectStreamClass desc) 644 throws IOException { 645 } 646 } 647 648 public static class ObjectInputStreamWithReadDesc extends 649 ObjectInputStream { 650 private Class returnClass; 651 652 public ObjectInputStreamWithReadDesc(InputStream is, Class returnClass) 653 throws IOException { 654 super(is); 655 this.returnClass = returnClass; 656 } 657 658 public ObjectStreamClass readClassDescriptor() throws IOException, 659 ClassNotFoundException { 660 return ObjectStreamClass.lookup(returnClass); 661 662 } 663 } 664 665 static class TestClassForSerialization implements Serializable { 666 private static final long serialVersionUID = 1L; 667 } 668 669 protected void setUp() throws Exception { 670 super.setUp(); 671 oos = new ObjectOutputStream(bao = new ByteArrayOutputStream()); 672 } 673 } 674 675 class Test implements Serializable { 676 private static final long serialVersionUID = 1L; 677 678 Class<?> classes[] = new Class[] { byte.class, short.class, int.class, 679 long.class, boolean.class, char.class, float.class, double.class }; 680 681 public boolean equals(Object o) { 682 if (!(o instanceof Test)) { 683 return false; 684 } 685 return Arrays.equals(classes, ((Test) o).classes); 686 } 687 } 688