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