Home | History | Annotate | Download | only in collator
      1 /* GENERATED SOURCE. DO NOT MODIFY. */
      2 //  2016 and later: Unicode, Inc. and others.
      3 // License & terms of use: http://www.unicode.org/copyright.html#License
      4 /*
      5  *******************************************************************************
      6  * Copyright (C) 2002-2014, International Business Machines Corporation and
      7  * others. All Rights Reserved.
      8  *******************************************************************************
      9  */
     10 
     11 /**
     12  * Port From:   ICU4C v2.1 : collate/CollationAPITest
     13  * Source File: $ICU4CRoot/source/test/intltest/apicoll.cpp
     14  **/
     15 
     16 package android.icu.dev.test.collator;
     17 
     18 import java.text.CharacterIterator;
     19 import java.text.StringCharacterIterator;
     20 import java.util.Arrays;
     21 import java.util.HashSet;
     22 import java.util.Locale;
     23 import java.util.MissingResourceException;
     24 import java.util.Set;
     25 
     26 import org.junit.Test;
     27 import org.junit.runner.RunWith;
     28 import org.junit.runners.JUnit4;
     29 
     30 import android.icu.dev.test.TestFmwk;
     31 import android.icu.impl.Utility;
     32 import android.icu.lang.UCharacter;
     33 import android.icu.text.CollationElementIterator;
     34 import android.icu.text.CollationKey;
     35 import android.icu.text.Collator;
     36 import android.icu.text.Collator.CollatorFactory;
     37 import android.icu.text.RawCollationKey;
     38 import android.icu.text.RuleBasedCollator;
     39 import android.icu.text.UCharacterIterator;
     40 import android.icu.text.UnicodeSet;
     41 import android.icu.util.ULocale;
     42 import android.icu.util.VersionInfo;
     43 import android.icu.testsharding.MainTestShard;
     44 
     45 @MainTestShard
     46 @RunWith(JUnit4.class)
     47 public class CollationAPITest extends TestFmwk {
     48     /**
     49      * This tests the collation key related APIs.
     50      * - constructor/destructor
     51      * - Collator.getCollationKey
     52      * - == and != operators
     53      * - comparison between collation keys
     54      * - creating collation key with a byte array and vice versa
     55      */
     56     @Test
     57     public void TestCollationKey() {
     58         logln("testing CollationKey begins...");
     59         Collator col = Collator.getInstance();
     60         col.setStrength(Collator.TERTIARY);
     61 
     62         String test1 = "Abcda";
     63         String test2 = "abcda";
     64 
     65         logln("Testing weird arguments");
     66         CollationKey sortk1 = col.getCollationKey("");
     67         // key gets reset here
     68         byte[] bytes = sortk1.toByteArray();
     69         doAssert(bytes.length == 3 && bytes[0] == 1 && bytes[1] == 1
     70                  && bytes[2] == 0,
     71                  "Empty string should return a collation key with empty levels");
     72 
     73         // Most control codes and CGJ are completely ignorable.
     74         // A string with only completely ignorables must compare equal to an empty string.
     75         CollationKey sortkIgnorable = col.getCollationKey("\u0001\u034f");
     76         doAssert(sortkIgnorable != null && sortkIgnorable.toByteArray().length == 3,
     77                  "Completely ignorable string should return a collation key with empty levels");
     78         doAssert(sortkIgnorable.compareTo(sortk1) == 0,
     79                  "Completely ignorable string should compare equal to empty string");
     80 
     81         // bogus key returned here
     82         sortk1 = col.getCollationKey(null);
     83         doAssert(sortk1 == null, "Error code should return bogus collation key");
     84 
     85         logln("Use tertiary comparison level testing ....");
     86         sortk1 = col.getCollationKey(test1);
     87         CollationKey sortk2 = col.getCollationKey(test2);
     88         doAssert((sortk1.compareTo(sortk2)) > 0, "Result should be \"Abcda\" >>> \"abcda\"");
     89 
     90         CollationKey sortkNew;
     91         sortkNew = sortk1;
     92         doAssert(!(sortk1.equals(sortk2)), "The sort keys should be different");
     93         doAssert((sortk1.hashCode() != sortk2.hashCode()), "sort key hashCode() failed");
     94         doAssert((sortk1.equals(sortkNew)), "The sort keys assignment failed");
     95         doAssert((sortk1.hashCode() == sortkNew.hashCode()), "sort key hashCode() failed");
     96 
     97         // port from apicoll
     98         try {
     99             col = Collator.getInstance();
    100         } catch (Exception e) {
    101             errln("Collator.getInstance() failed");
    102         }
    103         if (col.getStrength() != Collator.TERTIARY){
    104             errln("Default collation did not have tertiary strength");
    105         }
    106 
    107         // Need to use identical strength
    108         col.setStrength(Collator.IDENTICAL);
    109 
    110         CollationKey key1 = col.getCollationKey(test1);
    111         CollationKey key2 = col.getCollationKey(test2);
    112         CollationKey key3 = col.getCollationKey(test2);
    113 
    114         doAssert(key1.compareTo(key2) > 0,
    115                  "Result should be \"Abcda\" > \"abcda\"");
    116         doAssert(key2.compareTo(key1) < 0,
    117                 "Result should be \"abcda\" < \"Abcda\"");
    118         doAssert(key2.compareTo(key3) == 0,
    119                 "Result should be \"abcda\" ==  \"abcda\"");
    120 
    121         byte key2identical[] = key2.toByteArray();
    122 
    123         logln("Use secondary comparision level testing ...");
    124         col.setStrength(Collator.SECONDARY);
    125 
    126         key1 = col.getCollationKey(test1);
    127         key2 = col.getCollationKey(test2);
    128         key3 = col.getCollationKey(test2);
    129 
    130         doAssert(key1.compareTo(key2) == 0,
    131                 "Result should be \"Abcda\" == \"abcda\"");
    132         doAssert(key2.compareTo(key3) == 0,
    133                 "Result should be \"abcda\" ==  \"abcda\"");
    134 
    135         byte tempkey[] = key2.toByteArray();
    136         byte subkey2compat[] = new byte[tempkey.length];
    137         System.arraycopy(key2identical, 0, subkey2compat, 0, tempkey.length);
    138         subkey2compat[subkey2compat.length - 1] = 0;
    139         doAssert(Arrays.equals(tempkey, subkey2compat),
    140                  "Binary format for 'abcda' sortkey different for secondary strength!");
    141 
    142         logln("testing sortkey ends...");
    143     }
    144 
    145     @Test
    146     public void TestRawCollationKey()
    147     {
    148         // testing constructors
    149         RawCollationKey key = new RawCollationKey();
    150         if (key.bytes != null || key.size != 0) {
    151             errln("Empty default constructor expected to leave the bytes null "
    152                   + "and size 0");
    153         }
    154         byte array[] = new byte[128];
    155         key = new RawCollationKey(array);
    156         if (key.bytes != array || key.size != 0) {
    157             errln("Constructor taking an array expected to adopt it and "
    158                   + "retaining its size 0");
    159         }
    160         try {
    161             key = new RawCollationKey(array, 129);
    162             errln("Constructor taking an array and a size > array.length "
    163                   + "expected to throw an exception");
    164         } catch (IndexOutOfBoundsException e) {
    165                 logln("PASS: Constructor failed as expected");
    166         }
    167         try {
    168             key = new RawCollationKey(array, -1);
    169             errln("Constructor taking an array and a size < 0 "
    170                   + "expected to throw an exception");
    171         } catch (IndexOutOfBoundsException e) {
    172                 logln("PASS: Constructor failed as expected");
    173         }
    174         key = new RawCollationKey(array, array.length >> 1);
    175         if (key.bytes != array || key.size != (array.length >> 1)) {
    176             errln("Constructor taking an array and a size, "
    177                   + "expected to adopt it and take the size specified");
    178         }
    179         key = new RawCollationKey(10);
    180         if (key.bytes == null || key.bytes.length != 10 || key.size != 0) {
    181             errln("Constructor taking a specified capacity expected to "
    182                   + "create a new internal byte array with length 10 and "
    183                   + "retain size 0");
    184         }
    185     }
    186 
    187     void doAssert(boolean conditions, String message) {
    188         if (!conditions) {
    189             errln(message);
    190         }
    191     }
    192 
    193     /**
    194      * This tests the comparison convenience methods of a collator object.
    195      * - greater than
    196      * - greater than or equal to
    197      * - equal to
    198      */
    199     @Test
    200     public void TestCompare() {
    201         logln("The compare tests begin : ");
    202         Collator col = Collator.getInstance(Locale.ENGLISH);
    203 
    204         String test1 = "Abcda";
    205         String test2 = "abcda";
    206         logln("Use tertiary comparison level testing ....");
    207 
    208         doAssert((!col.equals(test1, test2) ), "Result should be \"Abcda\" != \"abcda\"");
    209         doAssert((col.compare(test1, test2) > 0 ), "Result should be \"Abcda\" >>> \"abcda\"");
    210 
    211         col.setStrength(Collator.SECONDARY);
    212         logln("Use secondary comparison level testing ....");
    213 
    214         doAssert((col.equals(test1, test2) ), "Result should be \"Abcda\" == \"abcda\"");
    215         doAssert((col.compare(test1, test2) == 0), "Result should be \"Abcda\" == \"abcda\"");
    216 
    217         col.setStrength(Collator.PRIMARY);
    218         logln("Use primary comparison level testing ....");
    219 
    220         doAssert((col.equals(test1, test2) ), "Result should be \"Abcda\" == \"abcda\"");
    221         doAssert((col.compare(test1, test2) == 0 ), "Result should be \"Abcda\" == \"abcda\"");
    222         logln("The compare tests end.");
    223     }
    224 
    225     /**
    226     * Tests decomposition setting
    227     */
    228     @Test
    229     public void TestDecomposition() {
    230         Collator en_US = null, el_GR = null, vi_VN = null;
    231 
    232         en_US = Collator.getInstance(new Locale("en", "US"));
    233         el_GR = Collator.getInstance(new Locale("el", "GR"));
    234         vi_VN = Collator.getInstance(new Locale("vi", "VN"));
    235 
    236 
    237         // there is no reason to have canonical decomposition in en_US OR default locale */
    238         if (vi_VN.getDecomposition() != Collator.CANONICAL_DECOMPOSITION)
    239         {
    240             errln("vi_VN collation did not have cannonical decomposition for normalization!");
    241         }
    242 
    243         if (el_GR.getDecomposition() != Collator.CANONICAL_DECOMPOSITION)
    244         {
    245             errln("el_GR collation did not have cannonical decomposition for normalization!");
    246         }
    247 
    248         if (en_US.getDecomposition() != Collator.NO_DECOMPOSITION)
    249         {
    250             errln("en_US collation had cannonical decomposition for normalization!");
    251         }
    252     }
    253 
    254     /**
    255      * This tests the duplication of a collator object.
    256      */
    257     @Test
    258     public void TestDuplicate() {
    259         //Clone does not be implemented
    260         Collator col1 = Collator.getInstance(Locale.ENGLISH);
    261 
    262         // Collator col2 = (Collator)col1.clone();
    263         // doAssert(col1.equals(col2), "Cloned object is not equal to the orginal");
    264         String ruleset = "&9 < a, A < b, B < c, C < d, D, e, E";
    265         RuleBasedCollator col3 = null;
    266         try {
    267             col3 = new RuleBasedCollator(ruleset);
    268         } catch (Exception e) {
    269             errln("Failure creating RuleBasedCollator with rule: \"" + ruleset + "\"\n" + e);
    270             return;
    271         }
    272         doAssert(!col1.equals(col3), "Cloned object is equal to some dummy");
    273         col3 = (RuleBasedCollator)col1;
    274         doAssert(col1.equals(col3), "Copied object is not equal to the orginal");
    275 
    276     }
    277 
    278     /**
    279      * This tests the CollationElementIterator related APIs.
    280      * - creation of a CollationElementIterator object
    281      * - == and != operators
    282      * - iterating forward
    283      * - reseting the iterator index
    284      * - requesting the order properties(primary, secondary or tertiary)
    285      */
    286     @Test
    287     public void TestElemIter() {
    288         // logln("testing sortkey begins...");
    289         Collator col = Collator.getInstance(Locale.ENGLISH);
    290 
    291 
    292         String testString1 = "XFILE What subset of all possible test cases has the highest probability of detecting the most errors?";
    293         String testString2 = "Xf_ile What subset of all possible test cases has the lowest probability of detecting the least errors?";
    294         // logln("Constructors and comparison testing....");
    295         CollationElementIterator iterator1 = ((RuleBasedCollator)col).getCollationElementIterator(testString1);
    296 
    297         CharacterIterator chariter=new StringCharacterIterator(testString1);
    298         // copy ctor
    299         CollationElementIterator iterator2 = ((RuleBasedCollator)col).getCollationElementIterator(chariter);
    300         UCharacterIterator uchariter=UCharacterIterator.getInstance(testString2);
    301         CollationElementIterator iterator3 = ((RuleBasedCollator)col).getCollationElementIterator(uchariter);
    302 
    303         int offset = 0;
    304         offset = iterator1.getOffset();
    305         if (offset != 0) {
    306             errln("Error in getOffset for collation element iterator");
    307             return;
    308         }
    309         iterator1.setOffset(6);
    310         iterator1.setOffset(0);
    311         int order1, order2, order3;
    312 
    313         order1 = iterator1.next();
    314         doAssert(!(iterator1.equals(iterator2)), "The first iterator advance failed");
    315         order2 = iterator2.next();
    316 
    317         // Code coverage for dummy "not designed" hashCode() which does "assert false".
    318         try {
    319             iterator1.hashCode();  // We don't expect any particular value.
    320         } catch (AssertionError ignored) {
    321             // Expected to be thrown if assertions are enabled.
    322         }
    323 
    324         // In ICU 52 and earlier we had iterator1.equals(iterator2)
    325         // but in ICU 53 this fails because the iterators differ (String vs. CharacterIterator).
    326         // doAssert((iterator1.equals(iterator2)), "The second iterator advance failed");
    327         doAssert(iterator1.getOffset() == iterator2.getOffset(), "The second iterator advance failed");
    328         doAssert((order1 == order2), "The order result should be the same");
    329         order3 = iterator3.next();
    330 
    331         doAssert((CollationElementIterator.primaryOrder(order1) ==
    332             CollationElementIterator.primaryOrder(order3)), "The primary orders should be the same");
    333         doAssert((CollationElementIterator.secondaryOrder(order1) ==
    334             CollationElementIterator.secondaryOrder(order3)), "The secondary orders should be the same");
    335         doAssert((CollationElementIterator.tertiaryOrder(order1) ==
    336             CollationElementIterator.tertiaryOrder(order3)), "The tertiary orders should be the same");
    337 
    338         order1 = iterator1.next();
    339         order3 = iterator3.next();
    340 
    341         doAssert((CollationElementIterator.primaryOrder(order1) ==
    342             CollationElementIterator.primaryOrder(order3)), "The primary orders should be identical");
    343         doAssert((CollationElementIterator.tertiaryOrder(order1) !=
    344             CollationElementIterator.tertiaryOrder(order3)), "The tertiary orders should be different");
    345 
    346         order1 = iterator1.next();
    347         order3 = iterator3.next();
    348         // invalid test wrong in UCA
    349         // doAssert((CollationElementIterator.secondaryOrder(order1) !=
    350         //    CollationElementIterator.secondaryOrder(order3)), "The secondary orders should not be the same");
    351 
    352         doAssert((order1 != CollationElementIterator.NULLORDER), "Unexpected end of iterator reached");
    353 
    354         iterator1.reset();
    355         iterator2.reset();
    356         iterator3.reset();
    357         order1 = iterator1.next();
    358 
    359         doAssert(!(iterator1.equals(iterator2)), "The first iterator advance failed");
    360 
    361         order2 = iterator2.next();
    362 
    363         // In ICU 52 and earlier we had iterator1.equals(iterator2)
    364         // but in ICU 53 this fails because the iterators differ (String vs. CharacterIterator).
    365         // doAssert((iterator1.equals(iterator2)), "The second iterator advance failed");
    366         doAssert(iterator1.getOffset() == iterator2.getOffset(), "The second iterator advance failed");
    367         doAssert((order1 == order2), "The order result should be the same");
    368 
    369         order3 = iterator3.next();
    370 
    371         doAssert((CollationElementIterator.primaryOrder(order1) ==
    372             CollationElementIterator.primaryOrder(order3)), "The primary orders should be the same");
    373         doAssert((CollationElementIterator.secondaryOrder(order1) ==
    374             CollationElementIterator.secondaryOrder(order3)), "The secondary orders should be the same");
    375         doAssert((CollationElementIterator.tertiaryOrder(order1) ==
    376             CollationElementIterator.tertiaryOrder(order3)), "The tertiary orders should be the same");
    377 
    378         order1 = iterator1.next();
    379         order2 = iterator2.next();
    380         order3 = iterator3.next();
    381 
    382         doAssert((CollationElementIterator.primaryOrder(order1) ==
    383             CollationElementIterator.primaryOrder(order3)), "The primary orders should be identical");
    384         doAssert((CollationElementIterator.tertiaryOrder(order1) !=
    385             CollationElementIterator.tertiaryOrder(order3)), "The tertiary orders should be different");
    386 
    387         order1 = iterator1.next();
    388         order3 = iterator3.next();
    389 
    390         // obsolete invalid test, removed
    391         // doAssert((CollationElementIterator.secondaryOrder(order1) !=
    392         //    CollationElementIterator.secondaryOrder(order3)), "The secondary orders should not be the same");
    393         doAssert((order1 != CollationElementIterator.NULLORDER), "Unexpected end of iterator reached");
    394         doAssert(!(iterator2.equals(iterator3)), "The iterators should be different");
    395         logln("testing CollationElementIterator ends...");
    396     }
    397 
    398     /**
    399      * This tests the hashCode method of a collator object.
    400      */
    401     @Test
    402     public void TestHashCode() {
    403         logln("hashCode tests begin.");
    404         Collator col1 = Collator.getInstance(Locale.ENGLISH);
    405 
    406         Collator col2 = null;
    407         Locale dk = new Locale("da", "DK", "");
    408         try {
    409             col2 = Collator.getInstance(dk);
    410         } catch (Exception e) {
    411             errln("Danish collation creation failed.");
    412             return;
    413         }
    414 
    415         Collator col3 = null;
    416         try {
    417             col3 = Collator.getInstance(Locale.ENGLISH);
    418         } catch (Exception e) {
    419             errln("2nd default collation creation failed.");
    420             return;
    421         }
    422 
    423         logln("Collator.hashCode() testing ...");
    424 
    425         doAssert(col1.hashCode() != col2.hashCode(), "Hash test1 result incorrect" );
    426         doAssert(!(col1.hashCode() == col2.hashCode()), "Hash test2 result incorrect" );
    427         doAssert(col1.hashCode() == col3.hashCode(), "Hash result not equal" );
    428 
    429         logln("hashCode tests end.");
    430 
    431         String test1 = "Abcda";
    432         String test2 = "abcda";
    433 
    434         CollationKey sortk1, sortk2, sortk3;
    435 
    436         sortk1 = col3.getCollationKey(test1);
    437         sortk2 = col3.getCollationKey(test2);
    438         sortk3 = col3.getCollationKey(test2);
    439 
    440         doAssert(sortk1.hashCode() != sortk2.hashCode(), "Hash test1 result incorrect");
    441         doAssert(sortk2.hashCode() == sortk3.hashCode(), "Hash result not equal" );
    442     }
    443 
    444     /**
    445      * This tests the properties of a collator object.
    446      * - constructor
    447      * - factory method getInstance
    448      * - compare and getCollationKey
    449      * - get/set decomposition mode and comparison level
    450      */
    451     @Test
    452     public void TestProperty() {
    453         /*
    454           All the collations have the same version in an ICU
    455           version.
    456           ICU 2.0 currVersionArray = {0x18, 0xC0, 0x02, 0x02};
    457           ICU 2.1 currVersionArray = {0x19, 0x00, 0x03, 0x03};
    458           ICU 2.8 currVersionArray = {0x29, 0x80, 0x00, 0x04};
    459         */
    460         logln("The property tests begin : ");
    461         logln("Test ctors : ");
    462         Collator col = Collator.getInstance(Locale.ENGLISH);
    463 
    464         logln("Test getVersion");
    465         // Check for a version greater than some value rather than equality
    466         // so that we need not update the expected version each time.
    467         VersionInfo expectedVersion = VersionInfo.getInstance(0x31, 0xC0, 0x00, 0x05);  // from ICU 4.4/UCA 5.2
    468         doAssert(col.getVersion().compareTo(expectedVersion) >= 0, "Expected minimum version "+expectedVersion.toString()+" got "+col.getVersion().toString());
    469 
    470         logln("Test getUCAVersion");
    471         // Assume that the UCD and UCA versions are the same,
    472         // rather than hardcoding (and updating each time) a particular UCA version.
    473         VersionInfo ucdVersion = UCharacter.getUnicodeVersion();
    474         VersionInfo ucaVersion = col.getUCAVersion();
    475         doAssert(ucaVersion.equals(ucdVersion),
    476                 "Expected UCA version "+ucdVersion.toString()+" got "+col.getUCAVersion().toString());
    477 
    478         doAssert((col.compare("ab", "abc") < 0), "ab < abc comparison failed");
    479         doAssert((col.compare("ab", "AB") < 0), "ab < AB comparison failed");
    480         doAssert((col.compare("blackbird", "black-bird") > 0), "black-bird > blackbird comparison failed");
    481         doAssert((col.compare("black bird", "black-bird") < 0), "black bird > black-bird comparison failed");
    482         doAssert((col.compare("Hello", "hello") > 0), "Hello > hello comparison failed");
    483 
    484         logln("Test ctors ends.");
    485 
    486         logln("testing Collator.getStrength() method ...");
    487         doAssert((col.getStrength() == Collator.TERTIARY), "collation object has the wrong strength");
    488         doAssert((col.getStrength() != Collator.PRIMARY), "collation object's strength is primary difference");
    489 
    490         logln("testing Collator.setStrength() method ...");
    491         col.setStrength(Collator.SECONDARY);
    492         doAssert((col.getStrength() != Collator.TERTIARY), "collation object's strength is secondary difference");
    493         doAssert((col.getStrength() != Collator.PRIMARY), "collation object's strength is primary difference");
    494         doAssert((col.getStrength() == Collator.SECONDARY), "collation object has the wrong strength");
    495 
    496         logln("testing Collator.setDecomposition() method ...");
    497         col.setDecomposition(Collator.NO_DECOMPOSITION);
    498         doAssert((col.getDecomposition() != Collator.CANONICAL_DECOMPOSITION), "Decomposition mode != Collator.CANONICAL_DECOMPOSITION");
    499         doAssert((col.getDecomposition() == Collator.NO_DECOMPOSITION), "Decomposition mode = Collator.NO_DECOMPOSITION");
    500 
    501 
    502         // Android patch: Add --omitCollationRules to genrb.
    503         // RuleBasedCollator rcol = (RuleBasedCollator)Collator.getInstance(new Locale("da", "DK"));
    504         // doAssert(rcol.getRules().length() != 0, "da_DK rules does not have length 0");
    505         // Android patch end.
    506 
    507         try {
    508             col = Collator.getInstance(Locale.FRENCH);
    509         } catch (Exception e) {
    510             errln("Creating French collation failed.");
    511             return;
    512         }
    513 
    514         col.setStrength(Collator.PRIMARY);
    515         logln("testing Collator.getStrength() method again ...");
    516         doAssert((col.getStrength() != Collator.TERTIARY), "collation object has the wrong strength");
    517         doAssert((col.getStrength() == Collator.PRIMARY), "collation object's strength is not primary difference");
    518 
    519         logln("testing French Collator.setStrength() method ...");
    520         col.setStrength(Collator.TERTIARY);
    521         doAssert((col.getStrength() == Collator.TERTIARY), "collation object's strength is not tertiary difference");
    522         doAssert((col.getStrength() != Collator.PRIMARY), "collation object's strength is primary difference");
    523         doAssert((col.getStrength() != Collator.SECONDARY), "collation object's strength is secondary difference");
    524 
    525     }
    526 
    527     @Test
    528     public void TestJunkCollator(){
    529         logln("Create junk collation: ");
    530         Locale abcd = new Locale("ab", "CD", "");
    531 
    532         Collator junk = Collator.getInstance(abcd);
    533         Collator col = Collator.getInstance();
    534 
    535 
    536         String colrules = ((RuleBasedCollator)col).getRules();
    537         String junkrules = ((RuleBasedCollator)junk).getRules();
    538         doAssert(colrules == junkrules || colrules.equals(junkrules),
    539                    "The default collation should be returned.");
    540         Collator frCol = null;
    541         try {
    542             frCol = Collator.getInstance(Locale.CANADA_FRENCH);
    543         } catch (Exception e) {
    544             errln("Creating fr_CA collator failed.");
    545             return;
    546         }
    547 
    548         doAssert(!(frCol.equals(junk)), "The junk is the same as the fr_CA collator.");
    549         logln("Collator property test ended.");
    550 
    551     }
    552 
    553     /**
    554     * This tests the RuleBasedCollator
    555     * - constructor/destructor
    556     * - getRules
    557     */
    558     @Test
    559     public void TestRuleBasedColl() {
    560         RuleBasedCollator col1 = null, col2 = null, col3 = null, col4 = null;
    561 
    562         String ruleset1 = "&9 < a, A < b, B < c, C; ch, cH, Ch, CH < d, D, e, E";
    563         String ruleset2 = "&9 < a, A < b, B < c, C < d, D, e, E";
    564         String ruleset3 = "&";
    565 
    566         try {
    567             col1 = new RuleBasedCollator(ruleset1);
    568         } catch (Exception e) {
    569             // only first error needs to be a warning since we exit function
    570             warnln("RuleBased Collator creation failed.");
    571             return;
    572         }
    573 
    574         try {
    575             col2 = new RuleBasedCollator(ruleset2);
    576         } catch (Exception e) {
    577             errln("RuleBased Collator creation failed.");
    578             return;
    579         }
    580 
    581         try {
    582             // empty rules fail
    583             col3 = new RuleBasedCollator(ruleset3);
    584             errln("Failure: Empty rules for the collator should fail");
    585             return;
    586         } catch (MissingResourceException e) {
    587             warnln(e.getMessage());
    588         } catch (Exception e) {
    589             logln("PASS: Empty rules for the collator failed as expected");
    590         }
    591 
    592         Locale locale = new Locale("aa", "AA");
    593         try {
    594             col3 = (RuleBasedCollator)Collator.getInstance(locale);
    595         } catch (Exception e) {
    596             errln("Fallback Collator creation failed.: %s");
    597             return;
    598         }
    599 
    600         try {
    601             col3 = (RuleBasedCollator)Collator.getInstance();
    602         } catch (Exception e) {
    603             errln("Default Collator creation failed.: %s");
    604             return;
    605         }
    606 
    607         String rule1 = col1.getRules();
    608         String rule2 = col2.getRules();
    609         String rule3 = col3.getRules();
    610 
    611         doAssert(!rule1.equals(rule2), "Default collator getRules failed");
    612         doAssert(!rule2.equals(rule3), "Default collator getRules failed");
    613         doAssert(!rule1.equals(rule3), "Default collator getRules failed");
    614 
    615         try {
    616             col4 = new RuleBasedCollator(rule2);
    617         } catch (Exception e) {
    618             errln("RuleBased Collator creation failed.");
    619             return;
    620         }
    621 
    622         String rule4 = col4.getRules();
    623         doAssert(rule2.equals(rule4), "Default collator getRules failed");
    624         // tests that modifier ! is always ignored
    625         String exclamationrules = "!&a<b";
    626         // java does not allow ! to be the start of the rule
    627         String thaistr = "\u0e40\u0e01\u0e2d";
    628         try {
    629             RuleBasedCollator col5 = new RuleBasedCollator(exclamationrules);
    630             RuleBasedCollator encol = (RuleBasedCollator)
    631                                         Collator.getInstance(Locale.ENGLISH);
    632             CollationElementIterator col5iter
    633                                    = col5.getCollationElementIterator(thaistr);
    634             CollationElementIterator encoliter
    635                                    = encol.getCollationElementIterator(
    636                                                                       thaistr);
    637             while (true) {
    638                 // testing with en since thai has its own tailoring
    639                 int ce = col5iter.next();
    640                 int ce2 = encoliter.next();
    641                 if (ce2 != ce) {
    642                     errln("! modifier test failed");
    643                 }
    644                 if (ce == CollationElementIterator.NULLORDER) {
    645                     break;
    646                 }
    647             }
    648         } catch (Exception e) {
    649             errln("RuleBased Collator creation failed for ! modifier.");
    650             return;
    651         }
    652     }
    653 
    654     /**
    655     * This tests the RuleBasedCollator
    656     * - getRules
    657     */
    658     @Test
    659     public void TestRules() {
    660         RuleBasedCollator coll = (RuleBasedCollator)Collator.getInstance(new Locale("","","")); //root
    661             // logln("PASS: RuleBased Collator creation passed");
    662 
    663 
    664         String rules = coll.getRules();
    665         if (rules != null && rules.length() != 0) {
    666             errln("Root tailored rules failed");
    667         }
    668     }
    669 
    670     @Test
    671     public void TestSafeClone() {
    672         String test1 = "abCda";
    673         String test2 = "abcda";
    674 
    675         // one default collator & two complex ones
    676         RuleBasedCollator someCollators[] = {
    677             (RuleBasedCollator)Collator.getInstance(Locale.ENGLISH),
    678             (RuleBasedCollator)Collator.getInstance(Locale.KOREA),
    679             (RuleBasedCollator)Collator.getInstance(Locale.JAPAN)
    680         };
    681         RuleBasedCollator someClonedCollators[] = new RuleBasedCollator[3];
    682 
    683         // change orig & clone & make sure they are independent
    684 
    685         for (int index = 0; index < someCollators.length; index ++)
    686         {
    687             try {
    688                 someClonedCollators[index]
    689                             = (RuleBasedCollator)someCollators[index].clone();
    690             } catch (CloneNotSupportedException e) {
    691                 errln("Error cloning collator");
    692             }
    693 
    694             someClonedCollators[index].setStrength(Collator.TERTIARY);
    695             someCollators[index].setStrength(Collator.PRIMARY);
    696             someClonedCollators[index].setCaseLevel(false);
    697             someCollators[index].setCaseLevel(false);
    698 
    699             doAssert(someClonedCollators[index].compare(test1, test2) > 0,
    700                      "Result should be \"abCda\" >>> \"abcda\" ");
    701             doAssert(someCollators[index].compare(test1, test2) == 0,
    702                      "Result should be \"abCda\" == \"abcda\" ");
    703         }
    704     }
    705 
    706     @Test
    707     public void TestGetTailoredSet()
    708     {
    709         logln("testing getTailoredSet...");
    710         String rules[] = {
    711             "&a < \u212b",
    712             "& S < \u0161 <<< \u0160",
    713         };
    714         String data[][] = {
    715             { "\u212b", "A\u030a", "\u00c5" },
    716             { "\u0161", "s\u030C", "\u0160", "S\u030C" }
    717         };
    718 
    719         int i = 0, j = 0;
    720 
    721         RuleBasedCollator coll;
    722         UnicodeSet set;
    723 
    724         for(i = 0; i < rules.length; i++) {
    725             try {
    726                 logln("Instantiating a collator from "+rules[i]);
    727                 coll = new RuleBasedCollator(rules[i]);
    728                 set = coll.getTailoredSet();
    729                 logln("Got set: "+set.toPattern(true));
    730                 if(set.size() < data[i].length) {
    731                     errln("Tailored set size smaller ("+set.size()+") than expected ("+data[i].length+")");
    732                 }
    733                 for(j = 0; j < data[i].length; j++) {
    734                     logln("Checking to see whether "+data[i][j]+" is in set");
    735                     if(!set.contains(data[i][j])) {
    736                         errln("Tailored set doesn't contain "+data[i][j]+"... It should");
    737                     }
    738                 }
    739             } catch (Exception e) {
    740                 warnln("Couldn't open collator with rules "+ rules[i]);
    741             }
    742         }
    743     }
    744 
    745     /**
    746      * Simple test to see if Collator is subclassable.
    747      * Also test coverage of base class methods that are overridden by RuleBasedCollator.
    748      */
    749     @Test
    750     public void TestSubClass()
    751     {
    752         class TestCollator extends Collator
    753         {
    754             @Override
    755             public boolean equals(Object that) {
    756                 return this == that;
    757             }
    758 
    759             @Override
    760             public int hashCode() {
    761                 return 0;
    762             }
    763 
    764             @Override
    765             public int compare(String source, String target) {
    766                 return source.compareTo(target);
    767             }
    768 
    769             @Override
    770             public CollationKey getCollationKey(String source)
    771             {   return new CollationKey(source,
    772                           getRawCollationKey(source, new RawCollationKey()));
    773             }
    774 
    775             @Override
    776             public RawCollationKey getRawCollationKey(String source,
    777                                                       RawCollationKey key)
    778             {
    779                 byte temp1[] = source.getBytes();
    780                 byte temp2[] = new byte[temp1.length + 1];
    781                 System.arraycopy(temp1, 0, temp2, 0, temp1.length);
    782                 temp2[temp1.length] = 0;
    783                 if (key == null) {
    784                     key = new RawCollationKey();
    785                 }
    786                 key.bytes = temp2;
    787                 key.size = temp2.length;
    788                 return key;
    789             }
    790 
    791             @Override
    792             public void setVariableTop(int ce)
    793             {
    794                 if (isFrozen()) {
    795                     throw new UnsupportedOperationException("Attempt to modify frozen object");
    796                 }
    797             }
    798 
    799             @Override
    800             public int setVariableTop(String str)
    801             {
    802                 if (isFrozen()) {
    803                     throw new UnsupportedOperationException("Attempt to modify frozen object");
    804                 }
    805 
    806                 return 0;
    807             }
    808 
    809             @Override
    810             public int getVariableTop()
    811             {
    812                 return 0;
    813             }
    814             @Override
    815             public VersionInfo getVersion()
    816             {
    817                 return VersionInfo.getInstance(0);
    818             }
    819             @Override
    820             public VersionInfo getUCAVersion()
    821             {
    822                 return VersionInfo.getInstance(0);
    823             }
    824         }
    825 
    826         Collator col1 = new TestCollator();
    827         Collator col2 = new TestCollator();
    828         if (col1.equals(col2)) {
    829             errln("2 different instance of TestCollator should fail");
    830         }
    831         if (col1.hashCode() != col2.hashCode()) {
    832             errln("Every TestCollator has the same hashcode");
    833         }
    834         String abc = "abc";
    835         String bcd = "bcd";
    836         if (col1.compare(abc, bcd) != abc.compareTo(bcd)) {
    837             errln("TestCollator compare should be the same as the default " +
    838                   "string comparison");
    839         }
    840         CollationKey key = col1.getCollationKey(abc);
    841         byte temp1[] = abc.getBytes();
    842         byte temp2[] = new byte[temp1.length + 1];
    843         System.arraycopy(temp1, 0, temp2, 0, temp1.length);
    844         temp2[temp1.length] = 0;
    845         if (!java.util.Arrays.equals(key.toByteArray(), temp2)
    846                 || !key.getSourceString().equals(abc)) {
    847             errln("TestCollator collationkey API is returning wrong values");
    848         }
    849         UnicodeSet set = col1.getTailoredSet();
    850         if (!set.equals(new UnicodeSet(0, 0x10FFFF))) {
    851             errln("Error getting default tailored set");
    852         }
    853 
    854         // Base class code coverage.
    855         // Most of these methods are dummies;
    856         // they are overridden by any subclass that supports their features.
    857 
    858         assertEquals("compare(strings as Object)", 0,
    859                 col1.compare(new StringBuilder("abc"), new StringBuffer("abc")));
    860 
    861         col1.setStrength(Collator.SECONDARY);
    862         assertNotEquals("getStrength()", Collator.PRIMARY, col1.getStrength());
    863 
    864         // setStrength2() is @internal and returns this.
    865         // The base class getStrength() always returns the same value,
    866         // since the base class does not have a field to store the strength.
    867         assertNotEquals("setStrength2().getStrength()", Collator.PRIMARY,
    868                 col1.setStrength2(Collator.IDENTICAL).getStrength());
    869 
    870         // (base class).setDecomposition() may or may not be implemented.
    871         try {
    872             col1.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
    873         } catch (UnsupportedOperationException expected) {
    874         }
    875         assertNotEquals("getDecomposition()", -1, col1.getDecomposition());  // don't care about the value
    876 
    877         // (base class).setMaxVariable() may or may not be implemented.
    878         try {
    879             col1.setMaxVariable(Collator.ReorderCodes.CURRENCY);
    880         } catch (UnsupportedOperationException expected) {
    881         }
    882         assertNotEquals("getMaxVariable()", -1, col1.getMaxVariable());  // don't care about the value
    883 
    884         // (base class).setReorderCodes() may or may not be implemented.
    885         try {
    886             col1.setReorderCodes(0, 1, 2);
    887         } catch (UnsupportedOperationException expected) {
    888         }
    889         try {
    890             col1.getReorderCodes();
    891         } catch (UnsupportedOperationException expected) {
    892         }
    893 
    894         assertFalse("getDisplayName()", Collator.getDisplayName(Locale.GERMAN).isEmpty());
    895         assertFalse("getDisplayName()", Collator.getDisplayName(Locale.GERMAN, Locale.ITALIAN).isEmpty());
    896 
    897         assertNotEquals("getLocale()", ULocale.GERMAN, col1.getLocale(ULocale.ACTUAL_LOCALE));
    898 
    899         // Cover Collator.setLocale() which is only package-visible.
    900         Object token = Collator.registerInstance(new TestCollator(), new ULocale("de-Japn-419"));
    901         Collator.unregister(token);
    902 
    903         // Freezable default implementations. freeze() may or may not be implemented.
    904         assertFalse("not yet frozen", col2.isFrozen());
    905         try {
    906             col2.freeze();
    907             assertTrue("now frozen", col2.isFrozen());
    908         } catch (UnsupportedOperationException expected) {
    909         }
    910         try {
    911             col2.setStrength(Collator.PRIMARY);
    912             if (col2.isFrozen()) {
    913                 fail("(frozen Collator).setStrength() should throw an exception");
    914             }
    915         } catch (UnsupportedOperationException expected) {
    916         }
    917         try {
    918             Collator col3 = col2.cloneAsThawed();
    919             assertFalse("!cloneAsThawed().isFrozen()", col3.isFrozen());
    920         } catch (UnsupportedOperationException expected) {
    921         }
    922     }
    923 
    924     /**
    925      * Simple test the collator setter and getters.
    926      * Similar to C++ apicoll.cpp TestAttribute().
    927      */
    928     @Test
    929     public void TestSetGet()
    930     {
    931         RuleBasedCollator collator = (RuleBasedCollator)Collator.getInstance();
    932         int decomp = collator.getDecomposition();
    933         int strength = collator.getStrength();
    934         boolean alt = collator.isAlternateHandlingShifted();
    935         boolean caselevel = collator.isCaseLevel();
    936         boolean french = collator.isFrenchCollation();
    937         boolean hquart = collator.isHiraganaQuaternary();
    938         boolean lowercase = collator.isLowerCaseFirst();
    939         boolean uppercase = collator.isUpperCaseFirst();
    940 
    941         collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
    942         if (collator.getDecomposition() != Collator.CANONICAL_DECOMPOSITION) {
    943             errln("Setting decomposition failed");
    944         }
    945         collator.setStrength(Collator.QUATERNARY);
    946         if (collator.getStrength() != Collator.QUATERNARY) {
    947             errln("Setting strength failed");
    948         }
    949         collator.setAlternateHandlingShifted(!alt);
    950         if (collator.isAlternateHandlingShifted() == alt) {
    951             errln("Setting alternate handling failed");
    952         }
    953         collator.setCaseLevel(!caselevel);
    954         if (collator.isCaseLevel() == caselevel) {
    955             errln("Setting case level failed");
    956         }
    957         collator.setFrenchCollation(!french);
    958         if (collator.isFrenchCollation() == french) {
    959             errln("Setting french collation failed");
    960         }
    961         collator.setHiraganaQuaternary(!hquart);
    962         if (collator.isHiraganaQuaternary() != hquart) {
    963             errln("Setting hiragana quartenary worked but should be a no-op since ICU 50");
    964         }
    965         collator.setLowerCaseFirst(!lowercase);
    966         if (collator.isLowerCaseFirst() == lowercase) {
    967             errln("Setting lower case first failed");
    968         }
    969         collator.setUpperCaseFirst(!uppercase);
    970         if (collator.isUpperCaseFirst() == uppercase) {
    971             errln("Setting upper case first failed");
    972         }
    973         collator.setDecompositionDefault();
    974         if (collator.getDecomposition() != decomp) {
    975             errln("Setting decomposition default failed");
    976         }
    977         collator.setStrengthDefault();
    978         if (collator.getStrength() != strength) {
    979             errln("Setting strength default failed");
    980         }
    981         collator.setAlternateHandlingDefault();
    982         if (collator.isAlternateHandlingShifted() != alt) {
    983             errln("Setting alternate handling default failed");
    984         }
    985         collator.setCaseLevelDefault();
    986         if (collator.isCaseLevel() != caselevel) {
    987             errln("Setting case level default failed");
    988         }
    989         collator.setFrenchCollationDefault();
    990         if (collator.isFrenchCollation() != french) {
    991             errln("Setting french handling default failed");
    992         }
    993         collator.setHiraganaQuaternaryDefault();
    994         if (collator.isHiraganaQuaternary() != hquart) {
    995             errln("Setting Hiragana Quartenary default failed");
    996         }
    997         collator.setCaseFirstDefault();
    998         if (collator.isLowerCaseFirst() != lowercase
    999             || collator.isUpperCaseFirst() != uppercase) {
   1000             errln("Setting case first handling default failed");
   1001         }
   1002     }
   1003 
   1004     @Test
   1005     public void TestVariableTopSetting() {
   1006         // Use the root collator, not the default collator.
   1007         // This test fails with en_US_POSIX which tailors the dollar sign after 'A'.
   1008         RuleBasedCollator coll = (RuleBasedCollator)Collator.getInstance(ULocale.ROOT);
   1009 
   1010         int oldVarTop = coll.getVariableTop();
   1011 
   1012         // ICU 53+: The character must be in a supported reordering group,
   1013         // and the variable top is pinned to the end of that group.
   1014         try {
   1015             coll.setVariableTop("A");
   1016             errln("setVariableTop(letter) did not detect illegal argument");
   1017         } catch(IllegalArgumentException expected) {
   1018         }
   1019 
   1020         // dollar sign (currency symbol)
   1021         int newVarTop = coll.setVariableTop("$");
   1022 
   1023         if(newVarTop != coll.getVariableTop()) {
   1024             errln("setVariableTop(dollar sign) != following getVariableTop()");
   1025         }
   1026 
   1027         String dollar = "$";
   1028         String euro = "\u20AC";
   1029         int newVarTop2 = coll.setVariableTop(euro);
   1030         assertEquals("setVariableTop(Euro sign) == following getVariableTop()",
   1031                      newVarTop2, coll.getVariableTop());
   1032         assertEquals("setVariableTop(Euro sign) == setVariableTop(dollar sign) (should pin to top of currency group)",
   1033                      newVarTop2, newVarTop);
   1034 
   1035         coll.setAlternateHandlingShifted(true);
   1036         assertEquals("empty==dollar", 0, coll.compare("", dollar));  // UCOL_EQUAL
   1037         assertEquals("empty==euro", 0, coll.compare("", euro));  // UCOL_EQUAL
   1038         assertEquals("dollar<zero", -1, coll.compare(dollar, "0"));  // UCOL_LESS
   1039 
   1040         coll.setVariableTop(oldVarTop);
   1041 
   1042         int newerVarTop = coll.setVariableTop("$");
   1043 
   1044         if(newVarTop != newerVarTop) {
   1045           errln("Didn't set vartop properly from String!\n");
   1046         }
   1047     }
   1048 
   1049     @Test
   1050     public void TestMaxVariable() {
   1051         RuleBasedCollator coll = (RuleBasedCollator)Collator.getInstance(ULocale.ROOT);
   1052 
   1053         try {
   1054             coll.setMaxVariable(Collator.ReorderCodes.OTHERS);
   1055             errln("setMaxVariable(others) did not detect illegal argument");
   1056         } catch(IllegalArgumentException expected) {
   1057         }
   1058 
   1059         coll.setMaxVariable(Collator.ReorderCodes.CURRENCY);
   1060 
   1061         if(Collator.ReorderCodes.CURRENCY != coll.getMaxVariable()) {
   1062           errln("setMaxVariable(currency) != following getMaxVariable()");
   1063         }
   1064 
   1065         coll.setAlternateHandlingShifted(true);
   1066         assertEquals("empty==dollar", 0, coll.compare("", "$"));  // UCOL_EQUAL
   1067         assertEquals("empty==euro", 0, coll.compare("", "\u20AC"));  // UCOL_EQUAL
   1068         assertEquals("dollar<zero", -1, coll.compare("$", "0"));  // UCOL_LESS
   1069     }
   1070 
   1071     @Test
   1072     public void TestGetLocale() {
   1073         String rules = "&a<x<y<z";
   1074 
   1075         Collator coll = Collator.getInstance(new ULocale("root"));
   1076         ULocale locale = coll.getLocale(ULocale.ACTUAL_LOCALE);
   1077         if(!locale.equals(ULocale.ROOT)) {
   1078           errln("Collator.getInstance(\"root\").getLocale(actual) != ULocale.ROOT; " +
   1079                 "getLocale().getName() = \"" + locale.getName() + "\"");
   1080         }
   1081 
   1082         coll = Collator.getInstance(new ULocale(""));
   1083         locale = coll.getLocale(ULocale.ACTUAL_LOCALE);
   1084         if(!locale.equals(ULocale.ROOT)) {
   1085             errln("Collator.getInstance(\"\").getLocale(actual) != ULocale.ROOT; " +
   1086                   "getLocale().getName() = \"" + locale.getName() + "\"");
   1087         }
   1088 
   1089         int i = 0;
   1090 
   1091         String[][] testStruct = {
   1092           // requestedLocale, validLocale, actualLocale
   1093           // Note: ULocale.ROOT.getName() == "" not "root".
   1094           { "de_DE", "de", "" },
   1095           { "sr_RS", "sr_Cyrl_RS", "sr" },
   1096           { "en_US_CALIFORNIA", "en_US", "" },
   1097           { "fr_FR_NONEXISTANT", "fr", "" },
   1098           // pinyin is the default, therefore suppressed.
   1099           { "zh_CN", "zh_Hans_CN", "zh" },
   1100           // zh_Hant has default=stroke but the data is in zh.
   1101           { "zh_TW", "zh_Hant_TW", "zh@collation=stroke" },
   1102           { "zh_TW@collation=pinyin", "zh_Hant_TW@collation=pinyin", "zh" },
   1103           { "zh_CN@collation=stroke", "zh_Hans_CN@collation=stroke", "zh@collation=stroke" },
   1104           // yue/yue_Hant aliased to zh_Hant, yue_Hans aliased to zh_Hans.
   1105           { "yue", "zh_Hant", "zh@collation=stroke" },
   1106           { "yue_HK", "zh_Hant", "zh@collation=stroke" },
   1107           { "yue_Hant", "zh_Hant", "zh@collation=stroke" },
   1108           { "yue_Hant_HK", "zh_Hant", "zh@collation=stroke" },
   1109           { "yue@collation=pinyin", "zh_Hant@collation=pinyin", "zh" },
   1110           { "yue_HK@collation=pinyin", "zh_Hant@collation=pinyin", "zh" },
   1111           { "yue_CN", "zh_Hans", "zh" },
   1112           { "yue_Hans", "zh_Hans", "zh" },
   1113           { "yue_Hans_CN", "zh_Hans", "zh" },
   1114           { "yue_Hans@collation=stroke", "zh_Hans@collation=stroke", "zh@collation=stroke" },
   1115           { "yue_CN@collation=stroke", "zh_Hans@collation=stroke", "zh@collation=stroke" }
   1116         };
   1117 
   1118         /* test opening collators for different locales */
   1119         for(i = 0; i<testStruct.length; i++) {
   1120             String requestedLocale = testStruct[i][0];
   1121             String validLocale = testStruct[i][1];
   1122             String actualLocale = testStruct[i][2];
   1123             try {
   1124                 coll = Collator.getInstance(new ULocale(requestedLocale));
   1125             } catch(Exception e) {
   1126                 errln(String.format("Failed to open collator for %s with %s", requestedLocale, e));
   1127                 continue;
   1128             }
   1129             // Note: C++ getLocale() recognizes ULOC_REQUESTED_LOCALE
   1130             // which does not exist in Java.
   1131             locale = coll.getLocale(ULocale.VALID_LOCALE);
   1132             if(!locale.equals(new ULocale(validLocale))) {
   1133               errln(String.format("[Coll %s]: Error in valid locale, expected %s, got %s",
   1134                     requestedLocale, validLocale, locale.getName()));
   1135             }
   1136             locale = coll.getLocale(ULocale.ACTUAL_LOCALE);
   1137             if(!locale.equals(new ULocale(actualLocale))) {
   1138               errln(String.format("[Coll %s]: Error in actual locale, expected %s, got %s",
   1139                     requestedLocale, actualLocale, locale.getName()));
   1140             }
   1141             // If we open a collator for the actual locale, we should get an equivalent one again.
   1142             Collator coll2;
   1143             try {
   1144                 coll2 = Collator.getInstance(locale);
   1145             } catch(Exception e) {
   1146                 errln(String.format("Failed to open collator for actual locale \"%s\" with %s",
   1147                         locale.getName(), e));
   1148                 continue;
   1149             }
   1150             ULocale actual2 = coll2.getLocale(ULocale.ACTUAL_LOCALE);
   1151             if(!actual2.equals(locale)) {
   1152               errln(String.format("[Coll actual \"%s\"]: Error in actual locale, got different one: \"%s\"",
   1153                     locale.getName(), actual2.getName()));
   1154             }
   1155             if(!coll2.equals(coll)) {
   1156               errln(String.format("[Coll actual \"%s\"]: Got different collator than before",
   1157                       locale.getName()));
   1158             }
   1159         }
   1160 
   1161         /* completely non-existent locale for collator should get a root collator */
   1162         {
   1163             try {
   1164                 coll = Collator.getInstance(new ULocale("blahaha"));
   1165             } catch(Exception e) {
   1166                 errln("Failed to open collator with " + e);
   1167                 return;
   1168             }
   1169             ULocale valid = coll.getLocale(ULocale.VALID_LOCALE);
   1170             String name = valid.getName();
   1171             if(name.length() != 0 && !name.equals("root")) {
   1172                 errln("Valid locale for nonexisting locale collator is \"" + name + "\" not root");
   1173             }
   1174             ULocale actual = coll.getLocale(ULocale.ACTUAL_LOCALE);
   1175             name = actual.getName();
   1176             if(name.length() != 0 && !name.equals("root")) {
   1177                 errln("Actual locale for nonexisting locale collator is \"" + name + "\" not root");
   1178             }
   1179         }
   1180 
   1181         /* collator instantiated from rules should have all locales null */
   1182         try {
   1183             coll = new RuleBasedCollator(rules);
   1184         } catch (Exception e) {
   1185             errln("RuleBasedCollator(" + rules + ") failed: " + e);
   1186             return;
   1187         }
   1188         locale = coll.getLocale(ULocale.VALID_LOCALE);
   1189         if(locale != null) {
   1190             errln(String.format("For collator instantiated from rules, valid locale %s is not bogus",
   1191                     locale.getName()));
   1192         }
   1193         locale = coll.getLocale(ULocale.ACTUAL_LOCALE);
   1194         if(locale != null) {
   1195             errln(String.format("For collator instantiated from rules, actual locale %s is not bogus",
   1196                     locale.getName()));
   1197         }
   1198     }
   1199 
   1200     @Test
   1201     public void TestBounds()
   1202     {
   1203         Collator coll = Collator.getInstance(new Locale("sh", ""));
   1204 
   1205         String test[] = { "John Smith", "JOHN SMITH",
   1206                           "john SMITH", "j\u00F6hn sm\u00EFth",
   1207                           "J\u00F6hn Sm\u00EFth", "J\u00D6HN SM\u00CFTH",
   1208                           "john smithsonian", "John Smithsonian",
   1209         };
   1210 
   1211         String testStr[] = {
   1212                           "\u010CAKI MIHALJ",
   1213                           "\u010CAKI MIHALJ",
   1214                           "\u010CAKI PIRO\u0160KA",
   1215                           "\u010CABAI ANDRIJA",
   1216                           "\u010CABAI LAJO\u0160",
   1217                           "\u010CABAI MARIJA",
   1218                           "\u010CABAI STEVAN",
   1219                           "\u010CABAI STEVAN",
   1220                           "\u010CABARKAPA BRANKO",
   1221                           "\u010CABARKAPA MILENKO",
   1222                           "\u010CABARKAPA MIROSLAV",
   1223                           "\u010CABARKAPA SIMO",
   1224                           "\u010CABARKAPA STANKO",
   1225                           "\u010CABARKAPA TAMARA",
   1226                           "\u010CABARKAPA TOMA\u0160",
   1227                           "\u010CABDARI\u0106 NIKOLA",
   1228                           "\u010CABDARI\u0106 ZORICA",
   1229                           "\u010CABI NANDOR",
   1230                           "\u010CABOVI\u0106 MILAN",
   1231                           "\u010CABRADI AGNEZIJA",
   1232                           "\u010CABRADI IVAN",
   1233                           "\u010CABRADI JELENA",
   1234                           "\u010CABRADI LJUBICA",
   1235                           "\u010CABRADI STEVAN",
   1236                           "\u010CABRDA MARTIN",
   1237                           "\u010CABRILO BOGDAN",
   1238                           "\u010CABRILO BRANISLAV",
   1239                           "\u010CABRILO LAZAR",
   1240                           "\u010CABRILO LJUBICA",
   1241                           "\u010CABRILO SPASOJA",
   1242                           "\u010CADE\u0160 ZDENKA",
   1243                           "\u010CADESKI BLAGOJE",
   1244                           "\u010CADOVSKI VLADIMIR",
   1245                           "\u010CAGLJEVI\u0106 TOMA",
   1246                           "\u010CAGOROVI\u0106 VLADIMIR",
   1247                           "\u010CAJA VANKA",
   1248                           "\u010CAJI\u0106 BOGOLJUB",
   1249                           "\u010CAJI\u0106 BORISLAV",
   1250                           "\u010CAJI\u0106 RADOSLAV",
   1251                           "\u010CAK\u0160IRAN MILADIN",
   1252                           "\u010CAKAN EUGEN",
   1253                           "\u010CAKAN EVGENIJE",
   1254                           "\u010CAKAN IVAN",
   1255                           "\u010CAKAN JULIJAN",
   1256                           "\u010CAKAN MIHAJLO",
   1257                           "\u010CAKAN STEVAN",
   1258                           "\u010CAKAN VLADIMIR",
   1259                           "\u010CAKAN VLADIMIR",
   1260                           "\u010CAKAN VLADIMIR",
   1261                           "\u010CAKARA ANA",
   1262                           "\u010CAKAREVI\u0106 MOMIR",
   1263                           "\u010CAKAREVI\u0106 NEDELJKO",
   1264                           "\u010CAKI \u0160ANDOR",
   1265                           "\u010CAKI AMALIJA",
   1266                           "\u010CAKI ANDRA\u0160",
   1267                           "\u010CAKI LADISLAV",
   1268                           "\u010CAKI LAJO\u0160",
   1269                           "\u010CAKI LASLO" };
   1270 
   1271         CollationKey testKey[] = new CollationKey[testStr.length];
   1272         for (int i = 0; i < testStr.length; i ++) {
   1273             testKey[i] = coll.getCollationKey(testStr[i]);
   1274         }
   1275 
   1276         Arrays.sort(testKey);
   1277         for(int i = 0; i < testKey.length - 1; i ++) {
   1278             CollationKey lower
   1279                            = testKey[i].getBound(CollationKey.BoundMode.LOWER,
   1280                                                  Collator.SECONDARY);
   1281             for (int j = i + 1; j < testKey.length; j ++) {
   1282                 CollationKey upper
   1283                            = testKey[j].getBound(CollationKey.BoundMode.UPPER,
   1284                                                  Collator.SECONDARY);
   1285                 for (int k = i; k <= j; k ++) {
   1286                     if (lower.compareTo(testKey[k]) > 0) {
   1287                         errln("Problem with lower bound at i = " + i + " j = "
   1288                               + j + " k = " + k);
   1289                     }
   1290                     if (upper.compareTo(testKey[k]) <= 0) {
   1291                         errln("Problem with upper bound at i = " + i + " j = "
   1292                               + j + " k = " + k);
   1293                     }
   1294                 }
   1295             }
   1296         }
   1297 
   1298         for (int i = 0; i < test.length; i ++)
   1299         {
   1300             CollationKey key = coll.getCollationKey(test[i]);
   1301             CollationKey lower = key.getBound(CollationKey.BoundMode.LOWER,
   1302                                               Collator.SECONDARY);
   1303             CollationKey upper = key.getBound(CollationKey.BoundMode.UPPER_LONG,
   1304                                               Collator.SECONDARY);
   1305             for (int j = i + 1; j < test.length; j ++) {
   1306                 key = coll.getCollationKey(test[j]);
   1307                 if (lower.compareTo(key) > 0) {
   1308                     errln("Problem with lower bound i = " + i + " j = " + j);
   1309                 }
   1310                 if (upper.compareTo(key) <= 0) {
   1311                     errln("Problem with upper bound i = " + i + " j = " + j);
   1312                 }
   1313             }
   1314         }
   1315     }
   1316 
   1317     @Test
   1318     public final void TestGetAll() {
   1319         Locale[] list = Collator.getAvailableLocales();
   1320         int errorCount = 0;
   1321         for (int i = 0; i < list.length; ++i) {
   1322             log("Locale name: ");
   1323             log(list[i].toString());
   1324             log(" , the display name is : ");
   1325             logln(list[i].getDisplayName());
   1326             try{
   1327                 logln("     ...... Or display as: " + Collator.getDisplayName(list[i]));
   1328                 logln("     ...... and display in Chinese: " +
   1329                       Collator.getDisplayName(list[i],Locale.CHINA));
   1330             }catch(MissingResourceException ex){
   1331                 errorCount++;
   1332                 logln("could not get displayName for " + list[i]);
   1333             }
   1334         }
   1335         if(errorCount>0){
   1336           warnln("Could not load the locale data.");
   1337         }
   1338     }
   1339 
   1340     private boolean
   1341     doSetsTest(UnicodeSet ref, UnicodeSet set, String inSet, String outSet) {
   1342         boolean ok = true;
   1343         set.clear();
   1344         set.applyPattern(inSet);
   1345 
   1346         if(!ref.containsAll(set)) {
   1347             err("Some stuff from "+inSet+" is not present in the set.\nMissing:"+
   1348                 set.removeAll(ref).toPattern(true)+"\n");
   1349             ok = false;
   1350         }
   1351 
   1352         set.clear();
   1353         set.applyPattern(outSet);
   1354         if(!ref.containsNone(set)) {
   1355             err("Some stuff from "+outSet+" is present in the set.\nUnexpected:"+
   1356                 set.retainAll(ref).toPattern(true)+"\n");
   1357             ok = false;
   1358         }
   1359         return ok;
   1360     }
   1361 
   1362     // capitst.c/TestGetContractionsAndUnsafes()
   1363     @Test
   1364     public void TestGetContractions() throws Exception {
   1365         /*        static struct {
   1366          const char* locale;
   1367          const char* inConts;
   1368          const char* outConts;
   1369          const char* inExp;
   1370          const char* outExp;
   1371          const char* unsafeCodeUnits;
   1372          const char* safeCodeUnits;
   1373          }
   1374          */
   1375         String tests[][] = {
   1376                 { "ru",
   1377                     "[{\u0418\u0306}{\u0438\u0306}]",
   1378                     "[\u0439\u0457]",
   1379                     "[\u00e6]",
   1380                     "[ae]",
   1381                     "[\u0418\u0438]",
   1382                     "[aAbBxv]"
   1383                 },
   1384                 { "uk",
   1385                     "[{\u0406\u0308}{\u0456\u0308}{\u0418\u0306}{\u0438\u0306}]",
   1386                     "[\u0407\u0419\u0439\u0457]",
   1387                     "[\u00e6]",
   1388                     "[ae]",
   1389                     "[\u0406\u0456\u0418\u0438]",
   1390                     "[aAbBxv]"
   1391                 },
   1392                 { "sh",
   1393                     "[{C\u0301}{C\u030C}{C\u0341}{DZ\u030C}{Dz\u030C}{D\u017D}{D\u017E}{lj}{nj}]",
   1394                     "[{\u309d\u3099}{\u30fd\u3099}]",
   1395                     "[\u00e6]",
   1396                     "[a]",
   1397                     "[nlcdzNLCDZ]",
   1398                     "[jabv]"
   1399                 },
   1400                 { "ja",
   1401                     /*
   1402                      * The "collv2" builder omits mappings if the collator maps their
   1403                      * character sequences to the same CEs.
   1404                      * For example, it omits Japanese contractions for NFD forms
   1405                      * of the voiced iteration mark (U+309E = U+309D + U+3099), such as
   1406                      * {\u3053\u3099\u309D\u3099}{\u3053\u309D\u3099}
   1407                      * {\u30B3\u3099\u30FD\u3099}{\u30B3\u30FD\u3099}.
   1408                      * It does add mappings for the precomposed forms.
   1409                      */
   1410                     "[{\u3053\u3099\u309D}{\u3053\u3099\u309E}{\u3053\u3099\u30FC}" +
   1411                      "{\u3053\u309D}{\u3053\u309E}{\u3053\u30FC}" +
   1412                      "{\u30B3\u3099\u30FC}{\u30B3\u3099\u30FD}{\u30B3\u3099\u30FE}" +
   1413                      "{\u30B3\u30FC}{\u30B3\u30FD}{\u30B3\u30FE}]",
   1414                     "[{\u30FD\u3099}{\u309D\u3099}{\u3053\u3099}{\u30B3\u3099}{lj}{nj}]",
   1415                     "[\u30FE\u00e6]",
   1416                     "[a]",
   1417                     "[\u3099]",
   1418                     "[]"
   1419                 }
   1420         };
   1421 
   1422         RuleBasedCollator coll = null;
   1423         int i = 0;
   1424         UnicodeSet conts = new UnicodeSet();
   1425         UnicodeSet exp = new UnicodeSet();
   1426         UnicodeSet set = new UnicodeSet();
   1427 
   1428         for(i = 0; i < tests.length; i++) {
   1429             logln("Testing locale: "+ tests[i][0]);
   1430             coll = (RuleBasedCollator)Collator.getInstance(new ULocale(tests[i][0]));
   1431             coll.getContractionsAndExpansions(conts, exp, true);
   1432             boolean ok = true;
   1433             logln("Contractions "+conts.size()+":\n"+conts.toPattern(true));
   1434             ok &= doSetsTest(conts, set, tests[i][1], tests[i][2]);
   1435             logln("Expansions "+exp.size()+":\n"+exp.toPattern(true));
   1436             ok &= doSetsTest(exp, set, tests[i][3], tests[i][4]);
   1437             if(!ok) {
   1438                 // In case of failure, log the rule string for better diagnostics.
   1439                 String rules = coll.getRules(false);
   1440                 logln("Collation rules (getLocale()="+
   1441                         coll.getLocale(ULocale.ACTUAL_LOCALE).toString()+"): "+
   1442                         Utility.escape(rules));
   1443             }
   1444 
   1445             // No unsafe set in ICU4J
   1446             //noConts = ucol_getUnsafeSet(coll, conts, &status);
   1447             //doSetsTest(conts, set, tests[i][5], tests[i][6]);
   1448             //log_verbose("Unsafes "+conts.size()+":\n"+conts.toPattern(true)+"\n");
   1449         }
   1450     }
   1451     private static final String bigone = "One";
   1452     private static final String littleone = "one";
   1453 
   1454     @Test
   1455     public void TestClone() {
   1456         logln("\ninit c0");
   1457         RuleBasedCollator c0 = (RuleBasedCollator)Collator.getInstance();
   1458         c0.setStrength(Collator.TERTIARY);
   1459         dump("c0", c0);
   1460 
   1461         logln("\ninit c1");
   1462         RuleBasedCollator c1 = (RuleBasedCollator)Collator.getInstance();
   1463         c1.setStrength(Collator.TERTIARY);
   1464         c1.setUpperCaseFirst(!c1.isUpperCaseFirst());
   1465         dump("c0", c0);
   1466         dump("c1", c1);
   1467         try{
   1468             logln("\ninit c2");
   1469             RuleBasedCollator c2 = (RuleBasedCollator)c1.clone();
   1470             c2.setUpperCaseFirst(!c2.isUpperCaseFirst());
   1471             dump("c0", c0);
   1472             dump("c1", c1);
   1473             dump("c2", c2);
   1474             if(c1.equals(c2)){
   1475                 errln("The cloned objects refer to same data");
   1476             }
   1477         }catch(CloneNotSupportedException ex){
   1478             errln("Could not clone the collator");
   1479         }
   1480     }
   1481 
   1482     private void dump(String msg, RuleBasedCollator c) {
   1483         logln(msg + " " + c.compare(bigone, littleone) +
   1484                            " s: " + c.getStrength() +
   1485                            " u: " + c.isUpperCaseFirst());
   1486     }
   1487 
   1488     @Test
   1489     public void TestIterNumeric() throws Exception {  // misnomer for Java, but parallel with C++ test
   1490         // Regression test for ticket #9915.
   1491         // The collation code sometimes masked the continuation marker away
   1492         // but later tested the result for isContinuation().
   1493         // This test case failed because the third bytes of the computed numeric-collation primaries
   1494         // were permutated with the script reordering table.
   1495         // It should have been possible to reproduce this with the root collator
   1496         // and characters with appropriate 3-byte primary weights.
   1497         // The effectiveness of this test depends completely on the collation elements
   1498         // and on the implementation code.
   1499         RuleBasedCollator coll = new RuleBasedCollator("[reorder Hang Hani]");
   1500         coll.setNumericCollation(true);
   1501         int result = coll.compare("40", "72");
   1502         assertTrue("40<72", result < 0);
   1503     }
   1504 
   1505     /*
   1506      * Tests the method public void setStrength(int newStrength)
   1507      */
   1508     @Test
   1509     public void TestSetStrength() {
   1510         // Tests when if ((newStrength != PRIMARY) && ... ) is true
   1511         int[] cases = { -1, 4, 5 };
   1512         for (int i = 0; i < cases.length; i++) {
   1513             try {
   1514                 // Assuming -1 is not one of the values
   1515                 Collator c = Collator.getInstance();
   1516                 c.setStrength(cases[i]);
   1517                 errln("Collator.setStrength(int) is suppose to return "
   1518                         + "an exception for an invalid newStrength value of " + cases[i]);
   1519             } catch (Exception e) {
   1520             }
   1521         }
   1522     }
   1523 
   1524     /*
   1525      * Tests the method public void setDecomposition(int decomposition)
   1526      */
   1527     @Test
   1528     public void TestSetDecomposition() {
   1529         // Tests when if ((decomposition != NO_DECOMPOSITION) && ...) is true
   1530         int[] cases = { 0, 1, 14, 15, 18, 19 };
   1531         for (int i = 0; i < cases.length; i++) {
   1532             try {
   1533                 // Assuming -1 is not one of the values
   1534                 Collator c = Collator.getInstance();
   1535                 c.setDecomposition(cases[i]);
   1536                 errln("Collator.setDecomposition(int) is suppose to return "
   1537                         + "an exception for an invalid decomposition value of " + cases[i]);
   1538             } catch (Exception e) {
   1539             }
   1540         }
   1541     }
   1542 
   1543     /*
   1544      * Tests the class CollatorFactory
   1545      */
   1546     @Test
   1547     public void TestCreateCollator() {
   1548         // The following class override public Collator createCollator(Locale loc)
   1549         class TestCreateCollator extends CollatorFactory {
   1550             @Override
   1551             public Set<String> getSupportedLocaleIDs() {
   1552                 return new HashSet<String>();
   1553             }
   1554 
   1555             public TestCreateCollator() {
   1556                 super();
   1557             }
   1558 
   1559             @Override
   1560             public Collator createCollator(ULocale c) {
   1561                 return null;
   1562             }
   1563         }
   1564         // The following class override public Collator createCollator(ULocale loc)
   1565         class TestCreateCollator1 extends CollatorFactory {
   1566             @Override
   1567             public Set<String> getSupportedLocaleIDs() {
   1568                 return new HashSet<String>();
   1569             }
   1570 
   1571             public TestCreateCollator1() {
   1572                 super();
   1573             }
   1574 
   1575             @Override
   1576             public Collator createCollator(Locale c) {
   1577                 return null;
   1578             }
   1579             @Override
   1580             public boolean visible(){
   1581                 return false;
   1582             }
   1583         }
   1584 
   1585         /*
   1586          * Tests the method public Collator createCollator(Locale loc) using TestCreateCollator1 class
   1587          */
   1588         try {
   1589             TestCreateCollator tcc = new TestCreateCollator();
   1590             tcc.createCollator(new Locale("en_US"));
   1591         } catch (Exception e) {
   1592             errln("Collator.createCollator(Locale) was not suppose to " + "return an exception.");
   1593         }
   1594 
   1595         /*
   1596          * Tests the method public Collator createCollator(ULocale loc) using TestCreateCollator1 class
   1597          */
   1598         try {
   1599             TestCreateCollator1 tcc = new TestCreateCollator1();
   1600             tcc.createCollator(new ULocale("en_US"));
   1601         } catch (Exception e) {
   1602             errln("Collator.createCollator(ULocale) was not suppose to " + "return an exception.");
   1603         }
   1604 
   1605         /*
   1606          * Tests the method public String getDisplayName(Locale objectLocale, Locale displayLocale) using TestCreateCollator1 class
   1607          */
   1608         try {
   1609             TestCreateCollator tcc = new TestCreateCollator();
   1610             tcc.getDisplayName(new Locale("en_US"), new Locale("jp_JP"));
   1611         } catch (Exception e) {
   1612             errln("Collator.getDisplayName(Locale,Locale) was not suppose to return an exception.");
   1613         }
   1614 
   1615         /*
   1616          * Tests the method public String getDisplayName(ULocale objectLocale, ULocale displayLocale) using TestCreateCollator1 class
   1617          */
   1618         try {
   1619             TestCreateCollator1 tcc = new TestCreateCollator1();
   1620             tcc.getDisplayName(new ULocale("en_US"), new ULocale("jp_JP"));
   1621         } catch (Exception e) {
   1622             errln("Collator.getDisplayName(ULocale,ULocale) was not suppose to return an exception.");
   1623         }
   1624     }
   1625     /* Tests the method
   1626      * public static final String[] getKeywordValues(String keyword)
   1627      */
   1628     @SuppressWarnings("static-access")
   1629     @Test
   1630     public void TestGetKeywordValues(){
   1631         // Tests when "if (!keyword.equals(KEYWORDS[0]))" is true
   1632         String[] cases = {"","dummy"};
   1633         for(int i=0; i<cases.length; i++){
   1634             try{
   1635                 Collator c = Collator.getInstance();
   1636                 @SuppressWarnings("unused")
   1637                 String[] s = c.getKeywordValues(cases[i]);
   1638                 errln("Collator.getKeywordValues(String) is suppose to return " +
   1639                         "an exception for an invalid keyword.");
   1640             } catch(Exception e){}
   1641         }
   1642     }
   1643 
   1644     @Test
   1645     public void TestBadKeywords() {
   1646         // Test locale IDs with errors.
   1647         // Valid locale IDs are tested via data-driven tests.
   1648         // Note: ICU4C tests with a bogus Locale. There is no such thing in ICU4J.
   1649 
   1650         // Unknown value.
   1651         String localeID = "it-u-ks-xyz";
   1652         try {
   1653             Collator.getInstance(new ULocale(localeID));
   1654             errln("Collator.getInstance(" + localeID + ") did not fail as expected");
   1655         } catch(IllegalArgumentException expected) {
   1656         } catch(Exception other) {
   1657             errln("Collator.getInstance(" + localeID + ") did not fail as expected - " + other);
   1658         }
   1659 
   1660         // Unsupported attributes.
   1661         localeID = "it@colHiraganaQuaternary=true";
   1662         try {
   1663             Collator.getInstance(new ULocale(localeID));
   1664             errln("Collator.getInstance(" + localeID + ") did not fail as expected");
   1665         } catch(UnsupportedOperationException expected) {
   1666         } catch(Exception other) {
   1667             errln("Collator.getInstance(" + localeID + ") did not fail as expected - " + other);
   1668         }
   1669 
   1670         localeID = "it-u-vt-u24";
   1671         try {
   1672             Collator.getInstance(new ULocale(localeID));
   1673             errln("Collator.getInstance(" + localeID + ") did not fail as expected");
   1674         } catch(UnsupportedOperationException expected) {
   1675         } catch(Exception other) {
   1676             errln("Collator.getInstance(" + localeID + ") did not fail as expected - " + other);
   1677         }
   1678     }
   1679 
   1680     @Test
   1681     public void TestGapTooSmall() {
   1682         // Try to tailor >20k characters into a too-small primary gap between symbols
   1683         // that have 3-byte primary weights.
   1684         // In FractionalUCA.txt:
   1685         // 263A; [0C BA D0, 05, 05]  # Zyyy So  [084A.0020.0002]  * WHITE SMILING FACE
   1686         // 263B; [0C BA D7, 05, 05]  # Zyyy So  [084B.0020.0002]  * BLACK SMILING FACE
   1687         try {
   1688             new RuleBasedCollator("&<*\u4E00-\u9FFF");
   1689             errln("no exception for primary-gap overflow");
   1690         } catch (UnsupportedOperationException e) {
   1691             assertTrue("exception message mentions 'gap'", e.getMessage().contains("gap"));
   1692         } catch (Exception e) {
   1693             errln("unexpected exception for primary-gap overflow: " + e);
   1694         }
   1695 
   1696         // CLDR 32/ICU 60 FractionalUCA.txt makes room at the end of the symbols range
   1697         // for several 2-byte primaries, or a large number of 3-byters.
   1698         // The reset point is primary-before what should be
   1699         // the special currency-first-primary contraction,
   1700         // which is hopefully fairly stable, but not guaranteed stable.
   1701         // In FractionalUCA.txt:
   1702         // FDD1 20AC; [0D 70 02, 05, 05]  # CURRENCY first primary
   1703         try {
   1704             Collator coll = new RuleBasedCollator("&[before 1]\uFDD1<*\u4E00-\u9FFF");
   1705             assertTrue("tailored Han before currency", coll.compare("\u4E00", "$") < 0);
   1706         } catch (Exception e) {
   1707             errln("unexpected exception for tailoring many characters at the end of symbols: " + e);
   1708         }
   1709     }
   1710 }
   1711