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  */
16 
17 package org.apache.harmony.tests.java.nio.charset;
18 
19 import java.nio.ByteBuffer;
20 import java.nio.CharBuffer;
21 import java.nio.charset.Charset;
22 import java.nio.charset.CharsetDecoder;
23 import java.nio.charset.CharsetEncoder;
24 import java.nio.charset.CoderResult;
25 import java.nio.charset.IllegalCharsetNameException;
26 import java.nio.charset.spi.CharsetProvider;
27 import java.nio.charset.UnsupportedCharsetException;
28 import java.security.Permission;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.Locale;
34 import java.util.Set;
35 import java.util.SortedMap;
36 import java.util.Vector;
37 
38 import junit.framework.TestCase;
39 
40 /**
41  * Test class java.nio.Charset.
42  */
43 public class CharsetTest extends TestCase {
44 
test_allAvailableCharsets()45   public void test_allAvailableCharsets() throws Exception {
46     // Check that we can instantiate every Charset, CharsetDecoder, and CharsetEncoder.
47     for (String charsetName : Charset.availableCharsets().keySet()) {
48       if (charsetName.equals("UTF-32")) {
49         // Our UTF-32 is broken. http://b/2702411
50         // TODO: remove this hack when UTF-32 is fixed.
51         continue;
52       }
53 
54       Charset cs = Charset.forName(charsetName);
55       assertNotNull(cs.newDecoder());
56       if (cs.canEncode()) {
57         CharsetEncoder enc = cs.newEncoder();
58         assertNotNull(enc);
59         assertNotNull(enc.replacement());
60       }
61     }
62   }
63 
test_defaultCharset()64   public void test_defaultCharset() {
65     assertEquals("UTF-8", Charset.defaultCharset().name());
66   }
67 
test_isRegistered()68   public void test_isRegistered() {
69     // Regression for HARMONY-45
70 
71     // Will contain names of charsets registered with IANA
72     Set<String> knownRegisteredCharsets = new HashSet<String>();
73 
74     // Will contain names of charsets not known to be registered with IANA
75     Set<String> unknownRegisteredCharsets = new HashSet<String>();
76 
77     Set<String> names = Charset.availableCharsets().keySet();
78     for (Iterator nameItr = names.iterator(); nameItr.hasNext();) {
79       String name = (String) nameItr.next();
80       if (name.toLowerCase(Locale.ROOT).startsWith("x-")) {
81         unknownRegisteredCharsets.add(name);
82       } else {
83         knownRegisteredCharsets.add(name);
84       }
85     }
86 
87     for (Iterator nameItr = knownRegisteredCharsets.iterator(); nameItr.hasNext();) {
88       String name = (String) nameItr.next();
89       Charset cs = Charset.forName(name);
90       if (!cs.isRegistered()) {
91         System.err.println("isRegistered was false for " + name + " " + cs.name() + " " + cs.aliases());
92       }
93       assertTrue("isRegistered was false for " + name + " " + cs.name() + " " + cs.aliases(), cs.isRegistered());
94     }
95     for (Iterator nameItr = unknownRegisteredCharsets.iterator(); nameItr.hasNext();) {
96       String name = (String) nameItr.next();
97       Charset cs = Charset.forName(name);
98       assertFalse("isRegistered was true for " + name + " " + cs.name() + " " + cs.aliases(), cs.isRegistered());
99     }
100   }
101 
test_guaranteedCharsetsAvailable()102   public void test_guaranteedCharsetsAvailable() throws Exception {
103     // All Java implementations must support these charsets.
104     assertNotNull(Charset.forName("ISO-8859-1"));
105     assertNotNull(Charset.forName("US-ASCII"));
106     assertNotNull(Charset.forName("UTF-16"));
107     assertNotNull(Charset.forName("UTF-16BE"));
108     assertNotNull(Charset.forName("UTF-16LE"));
109     assertNotNull(Charset.forName("UTF-8"));
110   }
111 
112   // http://code.google.com/p/android/issues/detail?id=42769
test_42769()113   public void test_42769() throws Exception {
114     ArrayList<Thread> threads = new ArrayList<Thread>();
115     for (int i = 0; i < 10; ++i) {
116       Thread t = new Thread(new Runnable() {
117         public void run() {
118           for (int i = 0; i < 50; ++i) {
119             Charset.availableCharsets();
120           }
121         }
122       });
123       threads.add(t);
124     }
125 
126     for (Thread t : threads) {
127       t.start();
128     }
129     for (Thread t : threads) {
130       t.join();
131     }
132   }
133 
test_have_canonical_EUC_JP()134   public void test_have_canonical_EUC_JP() throws Exception {
135     assertEquals("EUC-JP", Charset.forName("EUC-JP").name());
136   }
137 
test_EUC_JP_replacement_character()138   public void test_EUC_JP_replacement_character() throws Exception {
139     // We have text either side of the replacement character, because all kinds of errors
140     // could lead to a replacement character being returned.
141     assertEncodes(Charset.forName("EUC-JP"), " \ufffd ", ' ', 0xf4, 0xfe, ' ');
142     assertDecodes(Charset.forName("EUC-JP"), " \ufffd ", ' ', 0xf4, 0xfe, ' ');
143   }
144 
test_SCSU_replacement_character()145   public void test_SCSU_replacement_character() throws Exception {
146     // We have text either side of the replacement character, because all kinds of errors
147     // could lead to a replacement character being returned.
148     assertEncodes(Charset.forName("SCSU"), " \ufffd ", ' ', 14, 0xff, 0xfd, ' ');
149     assertDecodes(Charset.forName("SCSU"), " \ufffd ", ' ', 14, 0xff, 0xfd, ' ');
150   }
151 
test_Shift_JIS_replacement_character()152   public void test_Shift_JIS_replacement_character() throws Exception {
153     // We have text either side of the replacement character, because all kinds of errors
154     // could lead to a replacement character being returned.
155     assertEncodes(Charset.forName("Shift_JIS"), " \ufffd ", ' ', 0xfc, 0xfc, ' ');
156     assertDecodes(Charset.forName("Shift_JIS"), " \ufffd ", ' ', 0xfc, 0xfc, ' ');
157   }
158 
test_UTF_16()159   public void test_UTF_16() throws Exception {
160     Charset cs = Charset.forName("UTF-16");
161     // Writes big-endian, with a big-endian BOM.
162     assertEncodes(cs, "a\u0666", 0xfe, 0xff, 0, 'a', 0x06, 0x66);
163     // Reads whatever the BOM tells it to read...
164     assertDecodes(cs, "a\u0666", 0xfe, 0xff, 0, 'a', 0x06, 0x66);
165     assertDecodes(cs, "a\u0666", 0xff, 0xfe, 'a', 0, 0x66, 0x06);
166     // ...and defaults to reading big-endian if there's no BOM.
167     assertDecodes(cs, "a\u0666", 0, 'a', 0x06, 0x66);
168   }
169 
test_UTF_16BE()170   public void test_UTF_16BE() throws Exception {
171     Charset cs = Charset.forName("UTF-16BE");
172     // Writes big-endian, with no BOM.
173     assertEncodes(cs, "a\u0666", 0, 'a', 0x06, 0x66);
174     // Treats a little-endian BOM as an error and continues to read big-endian.
175     // This test uses REPLACE mode, so we get the U+FFFD replacement character in the result.
176     assertDecodes(cs, "\ufffda\u0666", 0xff, 0xfe, 0, 'a', 0x06, 0x66);
177     // Accepts a big-endian BOM and includes U+FEFF in the decoded output.
178     assertDecodes(cs, "\ufeffa\u0666", 0xfe, 0xff, 0, 'a', 0x06, 0x66);
179     // Defaults to reading big-endian.
180     assertDecodes(cs, "a\u0666", 0, 'a', 0x06, 0x66);
181   }
182 
test_UTF_16LE()183   public void test_UTF_16LE() throws Exception {
184     Charset cs = Charset.forName("UTF-16LE");
185     // Writes little-endian, with no BOM.
186     assertEncodes(cs, "a\u0666", 'a', 0, 0x66, 0x06);
187     // Accepts a little-endian BOM and includes U+FEFF in the decoded output.
188     assertDecodes(cs, "\ufeffa\u0666", 0xff, 0xfe, 'a', 0, 0x66, 0x06);
189     // Treats a big-endian BOM as an error and continues to read little-endian.
190     // This test uses REPLACE mode, so we get the U+FFFD replacement character in the result.
191     assertDecodes(cs, "\ufffda\u0666", 0xfe, 0xff, 'a', 0, 0x66, 0x06);
192     // Defaults to reading little-endian.
193     assertDecodes(cs, "a\u0666", 'a', 0, 0x66, 0x06);
194   }
195 
test_x_UTF_16LE_BOM()196   public void test_x_UTF_16LE_BOM() throws Exception {
197     Charset cs = Charset.forName("x-UTF-16LE-BOM");
198     // Writes little-endian, with a BOM.
199     assertEncodes(cs, "a\u0666", 0xff, 0xfe, 'a', 0, 0x66, 0x06);
200     // Accepts a little-endian BOM and swallows the BOM.
201     assertDecodes(cs, "a\u0666", 0xff, 0xfe, 'a', 0, 0x66, 0x06);
202     // Swallows a big-endian BOM, but continues to read little-endian!
203     assertDecodes(cs, "\u6100\u6606", 0xfe, 0xff, 'a', 0, 0x66, 0x06);
204     // Defaults to reading little-endian.
205     assertDecodes(cs, "a\u0666", 'a', 0, 0x66, 0x06);
206   }
207 
test_UTF_32()208   public void test_UTF_32() throws Exception {
209     Charset cs = Charset.forName("UTF-32");
210     // Writes big-endian, with no BOM.
211     assertEncodes(cs, "a\u0666", 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
212     // Reads whatever the BOM tells it to read...
213     assertDecodes(cs, "a\u0666", 0, 0, 0xfe, 0xff, 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
214     assertDecodes(cs, "a\u0666", 0xff, 0xfe, 0, 0, 'a', 0, 0, 0, 0x66, 0x06, 0, 0);
215     // ...and defaults to reading big-endian if there's no BOM.
216     assertDecodes(cs, "a\u0666", 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
217   }
218 
test_UTF_32BE()219   public void test_UTF_32BE() throws Exception {
220     Charset cs = Charset.forName("UTF-32BE");
221     // Writes big-endian, with no BOM.
222     assertEncodes(cs, "a\u0666", 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
223     // Treats a little-endian BOM as an error and continues to read big-endian.
224     // This test uses REPLACE mode, so we get the U+FFFD replacement character in the result.
225     assertDecodes(cs, "\ufffda\u0666", 0xff, 0xfe, 0, 0, 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
226     // Accepts a big-endian BOM and swallows the BOM.
227     assertDecodes(cs, "a\u0666", 0, 0, 0xfe, 0xff, 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
228     // Defaults to reading big-endian.
229     assertDecodes(cs, "a\u0666", 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
230   }
231 
test_UTF_32LE()232   public void test_UTF_32LE() throws Exception {
233     Charset cs = Charset.forName("UTF-32LE");
234     // Writes little-endian, with no BOM.
235     assertEncodes(cs, "a\u0666", 'a', 0, 0, 0, 0x66, 0x06, 0, 0);
236     // Accepts a little-endian BOM and swallows the BOM.
237     assertDecodes(cs, "a\u0666", 0xff, 0xfe, 0, 0, 'a', 0, 0, 0, 0x66, 0x06, 0, 0);
238     // Treats a big-endian BOM as an error and continues to read little-endian.
239     // This test uses REPLACE mode, so we get the U+FFFD replacement character in the result.
240     assertDecodes(cs, "\ufffda\u0666", 0, 0, 0xfe, 0xff, 'a', 0, 0, 0, 0x66, 0x06, 0, 0);
241     // Defaults to reading little-endian.
242     assertDecodes(cs, "a\u0666", 'a', 0, 0, 0, 0x66, 0x06, 0, 0);
243   }
244 
test_X_UTF_32BE_BOM()245   public void test_X_UTF_32BE_BOM() throws Exception {
246     Charset cs = Charset.forName("X-UTF-32BE-BOM");
247     // Writes big-endian, with a big-endian BOM.
248     assertEncodes(cs, "a\u0666", 0, 0, 0xfe, 0xff, 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
249     // Treats a little-endian BOM as an error and continues to read big-endian.
250     // This test uses REPLACE mode, so we get the U+FFFD replacement character in the result.
251     assertDecodes(cs, "\ufffda\u0666", 0xff, 0xfe, 0, 0, 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
252     // Swallows a big-endian BOM, and continues to read big-endian.
253     assertDecodes(cs, "a\u0666", 0, 0, 0xfe, 0xff, 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
254     // Defaults to reading big-endian.
255     assertDecodes(cs, "a\u0666", 0, 0, 0, 'a', 0, 0, 0x06, 0x66);
256   }
257 
test_X_UTF_32LE_BOM()258   public void test_X_UTF_32LE_BOM() throws Exception {
259     Charset cs = Charset.forName("X-UTF-32LE-BOM");
260     // Writes little-endian, with a little-endian BOM.
261     assertEncodes(cs, "a\u0666", 0xff, 0xfe, 0, 0, 'a', 0, 0, 0, 0x66, 0x06, 0, 0);
262     // Accepts a little-endian BOM and swallows the BOM.
263     assertDecodes(cs, "a\u0666", 0xff, 0xfe, 0, 0, 'a', 0, 0, 0, 0x66, 0x06, 0, 0);
264     // Treats a big-endian BOM as an error and continues to read little-endian.
265     // This test uses REPLACE mode, so we get the U+FFFD replacement character in the result.
266     assertDecodes(cs, "\ufffda\u0666", 0, 0, 0xfe, 0xff, 'a', 0, 0, 0, 0x66, 0x06, 0, 0);
267     // Defaults to reading little-endian.
268     assertDecodes(cs, "a\u0666", 'a', 0, 0, 0, 0x66, 0x06, 0, 0);
269   }
270 
toByteArray(int[] ints)271   private byte[] toByteArray(int[] ints) {
272     byte[] result = new byte[ints.length];
273     for (int i = 0; i < ints.length; ++i) {
274       result[i] = (byte) ints[i];
275     }
276     return result;
277   }
278 
assertEncodes(Charset cs, String s, int... expectedByteInts)279   private void assertEncodes(Charset cs, String s, int... expectedByteInts) throws Exception {
280     ByteBuffer out = cs.encode(s);
281     byte[] bytes = new byte[out.remaining()];
282     out.get(bytes);
283     assertEquals(Arrays.toString(toByteArray(expectedByteInts)), Arrays.toString(bytes));
284   }
285 
assertDecodes(Charset cs, String s, int... byteInts)286   private void assertDecodes(Charset cs, String s, int... byteInts) throws Exception {
287     ByteBuffer in = ByteBuffer.wrap(toByteArray(byteInts));
288     CharBuffer out = cs.decode(in);
289     assertEquals(s, out.toString());
290   }
291 
test_forNameLjava_lang_String()292   public void test_forNameLjava_lang_String() {
293     // Invoke forName two times with the same canonical name.
294     // It should return the same reference.
295     Charset cs1 = Charset.forName("UTF-8");
296     Charset cs2 = Charset.forName("UTF-8");
297     assertSame(cs1, cs2);
298 
299     // test forName: invoke forName two times for the same Charset using
300     // canonical name and alias, it should return the same reference.
301     Charset cs3 = Charset.forName("ASCII");
302     Charset cs4 = Charset.forName("US-ASCII");
303     assertSame(cs3, cs4);
304   }
305 
306   static MockCharset charset1 = new MockCharset("mockCharset00",
307                                                 new String[] { "mockCharset01", "mockCharset02" });
308 
309   static MockCharset charset2 = new MockCharset("mockCharset10",
310                                                 new String[] { "mockCharset11", "mockCharset12" });
311 
312   // Test the required 6 charsets are supported.
testRequiredCharsetSupported()313   public void testRequiredCharsetSupported() {
314     assertTrue(Charset.isSupported("US-ASCII"));
315     assertTrue(Charset.isSupported("ASCII"));
316     assertTrue(Charset.isSupported("ISO-8859-1"));
317     assertTrue(Charset.isSupported("ISO8859_1"));
318     assertTrue(Charset.isSupported("UTF-8"));
319     assertTrue(Charset.isSupported("UTF8"));
320     assertTrue(Charset.isSupported("UTF-16"));
321     assertTrue(Charset.isSupported("UTF-16BE"));
322     assertTrue(Charset.isSupported("UTF-16LE"));
323 
324     Charset c1 = Charset.forName("US-ASCII");
325     assertEquals("US-ASCII", Charset.forName("US-ASCII").name());
326     assertEquals("US-ASCII", Charset.forName("ASCII").name());
327     assertEquals("ISO-8859-1", Charset.forName("ISO-8859-1").name());
328     assertEquals("ISO-8859-1", Charset.forName("ISO8859_1").name());
329     assertEquals("UTF-8", Charset.forName("UTF-8").name());
330     assertEquals("UTF-8", Charset.forName("UTF8").name());
331     assertEquals("UTF-16", Charset.forName("UTF-16").name());
332     assertEquals("UTF-16BE", Charset.forName("UTF-16BE").name());
333     assertEquals("UTF-16LE", Charset.forName("UTF-16LE").name());
334 
335     assertNotSame(Charset.availableCharsets(), Charset.availableCharsets());
336     // assertSame(Charset.forName("US-ASCII"), Charset.availableCharsets().get("US-ASCII"));
337     // assertSame(Charset.forName("US-ASCII"), c1);
338     assertTrue(Charset.availableCharsets().containsKey("US-ASCII"));
339     assertTrue(Charset.availableCharsets().containsKey("ISO-8859-1"));
340     assertTrue(Charset.availableCharsets().containsKey("UTF-8"));
341     assertTrue(Charset.availableCharsets().containsKey("UTF-16"));
342     assertTrue(Charset.availableCharsets().containsKey("UTF-16BE"));
343     assertTrue(Charset.availableCharsets().containsKey("UTF-16LE"));
344   }
345 
testIsSupported_Null()346   public void testIsSupported_Null() {
347     try {
348       Charset.isSupported(null);
349       fail();
350     } catch (IllegalArgumentException expected) {
351     }
352   }
353 
testIsSupported_EmptyString()354   public void testIsSupported_EmptyString() {
355     try {
356       Charset.isSupported("");
357       fail();
358     } catch (IllegalArgumentException expected) {
359     }
360   }
361 
testIsSupported_InvalidInitialCharacter()362   public void testIsSupported_InvalidInitialCharacter() {
363     try {
364       Charset.isSupported(".char");
365       fail();
366     } catch (IllegalArgumentException expected) {
367     }
368   }
369 
testIsSupported_IllegalName()370   public void testIsSupported_IllegalName() {
371     try {
372       Charset.isSupported(" ///#$$");
373       fail();
374     } catch (IllegalCharsetNameException expected) {
375     }
376   }
377 
testIsSupported_NotSupported()378   public void testIsSupported_NotSupported() {
379     assertFalse(Charset.isSupported("well-formed-name-of-a-charset-that-does-not-exist"));
380   }
381 
testForName_Null()382   public void testForName_Null() {
383     try {
384       Charset.forName(null);
385       fail();
386     } catch (IllegalArgumentException expected) {
387     }
388   }
389 
testForName_EmptyString()390   public void testForName_EmptyString() {
391     try {
392       Charset.forName("");
393       fail();
394     } catch (IllegalArgumentException expected) {
395     }
396   }
397 
testForName_InvalidInitialCharacter()398   public void testForName_InvalidInitialCharacter() {
399     try {
400       Charset.forName(".char");
401       fail();
402     } catch (IllegalArgumentException expected) {
403     }
404   }
405 
testForName_IllegalName()406   public void testForName_IllegalName() {
407     try {
408       Charset.forName(" ///#$$");
409       fail();
410     } catch (IllegalCharsetNameException expected) {
411     }
412   }
413 
testForName_NotSupported()414   public void testForName_NotSupported() {
415     try {
416       Charset.forName("impossible");
417       fail();
418     } catch (UnsupportedCharsetException expected) {
419     }
420   }
421 
testConstructor_Normal()422   public void testConstructor_Normal() {
423     final String mockName = "mockChar1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.:-_";
424     MockCharset c = new MockCharset(mockName, new String[] { "mock" });
425     assertEquals(mockName, c.name());
426     assertEquals(mockName, c.displayName());
427     assertEquals(mockName, c.displayName(Locale.getDefault()));
428     assertEquals("mock", c.aliases().toArray()[0]);
429     assertEquals(1, c.aliases().toArray().length);
430   }
431 
testConstructor_EmptyCanonicalName()432   public void testConstructor_EmptyCanonicalName() {
433     try {
434       new MockCharset("", new String[0]);
435       fail();
436     } catch (IllegalCharsetNameException expected) {
437     }
438   }
439 
testConstructor_IllegalCanonicalName_Initial()440   public void testConstructor_IllegalCanonicalName_Initial() {
441     try {
442       new MockCharset("-123", new String[] { "mock" });
443       fail();
444     } catch (IllegalCharsetNameException expected) {
445     }
446   }
447 
testConstructor_IllegalCanonicalName_Middle()448   public void testConstructor_IllegalCanonicalName_Middle() {
449     try {
450       new MockCharset("1%%23", new String[] { "mock" });
451       fail();
452     } catch (IllegalCharsetNameException expected) {
453     }
454     try {
455       new MockCharset("1//23", new String[] { "mock" });
456       fail();
457     } catch (IllegalCharsetNameException expected) {
458     }
459   }
460 
testConstructor_NullCanonicalName()461   public void testConstructor_NullCanonicalName() {
462     try {
463       MockCharset c = new MockCharset(null, new String[] { "mock" });
464       fail();
465     } catch (NullPointerException expected) {
466     }
467   }
468 
testConstructor_NullAliases()469   public void testConstructor_NullAliases() {
470     MockCharset c = new MockCharset("mockChar", null);
471     assertEquals("mockChar", c.name());
472     assertEquals("mockChar", c.displayName());
473     assertEquals("mockChar", c.displayName(Locale.getDefault()));
474     assertEquals(0, c.aliases().toArray().length);
475   }
476 
testConstructor_NullAliase()477   public void testConstructor_NullAliase() {
478     try {
479       new MockCharset("mockChar", new String[] { "mock", null });
480       fail();
481     } catch (NullPointerException expected) {
482     }
483   }
484 
testConstructor_NoAliases()485   public void testConstructor_NoAliases() {
486     MockCharset c = new MockCharset("mockChar", new String[0]);
487     assertEquals("mockChar", c.name());
488     assertEquals("mockChar", c.displayName());
489     assertEquals("mockChar", c.displayName(Locale.getDefault()));
490     assertEquals(0, c.aliases().toArray().length);
491   }
492 
testConstructor_EmptyAliases()493   public void testConstructor_EmptyAliases() {
494     try {
495       new MockCharset("mockChar", new String[] { "" });
496       fail();
497     } catch (IllegalCharsetNameException expected) {
498     }
499   }
500 
501   // Test the constructor with illegal aliases: starting with neither a digit nor a letter.
testConstructor_IllegalAliases_Initial()502   public void testConstructor_IllegalAliases_Initial() {
503     try {
504       new MockCharset("mockChar", new String[] { "mock", "-123" });
505       fail();
506     } catch (IllegalCharsetNameException e) {
507     }
508   }
509 
testConstructor_IllegalAliases_Middle()510   public void testConstructor_IllegalAliases_Middle() {
511     try {
512       new MockCharset("mockChar", new String[] { "mock", "22##ab" });
513       fail();
514     } catch (IllegalCharsetNameException expected) {
515     }
516     try {
517       new MockCharset("mockChar", new String[] { "mock", "22%%ab" });
518       fail();
519     } catch (IllegalCharsetNameException expected) {
520     }
521   }
522 
testAliases_Multiple()523   public void testAliases_Multiple() {
524     final String mockName = "mockChar1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.:-_";
525     MockCharset c = new MockCharset("mockChar", new String[] { "mock", mockName, "mock2" });
526     assertEquals("mockChar", c.name());
527     assertEquals(3, c.aliases().size());
528     assertTrue(c.aliases().contains("mock"));
529     assertTrue(c.aliases().contains(mockName));
530     assertTrue(c.aliases().contains("mock2"));
531 
532     try {
533       c.aliases().clear();
534       fail();
535     } catch (UnsupportedOperationException expected) {
536     }
537   }
538 
testAliases_Duplicate()539   public void testAliases_Duplicate() {
540     final String mockName = "mockChar1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.:-_";
541     MockCharset c = new MockCharset("mockChar", new String[] { "mockChar",
542                                                                   "mock", mockName, "mock", "mockChar", "mock", "mock2" });
543     assertEquals("mockChar", c.name());
544     assertEquals(4, c.aliases().size());
545     assertTrue(c.aliases().contains("mockChar"));
546     assertTrue(c.aliases().contains("mock"));
547     assertTrue(c.aliases().contains(mockName));
548     assertTrue(c.aliases().contains("mock2"));
549   }
550 
testCanEncode()551   public void testCanEncode() {
552     MockCharset c = new MockCharset("mock", null);
553     assertTrue(c.canEncode());
554   }
555 
testIsRegistered()556   public void testIsRegistered() {
557     MockCharset c = new MockCharset("mock", null);
558     assertTrue(c.isRegistered());
559   }
560 
testDisplayName_Locale_Null()561   public void testDisplayName_Locale_Null() {
562     MockCharset c = new MockCharset("mock", null);
563     assertEquals("mock", c.displayName(null));
564   }
565 
testCompareTo_Normal()566   public void testCompareTo_Normal() {
567     MockCharset c1 = new MockCharset("mock", null);
568     assertEquals(0, c1.compareTo(c1));
569 
570     MockCharset c2 = new MockCharset("Mock", null);
571     assertEquals(0, c1.compareTo(c2));
572 
573     c2 = new MockCharset("mock2", null);
574     assertTrue(c1.compareTo(c2) < 0);
575     assertTrue(c2.compareTo(c1) > 0);
576 
577     c2 = new MockCharset("mack", null);
578     assertTrue(c1.compareTo(c2) > 0);
579     assertTrue(c2.compareTo(c1) < 0);
580 
581     c2 = new MockCharset("m.", null);
582     assertTrue(c1.compareTo(c2) > 0);
583     assertTrue(c2.compareTo(c1) < 0);
584 
585     c2 = new MockCharset("m:", null);
586     assertEquals("mock".compareToIgnoreCase("m:"), c1.compareTo(c2));
587     assertEquals("m:".compareToIgnoreCase("mock"), c2.compareTo(c1));
588 
589     c2 = new MockCharset("m-", null);
590     assertTrue(c1.compareTo(c2) > 0);
591     assertTrue(c2.compareTo(c1) < 0);
592 
593     c2 = new MockCharset("m_", null);
594     assertTrue(c1.compareTo(c2) > 0);
595     assertTrue(c2.compareTo(c1) < 0);
596   }
597 
598   public void testCompareTo_Null() {
599     MockCharset c1 = new MockCharset("mock", null);
600     try {
601       c1.compareTo(null);
602       fail();
603     } catch (NullPointerException expected) {
604     }
605   }
606 
607   public void testCompareTo_DiffCharsetClass() {
608     MockCharset c1 = new MockCharset("mock", null);
609     MockCharset2 c2 = new MockCharset2("Mock", new String[] { "myname" });
610     assertEquals(0, c1.compareTo(c2));
611     assertEquals(0, c2.compareTo(c1));
612   }
613 
614   public void testEquals_Normal() {
615     MockCharset c1 = new MockCharset("mock", null);
616     MockCharset2 c2 = new MockCharset2("mock", null);
617     assertTrue(c1.equals(c2));
618     assertTrue(c2.equals(c1));
619 
620     c2 = new MockCharset2("Mock", null);
621     assertFalse(c1.equals(c2));
622     assertFalse(c2.equals(c1));
623   }
624 
625   public void testEquals_Null() {
626     MockCharset c1 = new MockCharset("mock", null);
627     assertFalse(c1.equals(null));
628   }
629 
630   public void testEquals_NonCharsetObject() {
631     MockCharset c1 = new MockCharset("mock", null);
632     assertFalse(c1.equals("test"));
633   }
634 
635   public void testEquals_DiffCharsetClass() {
636     MockCharset c1 = new MockCharset("mock", null);
637     MockCharset2 c2 = new MockCharset2("mock", null);
638     assertTrue(c1.equals(c2));
639     assertTrue(c2.equals(c1));
640   }
641 
642   public void testHashCode_DiffCharsetClass() {
643     MockCharset c1 = new MockCharset("mock", null);
644     assertEquals(c1.hashCode(), "mock".hashCode());
645 
646     final String mockName = "mockChar1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.:-_";
647     c1 = new MockCharset(mockName, new String[] { "mockChar", "mock",
648                                                      mockName, "mock", "mockChar", "mock", "mock2" });
649     assertEquals(mockName.hashCode(), c1.hashCode());
650   }
651 
652   public void testEncode_CharBuffer_Normal() throws Exception {
653     MockCharset c1 = new MockCharset("testEncode_CharBuffer_Normal_mock", null);
654     ByteBuffer bb = c1.encode(CharBuffer.wrap("abcdefg"));
655     assertEquals("abcdefg", new String(bb.array(), "iso8859-1"));
656     bb = c1.encode(CharBuffer.wrap(""));
657     assertEquals("", new String(bb.array(), "iso8859-1"));
658   }
659 
660   public void testEncode_CharBuffer_Unmappable() throws Exception {
661     Charset c1 = Charset.forName("iso8859-1");
662     ByteBuffer bb = c1.encode(CharBuffer.wrap("abcd\u5D14efg"));
663     assertEquals(new String(bb.array(), "iso8859-1"),
664                  "abcd" + new String(c1.newEncoder().replacement(), "iso8859-1") + "efg");
665   }
666 
667   public void testEncode_CharBuffer_NullCharBuffer() {
668     MockCharset c = new MockCharset("mock", null);
669     try {
670       c.encode((CharBuffer) null);
671       fail();
672     } catch (NullPointerException expected) {
673     }
674   }
675 
676   public void testEncode_CharBuffer_NullEncoder() {
677     MockCharset2 c = new MockCharset2("mock2", null);
678     try {
679       c.encode(CharBuffer.wrap("hehe"));
680       fail();
681     } catch (NullPointerException expected) {
682     }
683   }
684 
685   public void testEncode_String_Normal() throws Exception {
686     MockCharset c1 = new MockCharset("testEncode_String_Normal_mock", null);
687     ByteBuffer bb = c1.encode("abcdefg");
688     assertEquals("abcdefg", new String(bb.array(), "iso8859-1"));
689     bb = c1.encode("");
690     assertEquals("", new String(bb.array(), "iso8859-1"));
691   }
692 
693   public void testEncode_String_Unmappable() throws Exception {
694     Charset c1 = Charset.forName("iso8859-1");
695     ByteBuffer bb = c1.encode("abcd\u5D14efg");
696     assertEquals(new String(bb.array(), "iso8859-1"),
697                  "abcd" + new String(c1.newEncoder().replacement(), "iso8859-1") + "efg");
698   }
699 
700   public void testEncode_String_NullString() {
701     MockCharset c = new MockCharset("mock", null);
702     try {
703       c.encode((String) null);
704       fail();
705     } catch (NullPointerException expected) {
706     }
707   }
708 
709   public void testEncode_String_NullEncoder() {
710     MockCharset2 c = new MockCharset2("mock2", null);
711     try {
712       c.encode("hehe");
713       fail();
714     } catch (NullPointerException expected) {
715     }
716   }
717 
718   public void testDecode_Normal() throws Exception {
719     MockCharset c1 = new MockCharset("mock", null);
720     CharBuffer cb = c1.decode(ByteBuffer.wrap("abcdefg".getBytes("iso8859-1")));
721     assertEquals("abcdefg", new String(cb.array()));
722     cb = c1.decode(ByteBuffer.wrap("".getBytes("iso8859-1")));
723     assertEquals("", new String(cb.array()));
724   }
725 
726   public void testDecode_Malformed() throws Exception {
727     Charset c1 = Charset.forName("iso8859-1");
728     CharBuffer cb = c1.decode(ByteBuffer.wrap("abcd\u5D14efg".getBytes("iso8859-1")));
729     byte[] replacement = c1.newEncoder().replacement();
730     assertEquals(new String(cb.array()).trim(), "abcd" + new String(replacement, "iso8859-1") + "efg");
731   }
732 
733   public void testDecode_NullByteBuffer() {
734     MockCharset c = new MockCharset("mock", null);
735     try {
736       c.decode(null);
737       fail();
738     } catch (NullPointerException expected) {
739     }
740   }
741 
742   public void testDecode_NullDecoder() {
743     MockCharset2 c = new MockCharset2("mock2", null);
744     try {
745       c.decode(ByteBuffer.wrap("hehe".getBytes()));
746       fail();
747     } catch (NullPointerException expected) {
748     }
749   }
750 
751   public void testToString() {
752     MockCharset c1 = new MockCharset("mock", null);
753     assertTrue(-1 != c1.toString().indexOf("mock"));
754   }
755 
756   static final class MockCharset extends Charset {
757     public MockCharset(String canonicalName, String[] aliases) {
758       super(canonicalName, aliases);
759     }
760 
761     public boolean contains(Charset cs) {
762       return false;
763     }
764 
765     public CharsetDecoder newDecoder() {
766       return new MockDecoder(this);
767     }
768 
769     public CharsetEncoder newEncoder() {
770       return new MockEncoder(this);
771     }
772   }
773 
774   static class MockCharset2 extends Charset {
775     public MockCharset2(String canonicalName, String[] aliases) {
776       super(canonicalName, aliases);
777     }
778 
779     public boolean contains(Charset cs) {
780       return false;
781     }
782 
783     public CharsetDecoder newDecoder() {
784       return null;
785     }
786 
787     public CharsetEncoder newEncoder() {
788       return null;
789     }
790   }
791 
792   static class MockEncoder extends java.nio.charset.CharsetEncoder {
793     public MockEncoder(Charset cs) {
794       super(cs, 1, 3, new byte[] { (byte) '?' });
795     }
796 
797     protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
798       while (in.remaining() > 0) {
799         out.put((byte) in.get());
800         // out.put((byte) '!');
801       }
802       return CoderResult.UNDERFLOW;
803     }
804   }
805 
806   static class MockDecoder extends java.nio.charset.CharsetDecoder {
MockDecoder(Charset cs)807     public MockDecoder(Charset cs) {
808       super(cs, 1, 10);
809     }
810 
decodeLoop(ByteBuffer in, CharBuffer out)811     protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
812       while (in.remaining() > 0) {
813         out.put((char) in.get());
814       }
815       return CoderResult.UNDERFLOW;
816     }
817   }
818 
819 
820   // Test the method isSupported(String) with charset supported by multiple providers.
testIsSupported_And_ForName_NormalProvider()821   public void testIsSupported_And_ForName_NormalProvider() throws Exception {
822     assertTrue(Charset.isSupported("mockCharset10"));
823     // ignore case problem in mock, intended
824     assertTrue(Charset.isSupported("MockCharset11"));
825     assertTrue(Charset.isSupported("MockCharset12"));
826     assertTrue(Charset.isSupported("MOCKCharset10"));
827     // intended case problem in mock
828     assertTrue(Charset.isSupported("MOCKCharset11"));
829     assertTrue(Charset.isSupported("MOCKCharset12"));
830 
831     assertTrue(Charset.forName("mockCharset10") instanceof MockCharset);
832     assertTrue(Charset.forName("mockCharset11") instanceof MockCharset);
833     assertTrue(Charset.forName("mockCharset12") instanceof MockCharset);
834 
835     assertTrue(Charset.forName("mockCharset10") == charset2);
836     // intended case problem in mock
837     Charset.forName("mockCharset11");
838     assertTrue(Charset.forName("mockCharset12") == charset2);
839   }
840 
841   // Test the method availableCharsets() with charset supported by multiple providers.
testAvailableCharsets_NormalProvider()842   public void testAvailableCharsets_NormalProvider() throws Exception {
843     assertTrue(Charset.availableCharsets().containsKey("mockCharset00"));
844     assertTrue(Charset.availableCharsets().containsKey("MOCKCharset00"));
845     assertTrue(Charset.availableCharsets().get("mockCharset00") instanceof MockCharset);
846     assertTrue(Charset.availableCharsets().get("MOCKCharset00") instanceof MockCharset);
847     assertFalse(Charset.availableCharsets().containsKey("mockCharset01"));
848     assertFalse(Charset.availableCharsets().containsKey("mockCharset02"));
849 
850     assertTrue(Charset.availableCharsets().get("mockCharset10") == charset2);
851     assertTrue(Charset.availableCharsets().get("MOCKCharset10") == charset2);
852     assertFalse(Charset.availableCharsets().containsKey("mockCharset11"));
853     assertFalse(Charset.availableCharsets().containsKey("mockCharset12"));
854 
855     assertTrue(Charset.availableCharsets().containsKey("mockCharset10"));
856     assertTrue(Charset.availableCharsets().containsKey("MOCKCharset10"));
857     assertTrue(Charset.availableCharsets().get("mockCharset10") == charset2);
858     assertFalse(Charset.availableCharsets().containsKey("mockCharset11"));
859     assertFalse(Charset.availableCharsets().containsKey("mockCharset12"));
860   }
861 
862   // Test the method forName(String) when the charset provider supports a
863   // built-in charset.
testForName_DuplicateWithBuiltInCharset()864   public void testForName_DuplicateWithBuiltInCharset() throws Exception {
865     assertFalse(Charset.forName("us-ascii") instanceof MockCharset);
866     assertFalse(Charset.availableCharsets().get("us-ascii") instanceof MockCharset);
867   }
868 
869   public static class MockCharsetProvider extends CharsetProvider {
charsetForName(String charsetName)870     public Charset charsetForName(String charsetName) {
871       if ("MockCharset00".equalsIgnoreCase(charsetName) ||
872           "MockCharset01".equalsIgnoreCase(charsetName) ||
873           "MockCharset02".equalsIgnoreCase(charsetName)) {
874         return charset1;
875       } else if ("MockCharset10".equalsIgnoreCase(charsetName) ||
876           "MockCharset11".equalsIgnoreCase(charsetName) ||
877           "MockCharset12".equalsIgnoreCase(charsetName)) {
878         return charset2;
879       }
880       return null;
881     }
882 
charsets()883     public Iterator charsets() {
884       Vector v = new Vector();
885       v.add(charset1);
886       v.add(charset2);
887       return v.iterator();
888     }
889   }
890 
891   // Another mock charset provider attempting to provide the built-in charset "ascii" again.
892   public static class MockCharsetProviderASCII extends CharsetProvider {
charsetForName(String charsetName)893     public Charset charsetForName(String charsetName) {
894       if ("US-ASCII".equalsIgnoreCase(charsetName) || "ASCII".equalsIgnoreCase(charsetName)) {
895         return new MockCharset("US-ASCII", new String[] { "ASCII" });
896       }
897       return null;
898     }
899 
charsets()900     public Iterator charsets() {
901       Vector v = new Vector();
902       v.add(new MockCharset("US-ASCII", new String[] { "ASCII" }));
903       return v.iterator();
904     }
905   }
906 }
907