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.tests.java.io;
19
20import java.io.BufferedInputStream;
21import java.io.ByteArrayInputStream;
22import java.io.File;
23import java.io.FileInputStream;
24import java.io.FileOutputStream;
25import java.io.IOException;
26import java.io.InputStream;
27import java.io.InputStreamReader;
28import java.nio.charset.StandardCharsets;
29import junit.framework.TestCase;
30
31public class BufferedInputStreamTest extends TestCase {
32
33    private static final String INPUT =
34             "Test_All_Tests\n" +
35             "Test_BufferedInputStream\n" +
36             "Test_java_io_BufferedOutputStream\n" +
37             "Test_java_io_ByteArrayInputStream\n" +
38             "Test_java_io_ByteArrayOutputStream\n" +
39             "Test_java_io_DataInputStream\n" +
40             "Test_java_io_File\n" +
41             "Test_java_io_FileDescriptor\n" +
42             "Test_java_io_FileInputStream\n" +
43             "Test_java_io_FileNotFoundException\n" +
44             "Test_java_io_FileOutputStream\n" +
45             "Test_java_io_FilterInputStream\n" +
46             "Test_java_io_FilterOutputStream\n" +
47             "Test_java_io_InputStream\n" +
48             "Test_java_io_IOException\n" +
49             "Test_java_io_OutputStream\n" +
50             "Test_java_io_PrintStream\n" +
51             "Test_java_io_RandomAccessFile\n" +
52             "Test_java_io_SyncFailedException\n" +
53             "Test_java_lang_AbstractMethodError\n" +
54             "Test_java_lang_ArithmeticException\n" +
55             "Test_java_lang_ArrayIndexOutOfBoundsException\n" +
56             "Test_java_lang_ArrayStoreException\n" +
57             "Test_java_lang_Boolean\n" +
58             "Test_java_lang_Byte\n" +
59             "Test_java_lang_Character\n" +
60             "Test_All_Tests\n" +
61             "Test_BufferedInputStream\n" +
62             "Test_java_io_BufferedOutputStream\n" +
63             "Test_java_io_ByteArrayInputStream\n" +
64             "Test_java_io_ByteArrayOutputStream\n" +
65             "Test_java_io_DataInputStream\n" +
66             "Test_java_io_File\n" +
67             "Test_java_io_FileDescriptor\n" +
68             "Test_java_io_FileInputStream\n" +
69             "Test_java_io_FileNotFoundException\n" +
70             "Test_java_io_FileOutputStream\n" +
71             "Test_java_io_FilterInputStream\n" +
72             "Test_java_io_FilterOutputStream\n" +
73             "Test_java_io_InputStream\n" +
74             "Test_java_io_IOException\n" +
75             "Test_java_io_OutputStream\n" +
76             "Test_java_io_PrintStream\n" +
77             "Test_java_io_RandomAccessFile\n" +
78             "Test_java_io_SyncFailedException\n" +
79             "Test_java_lang_AbstractMethodError\n" +
80             "Test_java_lang_ArithmeticException\n" +
81             "Test_java_lang_ArrayIndexOutOfBoundsException\n" +
82             "Test_java_lang_ArrayStoreException\n" +
83             "Test_java_lang_Boolean\n" +
84             "Test_java_lang_Byte\n" +
85             "Test_java_lang_Character\n";
86
87    private BufferedInputStream is;
88    private InputStream isBytes;
89
90
91    /*
92     * java.io.BufferedInputStream(InputStream)
93     */
94    public void test_ConstructorLjava_io_InputStream() {
95        try {
96            BufferedInputStream str = new BufferedInputStream(null);
97            str.read();
98            fail("Expected an IOException");
99        } catch (IOException e) {
100            // Expected
101        }
102    }
103
104    /*
105     * java.io.BufferedInputStream(InputStream)
106     */
107    public void test_ConstructorLjava_io_InputStreamI() throws IOException {
108        try {
109            BufferedInputStream str = new BufferedInputStream(null, 1);
110            str.read();
111            fail("Expected an IOException");
112        } catch (IOException e) {
113            // Expected
114        }
115
116        // Test for method java.io.BufferedInputStream(java.io.InputStream, int)
117
118        // Create buffer with hald size of file and fill it.
119        int bufferSize = INPUT.length() / 2;
120        is = new BufferedInputStream(isBytes, bufferSize);
121        // Ensure buffer gets filled by evaluating one read
122        is.read();
123        // Close underlying FileInputStream, all but 1 buffered bytes should
124        // still be available.
125        isBytes.close();
126        // Read the remaining buffered characters, no IOException should
127        // occur.
128        is.skip(bufferSize - 2);
129        is.read();
130        try {
131            // is.read should now throw an exception because it will have to
132            // be filled.
133            is.read();
134            fail("Exception should have been triggered by read()");
135        } catch (IOException e) {
136            // Expected
137        }
138
139        // regression test for harmony-2407
140        new MockBufferedInputStream(null);
141        assertNotNull(MockBufferedInputStream.buf);
142        MockBufferedInputStream.buf = null;
143        new MockBufferedInputStream(null, 100);
144        assertNotNull(MockBufferedInputStream.buf);
145    }
146
147    static class MockBufferedInputStream extends BufferedInputStream {
148        static byte[] buf;
149
150        MockBufferedInputStream(InputStream is) throws IOException {
151            super(is);
152            buf = super.buf;
153        }
154
155        MockBufferedInputStream(InputStream is, int size) throws IOException {
156            super(is, size);
157            buf = super.buf;
158        }
159    }
160
161    /**
162     * java.io.BufferedInputStream#available()
163     */
164    public void test_available() throws IOException {
165        assertTrue("Returned incorrect number of available bytes", is
166                .available() == INPUT.length());
167
168        // Test that a closed stream throws an IOE for available()
169        BufferedInputStream bis = new BufferedInputStream(
170                new ByteArrayInputStream(new byte[] { 'h', 'e', 'l', 'l', 'o',
171                        ' ', 't', 'i', 'm' }));
172        int available = bis.available();
173        bis.close();
174        assertTrue(available != 0);
175
176        try {
177            bis.available();
178            fail("Expected test to throw IOE.");
179        } catch (IOException ex) {
180            // expected
181        }
182    }
183
184    /**
185     * java.io.BufferedInputStream#close()
186     */
187    public void test_close() throws IOException {
188        new BufferedInputStream(isBytes).close();
189
190        // regression for HARMONY-667
191        BufferedInputStream buf = new BufferedInputStream(null, 5);
192        buf.close();
193
194        InputStream in = new InputStream() {
195            Object lock = new Object();
196
197            @Override
198            public int read() {
199                return 1;
200            }
201
202            @Override
203            public int read(byte[] buf, int offset, int length) {
204                synchronized (lock) {
205                    try {
206                        lock.wait(3000);
207                    } catch (InterruptedException e) {
208                        // Ignore
209                    }
210                }
211                return 1;
212            }
213
214            @Override
215            public void close() {
216                synchronized (lock) {
217                    lock.notifyAll();
218                }
219            }
220        };
221        final BufferedInputStream bufin = new BufferedInputStream(in);
222        Thread thread = new Thread(new Runnable() {
223            public void run() {
224                try {
225                    Thread.sleep(1000);
226                    bufin.close();
227                } catch (Exception e) {
228                    // Ignored
229                }
230            }
231        });
232        thread.start();
233        try {
234            bufin.read(new byte[100], 0, 99);
235            fail("Should throw IOException");
236        } catch (IOException e) {
237            // Expected
238        }
239    }
240
241    /**
242     * java.io.BufferedInputStream#mark(int)
243     */
244    public void test_markI() throws IOException {
245        byte[] buf1 = new byte[100];
246        byte[] buf2 = new byte[100];
247        is.skip(50);
248        is.mark(500);
249        is.read(buf1, 0, buf1.length);
250        is.reset();
251        is.read(buf2, 0, buf2.length);
252        is.reset();
253        assertTrue("Failed to mark correct position", new String(buf1, 0,
254                buf1.length).equals(new String(buf2, 0, buf2.length)));
255
256        byte[] bytes = new byte[256];
257        for (int i = 0; i < 256; i++) {
258            bytes[i] = (byte) i;
259        }
260        InputStream in = new BufferedInputStream(
261                new ByteArrayInputStream(bytes), 12);
262        in.skip(6);
263        in.mark(14);
264        in.read(new byte[14], 0, 14);
265        in.reset();
266        assertTrue("Wrong bytes", in.read() == 6 && in.read() == 7);
267
268        in = new BufferedInputStream(new ByteArrayInputStream(bytes), 12);
269        in.skip(6);
270        in.mark(8);
271        in.skip(7);
272        in.reset();
273        assertTrue("Wrong bytes 2", in.read() == 6 && in.read() == 7);
274
275        BufferedInputStream buf = new BufferedInputStream(
276                new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4 }), 2);
277        buf.mark(3);
278        bytes = new byte[3];
279        int result = buf.read(bytes);
280        assertEquals(3, result);
281        assertEquals("Assert 0:", 0, bytes[0]);
282        assertEquals("Assert 1:", 1, bytes[1]);
283        assertEquals("Assert 2:", 2, bytes[2]);
284        assertEquals("Assert 3:", 3, buf.read());
285
286        buf = new BufferedInputStream(new ByteArrayInputStream(new byte[] { 0,
287                1, 2, 3, 4 }), 2);
288        buf.mark(3);
289        bytes = new byte[4];
290        result = buf.read(bytes);
291        assertEquals(4, result);
292        assertEquals("Assert 4:", 0, bytes[0]);
293        assertEquals("Assert 5:", 1, bytes[1]);
294        assertEquals("Assert 6:", 2, bytes[2]);
295        assertEquals("Assert 7:", 3, bytes[3]);
296        assertEquals("Assert 8:", 4, buf.read());
297        assertEquals("Assert 9:", -1, buf.read());
298
299        buf = new BufferedInputStream(new ByteArrayInputStream(new byte[] { 0,
300                1, 2, 3, 4 }), 2);
301        buf.mark(Integer.MAX_VALUE);
302        buf.read();
303        buf.close();
304    }
305
306    /**
307     * java.io.BufferedInputStream#markSupported()
308     */
309    public void test_markSupported() {
310        assertTrue("markSupported returned incorrect value", is.markSupported());
311    }
312
313    /**
314     * java.io.BufferedInputStream#read()
315     */
316    public void test_read() throws IOException {
317        InputStreamReader isr = new InputStreamReader(is);
318        int c = isr.read();
319        assertEquals(INPUT.charAt(0), c);
320
321        byte[] bytes = new byte[256];
322        for (int i = 0; i < 256; i++) {
323            bytes[i] = (byte) i;
324        }
325        InputStream in = new BufferedInputStream(
326                new ByteArrayInputStream(bytes), 12);
327        assertEquals("Wrong initial byte", 0, in.read()); // Fill the
328        // buffer
329        byte[] buf = new byte[14];
330        in.read(buf, 0, 14); // Read greater than the buffer
331        assertTrue("Wrong block read data", new String(buf, 0, 14)
332                .equals(new String(bytes, 1, 14)));
333        assertEquals("Wrong bytes", 15, in.read()); // Check next byte
334    }
335
336    /**
337     * java.io.BufferedInputStream#read(byte[], int, int)
338     */
339    public void test_read$BII_Exception() throws IOException {
340        BufferedInputStream bis = new BufferedInputStream(null);
341        try {
342            bis.read(null, -1, -1);
343            fail("should throw NullPointerException");
344        } catch (NullPointerException e) {
345            // expected
346        }
347
348        try {
349            bis.read(new byte[0], -1, -1);
350            fail("should throw IndexOutOfBoundsException");
351        } catch (IndexOutOfBoundsException e) {
352            // expected
353        }
354
355        try {
356            bis.read(new byte[0], 1, -1);
357            fail("should throw IndexOutOfBoundsException");
358        } catch (IndexOutOfBoundsException e) {
359            // expected
360        }
361
362        try {
363            bis.read(new byte[0], 1, 1);
364            fail("should throw IndexOutOfBoundsException");
365        } catch (IndexOutOfBoundsException e) {
366            // expected
367        }
368
369        bis.close();
370
371        try {
372            bis.read(null, -1, -1);
373            fail("should throw IOException");
374        } catch (IOException e) {
375            // expected
376        }
377    }
378
379    /**
380     * java.io.BufferedInputStream#read(byte[], int, int)
381     */
382    public void test_read$BII() throws IOException {
383        byte[] buf1 = new byte[100];
384        is.skip(500);
385        is.mark(500);
386        is.read(buf1, 0, buf1.length);
387        assertTrue("Failed to read correct data", new String(buf1, 0,
388                buf1.length).equals(INPUT.substring(500, 600)));
389
390        BufferedInputStream bufin = new BufferedInputStream(new InputStream() {
391            int size = 2
392                    ,
393                    pos = 0;
394
395            byte[] contents = new byte[size];
396
397            @Override
398            public int read() throws IOException {
399                if (pos >= size) {
400                    throw new IOException("Read past end of data");
401                }
402                return contents[pos++];
403            }
404
405            @Override
406            public int read(byte[] buf, int off, int len) throws IOException {
407                if (pos >= size) {
408                    throw new IOException("Read past end of data");
409                }
410                int toRead = len;
411                if (toRead > available()) {
412                    toRead = available();
413                }
414                System.arraycopy(contents, pos, buf, off, toRead);
415                pos += toRead;
416                return toRead;
417            }
418
419            @Override
420            public int available() {
421                return size - pos;
422            }
423        });
424        bufin.read();
425        int result = bufin.read(new byte[2], 0, 2);
426        assertTrue("Incorrect result: " + result, result == 1);
427    }
428
429    /**
430     * java.io.BufferedInputStream#reset()
431     */
432    public void test_reset() throws IOException {
433        byte[] buf1 = new byte[10];
434        byte[] buf2 = new byte[10];
435        is.mark(2000);
436        is.read(buf1, 0, 10);
437        is.reset();
438        is.read(buf2, 0, 10);
439        is.reset();
440        assertTrue("Reset failed", new String(buf1, 0, buf1.length)
441                .equals(new String(buf2, 0, buf2.length)));
442
443        BufferedInputStream bIn = new BufferedInputStream(
444                new ByteArrayInputStream("1234567890".getBytes()));
445        bIn.mark(10);
446        for (int i = 0; i < 11; i++) {
447            bIn.read();
448        }
449        bIn.reset();
450    }
451
452    /**
453     * java.io.BufferedInputStream#reset()
454     */
455    public void test_reset_Exception() throws IOException {
456        BufferedInputStream bis = new BufferedInputStream(null);
457
458        // throws IOException with message "Mark has been invalidated"
459        try {
460            bis.reset();
461            fail("should throw IOException");
462        } catch (IOException e) {
463            // expected
464        }
465
466        // does not throw IOException
467        bis.mark(1);
468        bis.reset();
469
470        bis.close();
471
472        // throws IOException with message "stream is closed"
473        try {
474            bis.reset();
475            fail("should throw IOException");
476        } catch (IOException e) {
477            // expected
478        }
479    }
480
481    /**
482     * java.io.BufferedInputStream#reset()
483     */
484    public void test_reset_scenario1() throws IOException {
485        byte[] input = "12345678900".getBytes();
486        BufferedInputStream buffis = new BufferedInputStream(
487                new ByteArrayInputStream(input));
488        buffis.read();
489        buffis.mark(5);
490        buffis.skip(5);
491        buffis.reset();
492    }
493
494    /**
495     * java.io.BufferedInputStream#reset()
496     */
497    public void test_reset_scenario2() throws IOException {
498        byte[] input = "12345678900".getBytes();
499        BufferedInputStream buffis = new BufferedInputStream(
500                new ByteArrayInputStream(input));
501        buffis.mark(5);
502        buffis.skip(6);
503        buffis.reset();
504    }
505
506    /**
507     * java.io.BufferedInputStream#skip(long)
508     */
509    public void test_skipJ() throws IOException {
510        byte[] buf1 = new byte[10];
511        is.mark(2000);
512        // This fails with OpenJdk. The first call to skip() will skip |bufferSize|
513        // bytes, and the second call will potentially resize the buffer. Users need
514        // to be aware. The API behaviour is correct, obviously, but it remains to
515        // be seen whether anybody blindly expects skip to always skip the number
516        // of bytes requested.
517        //
518        // assertEquals(1000, is.skip(1000));
519        int bytesLeft = 1000;
520        while (bytesLeft > 0) {
521            bytesLeft -= is.skip(bytesLeft);
522        }
523
524        assertEquals(buf1.length, is.read(buf1, 0, buf1.length));
525        is.reset();
526        assertEquals("Failed to skip to correct position", new String(buf1, 0,
527                buf1.length), INPUT.substring(1000, 1010));
528
529        // regression for HARMONY-667
530        try {
531            BufferedInputStream buf = new BufferedInputStream(null, 5);
532            buf.skip(10);
533            fail("Should throw IOException");
534        } catch (IOException e) {
535            // Expected
536        }
537    }
538
539    /**
540     * java.io.BufferedInputStream#skip(long)
541     */
542    public void test_skip_NullInputStream() throws IOException {
543        BufferedInputStream buf = new BufferedInputStream(null, 5);
544        assertEquals(0, buf.skip(0));
545    }
546
547    /**
548     * Sets up the fixture, for example, open a network connection. This method
549     * is called before a test is executed.
550     */
551    @Override
552    protected void setUp() throws IOException {
553        File f = File.createTempFile("BufferedInputStreamTest", "tst");
554        FileOutputStream fos = new FileOutputStream(f);
555        fos.write(INPUT.getBytes(StandardCharsets.US_ASCII));
556        fos.close();
557
558        isBytes = new FileInputStream(f.getAbsolutePath());
559        is = new BufferedInputStream(isBytes, INPUT.length() / 2);
560    }
561
562    /**
563     * Tears down the fixture, for example, close a network connection. This
564     * method is called after a test is executed.
565     */
566    @Override
567    protected void tearDown() {
568        try {
569            is.close();
570        } catch (Exception e) {
571        }
572    }
573}
574