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