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 dalvik.annotation.TestTargetClass;
19import dalvik.annotation.TestTargets;
20import dalvik.annotation.TestTargetNew;
21import dalvik.annotation.TestLevel;
22
23import java.nio.ByteBuffer;
24import java.nio.CharBuffer;
25import java.nio.charset.CharacterCodingException;
26import java.nio.charset.Charset;
27import java.nio.charset.CharsetDecoder;
28import java.nio.charset.CharsetEncoder;
29import java.nio.charset.CoderResult;
30import java.nio.charset.CodingErrorAction;
31import java.nio.charset.MalformedInputException;
32import java.nio.charset.UnmappableCharacterException;
33import java.nio.charset.UnsupportedCharsetException;
34import java.util.Arrays;
35
36import junit.framework.TestCase;
37
38@TestTargetClass(CharsetEncoder.class)
39
40/**
41 * Super class for concrete charset test suites.
42 */
43public class AbstractCharsetEncoderTestCase extends TestCase {
44
45    Charset cs;
46
47    // Target encoder (tobj):
48    CharsetEncoder encoder;
49
50    static final String unistr = " buffer";// \u8000\u8001\u00a5\u3000\r\n";
51
52    byte[] unibytes = new byte[] { 32, 98, 117, 102, 102, 101, 114 };
53
54
55    // default for Charset abstract class
56    byte[] defaultReplacement = new byte[] { 63 };
57
58    // specific for Charset implementation subclass
59    byte[] specifiedReplacement = new byte[] { 26 };
60
61    byte[] unibytesWithRep = null;
62
63    byte[] surrogate = new byte[0];
64
65
66    protected void setUp() throws Exception {
67        super.setUp();
68        encoder = cs.newEncoder();
69        if (null == unibytesWithRep) {
70            byte[] replacement = encoder.replacement();
71            unibytesWithRep = new byte[replacement.length + unibytes.length];
72            System.arraycopy(replacement, 0, unibytesWithRep, 0,
73                    replacement.length);
74            System.arraycopy(unibytes, 0, unibytesWithRep, replacement.length,
75                    unibytes.length);
76        }
77    }
78
79    protected void tearDown() throws Exception {
80        super.tearDown();
81    }
82
83
84    /*
85     * Class under test for boolean canEncode(char)
86     */
87    @TestTargetNew(
88        level = TestLevel.PARTIAL_COMPLETE,
89        method = "canEncode",
90        args = {char.class}
91    )
92    public void testCanEncodechar() throws CharacterCodingException {
93        // for non-mapped char
94        assertTrue(encoder.canEncode('\uc2c0'));
95        // surrogate char for unicode
96        // 1st byte: d800-dbff
97        // 2nd byte: dc00-dfff
98        assertTrue(encoder.canEncode('\ud800'));
99        // valid surrogate pair
100        assertTrue(encoder.canEncode('\udc00'));
101    }
102
103    /*-----------------------------------------
104     * Class under test for illegal state case
105     * methods which can change internal states are two encode, flush, two canEncode, reset
106     * -----------------------------------------
107     */
108
109    // Normal case: just after reset, and it also means reset can be done
110    // anywhere
111    @TestTargets({
112        @TestTargetNew(
113            level = TestLevel.PARTIAL_COMPLETE,
114            method = "canEncode",
115            args = {char.class}
116        ),
117        @TestTargetNew(
118            level = TestLevel.PARTIAL_COMPLETE,
119            method = "canEncode",
120            args = {java.lang.CharSequence.class}
121        ),
122        @TestTargetNew(
123            level = TestLevel.PARTIAL_COMPLETE,
124            method = "encode",
125            args = {java.nio.CharBuffer.class}
126        ),
127        @TestTargetNew(
128            level = TestLevel.PARTIAL_COMPLETE,
129            method = "encode",
130            args = {java.nio.CharBuffer.class, java.nio.ByteBuffer.class, boolean.class}
131        ),
132        @TestTargetNew(
133            level = TestLevel.PARTIAL_COMPLETE,
134            method = "reset",
135            args = {}
136        )
137    })
138    public void testResetIllegalState() throws CharacterCodingException {
139        assertSame(encoder, encoder.reset());
140        encoder.canEncode('\ud901');
141        assertSame(encoder, encoder.reset());
142        encoder.canEncode("\ud901\udc00");
143        assertSame(encoder, encoder.reset());
144        encoder.encode(CharBuffer.wrap("aaa"));
145        assertSame(encoder, encoder.reset());
146        encoder.encode(CharBuffer.wrap("aaa"), ByteBuffer.allocate(3), false);
147        assertSame(encoder, encoder.reset());
148        encoder.encode(CharBuffer.wrap("aaa"), ByteBuffer.allocate(3), true);
149        assertSame(encoder, encoder.reset());
150    }
151
152    @TestTargets({
153        @TestTargetNew(
154            level = TestLevel.PARTIAL_COMPLETE,
155            method = "reset",
156            args = {}
157        ),
158        @TestTargetNew(
159            level = TestLevel.PARTIAL_COMPLETE,
160            method = "flush",
161            args = {java.nio.ByteBuffer.class}
162        )
163    })
164    public void testFlushIllegalState() throws CharacterCodingException {
165        CharBuffer in = CharBuffer.wrap("aaa");
166        ByteBuffer out = ByteBuffer.allocate(5);
167
168        // Normal case: after encode with endOfInput is true
169        assertSame(encoder, encoder.reset());
170        encoder.encode(in, out, true);
171        out.rewind();
172        CoderResult result = encoder.flush(out);
173
174        // Illegal state: flush twice
175        try {
176            encoder.flush(out);
177            fail("should throw IllegalStateException");
178        } catch (IllegalStateException e) {
179        }
180
181        // Illegal state: flush after encode with endOfInput is false
182        assertSame(encoder, encoder.reset());
183        encoder.encode(in, out, false);
184        try {
185            encoder.flush(out);
186            fail("should throw IllegalStateException");
187        } catch (IllegalStateException e) {
188        }
189    }
190
191    // test illegal states for encode facade
192    @TestTargets({
193        @TestTargetNew(
194            level = TestLevel.PARTIAL_COMPLETE,
195            method = "encode",
196            args = {java.nio.CharBuffer.class}
197        ),
198        @TestTargetNew(
199            level = TestLevel.PARTIAL_COMPLETE,
200            method = "canEncode",
201            args = {char.class}
202        ),
203        @TestTargetNew(
204            level = TestLevel.PARTIAL_COMPLETE,
205            method = "canEncode",
206            args = {java.lang.CharSequence.class}
207        ),
208        @TestTargetNew(
209            level = TestLevel.PARTIAL_COMPLETE,
210            method = "encode",
211            args = {java.nio.CharBuffer.class, java.nio.ByteBuffer.class, boolean.class}
212        ),
213        @TestTargetNew(
214            level = TestLevel.PARTIAL_COMPLETE,
215            method = "flush",
216            args = {java.nio.ByteBuffer.class}
217        )
218    })
219    public void testEncodeFacadeIllegalState() throws CharacterCodingException {
220        // encode facade can be execute in anywhere
221        CharBuffer in = CharBuffer.wrap("aaa");
222        // Normal case: just created
223        encoder.encode(in);
224        in.rewind();
225
226        // Normal case: just after encode facade
227        encoder.encode(in);
228        in.rewind();
229
230        // Normal case: just after canEncode
231        assertSame(encoder, encoder.reset());
232        encoder.canEncode("\ud902\udc00");
233        encoder.encode(in);
234        in.rewind();
235        assertSame(encoder, encoder.reset());
236        encoder.canEncode('\ud902');
237        encoder.encode(in);
238        in.rewind();
239
240        // Normal case: just after encode with that endOfInput is true
241        assertSame(encoder, encoder.reset());
242        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState2"),
243                ByteBuffer.allocate(30), true);
244        encoder.encode(in);
245        in.rewind();
246
247        // Normal case:just after encode with that endOfInput is false
248        assertSame(encoder, encoder.reset());
249        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState3"),
250                ByteBuffer.allocate(30), false);
251        encoder.encode(in);
252        in.rewind();
253
254        // Normal case: just after flush
255        assertSame(encoder, encoder.reset());
256        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState4"),
257                ByteBuffer.allocate(30), true);
258        encoder.flush(ByteBuffer.allocate(10));
259        encoder.encode(in);
260        in.rewind();
261    }
262
263    // test illegal states for two encode method with endOfInput is true
264    @TestTargets({
265        @TestTargetNew(
266            level = TestLevel.PARTIAL_COMPLETE,
267            method = "encode",
268            args = {java.nio.CharBuffer.class, java.nio.ByteBuffer.class, boolean.class}
269        ),
270        @TestTargetNew(
271            level = TestLevel.PARTIAL_COMPLETE,
272            method = "canEncode",
273            args = {char.class}
274        ),
275        @TestTargetNew(
276            level = TestLevel.PARTIAL_COMPLETE,
277            method = "canEncode",
278            args = {java.lang.CharSequence.class}
279        ),
280        @TestTargetNew(
281            level = TestLevel.PARTIAL_COMPLETE,
282            method = "reset",
283            args = {}
284        ),
285        @TestTargetNew(
286            level = TestLevel.PARTIAL_COMPLETE,
287            method = "flush",
288            args = {java.nio.ByteBuffer.class}
289        )
290    })
291    public void testEncodeTrueIllegalState() throws CharacterCodingException {
292        CharBuffer in = CharBuffer.wrap("aaa");
293        ByteBuffer out = ByteBuffer.allocate(5);
294        // Normal case: just created
295        encoder.encode(in, out, true);
296        in.rewind();
297        out.rewind();
298
299        in.rewind();
300        out.rewind();
301
302        // Normal case: just after encode with that endOfInput is true
303        assertSame(encoder, encoder.reset());
304        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState2"),
305                ByteBuffer.allocate(30), true);
306        encoder.encode(in, out, true);
307        in.rewind();
308        out.rewind();
309
310        // Normal case:just after encode with that endOfInput is false
311        assertSame(encoder, encoder.reset());
312        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState3"),
313                ByteBuffer.allocate(30), false);
314        encoder.encode(in, out, true);
315        in.rewind();
316        out.rewind();
317
318        // Illegal state: just after flush
319        assertSame(encoder, encoder.reset());
320        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState4"),
321                ByteBuffer.allocate(30), true);
322        encoder.flush(ByteBuffer.allocate(10));
323        try {
324            encoder.encode(in, out, true);
325            fail("should illegal state");
326        } catch (IllegalStateException e) {
327        }
328
329        // Normal case: after canEncode
330        assertSame(encoder, encoder.reset());
331        encoder.canEncode("\ud906\udc00");
332        encoder.encode(in, out, true);
333        in.rewind();
334        out.rewind();
335        assertSame(encoder, encoder.reset());
336        encoder.canEncode('\ud905');
337        encoder.encode(in, out, true);
338    }
339
340    // test illegal states for two encode method with endOfInput is false
341    @TestTargets({
342        @TestTargetNew(
343            level = TestLevel.PARTIAL_COMPLETE,
344            method = "encode",
345            args = {java.nio.CharBuffer.class, java.nio.ByteBuffer.class, boolean.class}
346        ),
347        @TestTargetNew(
348            level = TestLevel.PARTIAL_COMPLETE,
349            method = "encode",
350            args = {java.nio.CharBuffer.class}
351        ),
352        @TestTargetNew(
353            level = TestLevel.PARTIAL_COMPLETE,
354            method = "canEncode",
355            args = {char.class}
356        ),
357        @TestTargetNew(
358            level = TestLevel.PARTIAL_COMPLETE,
359            method = "canEncode",
360            args = {java.lang.CharSequence.class}
361        ),
362        @TestTargetNew(
363            level = TestLevel.PARTIAL_COMPLETE,
364            method = "reset",
365            args = {}
366        ),
367        @TestTargetNew(
368            level = TestLevel.PARTIAL_COMPLETE,
369            method = "flush",
370            args = {java.nio.ByteBuffer.class}
371        )
372    })
373    public void testEncodeFalseIllegalState() throws CharacterCodingException {
374        CharBuffer in = CharBuffer.wrap("aaa");
375        ByteBuffer out = ByteBuffer.allocate(5);
376        // Normal case: just created
377        encoder.encode(in, out, false);
378        in.rewind();
379        out.rewind();
380
381        // Illegal state: just after encode facade
382        assertSame(encoder, encoder.reset());
383        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState1"));
384        try {
385            encoder.encode(in, out, false);
386            fail("should illegal state");
387        } catch (IllegalStateException e) {
388        }
389
390        // Illegal state: just after encode with that endOfInput is true
391        assertSame(encoder, encoder.reset());
392        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState2"),
393                ByteBuffer.allocate(30), true);
394        try {
395            encoder.encode(in, out, false);
396            fail("should illegal state");
397        } catch (IllegalStateException e) {
398        }
399
400        // Normal case:just after encode with that endOfInput is false
401        assertSame(encoder, encoder.reset());
402        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState3"),
403                ByteBuffer.allocate(30), false);
404        encoder.encode(in, out, false);
405        in.rewind();
406        out.rewind();
407
408        // Illegal state: just after flush
409        assertSame(encoder, encoder.reset());
410        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState4"),
411                ByteBuffer.allocate(30), true);
412        encoder.flush(ByteBuffer.allocate(10));
413        try {
414            encoder.encode(in, out, false);
415            fail("should illegal state");
416        } catch (IllegalStateException e) {
417        }
418
419        // Normal case: after canEncode
420        assertSame(encoder, encoder.reset());
421        encoder.canEncode("\ud906\udc00");
422        encoder.encode(in, out, false);
423        in.rewind();
424        out.rewind();
425        assertSame(encoder, encoder.reset());
426        encoder.canEncode('\ud905');
427        encoder.encode(in, out, false);
428    }
429
430    // test illegal states for two canEncode methods
431    @TestTargets({
432        @TestTargetNew(
433            level = TestLevel.PARTIAL_COMPLETE,
434            method = "canEncode",
435            args = {char.class}
436        ),
437        @TestTargetNew(
438            level = TestLevel.PARTIAL_COMPLETE,
439            method = "canEncode",
440            args = {java.lang.CharSequence.class}
441        ),
442        @TestTargetNew(
443            level = TestLevel.PARTIAL_COMPLETE,
444            method = "reset",
445            args = {}
446        ),
447        @TestTargetNew(
448            level = TestLevel.PARTIAL_COMPLETE,
449            method = "flush",
450            args = {java.nio.ByteBuffer.class}
451        )
452    })
453    public void testCanEncodeIllegalState() throws CharacterCodingException {
454        // Normal case: just created
455        encoder.canEncode("\ud900\udc00");
456        encoder.canEncode('\ud900');
457
458        // Illegal state: just after encode with that endOfInput is true
459        assertSame(encoder, encoder.reset());
460        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState2"),
461                ByteBuffer.allocate(30), true);
462        try {
463            encoder.canEncode("\ud903\udc00");
464            fail("should throw illegal state exception");
465        } catch (IllegalStateException e) {
466        }
467
468        // Illegal state:just after encode with that endOfInput is false
469        assertSame(encoder, encoder.reset());
470        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState3"),
471                ByteBuffer.allocate(30), false);
472        try {
473            encoder.canEncode("\ud904\udc00");
474            fail("should throw illegal state exception");
475        } catch (IllegalStateException e) {
476        }
477
478        // Normal case: just after flush
479        encoder.encode(CharBuffer.wrap("testCanEncodeIllegalState4"),
480                ByteBuffer.allocate(30), true);
481        encoder.flush(ByteBuffer.allocate(10));
482        encoder.canEncode("\ud905\udc00");
483        encoder.canEncode('\ud906');
484
485        // Normal case: after reset again
486        assertSame(encoder, encoder.reset());
487        encoder.canEncode("\ud906\udc00");
488        encoder.canEncode('\ud905');
489    }
490
491    /*
492     * --------------------------------- illegal state test end
493     * ---------------------------------
494     */
495
496    /*
497     * Class under test for boolean canEncode(CharSequence)
498     */
499    @TestTargetNew(
500        level = TestLevel.PARTIAL_COMPLETE,
501        method = "canEncode",
502        args = {java.lang.CharSequence.class}
503    )
504    public void testCanEncodeCharSequence() {
505        // for non-mapped char
506        assertTrue(encoder.canEncode("\uc2c0"));
507        // surrogate char for unicode
508        // 1st byte: d800-dbff
509        // 2nd byte: dc00-dfff
510        assertTrue(encoder.canEncode("\ud800"));
511        // valid surrogate pair
512        assertTrue(encoder.canEncode("\ud800\udc00"));
513        // invalid surrogate pair
514        assertTrue(encoder.canEncode("\ud800\udb00"));
515    }
516
517
518
519    /*
520     * Class under test for ByteBuffer encode(CharBuffer)
521     */
522    @TestTargetNew(
523        level = TestLevel.PARTIAL_COMPLETE,
524        method = "encode",
525        args = {java.nio.CharBuffer.class}
526    )
527    public void testEncodeCharBuffer() throws CharacterCodingException {
528        // Null pointer
529        try {
530            encoder.encode(null);
531            fail("should throw null pointer exception");
532        } catch (NullPointerException e) {
533        }
534
535        // empty input buffer
536        ByteBuffer out = encoder.encode(CharBuffer.wrap(""));
537        assertEquals(out.position(), 0);
538        assertByteArray(out, new byte[0]);
539        // assertByteArray(out, surrogate);
540
541        // normal case
542        out = encoder.encode(CharBuffer.wrap(unistr));
543        assertEquals(out.position(), 0);
544        assertByteArray(out, addSurrogate(unibytes));
545
546        // Regression test for harmony-3378
547        Charset cs = Charset.forName("UTF-8");
548        CharsetEncoder encoder = cs.newEncoder();
549        encoder.onMalformedInput(CodingErrorAction.REPLACE);
550        encoder = encoder.replaceWith(new byte[] { (byte) 0xef, (byte) 0xbf,
551                (byte) 0xbd, });
552        CharBuffer in = CharBuffer.wrap("\ud800");
553        out = encoder.encode(in);
554        assertNotNull(out);
555    }
556
557    private byte[] addSurrogate(byte[] expected) {
558        if (surrogate.length > 0) {
559            byte[] temp = new byte[surrogate.length + expected.length];
560            System.arraycopy(surrogate, 0, temp, 0, surrogate.length);
561            System.arraycopy(expected, 0, temp, surrogate.length,
562                    expected.length);
563            expected = temp;
564        }
565        return expected;
566    }
567
568    /**
569     * @return
570     */
571    protected byte[] getEmptyByteArray() {
572        return new byte[0];
573    }
574
575    CharBuffer getMalformedCharBuffer() {
576        return CharBuffer.wrap("malform buffer");
577    }
578
579    CharBuffer getUnmapCharBuffer() {
580        return CharBuffer.wrap("unmap buffer");
581    }
582
583    CharBuffer getExceptionCharBuffer() {
584        return CharBuffer.wrap("runtime buffer");
585    }
586
587    @TestTargetNew(
588        level = TestLevel.PARTIAL_COMPLETE,
589        method = "encode",
590        args = {java.nio.CharBuffer.class}
591    )
592    public void testEncodeCharBufferException() throws CharacterCodingException {
593        ByteBuffer out;
594        CharBuffer in;
595        // MalformedException:
596        in = getMalformedCharBuffer();
597        encoder.onMalformedInput(CodingErrorAction.REPORT);
598        encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
599        if (in != null) {
600            try {
601                // regression test for Harmony-1379
602                encoder.encode(in);
603                fail("should throw MalformedInputException");
604            } catch (MalformedInputException e) {
605            }
606
607            encoder.reset();
608            in.rewind();
609            encoder.onMalformedInput(CodingErrorAction.IGNORE);
610            out = encoder.encode(in);
611            assertByteArray(out, addSurrogate(unibytes));
612
613            encoder.reset();
614            in.rewind();
615            encoder.onMalformedInput(CodingErrorAction.REPLACE);
616            out = encoder.encode(in);
617            assertByteArray(out, addSurrogate(unibytesWithRep));
618        }
619
620        // Unmapped Exception:
621        in = getUnmapCharBuffer();
622        encoder.onMalformedInput(CodingErrorAction.REPORT);
623        encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
624        if (in != null) {
625            encoder.reset();
626            try {
627                encoder.encode(in);
628                fail("should throw UnmappableCharacterException");
629            } catch (UnmappableCharacterException e) {
630            }
631
632            encoder.reset();
633            in.rewind();
634            encoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
635            out = encoder.encode(in);
636            assertByteArray(out, unibytes);
637
638            encoder.reset();
639            in.rewind();
640            encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
641            out = encoder.encode(in);
642            assertByteArray(out, unibytesWithRep);
643        }
644
645        // RuntimeException
646        try {
647            encoder.encode(getExceptionCharBuffer());
648            fail("should throw runtime exception");
649        } catch (RuntimeException e) {
650        }
651    }
652
653    /*
654     * utility method, extract given bytebuffer to a string and compare with
655     * give string
656     */
657    void assertByteArray(ByteBuffer out, byte[] expected) {
658        out = out.duplicate();
659        if (out.position() != 0) {
660            out.flip();
661        }
662        byte[] ba = new byte[out.limit() - out.position()];
663        out.get(ba);
664        // byte[] ba = out.array();
665        assertTrue(Arrays.equals(ba, expected));
666    }
667
668    /*
669     * Class under test for CoderResult encode(CharBuffer, ByteBuffer, boolean)
670     */
671    @TestTargetNew(
672        level = TestLevel.PARTIAL_COMPLETE,
673        method = "encode",
674        args = {java.nio.CharBuffer.class, java.nio.ByteBuffer.class, boolean.class}
675    )
676    public void testEncodeCharBufferByteBufferboolean()
677            throws CharacterCodingException {
678        ByteBuffer out = ByteBuffer.allocate(200);
679        CharBuffer in = CharBuffer.wrap(unistr);
680        // Null pointer
681        try {
682            encoder.encode(null, out, true);
683            fail("should throw null pointer exception");
684        } catch (NullPointerException e) {
685        }
686        try {
687            encoder.encode(in, null, true);
688            fail("should throw null pointer exception");
689        } catch (NullPointerException e) {
690        }
691
692        // normal case, one complete operation
693        assertSame(encoder, encoder.reset());
694        in.rewind();
695        out.rewind();
696        assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out, true));
697        assertEquals(out.limit(), 200);
698        assertTrue(out.position() > 0);
699        assertTrue(out.remaining() > 0);
700        assertEquals(out.capacity(), 200);
701        assertByteArray(out, addSurrogate(unibytes));
702        in.rewind();
703
704        encoder.flush(out);
705
706        // normal case, one complete operation, but call twice, first time set
707        // endOfInput to false
708        assertSame(encoder, encoder.reset());
709        in.rewind();
710        out = ByteBuffer.allocate(200);
711        assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out, false));
712        assertEquals(out.limit(), 200);
713        assertTrue(out.position() > 0);
714        assertTrue(out.remaining() > 0);
715        assertEquals(out.capacity(), 200);
716        assertByteArray(out, addSurrogate(unibytes));
717
718        in.rewind();
719        assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out, false));
720        in.rewind();
721        assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out, true));
722        assertEquals(out.limit(), 200);
723        assertTrue(out.position() > 0);
724        assertTrue(out.remaining() > 0);
725        assertEquals(out.capacity(), 200);
726
727        assertByteArray(out, addSurrogate(duplicateByteArray(unibytes, 3)));
728
729        // overflow
730        out = ByteBuffer.allocate(4);
731        assertSame(encoder, encoder.reset());
732        in.rewind();
733        out.rewind();
734        assertSame(CoderResult.OVERFLOW, encoder.encode(in, out, true));
735        assertEquals(out.limit(), 4);
736        assertEquals(out.position(), 4);
737        assertEquals(out.remaining(), 0);
738        assertEquals(out.capacity(), 4);
739        ByteBuffer temp = ByteBuffer.allocate(200);
740        out.flip();
741        temp.put(out);
742        out = temp;
743        assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out, true));
744        assertEquals(out.limit(), 200);
745        assertTrue(out.position() > 0);
746        assertTrue(out.remaining() > 0);
747        assertEquals(out.capacity(), 200);
748        assertByteArray(out, addSurrogate(unibytes));
749
750        assertSame(encoder, encoder.reset());
751        in.rewind();
752        out = ByteBuffer.allocate(4);
753        assertSame(CoderResult.OVERFLOW, encoder.encode(in, out, false));
754        assertEquals(out.limit(), 4);
755        assertEquals(out.position(), 4);
756        assertEquals(out.remaining(), 0);
757        assertEquals(out.capacity(), 4);
758        temp = ByteBuffer.allocate(200);
759        out.flip();
760        temp.put(out);
761        out = temp;
762        assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out, false));
763        assertEquals(out.limit(), 200);
764        assertTrue(out.position() > 0);
765        assertTrue(out.remaining() > 0);
766        assertEquals(out.capacity(), 200);
767        assertByteArray(out, addSurrogate(unibytes));
768    }
769
770    void printByteBuffer(ByteBuffer buffer) {
771        System.out.println("print buffer");
772        if (buffer.position() != 0) {
773            buffer.flip();
774        }
775        byte[] ba = buffer.array();
776        for (int i = 0; i < ba.length; i++) {
777            System.out.println(Integer.toHexString(ba[i]));
778        }
779    }
780
781    @TestTargetNew(
782        level = TestLevel.PARTIAL_COMPLETE,
783        method = "encode",
784        args = {java.nio.CharBuffer.class, java.nio.ByteBuffer.class, boolean.class}
785    )
786    public void testEncodeCharBufferByteBufferbooleanExceptionFalse()
787            throws CharacterCodingException {
788        implTestEncodeCharBufferByteBufferbooleanException(false);
789    }
790
791    @TestTargetNew(
792        level = TestLevel.PARTIAL_COMPLETE,
793        method = "encode",
794        args = {java.nio.CharBuffer.class, java.nio.ByteBuffer.class, boolean.class}
795    )
796    public void testEncodeCharBufferByteBufferbooleanExceptionTrue()
797            throws CharacterCodingException {
798        implTestEncodeCharBufferByteBufferbooleanException(true);
799    }
800
801    private byte[] duplicateByteArray(byte[] ba, int times) {
802        byte[] result = new byte[ba.length * times];
803        for (int i = 0; i < times; i++) {
804            System.arraycopy(ba, 0, result, i * ba.length, ba.length);
805        }
806        return result;
807    }
808
809    protected void implTestEncodeCharBufferByteBufferbooleanException(
810            boolean endOfInput) throws CharacterCodingException {
811        ByteBuffer out = ByteBuffer.allocate(100);
812
813        // MalformedException:
814        CharBuffer in = getMalformedCharBuffer();
815        encoder.onMalformedInput(CodingErrorAction.REPORT);
816        encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
817        if (in != null) {
818            encoder.reset();
819            CoderResult r = encoder.encode(in, out, endOfInput);
820            assertTrue(r.isMalformed());
821
822            encoder.reset();
823            out.clear();
824            in.rewind();
825            encoder.onMalformedInput(CodingErrorAction.IGNORE);
826            assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out,
827                    endOfInput));
828            assertCodingErrorAction(endOfInput, out, in, unibytes);
829
830            encoder.reset();
831            out.clear();
832            in.rewind();
833            encoder.onMalformedInput(CodingErrorAction.REPLACE);
834            assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out,
835                    endOfInput));
836            assertCodingErrorAction(endOfInput, out, in, unibytesWithRep);
837        } else {
838            // System.out.println("Cannot find malformed char buffer for "
839            //         + cs.name());
840        }
841
842        // Unmapped Exception:
843        in = getUnmapCharBuffer();
844        encoder.onMalformedInput(CodingErrorAction.REPORT);
845        encoder.onUnmappableCharacter(CodingErrorAction.REPORT);
846        if (in != null) {
847            encoder.reset();
848            out.clear();
849            assertTrue(encoder.encode(in, out, endOfInput).isUnmappable());
850
851            encoder.reset();
852            out.clear();
853            in.rewind();
854            encoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
855            assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out,
856                    endOfInput));
857            assertCodingErrorAction(endOfInput, out, in, unibytes);
858
859            encoder.reset();
860            out.clear();
861            in.rewind();
862            encoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
863            assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out,
864                    endOfInput));
865            assertCodingErrorAction(endOfInput, out, in, unibytesWithRep);
866        } else {
867            // System.out.println("Cannot find unmapped char buffer for "
868            //         + cs.name());
869        }
870
871        // RuntimeException
872        try {
873            encoder.encode(getExceptionCharBuffer());
874            fail("should throw runtime exception");
875        } catch (RuntimeException e) {
876        }
877    }
878
879    private void assertCodingErrorAction(boolean endOfInput, ByteBuffer out,
880            CharBuffer in, byte[] expect) {
881        if (endOfInput) {
882            assertByteArray(out, addSurrogate(expect));
883        } else {
884            in.rewind();
885            assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out,
886                    endOfInput));
887            in.rewind();
888            assertSame(CoderResult.UNDERFLOW, encoder.encode(in, out, true));
889            assertByteArray(out, addSurrogate(duplicateByteArray(expect, 3)));
890        }
891    }
892
893    /*
894     * Class under test for CoderResult flush(ByteBuffer)
895     */
896    @TestTargetNew(
897        level = TestLevel.PARTIAL_COMPLETE,
898        method = "encode",
899        args = {java.nio.CharBuffer.class, java.nio.ByteBuffer.class, boolean.class}
900    )
901    public void testFlush() throws CharacterCodingException {
902        ByteBuffer out = ByteBuffer.allocate(6);
903        CharBuffer in = CharBuffer.wrap("aaa");
904        assertEquals(in.remaining(), 3);
905
906        // by encode facade, so that internal state will be wrong
907        encoder.encode(CharBuffer.wrap("testFlush"), ByteBuffer.allocate(20),
908                true);
909        assertSame(CoderResult.UNDERFLOW, encoder
910                .flush(ByteBuffer.allocate(50)));
911    }
912
913    /*
914     * test isLegalReplacement(byte[])
915     */
916    @TestTargetNew(
917        level = TestLevel.PARTIAL_COMPLETE,
918        method = "isLegalReplacement",
919        args = {byte[].class}
920    )
921    public void testIsLegalReplacement() {
922        try {
923            encoder.isLegalReplacement(null);
924            fail("should throw null pointer exception");
925        } catch (NullPointerException e) {
926        }
927        assertTrue(encoder.isLegalReplacement(specifiedReplacement));
928
929        assertTrue(encoder.isLegalReplacement(new byte[200]));
930        byte[] ba = getIllegalByteArray();
931        if (ba != null) {
932            assertFalse(encoder.isLegalReplacement(ba));
933        }
934    }
935
936    @TestTargetNew(
937        level = TestLevel.PARTIAL_COMPLETE,
938        method = "isLegalReplacement",
939        args = {byte[].class}
940    )
941    public void testIsLegalReplacementEmptyArray() {
942        // ISO, ASC, GB, UTF8 encoder will throw exception in RI
943        // others will pass
944        // try {
945        assertTrue(encoder.isLegalReplacement(new byte[0]));
946        // fail("should throw ArrayIndexOutOfBoundsException");
947        // } catch (ArrayIndexOutOfBoundsException e) {
948        // }
949    }
950
951    @TestTargets({
952        @TestTargetNew(
953            level = TestLevel.COMPLETE,
954            method = "onMalformedInput",
955            args = {java.nio.charset.CodingErrorAction.class}
956        ),
957        @TestTargetNew(
958            level = TestLevel.COMPLETE,
959            method = "malformedInputAction",
960            args = {}
961        )
962    })
963    public void testOnMalformedInput() {
964        assertSame(CodingErrorAction.REPORT, encoder.malformedInputAction());
965        try {
966            encoder.onMalformedInput(null);
967            fail("should throw null pointer exception");
968        } catch (IllegalArgumentException e) {
969        }
970        encoder.onMalformedInput(CodingErrorAction.IGNORE);
971        assertSame(CodingErrorAction.IGNORE, encoder.malformedInputAction());
972    }
973
974    @TestTargets({
975        @TestTargetNew(
976            level = TestLevel.COMPLETE,
977            method = "onUnmappableCharacter",
978            args = {java.nio.charset.CodingErrorAction.class}
979        ),
980        @TestTargetNew(
981            level = TestLevel.COMPLETE,
982            method = "unmappableCharacterAction",
983            args = {}
984        )
985    })
986    public void testOnUnmappableCharacter() {
987        assertSame(CodingErrorAction.REPORT, encoder
988                .unmappableCharacterAction());
989        try {
990            encoder.onUnmappableCharacter(null);
991            fail("should throw null pointer exception");
992        } catch (IllegalArgumentException e) {
993        }
994        encoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
995        assertSame(CodingErrorAction.IGNORE, encoder
996                .unmappableCharacterAction());
997    }
998
999    @TestTargets({
1000        @TestTargetNew(
1001            level = TestLevel.COMPLETE,
1002            method = "replaceWith",
1003            args = {byte[].class}
1004        ),
1005        @TestTargetNew(
1006            level = TestLevel.COMPLETE,
1007            method = "replacement",
1008            args = {}
1009        )
1010    })
1011    public void testReplacement() {
1012        try {
1013            encoder.replaceWith(null);
1014            fail("should throw null pointer exception");
1015        } catch (IllegalArgumentException e) {
1016        }
1017        try {
1018            encoder.replaceWith(new byte[0]);
1019            fail("should throw null pointer exception");
1020        } catch (IllegalArgumentException e) {
1021        }
1022        try {
1023            encoder.replaceWith(new byte[100]);
1024            fail("should throw null pointer exception");
1025        } catch (IllegalArgumentException e) {
1026        }
1027
1028        byte[] nr = getLegalByteArray();
1029        assertSame(encoder, encoder.replaceWith(nr));
1030        assertSame(nr, encoder.replacement());
1031
1032        nr = getIllegalByteArray();
1033        try {
1034            encoder.replaceWith(new byte[100]);
1035            fail("should throw null pointer exception");
1036        } catch (IllegalArgumentException e) {
1037        }
1038    }
1039
1040    protected byte[] getLegalByteArray() {
1041        return new byte[] { 'a' };
1042    }
1043
1044    protected byte[] getIllegalByteArray() {
1045        return new byte[155];
1046    }
1047
1048}
1049