InputStreamReaderTest.java revision 37e83f5ac3ae56a0aeb4b52fc183b52307bd46ef
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 tests.api.java.io;
19
20import java.io.BufferedInputStream;
21import java.io.ByteArrayInputStream;
22import java.io.ByteArrayOutputStream;
23import java.io.IOException;
24import java.io.InputStream;
25import java.io.InputStreamReader;
26import java.io.OutputStreamWriter;
27import java.io.UnsupportedEncodingException;
28import java.nio.charset.Charset;
29import java.nio.charset.CharsetDecoder;
30import java.nio.charset.CodingErrorAction;
31import java.nio.charset.MalformedInputException;
32import java.util.Arrays;
33
34import tests.support.Support_ASimpleInputStream;
35
36import junit.framework.TestCase;
37import dalvik.annotation.TestLevel;
38import dalvik.annotation.TestTargetClass;
39import dalvik.annotation.TestTargetNew;
40import dalvik.annotation.TestTargets;
41
42/**
43 *
44 */
45@TestTargetClass(InputStreamReader.class)
46public class InputStreamReaderTest extends TestCase {
47
48    private final String source = "This is a test message with Unicode character. \u4e2d\u56fd is China's name in Chinese";
49
50    private InputStream in;
51
52    private InputStreamReader reader;
53
54    private InputStreamReader is;
55
56    private InputStream fis;
57
58    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";
59
60    static class LimitedByteArrayInputStream extends ByteArrayInputStream {
61
62        // A ByteArrayInputStream that only returns a single byte per read
63        byte[] bytes;
64
65        int count;
66
67        public LimitedByteArrayInputStream(int type) {
68            super(new byte[0]);
69            switch (type) {
70            case 0:
71                bytes = new byte[] { 0x61, 0x72 };
72                break;
73            case 1:
74                bytes = new byte[] { (byte) 0xff, (byte) 0xfe, 0x61, 0x72 };
75                break;
76            case 2:
77                bytes = new byte[] { '\u001b', '$', 'B', '6', 'e', 'B', 'h',
78                        '\u001b', '(', 'B' };
79                break;
80            }
81            count = bytes.length;
82        }
83
84        public int read() {
85            if (count == 0)
86                return -1;
87            count--;
88            return bytes[bytes.length - count];
89        }
90
91        public int read(byte[] buffer, int offset, int length) {
92            if (count == 0)
93                return -1;
94            if (length == 0)
95                return 0;
96            buffer[offset] = bytes[bytes.length - count];
97            count--;
98            return 1;
99        }
100
101        public int available() {
102            return count;
103        }
104    }
105
106    /*
107     * @see TestCase#setUp()
108     */
109    protected void setUp() throws Exception {
110        super.setUp();
111
112        try {
113            in = new ByteArrayInputStream(source.getBytes("UTF-8"));
114            reader = new InputStreamReader(in, "UTF-8");
115
116            ByteArrayOutputStream bos = new ByteArrayOutputStream();
117            OutputStreamWriter osw = new OutputStreamWriter(bos);
118            char[] buf = new char[fileString.length()];
119            fileString.getChars(0, fileString.length(), buf, 0);
120            osw.write(buf);
121            osw.close();
122            fis = new ByteArrayInputStream(bos.toByteArray());
123            is = new InputStreamReader(fis);
124        } catch (Exception e) {
125            fail("Exception during setUp : " + e.getMessage());
126        }
127    }
128
129    /*
130     * @see TestCase#tearDown()
131     */
132    protected void tearDown() throws Exception {
133        try {
134            in.close();
135            is.close();
136            fis.close();
137        } catch (IOException e) {
138        }
139
140        super.tearDown();
141    }
142
143    /*
144     * Class under test for int read()
145     */
146    @TestTargetNew(
147        level = TestLevel.PARTIAL_COMPLETE,
148        notes = "IOException checking missed.",
149        method = "read",
150        args = {}
151    )
152    public void testRead() throws IOException {
153        assertEquals('T', (char) reader.read());
154        assertEquals('h', (char) reader.read());
155        assertEquals('i', (char) reader.read());
156        assertEquals('s', (char) reader.read());
157        assertEquals(' ', (char) reader.read());
158        reader.read(new char[source.length() - 5], 0, source.length() - 5);
159        assertEquals(-1, reader.read());
160    }
161
162    /*
163     * Class under test for int read()
164     * Regression for Harmony-411
165     */
166    @TestTargetNew(
167        level = TestLevel.PARTIAL_COMPLETE,
168        notes = "IOException checking missed.",
169        method = "read",
170        args = {}
171    )
172
173    public void testRead1() throws IOException {
174        // if the decoder is constructed by InputStreamReader itself, the decoder's
175        // default error action is REPLACE
176        InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(
177                new byte[] { -32, -96 }), "UTF-8");
178        assertEquals("read() return incorrect value", 65533, isr.read());
179
180        InputStreamReader isr2 = new InputStreamReader(new ByteArrayInputStream(
181                new byte[] { -32, -96 }), Charset.forName("UTF-8"));
182        assertEquals("read() return incorrect value", 65533, isr2.read());
183
184        // if the decoder is passed in, keep its status intacted
185        CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
186        decoder.onMalformedInput(CodingErrorAction.REPORT);
187        InputStreamReader isr3 = new InputStreamReader(new ByteArrayInputStream(
188                new byte[] { -32, -96 }), decoder);
189        try{
190           isr3.read();
191           fail("Should throw MalformedInputException");
192        }catch(MalformedInputException e){
193            //expected
194        }
195
196        CharsetDecoder decoder2 = Charset.forName("UTF-8").newDecoder();
197        decoder2.onMalformedInput(CodingErrorAction.IGNORE);
198        InputStreamReader isr4 = new InputStreamReader(new ByteArrayInputStream(
199                new byte[] { -32, -96 }), decoder2);
200        assertEquals("read() return incorrect value", -1, isr4.read());
201
202        CharsetDecoder decoder3 = Charset.forName("UTF-8").newDecoder();
203        decoder3.onMalformedInput(CodingErrorAction.REPLACE);
204        InputStreamReader isr5 = new InputStreamReader(new ByteArrayInputStream(
205                new byte[] { -32, -96 }), decoder3);
206        assertEquals("read() return incorrect value", 65533, isr5.read());
207    }
208
209    /*
210     * Class under test for int read(char[], int, int)
211     */
212    @TestTargetNew(
213        level = TestLevel.PARTIAL_COMPLETE,
214        notes = "IOException checking missed.",
215        method = "read",
216        args = {char[].class, int.class, int.class}
217    )
218    public void testReadcharArrayintint() throws IOException {
219        try {
220            reader.read(new char[3], -1, 0);
221            fail("Should throw IndexOutOfBoundsException");
222        } catch (IndexOutOfBoundsException e) {
223            //expected
224        }
225        try {
226            reader.read(new char[3], 0, -1);
227            fail("Should throw IndexOutOfBoundsException");
228        } catch (IndexOutOfBoundsException e) {
229            //expected
230        }
231        try {
232            reader.read(new char[3], 4, 0);
233            fail("Should throw IndexOutOfBoundsException");
234        } catch (IndexOutOfBoundsException e) {
235            //expected
236        }
237        try {
238            reader.read(new char[3], 3, 1);
239            fail("Should throw IndexOutOfBoundsException");
240        } catch (IndexOutOfBoundsException e) {
241            //expected
242        }
243        try {
244            reader.read(new char[3], 1, 3);
245            fail("Should throw IndexOutOfBoundsException");
246        } catch (IndexOutOfBoundsException e) {
247            //expected
248        }
249        try {
250            reader.read(new char[3], 0, 4);
251            fail("Should throw IndexOutOfBoundsException");
252        } catch (IndexOutOfBoundsException e) {
253            //expected
254        }
255
256        try {
257            reader.read(null, 0, 0);
258            fail("Should throw NullPointerException");
259        } catch (NullPointerException e) {
260            //expected
261        }
262
263        assertEquals(0, reader.read(new char[3], 3, 0));
264        char[] chars = new char[source.length()];
265        assertEquals(0, reader.read(chars, 0, 0));
266        assertEquals(0, chars[0]);
267        assertEquals(3, reader.read(chars, 0, 3));
268        assertEquals(5, reader.read(chars, 3, 5));
269        assertEquals(source.length() - 8, reader.read(chars, 8,
270                chars.length - 8));
271        assertTrue(Arrays.equals(chars, source.toCharArray()));
272        assertEquals(-1, reader.read(chars, 0, chars.length));
273        assertTrue(Arrays.equals(chars, source.toCharArray()));
274    }
275    @TestTargetNew(
276        level = TestLevel.PARTIAL_COMPLETE,
277        notes = "IOException checking missed.",
278        method = "read",
279        args = {char[].class, int.class, int.class}
280    )
281    public void testReadcharArrayintint2() throws IOException {
282        char[] chars = new char[source.length()];
283        assertEquals(source.length() - 3, reader.read(chars, 0,
284                chars.length - 3));
285        assertEquals(3, reader.read(chars, 0, 10));
286    }
287    @TestTargetNew(
288        level = TestLevel.PARTIAL_COMPLETE,
289        notes = "IOException checking missed.",
290        method = "ready",
291        args = {}
292    )
293    public void testReady() throws IOException {
294        assertTrue(reader.ready());
295        reader.read(new char[source.length()]);
296        assertFalse(reader.ready());
297    }
298    @TestTargetNew(
299        level = TestLevel.PARTIAL_COMPLETE,
300        notes = "IOException checking missed.",
301        method = "read",
302        args = {}
303    )
304    public void testSpecialCharsetReading() throws Exception {
305        reader.close();
306        in = this.getClass().getClassLoader().getResourceAsStream(
307                "tests/api/java/io/testfile-utf8.txt");
308        reader = new InputStreamReader(in, "utf-8");
309        int c;
310        StringBuffer sb = new StringBuffer();
311        while ((c = reader.read()) != -1) {
312            sb.append((char) c);
313        }
314        // delete BOM
315        assertEquals(source, sb.deleteCharAt(0).toString());
316
317        sb.setLength(0);
318        reader.close();
319        in = this.getClass().getClassLoader().getResourceAsStream(
320                "tests/api/java/io/testfile.txt");
321        reader = new InputStreamReader(in, "GB2312");
322
323        while ((c = reader.read()) != -1) {
324            sb.append((char) c);
325        }
326        assertEquals(source, sb.toString());
327    }
328
329    @TestTargets({
330        @TestTargetNew(
331            level = TestLevel.PARTIAL_COMPLETE,
332            notes = "IOException checking.",
333            method = "read",
334            args = {}
335        ),
336        @TestTargetNew(
337            level = TestLevel.PARTIAL_COMPLETE,
338            notes = "IOException checking.",
339            method = "ready",
340            args = {}
341        )
342    })
343    public void testAfterClose() throws IOException {
344        reader.close();
345        in = new BufferedInputStream(this.getClass().getClassLoader()
346                .getResourceAsStream("tests/api/java/io/testfile-utf8.txt"));
347        reader = new InputStreamReader(in, "utf-8");
348        in.close();
349        try {
350            int count = reader.read(new char[1]);
351            fail("count:" + count);
352        } catch (IOException e) {
353        }
354        try {
355            reader.read();
356            fail();
357        } catch (IOException e) {
358        }
359
360        assertFalse(reader.ready());
361        Charset cs = Charset.forName("utf-8");
362        assertEquals(cs, Charset.forName(reader.getEncoding()));
363        reader.close();
364    }
365
366    /*
367     * Class under test for void InputStreamReader(InputStream)
368     */
369    @TestTargetNew(
370        level = TestLevel.COMPLETE,
371        notes = "",
372        method = "InputStreamReader",
373        args = {java.io.InputStream.class}
374    )
375    public void testInputStreamReaderInputStream() throws IOException {
376        try {
377            reader = new InputStreamReader(null);
378            fail();
379        } catch (NullPointerException e) {
380        }
381        InputStreamReader reader2 = new InputStreamReader(in);
382        reader2.close();
383    }
384
385    /*
386     * Class under test for void InputStreamReader(InputStream, String)
387     */
388    @TestTargetNew(
389        level = TestLevel.COMPLETE,
390        notes = "",
391        method = "InputStreamReader",
392        args = {java.io.InputStream.class, java.lang.String.class}
393    )
394    public void testInputStreamReaderInputStreamString() throws IOException {
395        try {
396            reader = new InputStreamReader(null, "utf-8");
397            fail();
398        } catch (NullPointerException e) {
399        }
400        try {
401            reader = new InputStreamReader(in, (String) null);
402            fail();
403        } catch (NullPointerException e) {
404        }
405        try {
406            reader = new InputStreamReader(in, "");
407            fail();
408        } catch (UnsupportedEncodingException e) {
409        }
410        try {
411            reader = new InputStreamReader(in, "badname");
412            fail();
413        } catch (UnsupportedEncodingException e) {
414        }
415        InputStreamReader reader2 = new InputStreamReader(in, "utf-8");
416        assertEquals(Charset.forName(reader2.getEncoding()), Charset
417                .forName("utf-8"));
418        reader2.close();
419        reader2 = new InputStreamReader(in, "utf8");
420        assertEquals(Charset.forName(reader2.getEncoding()), Charset
421                .forName("utf-8"));
422        reader2.close();
423    }
424
425    /*
426     * Class under test for void InputStreamReader(InputStream, CharsetDecoder)
427     */
428    @TestTargetNew(
429        level = TestLevel.COMPLETE,
430        notes = "",
431        method = "InputStreamReader",
432        args = {java.io.InputStream.class, java.nio.charset.CharsetDecoder.class}
433    )
434    public void testInputStreamReaderInputStreamCharsetDecoder()
435            throws Exception {
436        CharsetDecoder decoder = Charset.forName("utf-8").newDecoder();
437        try {
438            reader = new InputStreamReader(null, decoder);
439            fail();
440        } catch (NullPointerException e) {
441        }
442        try {
443            reader = new InputStreamReader(in, (CharsetDecoder) null);
444            fail();
445        } catch (NullPointerException e) {
446        }
447        InputStreamReader reader2 = new InputStreamReader(in, decoder);
448        assertEquals(Charset.forName(reader2.getEncoding()), decoder.charset());
449        reader2.close();
450    }
451
452    /*
453     * Class under test for void InputStreamReader(InputStream, Charset)
454     */
455    @TestTargetNew(
456        level = TestLevel.COMPLETE,
457        notes = "",
458        method = "InputStreamReader",
459        args = {java.io.InputStream.class, java.nio.charset.Charset.class}
460    )
461    public void testInputStreamReaderInputStreamCharset() throws IOException {
462        Charset cs = Charset.forName("utf-8");
463        try {
464            reader = new InputStreamReader(null, cs);
465            fail();
466        } catch (NullPointerException e) {
467        }
468        try {
469            reader = new InputStreamReader(in, (Charset) null);
470            fail();
471        } catch (NullPointerException e) {
472        }
473        InputStreamReader reader2 = new InputStreamReader(in, cs);
474        assertEquals(Charset.forName(reader2.getEncoding()), cs);
475        reader2.close();
476    }
477    @TestTargetNew(
478        level = TestLevel.PARTIAL_COMPLETE,
479        notes = "",
480        method = "read",
481        args = {char[].class, int.class, int.class}
482    )
483    public void testInputStreamReaderSuccessiveReads() throws IOException {
484        byte[] data = new byte[8192 * 2];
485        Arrays.fill(data, (byte) 116); // 116 = ISO-8859-1 value for 't'
486        ByteArrayInputStream bis = new ByteArrayInputStream(data);
487        InputStreamReader isr = new InputStreamReader(bis, "ISO-8859-1");
488
489        // One less than the InputStreamReader.BUFFER_SIZE
490        char[] buf = new char[8191];
491        int bytesRead = isr.read(buf, 0, buf.length);
492        if (bytesRead == -1) {
493            throw new RuntimeException();
494        }
495        bytesRead = isr.read(buf, 0, buf.length);
496        if (bytesRead == -1) {
497            throw new RuntimeException();
498        }
499    }
500
501    /**
502     * @tests java.io.InputStreamReader#InputStreamReader(java.io.InputStream)
503     */
504    @TestTargetNew(
505        level = TestLevel.COMPLETE,
506        notes = "See setUp.",
507        method = "InputStreamReader",
508        args = {java.io.InputStream.class}
509    )
510    public void test_ConstructorLjava_io_InputStream() {
511        // Test for method java.io.InputStreamReader(java.io.InputStream)
512        assertTrue("Used to test other methods", true);
513    }
514
515    /**
516     * @tests java.io.InputStreamReader#InputStreamReader(java.io.InputStream,
517     *        java.lang.String)
518     */
519    @TestTargetNew(
520        level = TestLevel.COMPLETE,
521        notes = "Verifies InputStreamReader(java.io.InputStream) constructor.",
522        method = "InputStreamReader",
523        args = {java.io.InputStream.class}
524    )
525    public void test_ConstructorLjava_io_InputStreamLjava_lang_String() {
526        // Test for method java.io.InputStreamReader(java.io.InputStream,
527        // java.lang.String)
528        try {
529            is = new InputStreamReader(fis, "8859_1");
530        } catch (UnsupportedEncodingException e) {
531            fail("Unable to create input stream : " + e.getMessage());
532        }
533
534        try {
535            is = new InputStreamReader(fis, "Bogus");
536        } catch (UnsupportedEncodingException e) {
537            return;
538        }
539        fail("Failed to throw Unsupported Encoding exception");
540    }
541
542    /**
543     * @tests java.io.InputStreamReader#close()
544     */
545    @TestTargetNew(
546        level = TestLevel.PARTIAL_COMPLETE,
547        method = "close",
548        args = {}
549    )
550    public void test_close() {
551        // Test for method void java.io.InputStreamReader.close()
552        try {
553            is.close();
554        } catch (IOException e) {
555            fail("Failed to close reader : " + e.getMessage());
556        }
557        try {
558            is.read();
559            fail("Test 1: IOException expected.");
560        } catch (IOException e) {
561            // Exception means read failed due to close
562        }
563
564        is = new InputStreamReader(new Support_ASimpleInputStream(true));
565        try {
566            is.read();
567            fail("Test 2: IOException expected.");
568        } catch (IOException e) {
569            // Expected.
570        }
571
572    }
573
574    @TestTargetNew(
575            level = TestLevel.PARTIAL_COMPLETE,
576            method = "close",
577            args = {}
578    )
579    public void testClose() throws IOException {
580        reader.close();
581        try {
582            reader.ready();
583            fail("Should throw IOException");
584        } catch (IOException e) {
585        }
586        reader.close();
587    }
588
589    /**
590     * @tests java.io.InputStreamReader#getEncoding()
591     */
592    @TestTargetNew(
593        level = TestLevel.COMPLETE,
594        notes = "Verifies getEncoding() method.",
595        method = "getEncoding",
596        args = {}
597    )
598    public void test_getEncoding() {
599        // Test for method java.lang.String
600        // java.io.InputStreamReader.getEncoding()
601        try {
602            is = new InputStreamReader(fis, "8859_1");
603        } catch (UnsupportedEncodingException e) {
604            assertEquals("Returned incorrect encoding",
605                    "8859_1", is.getEncoding());
606        }
607    }
608
609    /**
610     * @tests java.io.InputStreamReader#read()
611     */
612    @TestTargetNew(
613        level = TestLevel.PARTIAL_COMPLETE,
614        notes = "",
615        method = "read",
616        args = {}
617    )
618    public void test_read() throws IOException{
619        // Test for method int java.io.InputStreamReader.read()
620        try {
621            int c = is.read();
622            assertTrue("returned incorrect char", (char) c == fileString
623                    .charAt(0));
624            InputStreamReader reader = new InputStreamReader(
625                    new ByteArrayInputStream(new byte[] { (byte) 0xe8,
626                            (byte) 0x9d, (byte) 0xa5 }), "UTF8");
627            assertTrue("wrong double byte char", reader.read() == '\u8765');
628        } catch (IOException e) {
629            fail("Exception during read test : " + e.getMessage());
630        }
631
632        // Regression for HARMONY-166
633        InputStream in;
634        InputStreamReader reader;
635
636        in = new LimitedByteArrayInputStream(0);
637        reader = new InputStreamReader(in, "UTF-16BE");
638        assertEquals("Incorrect byte UTF-16BE", '\u6172', reader.read());
639
640        in = new LimitedByteArrayInputStream(0);
641        reader = new InputStreamReader(in, "UTF-16LE");
642        assertEquals("Incorrect byte UTF-16BE", '\u7261', reader.read());
643
644        in = new LimitedByteArrayInputStream(1);
645        reader = new InputStreamReader(in, "UTF-16");
646        assertEquals("Incorrect byte UTF-16BE", '\u7261', reader.read());
647
648        in = new LimitedByteArrayInputStream(2);
649        reader = new InputStreamReader(in, "ISO2022JP");
650        assertEquals("Incorrect byte ISO2022JP 1", '\u4e5d', reader.read());
651        assertEquals("Incorrect byte ISO2022JP 2", '\u7b2c', reader.read());
652    }
653
654    /**
655     * @tests java.io.InputStreamReader#read(char[], int, int)
656     */
657    @TestTargetNew(
658        level = TestLevel.PARTIAL_COMPLETE,
659        notes = "",
660        method = "read",
661        args = {char[].class, int.class, int.class}
662    )
663     public void test_read$CII() {
664        // Test for method int java.io.InputStreamReader.read(char [], int, int)
665        try {
666            char[] rbuf = new char[100];
667            char[] sbuf = new char[100];
668            fileString.getChars(0, 100, sbuf, 0);
669            is.read(rbuf, 0, 100);
670            for (int i = 0; i < rbuf.length; i++)
671                assertTrue("returned incorrect chars", rbuf[i] == sbuf[i]);
672        } catch (IOException e) {
673            fail("Exception during read test : " + e.getMessage());
674        }
675    }
676
677    /**
678     * @tests java.io.InputStreamReader#ready()
679     */
680    @TestTargetNew(
681        level = TestLevel.PARTIAL_COMPLETE,
682        notes = "[No verification for empty buffer]",
683        method = "ready",
684        args = {}
685    )
686    public void test_ready() {
687        // Test for method boolean java.io.InputStreamReader.ready()
688        try {
689            assertTrue("Ready test failed", is.ready());
690            is.read();
691            assertTrue("More chars, but not ready", is.ready());
692        } catch (IOException e) {
693            fail("Exception during ready test : " + e.getMessage());
694        }
695    }
696
697    /**
698     * Test for regression of a bug that dropped characters when
699     * multibyte encodings spanned buffer boundaries.
700     */
701    @TestTargetNew(
702        level = TestLevel.PARTIAL_COMPLETE,
703        notes = "",
704        method = "read",
705        args = {}
706    )
707    public void test_readWhenCharacterSpansBuffer() {
708        final byte[] suffix = {
709            (byte) 0x93, (byte) 0xa1, (byte) 0x8c, (byte) 0xb4,
710            (byte) 0x97, (byte) 0x43, (byte) 0x88, (byte) 0xea,
711            (byte) 0x98, (byte) 0x59
712        };
713        final char[] decodedSuffix = {
714            (char) 0x85e4, (char) 0x539f, (char) 0x4f51, (char) 0x4e00,
715            (char) 0x90ce
716        };
717        final int prefixLength = 8189;
718
719        byte[] bytes = new byte[prefixLength + 10];
720        Arrays.fill(bytes, (byte) ' ');
721        System.arraycopy(suffix, 0, bytes, prefixLength, suffix.length);
722        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
723
724        try {
725            InputStreamReader isr = new InputStreamReader(is, "SHIFT_JIS");
726            char[] chars = new char[8192];
727            int at = 0;
728
729            for (;;) {
730                int amt = isr.read(chars);
731                if (amt <= 0) {
732                    break;
733                }
734
735                for (int i = 0; i < amt; i++) {
736                    char c = chars[i];
737                    if (at < prefixLength) {
738                        if (c != ' ') {
739                            fail("Found bad prefix character " +
740                                    (int) c + " at " + at);
741                        }
742                    } else {
743                        char decoded = decodedSuffix[at - prefixLength];
744                        if (c != decoded) {
745                            fail("Found mismatched character " +
746                                    (int) c + " at " + at);
747                        }
748                    }
749                    at++;
750                }
751            }
752        } catch (IOException ex) {
753            throw new RuntimeException("unexpected exception", ex);
754        }
755    }
756}
757