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 libcore.java.io;
19
20import java.io.ByteArrayInputStream;
21import java.io.ByteArrayOutputStream;
22import java.io.FileInputStream;
23import java.io.FileOutputStream;
24import java.io.IOException;
25import java.io.NotActiveException;
26import java.io.ObjectInputStream;
27import java.io.ObjectOutputStream;
28import java.io.OutputStream;
29import java.io.Serializable;
30import junit.framework.TestCase;
31import tests.support.Support_ASimpleOutputStream;
32import tests.support.Support_OutputStream;
33
34public class OldObjectOutputStreamTest extends TestCase implements Serializable {
35
36    static final long serialVersionUID = 1L;
37
38    java.io.File f;
39
40    public class SerializableTestHelper implements Serializable {
41        public String aField1;
42
43        public String aField2;
44
45        SerializableTestHelper(String s, String t) {
46            aField1 = s;
47            aField2 = t;
48        }
49
50        private void readObject(ObjectInputStream ois) throws IOException {
51            // note aField2 is not read
52            try {
53                ObjectInputStream.GetField fields = ois.readFields();
54                aField1 = (String) fields.get("aField1", "Zap");
55            } catch (Exception e) {
56            }
57        }
58
59        private void writeObject(ObjectOutputStream oos) throws IOException {
60            // note aField2 is not written
61            ObjectOutputStream.PutField fields = oos.putFields();
62            fields.put("aField1", aField1);
63            oos.writeFields();
64        }
65
66        public String getText1() {
67            return aField1;
68        }
69
70        public String getText2() {
71            return aField2;
72        }
73    }
74
75    private static class BasicObjectOutputStream extends ObjectOutputStream {
76        public boolean writeStreamHeaderCalled;
77
78        public BasicObjectOutputStream() throws IOException, SecurityException {
79            super();
80            writeStreamHeaderCalled = false;
81        }
82
83        public BasicObjectOutputStream(OutputStream output) throws IOException {
84            super(output);
85        }
86
87        public void drain() throws IOException {
88            super.drain();
89        }
90
91        public boolean enableReplaceObject(boolean enable)
92                throws SecurityException {
93            return super.enableReplaceObject(enable);
94        }
95
96        public void writeObjectOverride(Object object) throws IOException {
97            super.writeObjectOverride(object);
98        }
99
100        public void writeStreamHeader() throws IOException {
101            super.writeStreamHeader();
102            writeStreamHeaderCalled = true;
103        }
104}
105
106    private static class NoFlushTestOutputStream extends ByteArrayOutputStream {
107        public boolean flushCalled;
108
109        public NoFlushTestOutputStream() {
110            super();
111            flushCalled = false;
112        }
113
114        public void flush() throws IOException {
115            super.flush();
116            flushCalled = true;
117        }
118    }
119
120    protected static final String MODE_XLOAD = "xload";
121
122    protected static final String MODE_XDUMP = "xdump";
123
124    static final String FOO = "foo";
125
126    static final String MSG_WITE_FAILED = "Failed to write: ";
127
128    private static final boolean DEBUG = false;
129
130    protected static boolean xload = false;
131
132    protected static boolean xdump = false;
133
134    protected static String xFileName = null;
135
136    protected ObjectInputStream ois;
137
138    protected ObjectOutputStream oos;
139
140    protected ObjectOutputStream oos_ioe;
141
142    protected Support_OutputStream sos;
143
144    protected ByteArrayOutputStream bao;
145
146    static final int INIT_INT_VALUE = 7;
147
148    static final String INIT_STR_VALUE = "a string that is blortz";
149
150    /**
151     * java.io.ObjectOutputStream#ObjectOutputStream(java.io.OutputStream)
152     */
153    public void test_ConstructorLjava_io_OutputStream() throws IOException {
154        oos.close();
155        oos = new ObjectOutputStream(new ByteArrayOutputStream());
156        oos.close();
157
158        try {
159            oos = new ObjectOutputStream(null);
160            fail("Test 1: NullPointerException expected.");
161        } catch (NullPointerException e) {
162            // Expected.
163        }
164
165        Support_ASimpleOutputStream sos = new Support_ASimpleOutputStream(true);
166        try {
167            oos = new ObjectOutputStream(sos);
168            fail("Test 2: IOException expected.");
169        } catch (IOException e) {
170            // Expected.
171        }
172    }
173
174    public void test_close() throws IOException {
175        int outputSize = bao.size();
176        // Writing of a primitive type should be buffered.
177        oos.writeInt(42);
178        assertTrue("Test 1: Primitive data unexpectedly written to the target stream.",
179                bao.size() == outputSize);
180        // Closing should write the buffered data to the target stream.
181        oos.close();
182        assertTrue("Test 2: Primitive data has not been written to the the target stream.",
183                bao.size() > outputSize);
184
185        try {
186            oos_ioe.close();
187            fail("Test 3: IOException expected.");
188        } catch (IOException e) {
189            // Expected.
190        }
191    }
192
193    public void test_drain() throws IOException {
194        NoFlushTestOutputStream target = new NoFlushTestOutputStream();
195        BasicObjectOutputStream boos = new BasicObjectOutputStream(target);
196        int initialSize = target.size();
197        boolean written = false;
198
199        boos.writeBytes("Lorem ipsum");
200        // If there is no buffer then the bytes have already been written.
201        written = (target.size() > initialSize);
202
203        boos.drain();
204        assertTrue("Content has not been written to the target.",
205                written || (target.size() > initialSize));
206        assertFalse("flush() has been called on the target.",
207                target.flushCalled);
208    }
209
210    public void test_enableReplaceObjectB() throws IOException {
211        // Start testing without a SecurityManager.
212        BasicObjectOutputStream boos = new BasicObjectOutputStream();
213        assertFalse("Test 1: Object resolving must be disabled by default.",
214                boos.enableReplaceObject(true));
215
216        assertTrue("Test 2: enableReplaceObject did not return the previous value.",
217                boos.enableReplaceObject(false));
218    }
219
220    public void test_flush() throws Exception {
221        // Test for method void java.io.ObjectOutputStream.flush()
222        int size = bao.size();
223        oos.writeByte(127);
224        assertTrue("Test 1: Data already flushed.", bao.size() == size);
225        oos.flush();
226        assertTrue("Test 2: Failed to flush data.", bao.size() > size);
227
228        try {
229            oos_ioe.flush();
230            fail("Test 3: IOException expected.");
231        } catch (IOException e) {
232            // Expected.
233        }
234    }
235
236    public void test_putFields() throws Exception {
237        /*
238         * "SerializableTestHelper" is an object created for these tests with
239         * two fields (Strings) and simple implementations of readObject and
240         * writeObject which simply read and write the first field but not the
241         * second one.
242         */
243        SerializableTestHelper sth;
244
245        try {
246            oos.putFields();
247            fail("Test 1: NotActiveException expected.");
248        } catch (NotActiveException e) {
249            // Expected.
250        }
251
252        oos.writeObject(new SerializableTestHelper("Gabba", "Jabba"));
253        oos.flush();
254        ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
255        sth = (SerializableTestHelper) (ois.readObject());
256        assertEquals("Test 2: readFields or writeFields failed; first field not set.",
257                "Gabba", sth.getText1());
258        assertNull("Test 3: readFields or writeFields failed; second field should not have been set.",
259                sth.getText2());
260    }
261
262    public void test_reset() throws Exception {
263        String o = "HelloWorld";
264        sos = new Support_OutputStream(200);
265        oos.close();
266        oos = new ObjectOutputStream(sos);
267        oos.writeObject(o);
268        oos.writeObject(o);
269        oos.reset();
270        oos.writeObject(o);
271
272        sos.setThrowsException(true);
273        try {
274            oos.reset();
275            fail("Test 1: IOException expected.");
276        } catch (IOException e) {
277            // Expected.
278        }
279        sos.setThrowsException(false);
280
281        ois = new ObjectInputStream(new ByteArrayInputStream(sos.toByteArray()));
282        assertEquals("Test 2: Incorrect object read.", o, ois.readObject());
283        assertEquals("Test 3: Incorrect object read.", o, ois.readObject());
284        assertEquals("Test 4: Incorrect object read.", o, ois.readObject());
285        ois.close();
286    }
287
288    public void test_write$BII() throws Exception {
289        byte[] buf = new byte[10];
290        ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
291        try {
292            ois.read(buf, 0, -1);
293            fail("IndexOutOfBoundsException not thrown");
294        } catch (IndexOutOfBoundsException e) {
295            // Expected
296        }
297        try {
298            ois.read(buf, -1, 1);
299            fail("IndexOutOfBoundsException not thrown");
300        } catch (IndexOutOfBoundsException e) {
301            // Expected
302        }
303        try {
304            ois.read(buf, 10, 1);
305            fail("IndexOutOfBoundsException not thrown");
306        } catch (IndexOutOfBoundsException e) {
307            // Expected
308        }
309        ois.close();
310
311    }
312
313    public void test_writeObjectOverrideLjava_lang_Object() throws IOException {
314        BasicObjectOutputStream boos =
315                new BasicObjectOutputStream(new ByteArrayOutputStream());
316
317        try {
318            boos.writeObjectOverride(new Object());
319            fail("IOException expected.");
320        }
321        catch (IOException e) {
322        }
323        finally {
324            boos.close();
325        }
326    }
327
328    public void test_writeStreamHeader() throws IOException {
329        BasicObjectOutputStream boos;
330        ByteArrayOutputStream baos = new ByteArrayOutputStream();
331        short s;
332        byte[] buffer;
333
334        // Test 1: Make sure that writeStreamHeader() has been called.
335        boos = new BasicObjectOutputStream(baos);
336        try {
337            assertTrue("Test 1: writeStreamHeader() has not been called.",
338                         boos.writeStreamHeaderCalled);
339
340            // Test 2: Check that at least four bytes have been written.
341            buffer = baos.toByteArray();
342            assertTrue("Test 2: At least four bytes should have been written",
343                        buffer.length >= 4);
344
345            // Test 3: Check the magic number.
346            s = buffer[0];
347            s <<= 8;
348            s += ((short) buffer[1] & 0x00ff);
349            assertEquals("Test 3: Invalid magic number written.",
350                        java.io.ObjectStreamConstants.STREAM_MAGIC, s);
351
352            // Test 4: Check the stream version number.
353            s = buffer[2];
354            s <<= 8;
355            s += ((short) buffer[3] & 0x00ff);
356            assertEquals("Invalid stream version number written.",
357                        java.io.ObjectStreamConstants.STREAM_VERSION, s);
358        }
359        finally {
360            boos.close();
361        }
362    }
363
364    /**
365     * Sets up the fixture, for example, open a network connection. This method
366     * is called before a test is executed.
367     */
368    protected void setUp() throws Exception {
369        super.setUp();
370        oos = new ObjectOutputStream(bao = new ByteArrayOutputStream());
371        oos_ioe = new ObjectOutputStream(sos = new Support_OutputStream());
372        sos.setThrowsException(true);
373    }
374
375    /**
376     * Tears down the fixture, for example, close a network connection. This
377     * method is called after a test is executed.
378     */
379    protected void tearDown() throws Exception {
380        super.tearDown();
381        if (oos != null) {
382            try {
383                oos.close();
384            } catch (Exception e) {}
385        }
386        if (oos_ioe != null) {
387            try {
388                oos_ioe.close();
389            } catch (Exception e) {}
390        }
391        if (f != null && f.exists()) {
392            if (!f.delete()) {
393                fail("Error cleaning up files during teardown");
394            }
395        }
396    }
397
398    protected Object reload() throws IOException, ClassNotFoundException {
399
400        // Choose the load stream
401        if (xload || xdump) {
402            // Load from pre-existing file
403            ois = new ObjectInputStream(new FileInputStream(xFileName + "-"
404                    + getName() + ".ser"));
405        } else {
406            // Just load from memory, we dumped to memory
407            ois = new ObjectInputStream(new ByteArrayInputStream(bao
408                    .toByteArray()));
409        }
410
411        try {
412            return ois.readObject();
413        } finally {
414            ois.close();
415        }
416    }
417
418    protected void dump(Object o) throws IOException, ClassNotFoundException {
419
420        // Choose the dump stream
421        if (xdump) {
422            oos = new ObjectOutputStream(new FileOutputStream(
423                    f = new java.io.File(xFileName + "-" + getName() + ".ser")));
424        } else {
425            oos = new ObjectOutputStream(bao = new ByteArrayOutputStream());
426        }
427
428        // Dump the object
429        try {
430            oos.writeObject(o);
431        } finally {
432            oos.close();
433        }
434    }
435}
436