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
18package org.apache.harmony.luni.tests.java.io;
19
20import java.io.ByteArrayInputStream;
21import java.io.ByteArrayOutputStream;
22import java.io.DataInputStream;
23import java.io.FileInputStream;
24import java.io.FileOutputStream;
25import java.io.IOException;
26import java.io.InputStream;
27import java.io.InvalidObjectException;
28import java.io.NotActiveException;
29import java.io.ObjectInputStream;
30import java.io.ObjectOutputStream;
31import java.io.ObjectStreamClass;
32import java.io.ObjectStreamException;
33import java.io.Serializable;
34import java.io.StreamCorruptedException;
35import java.io.WriteAbortedException;
36import java.security.Permission;
37import java.security.PermissionCollection;
38import java.util.ArrayList;
39import java.util.Arrays;
40import java.util.Calendar;
41import java.util.GregorianCalendar;
42import java.util.HashMap;
43import java.util.HashSet;
44import java.util.Hashtable;
45import java.util.IdentityHashMap;
46import java.util.LinkedHashMap;
47import java.util.LinkedHashSet;
48import java.util.LinkedList;
49import java.util.List;
50import java.util.Map;
51import java.util.PropertyPermission;
52import java.util.Set;
53import java.util.SimpleTimeZone;
54import java.util.SortedMap;
55import java.util.SortedSet;
56import java.util.TimeZone;
57import java.util.TreeMap;
58import java.util.TreeSet;
59import java.util.Vector;
60import libcore.io.Streams;
61
62/**
63 * Automated Test Suite for class java.io.ObjectOutputStream
64 *
65 */
66@SuppressWarnings("serial")
67public class SerializationStressTest extends junit.framework.TestCase implements
68		Serializable {
69
70	// protected static final String MODE_XLOAD = "xload";
71
72	// protected static final String MODE_XDUMP = "xdump";
73
74	static final String FOO = "foo";
75
76	static final String MSG_TEST_FAILED = "Failed to write/read/assertion checking: ";
77
78	protected static final boolean DEBUG = false;
79
80	protected static boolean xload = false;
81
82	protected static boolean xdump = false;
83
84	protected static String xFileName = null;
85
86	protected transient int dumpCount = 0;
87
88	protected transient ObjectInputStream ois;
89
90	protected transient ObjectOutputStream oos;
91
92	protected transient ByteArrayOutputStream bao;
93
94	// -----------------------------------------------------------------------------------
95
96	private static class ObjectInputStreamSubclass extends ObjectInputStream {
97		private Vector<Class> resolvedClasses = new Vector<Class>();
98
99		public ObjectInputStreamSubclass(InputStream in) throws IOException,
100				StreamCorruptedException {
101			super(in);
102		}
103
104		public Class<?> resolveClass(ObjectStreamClass osClass)
105				throws IOException, ClassNotFoundException {
106			Class result = super.resolveClass(osClass);
107			resolvedClasses.addElement(result);
108			return result;
109		}
110
111		public Class[] resolvedClasses() {
112			return (Class[]) resolvedClasses.toArray(new Class[resolvedClasses
113					.size()]);
114		}
115	}
116	static final Map<String , String> TABLE = new Hashtable<String , String>();
117
118	static final Map<String , String> MAP = new HashMap<String , String>();
119
120	static final SortedMap<String , String> TREE = new TreeMap<String , String>();
121
122	static final LinkedHashMap<String , String> LINKEDMAP = new LinkedHashMap<String , String>();
123
124	static final LinkedHashSet<String> LINKEDSET = new LinkedHashSet<String>();
125
126	static final IdentityHashMap<String , String> IDENTITYMAP = new IdentityHashMap<String , String>();
127
128	static final List<String> ALIST = Arrays.asList(new String[] { "a", "list", "of",
129			"strings" });
130
131	static final List<String> LIST = new ArrayList<String>(ALIST);
132
133	static final Set<String> SET = new HashSet<String>(Arrays.asList(new String[] { "one",
134			"two", "three" }));
135
136	static final SortedSet<String> SORTSET = new TreeSet<String>(Arrays.asList(new String[] {
137			"one", "two", "three" }));
138
139	static final java.text.DateFormat DATEFORM = java.text.DateFormat
140			.getInstance();
141
142	static final java.text.ChoiceFormat CHOICE = new java.text.ChoiceFormat(
143			"1#one|2#two|3#three");
144
145	static final java.text.NumberFormat NUMBERFORM = java.text.NumberFormat
146			.getInstance();
147
148	static final java.text.MessageFormat MESSAGE = new java.text.MessageFormat(
149			"the time: {0,time} and date {0,date}");
150
151	static final LinkedList<String> LINKEDLIST = new LinkedList<String>(Arrays
152			.asList(new String[] { "a", "linked", "list", "of", "strings" }));
153
154	static final SimpleTimeZone TIME_ZONE = new SimpleTimeZone(3600000,
155			"S-TEST");
156
157	static final Calendar CALENDAR = new GregorianCalendar(TIME_ZONE);
158
159	static {
160		TABLE.put("one", "1");
161		TABLE.put("two", "2");
162		TABLE.put("three", "3");
163		MAP.put("one", "1");
164		MAP.put("two", "2");
165		MAP.put("three", "3");
166		LINKEDMAP.put("one", "1");
167		LINKEDMAP.put("two", "2");
168		LINKEDMAP.put("three", "3");
169		IDENTITYMAP.put("one", "1");
170		IDENTITYMAP.put("two", "2");
171		IDENTITYMAP.put("three", "3");
172		LINKEDSET.add("one");
173		LINKEDSET.add("two");
174		LINKEDSET.add("three");
175		TREE.put("one", "1");
176		TREE.put("two", "2");
177		TREE.put("three", "3");
178		// To make sure they all use the same Calendar
179		CALENDAR.setTimeZone(new SimpleTimeZone(0, "GMT"));
180		CALENDAR.set(1999, Calendar.JUNE, 23, 15, 47, 13);
181		CALENDAR.set(Calendar.MILLISECOND, 553);
182		DATEFORM.setCalendar(CALENDAR);
183		java.text.DateFormatSymbols symbols = new java.text.DateFormatSymbols();
184		symbols.setZoneStrings(new String[][] { { "a", "b", "c", "d", "e" },
185				{ "f", "g", "h", "i", "j" } });
186		((java.text.SimpleDateFormat) DATEFORM).setDateFormatSymbols(symbols);
187		DATEFORM.setNumberFormat(new java.text.DecimalFormat("#.#;'-'#.#"));
188		DATEFORM.setTimeZone(TimeZone.getTimeZone("EST"));
189		((java.text.DecimalFormat) NUMBERFORM).applyPattern("#.#;'-'#.#");
190		MESSAGE.setFormat(0, DATEFORM);
191		MESSAGE.setFormat(1, DATEFORM);
192	}
193
194	public SerializationStressTest() {
195	}
196
197	public SerializationStressTest(String name) {
198		super(name);
199	}
200
201	public String getDumpName() {
202		return getName() + dumpCount;
203	}
204
205	protected void dump(Object o) throws IOException, ClassNotFoundException {
206		if (dumpCount > 0)
207			setUp();
208		// Dump the object
209		try {
210			oos.writeObject(o);
211		} finally {
212			oos.close();
213		}
214	}
215
216	protected Object dumpAndReload(Object o) throws IOException,
217			ClassNotFoundException {
218		dump(o);
219		return reload();
220	}
221
222	protected InputStream loadStream() throws IOException {
223		// Choose the load stream
224		if (xload || xdump) {
225			// Load from pre-existing file
226			return new FileInputStream(xFileName + "-" + getDumpName() + ".ser");
227		} else {
228			// Just load from memory, we dumped to memory
229			return new ByteArrayInputStream(bao.toByteArray());
230		}
231	}
232
233	protected Object reload() throws IOException, ClassNotFoundException {
234		ois = new ObjectInputStream(loadStream());
235		dumpCount++;
236		try {
237			return ois.readObject();
238		} finally {
239			ois.close();
240		}
241	}
242
243	/**
244	 * Sets up the fixture, for example, open a network connection. This method
245	 * is called before a test is executed.
246	 */
247	protected void setUp() {
248		try {
249			if (xdump) {
250				oos = new ObjectOutputStream(new FileOutputStream(xFileName
251						+ "-" + getDumpName() + ".ser"));
252			} else {
253				oos = new ObjectOutputStream(bao = new ByteArrayOutputStream());
254			}
255		} catch (Exception e) {
256			fail("Exception thrown during setup : " + e.getMessage());
257		}
258	}
259
260	/**
261	 * Tears down the fixture, for example, close a network connection. This
262	 * method is called after a test is executed.
263	 */
264	protected void tearDown() {
265		if (oos != null) {
266			try {
267				oos.close();
268			} catch (Exception e) {
269			}
270		}
271	}
272
273	public void test_1_Constructor() throws Exception {
274		// Test for method java.io.ObjectOutputStream(java.io.OutputStream)
275                oos.close();
276                oos = new ObjectOutputStream(new ByteArrayOutputStream());
277                oos.close();
278	}
279
280	public void test_2_close() {
281		// Test for method void java.io.ObjectOutputStream.close()
282		try {
283			oos.close();
284			oos = new ObjectOutputStream(bao = new ByteArrayOutputStream());
285			oos.close();
286			oos.writeChar('T');
287			oos.writeObject(FOO);
288			// Writing to a closed stream does not cause problems. This is
289			// the expected behavior
290		} catch (IOException e) {
291			fail("Operation on closed stream threw IOException : "
292					+ e.getMessage());
293		}
294	}
295
296	public void test_3_defaultWriteObject() {
297		// Test for method void java.io.ObjectOutputStream.defaultWriteObject()
298
299		try {
300			oos.defaultWriteObject();
301		} catch (NotActiveException e) {
302			// Correct
303			return;
304		} catch (IOException e) {
305		}
306		fail(
307				"Failed to throw NotActiveException when invoked outside readObject");
308	}
309
310	public void test_4_flush() {
311		// Test for method void java.io.ObjectOutputStream.flush()
312		try {
313			oos.close();
314			oos = new ObjectOutputStream(bao = new ByteArrayOutputStream());
315			int size = bao.size();
316			oos.writeByte(127);
317			assertTrue("Data flushed already", bao.size() == size);
318			oos.flush();
319			assertTrue("Failed to flush data", bao.size() > size);
320			// we don't know how many bytes are actually written for 1 byte,
321			// so we test > <before>
322			oos.close();
323			oos = null;
324		} catch (IOException e) {
325			fail("IOException serializing data : " + e.getMessage());
326		}
327	}
328
329	public void test_5_reset() {
330		// Test for method void java.io.ObjectOutputStream.reset()
331		try {
332			String o = "HelloWorld";
333			oos.writeObject(o);
334			oos.writeObject(o);
335			oos.reset();
336			oos.writeObject(o);
337			ois = new ObjectInputStream(loadStream());
338			ois.close();
339		} catch (IOException e) {
340			fail("IOException serializing data : " + e.getMessage());
341		}
342	}
343
344	public void test_6_write() {
345		// Test for method void java.io.ObjectOutputStream.write(byte [], int,
346		// int)
347		try {
348			byte[] buf = new byte[255];
349			byte[] output = new byte[255];
350			for (int i = 0; i < output.length; i++)
351				output[i] = (byte) i;
352			oos.write(output, 0, output.length);
353			oos.close();
354			ois = new ObjectInputStream(loadStream());
355			ois.readFully(buf);
356			ois.close();
357			for (int i = 0; i < output.length; i++)
358				if (buf[i] != output[i])
359					fail("Read incorrect byte: " + i);
360		} catch (IOException e) {
361			fail("IOException serializing data : " + e.getMessage());
362		}
363	}
364
365	public void test_6a_write() {
366		// Test for method void java.io.ObjectOutputStream.write(byte [], int,
367		// int)
368		try {
369			byte[] buf = new byte[256];
370			byte[] output = new byte[256];
371			for (int i = 0; i < output.length; i++)
372				output[i] = (byte) (i & 0xff);
373			oos.write(output, 0, output.length);
374			oos.close();
375			ois = new ObjectInputStream(loadStream());
376			ois.readFully(buf);
377			ois.close();
378			for (int i = 0; i < output.length; i++)
379				if (buf[i] != output[i])
380					fail("Read incorrect byte: " + i);
381		} catch (IOException e) {
382			fail("IOException serializing data : " + e.getMessage());
383		}
384	}
385
386	public void test_7_write() {
387		// Test for method void java.io.ObjectOutputStream.write(int)
388		try {
389			oos.write('T');
390			oos.close();
391			ois = new ObjectInputStream(loadStream());
392			assertEquals("Read incorrect byte", 'T', ois.read());
393			ois.close();
394		} catch (IOException e) {
395			fail("IOException serializing data : " + e.getMessage());
396		}
397	}
398
399	public void test_8_write() {
400		// Test for method void java.io.ObjectOutputStream.write(byte [])
401		try {
402			byte[] buf = new byte[10];
403			oos.write("HelloWorld".getBytes());
404			oos.close();
405			ois = new ObjectInputStream(loadStream());
406			ois.read(buf, 0, 10);
407			ois.close();
408			assertEquals("Read incorrect bytes", "HelloWorld", new String(buf, 0, 10)
409					);
410		} catch (IOException e) {
411			fail("IOException serializing data : " + e.getMessage());
412		}
413	}
414
415	public void test_9_writeBoolean() {
416		// Test for method void java.io.ObjectOutputStream.writeBoolean(boolean)
417		try {
418			oos.writeBoolean(true);
419			oos.close();
420			ois = new ObjectInputStream(loadStream());
421			assertTrue("Wrote incorrect byte value", ois.readBoolean());
422		} catch (IOException e) {
423			fail("IOException serializing data : " + e.getMessage());
424		}
425	}
426
427	public void test_10_writeByte() {
428		// Test for method void java.io.ObjectOutputStream.writeByte(int)
429		try {
430			oos.writeByte(127);
431			oos.close();
432			ois = new ObjectInputStream(loadStream());
433			assertEquals("Wrote incorrect byte value", 127, ois.readByte());
434		} catch (IOException e) {
435			fail("IOException serializing data : " + e.getMessage());
436		}
437	}
438
439	public void test_11_writeBytes() {
440		// Test for method void
441		// java.io.ObjectOutputStream.writeBytes(java.lang.String)
442		try {
443			byte[] buf = new byte[10];
444			oos.writeBytes("HelloWorld");
445			oos.close();
446			ois = new ObjectInputStream(loadStream());
447			ois.readFully(buf);
448			ois.close();
449			assertEquals("Wrote incorrect bytes value", "HelloWorld", new String(buf, 0, 10, "UTF-8")
450					);
451		} catch (IOException e) {
452			fail("IOException serializing data : " + e.getMessage());
453		}
454	}
455
456	public void test_12_writeChar() {
457		// Test for method void java.io.ObjectOutputStream.writeChar(int)
458		try {
459			oos.writeChar('T');
460			oos.close();
461			ois = new ObjectInputStream(loadStream());
462			assertEquals("Wrote incorrect char value", 'T', ois.readChar());
463		} catch (IOException e) {
464			fail("IOException serializing data : " + e.getMessage());
465		}
466	}
467
468	public void test_13_writeChars() {
469		// Test for method void
470		// java.io.ObjectOutputStream.writeChars(java.lang.String)
471		try {
472			int avail = 0;
473			char[] buf = new char[10];
474			oos.writeChars("HelloWorld");
475			oos.close();
476			ois = new ObjectInputStream(loadStream());
477			// Number of prim data bytes in stream / 2 to give char index
478			avail = ois.available() / 2;
479			for (int i = 0; i < avail; ++i)
480				buf[i] = ois.readChar();
481			ois.close();
482			assertEquals("Wrote incorrect chars", "HelloWorld", new String(buf, 0, 10)
483					);
484		} catch (IOException e) {
485			fail("IOException serializing data : " + e.getMessage());
486		}
487	}
488
489	public void test_14_writeDouble() {
490		// Test for method void java.io.ObjectOutputStream.writeDouble(double)
491		try {
492			oos.writeDouble(Double.MAX_VALUE);
493			oos.close();
494			ois = new ObjectInputStream(loadStream());
495			assertTrue("Wrote incorrect double value",
496					ois.readDouble() == Double.MAX_VALUE);
497		} catch (IOException e) {
498			fail("IOException serializing data : " + e.getMessage());
499		}
500	}
501
502	public void test_15_writeFloat() {
503		// Test for method void java.io.ObjectOutputStream.writeFloat(float)
504		try {
505			oos.writeFloat(Float.MAX_VALUE);
506			oos.close();
507			ois = new ObjectInputStream(loadStream());
508			assertTrue("Wrote incorrect double value",
509					ois.readFloat() == Float.MAX_VALUE);
510			ois.close();
511			ois = null;
512		} catch (IOException e) {
513			fail("IOException serializing data : " + e.getMessage());
514		}
515	}
516
517	public void test_16_writeInt() {
518		// Test for method void java.io.ObjectOutputStream.writeInt(int)
519		try {
520			oos.writeInt(Integer.MAX_VALUE);
521			oos.close();
522			ois = new ObjectInputStream(loadStream());
523			assertTrue("Wrote incorrect double value",
524					ois.readInt() == Integer.MAX_VALUE);
525			ois.close();
526		} catch (IOException e) {
527			fail("IOException serializing data : " + e.getMessage());
528		}
529	}
530
531	public void test_17_writeLong() {
532		// Test for method void java.io.ObjectOutputStream.writeLong(long)
533		try {
534			oos.writeLong(Long.MAX_VALUE);
535			oos.close();
536			ois = new ObjectInputStream(loadStream());
537			assertTrue("Wrote incorrect double value",
538					ois.readLong() == Long.MAX_VALUE);
539		} catch (IOException e) {
540			fail("IOException serializing data : " + e.getMessage());
541		}
542	}
543
544	public void test_19_writeShort() {
545		// Test for method void java.io.ObjectOutputStream.writeShort(int)
546		try {
547			oos.writeShort(127);
548			oos.close();
549			ois = new ObjectInputStream(loadStream());
550			assertEquals("Wrote incorrect short value", 127, ois.readShort());
551		} catch (IOException e) {
552			fail("IOException serializing data : " + e.getMessage());
553		}
554	}
555
556	public void test_20_writeUTF() {
557		// Test for method void
558		// java.io.ObjectOutputStream.writeUTF(java.lang.String)
559		try {
560			oos.writeUTF("HelloWorld");
561			oos.close();
562			ois = new ObjectInputStream(loadStream());
563			assertEquals("Wrote incorrect UTF value",
564					"HelloWorld", ois.readUTF());
565		} catch (IOException e) {
566			fail("IOException serializing data : " + e.getMessage());
567		}
568	}
569
570	public void test_25_available() {
571		try {
572			oos.writeObject(FOO);
573			oos.writeObject(FOO);
574			oos.flush();
575			int available1 = 0;
576			int available2 = 0;
577			Object obj1 = null;
578			Object obj2 = null;
579			ObjectInputStream ois = new ObjectInputStream(loadStream());
580			available1 = ois.available();
581			obj1 = ois.readObject();
582			available2 = ois.available();
583			obj2 = ois.readObject();
584
585			assertEquals("available returned incorrect value", 0, available1);
586			assertEquals("available returned incorrect value", 0, available2);
587
588			assertTrue("available caused incorrect reading", FOO.equals(obj1));
589			assertTrue("available returned incorrect value", FOO.equals(obj2));
590
591		} catch (IOException e) {
592			fail("IOException serializing object : " + e.getMessage());
593		} catch (ClassNotFoundException e) {
594			fail("Unable to read Object type : " + e.toString());
595		} catch (Error err) {
596			System.out.println("Error " + err);
597			throw err;
598		}
599
600	}
601
602	protected void t_MixPrimitivesAndObjects() throws IOException,
603			ClassNotFoundException {
604		int i = 7;
605		String s1 = "string 1";
606		String s2 = "string 2";
607		byte[] bytes = { 1, 2, 3 };
608
609		oos.writeInt(i);
610		oos.writeObject(s1);
611		oos.writeUTF(s2);
612		oos.writeObject(bytes);
613		oos.close();
614		try {
615			ois = new ObjectInputStream(loadStream());
616
617			int j = ois.readInt();
618			assertTrue("Wrong int :" + j, i == j);
619
620			String l1 = (String) ois.readObject();
621			assertTrue("Wrong obj String :" + l1, s1.equals(l1));
622
623			String l2 = (String) ois.readUTF();
624			assertTrue("Wrong UTF String :" + l2, s2.equals(l2));
625
626			byte[] bytes2 = (byte[]) ois.readObject();
627			assertTrue("Wrong byte[]", Arrays.equals(bytes, bytes2));
628
629		} finally {
630			ois.close();
631		}
632	}
633
634	public void test_resolveClass() {
635		try {
636			oos.writeObject(new Object[] { Integer.class, new Integer(1) });
637			oos.close();
638
639			ois = new ObjectInputStreamSubclass(loadStream());
640			ois.readObject();
641			ois.close();
642		} catch (IOException e1) {
643			fail("IOException : " + e1.getMessage());
644		} catch (ClassNotFoundException e2) {
645			fail("ClassNotFoundException : " + e2.getMessage());
646		}
647
648		Class[] resolvedClasses = ((ObjectInputStreamSubclass) ois)
649				.resolvedClasses();
650		assertEquals("missing resolved", 3, resolvedClasses.length);
651		assertTrue("resolved class 1", resolvedClasses[0] == Object[].class);
652		assertTrue("resolved class 2", resolvedClasses[1] == Integer.class);
653		assertTrue("resolved class 3", resolvedClasses[2] == Number.class);
654	}
655
656    public void test_reset() throws IOException, ClassNotFoundException {
657        oos.reset();
658        oos.writeObject("R");
659        oos.reset();
660        oos.writeByte(24);
661        oos.close();
662
663        DataInputStream dis = new DataInputStream(loadStream());
664        byte[] input = Streams.readFully(dis);
665        byte[] result = new byte[] { (byte) 0xac, (byte) 0xed, (byte) 0,
666                (byte) 5, (byte) 0x79, (byte) 0x74, (byte) 0, (byte) 1,
667                (byte) 'R', (byte) 0x79, (byte) 0x77, (byte) 1, (byte) 24 };
668        assertTrue("incorrect output", Arrays.equals(input, result));
669
670        ois = new ObjectInputStreamSubclass(loadStream());
671        assertEquals("Wrong result from readObject()", "R", ois.readObject());
672        assertEquals("Wrong result from readByte()", 24, ois.readByte());
673        ois.close();
674    }
675
676	private static class ResolveObjectTest implements Serializable {
677		Object field1, field2;
678	}
679
680	private static class ResolveObjectInputStream extends ObjectInputStream {
681		ResolveObjectInputStream(InputStream in)
682				throws StreamCorruptedException, IOException {
683			super(in);
684		}
685
686		public void enableResolve() {
687			enableResolveObject(true);
688		}
689
690		public Object resolveObject(Object obj) {
691			if (obj instanceof Vector) // test_1_resolveObject()
692				return new Hashtable();
693			else if ("abc".equals(obj)) // test_2_resolveObject()
694				return "ABC";
695			else if (obj instanceof String) // test_3_resolveObject()
696				return String.valueOf(((String) obj).length());
697			else if (obj instanceof int[]) // test_4_resolveObject()
698				return new Object[1];
699			else if (obj instanceof Object[] && ((Object[]) obj).length == 2) // test_5_resolveObject()
700				return new char[1];
701			return obj;
702		}
703	}
704
705	public void test_1_resolveObject() {
706		try {
707			ResolveObjectTest obj = new ResolveObjectTest();
708			obj.field1 = new Vector();
709			obj.field2 = obj.field1;
710			oos.writeObject(obj);
711			oos.close();
712			ois = new ResolveObjectInputStream(loadStream());
713			((ResolveObjectInputStream) ois).enableResolve();
714			ResolveObjectTest result = null;
715			try {
716				result = (ResolveObjectTest) ois.readObject();
717			} catch (ClassNotFoundException e) {
718				fail(e.toString());
719			}
720			assertTrue("Object not resolved",
721					result.field1 instanceof Hashtable);
722			assertTrue("Second reference not resolved",
723					result.field1 == result.field2);
724		} catch (IOException e) {
725			fail("IOException serializing data : " + e.getMessage());
726		}
727	}
728
729	public void test_2_resolveObject() {
730		try {
731			ResolveObjectTest obj = new ResolveObjectTest();
732			obj.field1 = "abc";
733			obj.field2 = obj.field1;
734			oos.writeObject(obj);
735			oos.close();
736			ois = new ResolveObjectInputStream(loadStream());
737			((ResolveObjectInputStream) ois).enableResolve();
738			ResolveObjectTest result = null;
739			try {
740				result = (ResolveObjectTest) ois.readObject();
741			} catch (ClassNotFoundException e) {
742				fail(e.toString());
743			}
744			assertEquals("String not resolved", "ABC", result.field1);
745			assertTrue("Second reference not resolved",
746					result.field1 == result.field2);
747		} catch (IOException e) {
748			fail("IOException serializing data : " + e.getMessage());
749		}
750	}
751
752	public void test_3_resolveObject() {
753		try {
754			ResolveObjectTest obj = new ResolveObjectTest();
755			char[] lchars = new char[70000];
756			obj.field1 = new String(lchars);
757			obj.field2 = obj.field1;
758			oos.writeObject(obj);
759			oos.close();
760			ois = new ResolveObjectInputStream(loadStream());
761			((ResolveObjectInputStream) ois).enableResolve();
762			ResolveObjectTest result = null;
763			try {
764				result = (ResolveObjectTest) ois.readObject();
765			} catch (ClassNotFoundException e) {
766				fail(e.toString());
767			}
768			assertTrue("Long String not resolved", "70000"
769					.equals(result.field1));
770			assertTrue("Second reference not resolved",
771					result.field1 == result.field2);
772		} catch (IOException e) {
773			fail("IOException serializing data : " + e.getMessage());
774		}
775	}
776
777	public void test_4_resolveObject() {
778		try {
779			ResolveObjectTest obj = new ResolveObjectTest();
780			obj.field1 = new int[5];
781			obj.field2 = obj.field1;
782			oos.writeObject(obj);
783			oos.close();
784			ois = new ResolveObjectInputStream(loadStream());
785			((ResolveObjectInputStream) ois).enableResolve();
786			ResolveObjectTest result = null;
787			try {
788				result = (ResolveObjectTest) ois.readObject();
789			} catch (ClassNotFoundException e) {
790				fail(e.toString());
791			}
792			Class cl = new Object[0].getClass();
793			assertTrue("int[] not resolved", result.field1.getClass() == cl);
794			assertTrue("Second reference not resolved",
795					result.field1 == result.field2);
796		} catch (IOException e) {
797			fail("IOException serializing data : " + e.getMessage());
798		}
799	}
800
801	public void test_5_resolveObject() {
802		try {
803			ResolveObjectTest obj = new ResolveObjectTest();
804			obj.field1 = new Object[2];
805			obj.field2 = obj.field1;
806			oos.writeObject(obj);
807			oos.close();
808			ois = new ResolveObjectInputStream(loadStream());
809			((ResolveObjectInputStream) ois).enableResolve();
810			ResolveObjectTest result = null;
811			try {
812				result = (ResolveObjectTest) ois.readObject();
813			} catch (ClassNotFoundException e) {
814				fail(e.toString());
815			}
816			Class cl = new char[0].getClass();
817			assertTrue("int[] not resolved", result.field1.getClass() == cl);
818			assertTrue("Second reference not resolved",
819					result.field1 == result.field2);
820		} catch (IOException e) {
821			fail("IOException serializing data : " + e.getMessage());
822		}
823	}
824
825	static class WriteReplaceTestA implements Serializable {
826		public Object writeReplace() throws ObjectStreamException {
827			return new ReadResolveTestB();
828		}
829	}
830
831	static class WriteReplaceTestB extends WriteReplaceTestA {
832	}
833
834	static class WriteReplaceTestC extends WriteReplaceTestA {
835		public Object writeReplace() throws ObjectStreamException {
836			return new ReadResolveTestC();
837		}
838	}
839
840	static class WriteReplaceTestD implements Serializable {
841		private Object writeReplace() throws ObjectStreamException {
842			return new ReadResolveTestD();
843		}
844	}
845
846	static class WriteReplaceTestE extends WriteReplaceTestD {
847	}
848
849	static class WriteReplaceTestF implements Serializable {
850		int type, readType;
851
852		public WriteReplaceTestF(int type, int readType) {
853			this.type = type;
854			this.readType = readType;
855		}
856
857		public Object writeReplace() throws ObjectStreamException {
858			switch (type) {
859			case 0:
860				throw new InvalidObjectException("invalid");
861			case 1:
862				throw new RuntimeException("runtime");
863			case 2:
864				throw new Error("error");
865			default:
866				return new ReadResolveTestE(readType);
867			}
868		}
869	}
870
871	static class ReadResolveTestA implements Serializable {
872		public Object readResolve() throws ObjectStreamException {
873			return new ReadResolveTestA();
874		}
875	}
876
877	static class ReadResolveTestB extends ReadResolveTestA {
878	}
879
880	static class ReadResolveTestC implements Serializable {
881		private Object readResolve() throws ObjectStreamException {
882			return new ReadResolveTestB();
883		}
884	}
885
886	static class ReadResolveTestD extends ReadResolveTestC {
887	}
888
889	static class ReadResolveTestE implements Serializable {
890		int type;
891
892		public ReadResolveTestE(int type) {
893			this.type = type;
894		}
895
896		public Object readResolve() throws ObjectStreamException {
897			switch (type) {
898			case 0:
899				throw new InvalidObjectException("invalid");
900			case 1:
901				throw new RuntimeException("runtime");
902			case 2:
903				throw new Error("error");
904			case 3:
905				return this;
906			default:
907				return new ReadResolveTestF();
908			}
909		}
910	}
911
912	static class ReadResolveTestF implements Serializable {
913	}
914
915	public void test_1_writeReplace() {
916		try {
917			Vector<Object> v = new Vector<Object>();
918			v.addElement(new WriteReplaceTestA());
919			v.addElement(new WriteReplaceTestB());
920			v.addElement(new WriteReplaceTestB());
921			v.addElement(new WriteReplaceTestC());
922			v.addElement(new WriteReplaceTestD());
923			v.addElement(new WriteReplaceTestE());
924			oos.writeObject(v);
925			oos.close();
926			ois = new ObjectInputStream(loadStream());
927			Vector result = (Vector) ois.readObject();
928			assertTrue("invalid 0 : " + result.elementAt(0), result
929					.elementAt(0).getClass() == ReadResolveTestA.class);
930			assertTrue("invalid 1 : " + result.elementAt(1), result
931					.elementAt(1).getClass() == ReadResolveTestA.class);
932			assertTrue("invalid 2 : " + result.elementAt(2), result
933					.elementAt(2).getClass() == ReadResolveTestA.class);
934			assertTrue("invalid 3 : " + result.elementAt(3), result
935					.elementAt(3).getClass() == ReadResolveTestB.class);
936			assertTrue("invalid 4 : " + result.elementAt(4), result
937					.elementAt(4).getClass() == ReadResolveTestD.class);
938			assertTrue("invalid 5 : " + result.elementAt(5), result
939					.elementAt(5).getClass() == WriteReplaceTestE.class);
940		} catch (IOException e) {
941			fail("IOException serializing data : " + e.getMessage());
942		} catch (ClassNotFoundException e) {
943			fail("ClassNotFoundException serializing data : " + e.getMessage());
944		}
945	}
946
947	public void test_2_writeReplace() {
948		try {
949			boolean exception = false;
950			try {
951				oos.writeObject(new WriteReplaceTestF(0, -1));
952			} catch (ObjectStreamException e) {
953				exception = true;
954			}
955			assertTrue("Should throw ObjectStreamException", exception);
956			exception = false;
957			try {
958				oos.writeObject(new WriteReplaceTestF(1, -1));
959			} catch (RuntimeException e) {
960				exception = true;
961			}
962			assertTrue("Should throw RuntimeException", exception);
963			exception = false;
964			try {
965				oos.writeObject(new WriteReplaceTestF(2, -1));
966			} catch (Error e) {
967				exception = true;
968			}
969			assertTrue("Should throw Error", exception);
970
971			oos.writeObject(new WriteReplaceTestF(3, 0));
972			oos.writeObject(new WriteReplaceTestF(3, 1));
973			oos.writeObject(new WriteReplaceTestF(3, 2));
974			WriteReplaceTestF test = new WriteReplaceTestF(3, 3);
975			oos.writeObject(test);
976			oos.writeObject(test);
977			WriteReplaceTestF test2 = new WriteReplaceTestF(3, 4);
978			oos.writeObject(test2);
979			oos.writeObject(test2);
980			oos.close();
981			ois = new ObjectInputStream(loadStream());
982			try {
983				ois.readObject();
984			} catch (WriteAbortedException e) {
985			}
986
987			exception = false;
988			try {
989				ois.readObject();
990			} catch (ObjectStreamException e) {
991				exception = true;
992			}
993			assertTrue("Expected ObjectStreamException", exception);
994			exception = false;
995			try {
996				ois.readObject();
997			} catch (RuntimeException e) {
998				exception = true;
999			}
1000			assertTrue("Expected RuntimeException", exception);
1001			exception = false;
1002			try {
1003				ois.readObject();
1004			} catch (Error e) {
1005				exception = true;
1006			}
1007			assertTrue("Expected Error", exception);
1008
1009			Object readE1 = ois.readObject();
1010			Object readE2 = ois.readObject();
1011			assertTrue("Replaced objects should be identical", readE1 == readE2);
1012			Object readF1 = ois.readObject();
1013			Object readF2 = ois.readObject();
1014			assertTrue("Replaced resolved objects should be identical: "
1015					+ readF1 + " " + readF2, readF1 == readF2);
1016		} catch (IOException e) {
1017			fail("IOException serializing data : " + e.getMessage());
1018		} catch (ClassNotFoundException e) {
1019			fail("ClassNotFoundException serializing data : " + e.getMessage());
1020		}
1021	}
1022}
1023