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 junit.framework.TestCase;
21import java.io.BufferedInputStream;
22import java.io.ByteArrayInputStream;
23import java.io.ByteArrayOutputStream;
24import java.io.IOException;
25import java.io.InputStream;
26import java.io.InputStreamReader;
27import java.io.OutputStreamWriter;
28import java.io.UnsupportedEncodingException;
29import java.nio.charset.Charset;
30import java.nio.charset.CharsetDecoder;
31import java.nio.charset.CodingErrorAction;
32import java.nio.charset.MalformedInputException;
33import java.util.Arrays;
34
35public class InputStreamReaderTest extends TestCase {
36
37    static class LimitedByteArrayInputStream extends ByteArrayInputStream {
38
39        // A ByteArrayInputStream that only returns a single byte per read
40        byte[] bytes;
41
42        int count;
43
44        public LimitedByteArrayInputStream(int type) {
45            super(new byte[0]);
46            switch (type) {
47                case 0:
48                    bytes = new byte[] { 0x61, 0x72 };
49                    break;
50                case 1:
51                    bytes = new byte[] { (byte) 0xff, (byte) 0xfe, 0x61, 0x72 };
52                    break;
53                case 2:
54                    bytes = new byte[] { '\u001b', '$', 'B', '6', 'e', 'B', 'h',
55                            '\u001b', '(', 'B' };
56                    break;
57            }
58            count = bytes.length;
59        }
60
61        @Override
62        public int available() {
63            return count;
64        }
65
66        @Override
67        public int read() {
68            if (count == 0) {
69                return -1;
70            }
71            count--;
72            return bytes[bytes.length - count];
73        }
74
75        @Override
76        public int read(byte[] buffer, int offset, int length) {
77            if (count == 0) {
78                return -1;
79            }
80            if (length == 0) {
81                return 0;
82            }
83            buffer[offset] = bytes[bytes.length - count];
84            count--;
85            return 1;
86        }
87    }
88
89    public String fileString = "Test_All_Tests\nTest_java_io_BufferedInputStream\nTest_java_io_BufferedOutputStream\nTest_java_io_ByteArrayInputStream\nTest_java_io_ByteArrayOutputStream\nTest_java_io_DataInputStream\n";
90
91    private InputStream fis;
92
93    private InputStream in;
94
95    private InputStreamReader is;
96
97    private InputStreamReader reader;
98
99    private final String source = "This is a test message with Unicode character. \u4e2d\u56fd is China's name in Chinese";
100
101    /*
102     * @see TestCase#setUp()
103     */
104    @Override
105    protected void setUp() throws Exception {
106        super.setUp();
107
108        in = new ByteArrayInputStream(source.getBytes("UTF-8"));
109        reader = new InputStreamReader(in, "UTF-8");
110
111        ByteArrayOutputStream bos = new ByteArrayOutputStream();
112        OutputStreamWriter osw = new OutputStreamWriter(bos);
113        char[] buf = new char[fileString.length()];
114        fileString.getChars(0, fileString.length(), buf, 0);
115        osw.write(buf);
116        osw.close();
117        fis = new ByteArrayInputStream(bos.toByteArray());
118        is = new InputStreamReader(fis);
119    }
120
121    /*
122     * @see TestCase#tearDown()
123     */
124    @Override
125    protected void tearDown() throws Exception {
126        try {
127            in.close();
128            is.close();
129            fis.close();
130        } catch (IOException e) {
131            // Ignored
132        }
133
134        super.tearDown();
135    }
136
137    /**
138     * java.io.InputStreamReader#close()
139     */
140    public void test_close() throws IOException {
141        is.close();
142        try {
143            is.read();
144            fail("Should throw IOException");
145        } catch (IOException e) {
146            // Expected
147        }
148
149        reader.close();
150        try {
151            reader.ready();
152            fail("Should throw IOException");
153        } catch (IOException e) {
154            // Expected
155        }
156
157        // Should be a no-op
158        reader.close();
159
160        // Tests after reader closed
161        in = new BufferedInputStream(
162                this
163                        .getClass()
164                        .getClassLoader()
165                        .getResourceAsStream(
166                                "org/apache/harmony/luni/tests/java/io/testfile-utf8.txt"));
167        reader = new InputStreamReader(in, "utf-8");
168        in.close();
169        try {
170            int count = reader.read(new char[1]);
171            fail("count:" + count);
172        } catch (IOException e) {
173            // Expected
174        }
175        try {
176            reader.read();
177            fail();
178        } catch (IOException e) {
179            // Expected
180        }
181
182        assertFalse(reader.ready());
183        Charset cs = Charset.forName("utf-8");
184        assertEquals(cs, Charset.forName(reader.getEncoding()));
185    }
186
187    /**
188     * java.io.InputStreamReader#InputStreamReader(java.io.InputStream)
189     */
190    public void test_ConstructorLjava_io_InputStream() throws IOException {
191        try {
192            reader = new InputStreamReader(null);
193            fail();
194        } catch (NullPointerException e) {
195            // Expected
196        }
197        InputStreamReader reader2 = new InputStreamReader(in);
198        reader2.close();
199    }
200
201    /**
202     * java.io.InputStreamReader#InputStreamReader(java.io.InputStream,
203     *java.lang.String)
204     */
205    public void test_ConstructorLjava_io_InputStreamLjava_lang_String()
206            throws IOException {
207        is = new InputStreamReader(fis, "8859_1");
208
209        try {
210            is = new InputStreamReader(fis, "Bogus");
211            fail("Failed to throw Unsupported Encoding exception");
212        } catch (UnsupportedEncodingException e) {
213            assertNotNull(e.getMessage());
214        }
215
216        try {
217            reader = new InputStreamReader(null, "utf-8");
218            fail();
219        } catch (NullPointerException e) {
220            // Expected
221        }
222        try {
223            reader = new InputStreamReader(in, (String) null);
224            fail();
225        } catch (NullPointerException e) {
226            // Expected
227        }
228        try {
229            reader = new InputStreamReader(in, "");
230            fail();
231        } catch (UnsupportedEncodingException e) {
232            // Expected
233        }
234        try {
235            reader = new InputStreamReader(in, "badname");
236            fail();
237        } catch (UnsupportedEncodingException e) {
238            // Expected
239        }
240        InputStreamReader reader2 = new InputStreamReader(in, "utf-8");
241        assertEquals(Charset.forName(reader2.getEncoding()), Charset
242                .forName("utf-8"));
243        reader2.close();
244        reader2 = new InputStreamReader(in, "utf8");
245        assertEquals(Charset.forName(reader2.getEncoding()), Charset
246                .forName("utf-8"));
247        reader2.close();
248    }
249
250    /**
251     * java.io.InputStreamReader(java.io.InputStream,
252     *java.nio.charset.Charset)
253     */
254    public void test_ConstructorLjava_io_InputStreamLjava_nio_charset_Charset()
255            throws IOException {
256        Charset cs = Charset.forName("utf-8");
257        try {
258            reader = new InputStreamReader(null, cs);
259            fail();
260        } catch (NullPointerException e) {
261            // Expected
262        }
263        try {
264            reader = new InputStreamReader(in, (Charset) null);
265            fail();
266        } catch (NullPointerException e) {
267            // Expected
268        }
269        InputStreamReader reader2 = new InputStreamReader(in, cs);
270        assertEquals(Charset.forName(reader2.getEncoding()), cs);
271        reader2.close();
272    }
273
274    /**
275     * java.io.InputStreamReader(java.io.InputStream,
276     *java.nio.charset.CharsetDecoder)
277     */
278    public void test_ConstructorLjava_io_InputStreamLjava_nio_charset_CharsetDecoder()
279            throws IOException {
280        CharsetDecoder decoder = Charset.forName("utf-8").newDecoder();
281        try {
282            reader = new InputStreamReader(null, decoder);
283            fail();
284        } catch (NullPointerException e) {
285            // Expected
286        }
287        try {
288            reader = new InputStreamReader(in, (CharsetDecoder) null);
289            fail();
290        } catch (NullPointerException e) {
291            // Expected
292        }
293        InputStreamReader reader2 = new InputStreamReader(in, decoder);
294        assertEquals(Charset.forName(reader2.getEncoding()), decoder.charset());
295        reader2.close();
296    }
297
298    /**
299     * Unlike the RI, we return a canonical encoding name and not something
300     * java specific.
301     */
302    public void test_getEncoding() throws IOException {
303        InputStreamReader isr = new InputStreamReader(fis, "8859_1");
304        assertEquals("ISO-8859-1", isr.getEncoding());
305
306        isr = new InputStreamReader(fis, "ISO-8859-1");
307        assertEquals("ISO-8859-1", isr.getEncoding());
308
309        byte b[] = new byte[5];
310        isr = new InputStreamReader(new ByteArrayInputStream(b), "UTF-16BE");
311        isr.close();
312        assertNull(isr.getEncoding());
313
314        try {
315            isr = new InputStreamReader(System.in, "UTF-16BE");
316        } catch (UnsupportedEncodingException e) {
317            // Ignored
318        }
319        assertEquals("UTF-16BE", isr.getEncoding());
320    }
321
322    /**
323     * java.io.InputStreamReader#read()
324     */
325    public void test_read() throws IOException {
326        assertEquals('T', (char) reader.read());
327        assertEquals('h', (char) reader.read());
328        assertEquals('i', (char) reader.read());
329        assertEquals('s', (char) reader.read());
330        assertEquals(' ', (char) reader.read());
331        reader.read(new char[source.length() - 5], 0, source.length() - 5);
332        assertEquals(-1, reader.read());
333
334        int c = is.read();
335        assertTrue("returned incorrect char", (char) c == fileString.charAt(0));
336        InputStreamReader reader = new InputStreamReader(
337                new ByteArrayInputStream(new byte[] { (byte) 0xe8, (byte) 0x9d,
338                        (byte) 0xa5 }), "UTF8");
339        assertTrue("wrong double byte char", reader.read() == '\u8765');
340
341        // Regression for HARMONY-166
342        InputStream in;
343
344        in = new LimitedByteArrayInputStream(0);
345        reader = new InputStreamReader(in, "UTF-16BE");
346        assertEquals("Incorrect byte UTF-16BE", '\u6172', reader.read());
347
348        in = new LimitedByteArrayInputStream(0);
349        reader = new InputStreamReader(in, "UTF-16LE");
350        assertEquals("Incorrect byte UTF-16BE", '\u7261', reader.read());
351
352        in = new LimitedByteArrayInputStream(1);
353        reader = new InputStreamReader(in, "UTF-16");
354        assertEquals("Incorrect byte UTF-16BE", '\u7261', reader.read());
355
356        /*
357         * Temporarily commented out due to lack of ISO2022 support in ICU4J 3.8
358         * in = new LimitedByteArrayInputStream(2); reader = new
359         * InputStreamReader(in, "ISO2022JP"); assertEquals("Incorrect byte
360         * ISO2022JP 1", '\u4e5d', reader.read()); assertEquals("Incorrect byte
361         * ISO2022JP 2", '\u7b2c', reader.read());
362         */
363    }
364
365    /*
366     * Class under test for int read() Regression for Harmony-411
367     */
368    public void test_read_1() throws IOException {
369        // if the decoder is constructed by InputStreamReader itself, the
370        // decoder's default error action is REPLACE
371        InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(
372                new byte[] { -32, -96 }), "UTF-8");
373        assertEquals("read() return incorrect value", 65533, isr.read());
374
375        InputStreamReader isr2 = new InputStreamReader(
376                new ByteArrayInputStream(new byte[] { -32, -96 }), Charset
377                .forName("UTF-8"));
378        assertEquals("read() return incorrect value", 65533, isr2.read());
379
380        // if the decoder is passed in, keep its status intact
381        CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
382        decoder.onMalformedInput(CodingErrorAction.REPORT);
383        InputStreamReader isr3 = new InputStreamReader(
384                new ByteArrayInputStream(new byte[] { -32, -96 }), decoder);
385        try {
386            isr3.read();
387            fail("Should throw MalformedInputException");
388        } catch (MalformedInputException e) {
389            // expected
390        }
391
392        CharsetDecoder decoder2 = Charset.forName("UTF-8").newDecoder();
393        decoder2.onMalformedInput(CodingErrorAction.IGNORE);
394        InputStreamReader isr4 = new InputStreamReader(
395                new ByteArrayInputStream(new byte[] { -32, -96 }), decoder2);
396        assertEquals("read() return incorrect value", -1, isr4.read());
397
398        CharsetDecoder decoder3 = Charset.forName("UTF-8").newDecoder();
399        decoder3.onMalformedInput(CodingErrorAction.REPLACE);
400        InputStreamReader isr5 = new InputStreamReader(
401                new ByteArrayInputStream(new byte[] { -32, -96 }), decoder3);
402        assertEquals("read() return incorrect value", 65533, isr5.read());
403    }
404
405    public void test_read_specialCharset() throws IOException {
406        reader.close();
407        in = this.getClass().getClassLoader().getResourceAsStream(
408                "tests/api/java/io/testfile-utf8.txt");
409        reader = new InputStreamReader(in, "utf-8");
410        int c;
411        StringBuffer sb = new StringBuffer();
412        while ((c = reader.read()) != -1) {
413            sb.append((char) c);
414        }
415        // delete BOM
416        assertEquals(source, sb.deleteCharAt(0).toString());
417
418        sb.setLength(0);
419        reader.close();
420        in = this.getClass().getClassLoader().getResourceAsStream(
421                "tests/api/java/io/testfile.txt");
422
423        reader = new InputStreamReader(in, "gb18030");
424        while ((c = reader.read()) != -1) {
425            sb.append((char) c);
426        }
427        assertEquals(source, sb.toString());
428    }
429
430    /**
431     * java.io.InputStreamReader#read(char[], int, int)
432     */
433    public void test_read$CII() throws IOException {
434        char[] rbuf = new char[100];
435        char[] sbuf = new char[100];
436        fileString.getChars(0, 100, sbuf, 0);
437        is.read(rbuf, 0, 100);
438        for (int i = 0; i < rbuf.length; i++) {
439            assertTrue("returned incorrect chars", rbuf[i] == sbuf[i]);
440        }
441
442        // Test successive reads
443        byte[] data = new byte[8192 * 2];
444        Arrays.fill(data, (byte) 116); // 116 = ISO-8859-1 value for 't'
445        ByteArrayInputStream bis = new ByteArrayInputStream(data);
446        InputStreamReader isr = new InputStreamReader(bis, "ISO-8859-1");
447
448        // One less than the InputStreamReader.BUFFER_SIZE
449        char[] buf = new char[8191];
450        int bytesRead = isr.read(buf, 0, buf.length);
451        assertFalse(-1 == bytesRead);
452        bytesRead = isr.read(buf, 0, buf.length);
453        assertFalse(-1 == bytesRead);
454
455        bis = new ByteArrayInputStream(source.getBytes("UTF-8"));
456        isr = new InputStreamReader(in, "UTF-8");
457        char[] chars = new char[source.length()];
458        assertEquals(source.length() - 3, isr.read(chars, 0, chars.length - 3));
459        assertEquals(3, isr.read(chars, 0, 10));
460    }
461
462    /*
463     * Class under test for int read(char[], int, int)
464     */
465    public void test_read$CII_1() throws IOException {
466        try {
467            reader.read(null, -1, 1);
468            fail();
469        } catch (NullPointerException expected) {
470        } catch (IndexOutOfBoundsException expected) {
471        }
472
473        try {
474            reader.read(null, 0, -1);
475            fail("Should throw NullPointerException");
476        } catch (NullPointerException e) {
477        } catch (IndexOutOfBoundsException expected) {
478        }
479
480        try {
481            reader.read(null, 0, 1);
482            fail();
483        } catch (NullPointerException e) {
484            // Expected
485        }
486        try {
487            reader.read(new char[3], -1, 1);
488            fail();
489        } catch (IndexOutOfBoundsException e) {
490            // Expected
491        }
492        try {
493            reader.read(new char[3], 0, -1);
494            fail();
495        } catch (IndexOutOfBoundsException e) {
496            // Expected
497        }
498        try {
499            reader.read(new char[3], 1, 3);
500            fail();
501        } catch (IndexOutOfBoundsException e) {
502            // Expected
503        }
504        assertEquals(0, reader.read(new char[3], 3, 0));
505        char[] chars = new char[source.length()];
506        assertEquals(0, reader.read(chars, 0, 0));
507        assertEquals(0, chars[0]);
508        assertEquals(3, reader.read(chars, 0, 3));
509        assertEquals(5, reader.read(chars, 3, 5));
510        assertEquals(source.length() - 8, reader.read(chars, 8,
511                chars.length - 8));
512        assertTrue(Arrays.equals(chars, source.toCharArray()));
513        assertEquals(-1, reader.read(chars, 0, chars.length));
514        assertTrue(Arrays.equals(chars, source.toCharArray()));
515    }
516
517    /**
518     * java.io.InputStreamReader#ready()
519     */
520    public void test_ready() throws IOException {
521        assertTrue("Ready test failed", is.ready());
522        is.read();
523        assertTrue("More chars, but not ready", is.ready());
524
525        assertTrue(reader.ready());
526        reader.read(new char[source.length()]);
527        assertFalse(reader.ready());
528    }
529}
530