1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package tests.api.java.nio.charset;
17
18import java.io.UnsupportedEncodingException;
19import java.nio.ByteBuffer;
20import java.nio.CharBuffer;
21import java.nio.charset.CharacterCodingException;
22import java.nio.charset.Charset;
23import java.nio.charset.CharsetDecoder;
24import java.nio.charset.CoderResult;
25import java.nio.charset.CodingErrorAction;
26import java.nio.charset.MalformedInputException;
27import java.nio.charset.UnmappableCharacterException;
28
29import junit.framework.TestCase;
30
31/**
32 * API unit test for java.nio.CharsetDecoder
33 */
34public class CharsetDecoderTest extends TestCase {
35
36    protected static final int MAX_BYTES = 3;
37
38    protected static final double AVER_BYTES = 0.5;
39
40    // default charset
41    private static final Charset MOCKCS = new CharsetEncoderTest.MockCharset(
42            "mock", new String[0]);
43
44    Charset cs = MOCKCS;
45
46    // default decoder
47    protected static CharsetDecoder decoder;
48
49    String bom = "";
50
51    protected void setUp() throws Exception {
52        super.setUp();
53        decoder = cs.newDecoder();
54    }
55
56    protected void tearDown() throws Exception {
57        super.tearDown();
58    }
59
60    // FIXME: give up this tests
61    // /*
62    // * test default value
63    // */
64    // public void testDefaultCharsPerByte() {
65    // assertTrue(decoder.averageCharsPerByte() == AVER_BYTES);
66    // assertTrue(decoder.maxCharsPerByte() == MAX_BYTES);
67    // }
68
69    public void testDefaultValues() {
70        assertSame(cs, decoder.charset());
71        try {
72            decoder.detectedCharset();
73            fail("should unsupported");
74        } catch (UnsupportedOperationException e) {
75        }
76        try {
77            assertTrue(decoder.isCharsetDetected());
78            fail("should unsupported");
79        } catch (UnsupportedOperationException e) {
80        }
81        assertFalse(decoder.isAutoDetecting());
82        assertSame(CodingErrorAction.REPORT, decoder.malformedInputAction());
83        assertSame(CodingErrorAction.REPORT, decoder
84                .unmappableCharacterAction());
85        assertEquals(decoder.replacement(), "\ufffd");
86    }
87
88    /*
89     * test constructor
90     */
91    public void testCharsetDecoder() {
92        // default value
93        decoder = new MockCharsetDecoder(cs, (float) AVER_BYTES, MAX_BYTES);
94
95        // normal case
96        CharsetDecoder ec = new MockCharsetDecoder(cs, 1, MAX_BYTES);
97        assertSame(ec.charset(), cs);
98        assertEquals(1.0, ec.averageCharsPerByte(), 0.0);
99        assertTrue(ec.maxCharsPerByte() == MAX_BYTES);
100
101        /*
102         * ------------------------ Exceptional cases -------------------------
103         */
104        // Normal case: null charset
105        ec = new MockCharsetDecoder(null, 1, MAX_BYTES);
106        assertNull(ec.charset());
107        assertEquals(1.0, ec.averageCharsPerByte(), 0.0);
108        assertTrue(ec.maxCharsPerByte() == MAX_BYTES);
109
110        ec = new MockCharsetDecoder(new CharsetEncoderTest.MockCharset("mock",
111                new String[0]), 1, MAX_BYTES);
112
113        // Commented out since the comment is wrong since MAX_BYTES > 1
114        // // OK: average length less than max length
115        // ec = new MockCharsetDecoder(cs, MAX_BYTES, 1);
116        // assertTrue(ec.averageCharsPerByte() == MAX_BYTES);
117        // assertTrue(ec.maxCharsPerByte() == 1);
118
119        // Illegal Argument: zero length
120        try {
121            ec = new MockCharsetDecoder(cs, 0, MAX_BYTES);
122            fail("should throw IllegalArgumentException");
123        } catch (IllegalArgumentException e) {
124        }
125        try {
126            ec = new MockCharsetDecoder(cs, 1, 0);
127            fail("should throw IllegalArgumentException");
128        } catch (IllegalArgumentException e) {
129        }
130
131        // Illegal Argument: negative length
132        try {
133            ec = new MockCharsetDecoder(cs, -1, MAX_BYTES);
134            fail("should throw IllegalArgumentException");
135        } catch (IllegalArgumentException e) {
136        }
137        try {
138            ec = new MockCharsetDecoder(cs, 1, -1);
139            fail("should throw IllegalArgumentException");
140        } catch (IllegalArgumentException e) {
141        }
142    }
143
144    /*
145     * test onMalformedInput
146     */
147    public void testOnMalformedInput() {
148        assertSame(CodingErrorAction.REPORT, decoder.malformedInputAction());
149        try {
150            decoder.onMalformedInput(null);
151            fail("should throw null pointer exception");
152        } catch (IllegalArgumentException e) {
153        }
154        decoder.onMalformedInput(CodingErrorAction.IGNORE);
155        assertSame(CodingErrorAction.IGNORE, decoder.malformedInputAction());
156    }
157
158    /*
159     * test unmappableCharacter
160     */
161    public void testOnUnmappableCharacter() {
162        assertSame(CodingErrorAction.REPORT, decoder
163                .unmappableCharacterAction());
164        try {
165            decoder.onUnmappableCharacter(null);
166            fail("should throw null pointer exception");
167        } catch (IllegalArgumentException e) {
168        }
169        decoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
170        assertSame(CodingErrorAction.IGNORE, decoder
171                .unmappableCharacterAction());
172    }
173
174    /*
175     * test replaceWith
176     */
177    public void testReplaceWith() {
178        try {
179            decoder.replaceWith(null);
180            fail("should throw null pointer exception");
181        } catch (IllegalArgumentException e) {
182        }
183        try {
184            decoder.replaceWith("");
185            fail("should throw null pointer exception");
186        } catch (IllegalArgumentException e) {
187        }
188        try {
189            decoder.replaceWith("testReplaceWith");
190            fail("should throw illegal argument exception");
191        } catch (IllegalArgumentException e) {
192        }
193
194        decoder.replaceWith("a");
195        assertSame("a", decoder.replacement());
196    }
197
198    /*
199     * Class under test for CharBuffer decode(ByteBuffer)
200     */
201    public void testDecodeByteBuffer() throws CharacterCodingException {
202        implTestDecodeByteBuffer();
203    }
204
205    void implTestDecodeByteBuffer() throws CharacterCodingException {
206        // Null pointer
207        try {
208            decoder.decode(null);
209            fail("should throw null pointer exception");
210        } catch (NullPointerException e) {
211        }
212
213        // empty input buffer
214        CharBuffer out = decoder.decode(ByteBuffer.allocate(0));
215        assertCharBufferValue("", out);
216
217        // normal case
218        ByteBuffer in = getByteBuffer();
219        out = decoder.decode(in);
220        assertEquals(0, out.position());
221        assertEquals(getString().length(), out.limit());
222        assertEquals(getString().length(), out.remaining());
223        assertCharBufferValue(getString(), out);
224
225        // normal read only case
226        in = getByteBuffer().asReadOnlyBuffer();
227        out = decoder.decode(in);
228        assertEquals(out.position(), 0);
229        assertEquals(out.limit(), getString().length());
230        assertEquals(out.remaining(), getString().length());
231        assertCharBufferValue(getString(), out);
232    }
233
234    public void testDecodeByteBufferException()
235            throws CharacterCodingException, UnsupportedEncodingException {
236        CharBuffer out;
237        ByteBuffer in;
238        String replaceStr = decoder.replacement() + getString();
239
240        // MalformedException:
241        decoder.onMalformedInput(CodingErrorAction.REPORT);
242        decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
243        in = getMalformedByteBuffer();
244        if (in != null) {
245            try {
246                CharBuffer buffer = decoder.decode(in);
247                assertTrue(buffer.remaining() > 0);
248                fail("should throw MalformedInputException");
249            } catch (MalformedInputException e) {
250            }
251
252            decoder.reset();
253            in.rewind();
254            decoder.onMalformedInput(CodingErrorAction.IGNORE);
255            out = decoder.decode(in);
256            assertCharBufferValue(getString(), out);
257
258            decoder.reset();
259            in.rewind();
260            decoder.onMalformedInput(CodingErrorAction.REPLACE);
261            out = decoder.decode(in);
262            assertCharBufferValue(replaceStr, out);
263        }
264
265        // Unmapped Exception:
266        decoder.onMalformedInput(CodingErrorAction.REPORT);
267        decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
268        in = getUnmappedByteBuffer();
269        if (in != null) {
270            try {
271                decoder.decode(in);
272                fail("should throw UnmappableCharacterException");
273            } catch (UnmappableCharacterException e) {
274            }
275
276            decoder.reset();
277            in.rewind();
278            decoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
279            out = decoder.decode(in);
280            assertCharBufferValue(getString(), out);
281
282            decoder.reset();
283            in.rewind();
284            decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
285            out = decoder.decode(in);
286            assertCharBufferValue(replaceStr, out);
287        }
288
289        // RuntimeException
290        try {
291            decoder.decode(getExceptionByteArray());
292            fail("should throw runtime exception");
293        } catch (RuntimeException e) {
294        }
295    }
296
297    /*
298     * Class under test for CoderResult decode(ByteBuffer, CharBuffer, boolean)
299     */
300    public void testDecodeByteBufferCharBuffer() {
301        implTestDecodeByteBufferCharBuffer(getByteBuffer());
302    }
303
304    public void testDecodeByteBufferCharBufferReadOnly() {
305        implTestDecodeByteBufferCharBuffer(getByteBuffer());
306    }
307
308    void implTestDecodeByteBufferCharBuffer(ByteBuffer in) {
309        CharBuffer out = CharBuffer.allocate(100);
310
311        // Null pointer
312        decoder.reset();
313        try {
314            decoder.decode(null, out, true);
315            fail("NullPointerException expected");
316        } catch (NullPointerException e) {
317        }
318        try {
319            decoder.decode(in, null, true);
320            fail("NullPointerException expected");
321        } catch (NullPointerException e) {
322        }
323
324        // normal case, one complete operation
325        decoder.reset();
326        in.rewind();
327        out.rewind();
328        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, true));
329        assertEquals(out.limit(), 100);
330        assertEquals(out.position(), getString().length());
331        assertEquals(out.remaining(), 100 - getString().length());
332        assertEquals(out.capacity(), 100);
333        assertCharBufferValue(getString(), out);
334        decoder.flush(out);
335
336        // normal case, one complete operation, but call twice, first time set
337        // endOfInput to false
338        decoder.reset();
339        in.rewind();
340        out.clear();
341        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, false));
342        assertEquals(out.limit(), 100);
343        assertEquals(out.position(), getString().length());
344        assertEquals(out.remaining(), 100 - getString().length());
345        assertEquals(out.capacity(), 100);
346        assertCharBufferValue(getString(), out);
347
348        decoder.reset();
349        in.rewind();
350        out.clear();
351        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, false));
352        in = getHeadlessByteBuffer();
353        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, false));
354        in.rewind();
355        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, true));
356        assertEquals(out.limit(), 100);
357        assertTrue(out.position() > 0);
358        assertEquals(out.remaining(), out.capacity() - out.position());
359        assertEquals(out.capacity(), 100);
360        assertCharBufferValue(getString() + getString() + getString(), out);
361
362        // overflow
363        out = CharBuffer.allocate(4);
364        decoder.reset();
365        in = getByteBuffer();
366        out.rewind();
367        assertSame(CoderResult.OVERFLOW, decoder.decode(in, out, false));
368
369        assertCharBufferValue(getString().substring(0, 4), out);
370        out = CharBuffer.allocate(100);
371        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, false));
372        assertCharBufferValue(getString().substring(4), out);
373        in.rewind();
374        out = CharBuffer.allocate(100);
375        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, true));
376        assertCharBufferValue(bom + getString(), out);
377    }
378
379    public void testDecodeCharBufferByteBufferUnmappedException()
380            throws CharacterCodingException, UnsupportedEncodingException {
381        implTestDecodeCharBufferByteBufferUnmappedException(
382                getUnmappedByteBuffer(), true);
383    }
384
385    public void testDecodeCharBufferByteIncompleteBufferUnmappedException()
386            throws CharacterCodingException, UnsupportedEncodingException {
387        implTestDecodeCharBufferByteBufferUnmappedException(
388                getUnmappedByteBuffer(), false);
389    }
390
391    public void testDecodeCharBufferByteReadOnlyBufferUnmappedException()
392            throws CharacterCodingException, UnsupportedEncodingException {
393        implTestDecodeCharBufferByteBufferUnmappedException(
394                readOnly(getUnmappedByteBuffer()), true);
395    }
396
397    public void testDecodeCharBufferByteReadOnlyIncompleteBufferUnmappedException()
398            throws CharacterCodingException, UnsupportedEncodingException {
399        implTestDecodeCharBufferByteBufferUnmappedException(
400                readOnly(getUnmappedByteBuffer()), false);
401    }
402
403    void implTestDecodeCharBufferByteBufferUnmappedException(ByteBuffer in,
404            boolean endOfInput) throws CharacterCodingException,
405            UnsupportedEncodingException {
406        if (null == in) {
407            return;
408        }
409        CharBuffer out = CharBuffer.allocate(50);
410
411        decoder.onMalformedInput(CodingErrorAction.REPORT);
412        decoder.reset();
413        decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
414        CoderResult result = decoder.decode(in, out, endOfInput);
415        assertTrue(result.isUnmappable());
416
417        decoder.reset();
418        out.clear();
419        in.rewind();
420        decoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
421        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, endOfInput));
422        assertCharBufferValue(getString(), out);
423
424        decoder.reset();
425        out.clear();
426        in.rewind();
427        decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
428        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, endOfInput));
429        assertCharBufferValue(decoder.replacement() + getString(), out);
430    }
431
432    public void testDecodeCharBufferByteBufferMalformedException()
433            throws CharacterCodingException, UnsupportedEncodingException {
434        implTestDecodeCharBufferByteBufferMalformedException(
435                getMalformedByteBuffer(), true);
436    }
437
438    public void testDecodeCharBufferByteIncompleteBufferMalformedException()
439            throws CharacterCodingException, UnsupportedEncodingException {
440
441        implTestDecodeCharBufferByteBufferMalformedException(
442                getMalformedByteBuffer(), false);
443    }
444
445    public void testDecodeCharBufferByteReadOnlyBufferMalformedException()
446            throws CharacterCodingException, UnsupportedEncodingException {
447        implTestDecodeCharBufferByteBufferMalformedException(
448                readOnly(getMalformedByteBuffer()), true);
449    }
450
451    public void testDecodeCharBufferByteReadOnlyIncompleteBufferMalformedException()
452            throws CharacterCodingException, UnsupportedEncodingException {
453        implTestDecodeCharBufferByteBufferMalformedException(
454                readOnly(getMalformedByteBuffer()), false);
455    }
456
457    void implTestDecodeCharBufferByteBufferMalformedException(ByteBuffer in,
458            boolean endOfInput) throws CharacterCodingException,
459            UnsupportedEncodingException {
460        if (null == in) {
461            return;
462        }
463        CharBuffer out = CharBuffer.allocate(getString().length() * 3);
464        decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
465        decoder.reset();
466        decoder.onMalformedInput(CodingErrorAction.REPORT);
467        CoderResult result = decoder.decode(in, out, endOfInput);
468        assertTrue(result.isMalformed());
469
470        decoder.reset();
471        out.clear();
472        in.rewind();
473        decoder.onMalformedInput(CodingErrorAction.IGNORE);
474        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, endOfInput));
475        assertCharBufferValue(getString(), out);
476
477        decoder.reset();
478        out.clear();
479        in.rewind();
480        decoder.onMalformedInput(CodingErrorAction.REPLACE);
481        assertSame(CoderResult.UNDERFLOW, decoder.decode(in, out, endOfInput));
482        assertCharBufferValue(decoder.replacement() + getString(), out);
483    }
484
485    public void testDecodeCharBufferByteBufferException()
486            throws CharacterCodingException, UnsupportedEncodingException {
487        implTestDecodeCharBufferByteBufferException(getExceptionByteArray(),
488                true);
489    }
490
491    public void testDecodeCharBufferByteIncompleteBufferException()
492            throws CharacterCodingException, UnsupportedEncodingException {
493        implTestDecodeCharBufferByteBufferException(getExceptionByteArray(),
494                false);
495    }
496
497    public void testDecodeCharBufferByteReadOnlyBufferException()
498            throws CharacterCodingException, UnsupportedEncodingException {
499        implTestDecodeCharBufferByteBufferException(
500                readOnly(getExceptionByteArray()), true);
501    }
502
503    public void testDecodeCharBufferByteReadOnlyIncompleteBufferException()
504            throws CharacterCodingException, UnsupportedEncodingException {
505        implTestDecodeCharBufferByteBufferException(
506                readOnly(getExceptionByteArray()), false);
507    }
508
509    void implTestDecodeCharBufferByteBufferException(ByteBuffer in,
510            boolean endOfInput) throws CharacterCodingException,
511            UnsupportedEncodingException {
512        CharBuffer out = CharBuffer.allocate(50);
513        decoder.reset();
514        try {
515            decoder.decode(in, out, endOfInput);
516            fail("should throw runtime exception");
517        } catch (RuntimeException e) {
518        }
519    }
520
521    private ByteBuffer readOnly(ByteBuffer b) {
522        if (null == b) {
523            return null;
524        }
525        return b.asReadOnlyBuffer();
526    }
527
528    protected String getString() {
529        return " buffer";
530    }
531
532    protected ByteBuffer getByteBuffer() {
533        return ByteBuffer.wrap(new byte[] { 32, 98, 117, 102, 102, 101, 114 });
534    }
535
536    protected ByteBuffer getHeadlessByteBuffer() {
537        return getByteBuffer();
538    }
539
540    ByteBuffer getExceptionByteArray() throws UnsupportedEncodingException {
541        // "runtime"
542        return ByteBuffer
543                .wrap(new byte[] { 114, 117, 110, 116, 105, 109, 101 });
544    }
545
546    ByteBuffer getUnmappedByteBuffer() throws UnsupportedEncodingException {
547        // "unmap buffer"
548        byte[] ba = new byte[] { 117, 110, 109, 97, 112, 32, 98, 117, 102, 102,
549                101, 114 };
550        return ByteBuffer.wrap(ba);
551    }
552
553    ByteBuffer getMalformedByteBuffer() throws UnsupportedEncodingException {
554        // "malform buffer"
555        byte[] ba = new byte[] { 109, 97, 108, 102, 111, 114, 109, 32, 98, 117,
556                102, 102, 101, 114 };
557        return ByteBuffer.wrap(ba);
558    }
559
560    private void assertCharBufferValue(String expected, CharBuffer out) {
561        if (out.position() != 0) {
562            out.flip();
563        }
564        assertEquals(expected, new String(out.array(), out.arrayOffset(), out
565                .arrayOffset() + out.limit()));
566    }
567
568    /*
569     * test flush
570     */
571    public void testFlush() throws CharacterCodingException {
572        CharBuffer out = CharBuffer.allocate(10);
573        ByteBuffer in = ByteBuffer.wrap(new byte[] { 12, 12 });
574        decoder.decode(in, out, true);
575        assertSame(CoderResult.UNDERFLOW, decoder.flush(out));
576
577        decoder.reset();
578        decoder.decode((ByteBuffer) in.rewind(), (CharBuffer) out.rewind(),
579                true);
580        assertSame(CoderResult.UNDERFLOW, decoder
581                .flush(CharBuffer.allocate(10)));
582    }
583
584    /*
585     * ---------------------------------- methods to test illegal state
586     * -----------------------------------
587     */
588    // Normal case: just after reset, and it also means reset can be done
589    // anywhere
590    public void testResetIllegalState() throws CharacterCodingException {
591        decoder.reset();
592        decoder.decode(getByteBuffer());
593        decoder.reset();
594        decoder.decode(getByteBuffer(), CharBuffer.allocate(3), false);
595        decoder.reset();
596        decoder.decode(getByteBuffer(), CharBuffer.allocate(3), true);
597        decoder.reset();
598    }
599
600    public void testFlushIllegalState() throws CharacterCodingException {
601        ByteBuffer in = ByteBuffer.wrap(new byte[] { 98, 98 });
602        CharBuffer out = CharBuffer.allocate(5);
603
604        // Illegal state: after reset.
605        decoder.reset();
606        try {
607            decoder.flush(out);
608            fail();
609        } catch (IllegalStateException expected) {
610        }
611
612        // Normal case: after decode with endOfInput is true
613        decoder.reset();
614        decoder.decode(in, out, true);
615        out.rewind();
616        CoderResult result = decoder.flush(out);
617        assertSame(result, CoderResult.UNDERFLOW);
618
619        // Good state: flush twice
620        decoder.flush(out);
621
622        // Illegal state: flush after decode with endOfInput is false
623        decoder.reset();
624        decoder.decode(in, out, false);
625        try {
626            decoder.flush(out);
627            fail();
628        } catch (IllegalStateException expected) {
629        }
630    }
631
632    // test illegal states for decode facade
633    public void testDecodeFacadeIllegalState() throws CharacterCodingException {
634        // decode facade can be execute in anywhere
635        ByteBuffer in = getByteBuffer();
636
637        // Normal case: just created
638        decoder.decode(in);
639        in.rewind();
640
641        // Normal case: just after decode facade
642        decoder.decode(in);
643        in.rewind();
644
645        // Normal case: just after decode with that endOfInput is true
646        decoder.reset();
647        decoder.decode(getByteBuffer(), CharBuffer.allocate(30), true);
648        decoder.decode(in);
649        in.rewind();
650
651        // Normal case:just after decode with that endOfInput is false
652        decoder.reset();
653        decoder.decode(getByteBuffer(), CharBuffer.allocate(30), false);
654        decoder.decode(in);
655        in.rewind();
656
657        // Normal case: just after flush
658        decoder.reset();
659        decoder.decode(getByteBuffer(), CharBuffer.allocate(30), true);
660        decoder.flush(CharBuffer.allocate(10));
661        decoder.decode(in);
662        in.rewind();
663    }
664
665    // test illegal states for two decode method with endOfInput is true
666    public void testDecodeTrueIllegalState() throws CharacterCodingException {
667        ByteBuffer in = ByteBuffer.wrap(new byte[] { 98, 98 });
668        CharBuffer out = CharBuffer.allocate(100);
669        // Normal case: just created
670        decoder.decode(in, out, true);
671        in.rewind();
672        out.rewind();
673
674        // Normal case: just after decode with that endOfInput is true
675        decoder.reset();
676        decoder.decode(in, CharBuffer.allocate(30), true);
677        in.rewind();
678        decoder.decode(in, out, true);
679        in.rewind();
680        out.rewind();
681
682        // Normal case:just after decode with that endOfInput is false
683        decoder.reset();
684        decoder.decode(in, CharBuffer.allocate(30), false);
685        in.rewind();
686        decoder.decode(in, out, true);
687        in.rewind();
688        out.rewind();
689
690        // Illegal state: just after flush
691        decoder.reset();
692        decoder.decode(in, CharBuffer.allocate(30), true);
693        decoder.flush(CharBuffer.allocate(10));
694        in.rewind();
695        try {
696            decoder.decode(in, out, true);
697            fail("should illegal state");
698        } catch (IllegalStateException e) {
699        }
700        in.rewind();
701        out.rewind();
702
703    }
704
705    // test illegal states for two decode method with endOfInput is false
706    public void testDecodeFalseIllegalState() throws CharacterCodingException {
707        ByteBuffer in = ByteBuffer.wrap(new byte[] { 98, 98 });
708        CharBuffer out = CharBuffer.allocate(5);
709        // Normal case: just created
710        decoder.decode(in, out, false);
711        in.rewind();
712        out.rewind();
713
714        // Illegal state: just after decode facade
715        decoder.reset();
716        decoder.decode(in);
717        in.rewind();
718        try {
719            decoder.decode(in, out, false);
720            fail("should illegal state");
721        } catch (IllegalStateException e) {
722        }
723        in.rewind();
724        out.rewind();
725
726        // Illegal state: just after decode with that endOfInput is true
727        decoder.reset();
728        decoder.decode(in, CharBuffer.allocate(30), true);
729        in.rewind();
730        try {
731            decoder.decode(in, out, false);
732            fail("should illegal state");
733        } catch (IllegalStateException e) {
734        }
735        in.rewind();
736        out.rewind();
737
738        // Normal case:just after decode with that endOfInput is false
739        decoder.reset();
740        decoder.decode(in, CharBuffer.allocate(30), false);
741        in.rewind();
742        decoder.decode(in, out, false);
743        in.rewind();
744        out.rewind();
745
746        // Illegal state: just after flush
747        decoder.reset();
748        decoder.decode(in, CharBuffer.allocate(30), true);
749        in.rewind();
750        decoder.flush(CharBuffer.allocate(10));
751        try {
752            decoder.decode(in, out, false);
753            fail("should illegal state");
754        } catch (IllegalStateException e) {
755        }
756    }
757
758    /*
759     * --------------------------------- illegal state test end
760     * ---------------------------------
761     */
762
763    public void testImplFlush() {
764        decoder = new MockCharsetDecoder(cs, 1, 3);
765        assertEquals(CoderResult.UNDERFLOW, ((MockCharsetDecoder) decoder)
766                .pubImplFlush(null));
767    }
768
769    public void testImplOnMalformedInput() {
770        decoder = new MockCharsetDecoder(cs, 1, 3);
771        assertEquals(CoderResult.UNDERFLOW, ((MockCharsetDecoder) decoder)
772                .pubImplFlush(null));
773
774    }
775
776    public void testImplOnUnmappableCharacter() {
777        decoder = new MockCharsetDecoder(cs, 1, 3);
778        ((MockCharsetDecoder) decoder).pubImplOnUnmappableCharacter(null);
779    }
780
781    public void testImplReplaceWith() {
782        decoder = new MockCharsetDecoder(cs, 1, 3);
783        ((MockCharsetDecoder) decoder).pubImplReplaceWith(null);
784    }
785
786    public void testImplReset() {
787        decoder = new MockCharsetDecoder(cs, 1, 3);
788        ((MockCharsetDecoder) decoder).pubImplReset();
789    }
790
791    /*
792     * mock decoder
793     */
794    public static class MockCharsetDecoder extends CharsetDecoder {
795        public MockCharsetDecoder(Charset cs, float ave, float max) {
796            super(cs, ave, max);
797        }
798
799        protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
800            int inPosition = in.position();
801            byte[] input = new byte[in.remaining()];
802            in.get(input);
803            String result;
804            try {
805                result = new String(input, "UTF-8");
806            } catch (UnsupportedEncodingException e) {
807                throw new AssertionError(e);
808            }
809            if (result.startsWith("malform")) {
810                // reset the cursor to the error position
811                in.position(inPosition);
812                // set the error length
813                return CoderResult.malformedForLength("malform".length());
814            } else if (result.startsWith("unmap")) {
815                // reset the cursor to the error position
816                in.position(inPosition);
817                // set the error length
818                return CoderResult.unmappableForLength("unmap".length());
819            } else if (result.startsWith("runtime")) {
820                // reset the cursor to the error position
821                in.position(0);
822                // set the error length
823                throw new RuntimeException("runtime");
824            }
825            int inLeft = input.length;
826            int outLeft = out.remaining();
827            CoderResult r = CoderResult.UNDERFLOW;
828            int length = inLeft;
829            if (outLeft < inLeft) {
830                r = CoderResult.OVERFLOW;
831                length = outLeft;
832                in.position(inPosition + outLeft);
833            }
834            for (int i = 0; i < length; i++) {
835                out.put((char) input[i]);
836            }
837            return r;
838        }
839
840        protected CoderResult implFlush(CharBuffer out) {
841            CoderResult result = super.implFlush(out);
842            if (out.remaining() >= 5) {
843                // TODO
844                // out.put("flush");
845                result = CoderResult.UNDERFLOW;
846            } else {
847                // out.put("flush", 0, out.remaining());
848                result = CoderResult.OVERFLOW;
849            }
850            return result;
851        }
852
853        public CoderResult pubImplFlush(CharBuffer out) {
854            return super.implFlush(out);
855        }
856
857        public void pubImplOnMalformedInput(CodingErrorAction newAction) {
858            super.implOnMalformedInput(newAction);
859        }
860
861        public void pubImplOnUnmappableCharacter(CodingErrorAction newAction) {
862            super.implOnUnmappableCharacter(newAction);
863        }
864
865        public void pubImplReplaceWith(String newReplacement) {
866            super.implReplaceWith(newReplacement);
867        }
868
869        public void pubImplReset() {
870            super.implReset();
871        }
872
873    }
874
875}
876