Home | History | Annotate | Download | only in collator
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  *******************************************************************************
      5  * Copyright (C) 2002-2016, International Business Machines Corporation and
      6  * others. All Rights Reserved.
      7  *******************************************************************************
      8  */
      9 
     10 /**
     11  * Port From:   ICU4C v2.1 : cintltest
     12  * Source File: $ICU4CRoot/source/test/cintltest/cmsccoll.c
     13  */
     14 
     15 package com.ibm.icu.dev.test.collator;
     16 
     17 import java.util.Arrays;
     18 import java.util.Locale;
     19 import java.util.Set;
     20 import java.util.TreeSet;
     21 
     22 import org.junit.Test;
     23 import org.junit.runner.RunWith;
     24 import org.junit.runners.JUnit4;
     25 
     26 import com.ibm.icu.dev.test.TestFmwk;
     27 import com.ibm.icu.impl.ICUData;
     28 import com.ibm.icu.impl.ICUResourceBundle;
     29 import com.ibm.icu.impl.Utility;
     30 import com.ibm.icu.lang.UScript;
     31 import com.ibm.icu.text.CollationElementIterator;
     32 import com.ibm.icu.text.CollationKey;
     33 import com.ibm.icu.text.CollationKey.BoundMode;
     34 import com.ibm.icu.text.Collator;
     35 import com.ibm.icu.text.Collator.ReorderCodes;
     36 import com.ibm.icu.text.Normalizer;
     37 import com.ibm.icu.text.RawCollationKey;
     38 import com.ibm.icu.text.RuleBasedCollator;
     39 import com.ibm.icu.text.UTF16;
     40 import com.ibm.icu.text.UnicodeSet;
     41 import com.ibm.icu.text.UnicodeSetIterator;
     42 import com.ibm.icu.util.ULocale;
     43 import com.ibm.icu.util.UResourceBundle;
     44 
     45 @RunWith(JUnit4.class)
     46 public class CollationMiscTest extends TestFmwk {
     47     //private static final int NORM_BUFFER_TEST_LEN_ = 32;
     48     private static final class Tester
     49     {
     50         int u;
     51         String NFC;
     52         String NFD;
     53     }
     54 
     55     private static final boolean hasCollationElements(Locale locale)
     56     {
     57         ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUData.ICU_COLLATION_BASE_NAME,locale);
     58         if (rb != null) {
     59             try {
     60                 String collkey = rb.getStringWithFallback("collations/default");
     61                 ICUResourceBundle elements = rb.getWithFallback("collations/" + collkey);
     62                 if (elements != null) {
     63                     return true;
     64                 }
     65             } catch (Exception e) {
     66             }
     67         }
     68         return false;
     69     }
     70 
     71     @Test
     72     public void TestComposeDecompose()
     73     {
     74         Tester t[] = new Tester[0x30000];
     75         t[0] = new Tester();
     76         logln("Testing UCA extensively\n");
     77         RuleBasedCollator coll;
     78         try {
     79             coll = (RuleBasedCollator)Collator.getInstance(Locale.ENGLISH);
     80         }
     81         catch (Exception e) {
     82             warnln("Error opening collator\n");
     83             return;
     84         }
     85 
     86         int noCases = 0;
     87         for (int u = 0; u < 0x30000; u ++) {
     88             String comp = UTF16.valueOf(u);
     89             int len = comp.length();
     90             t[noCases].NFC = Normalizer.normalize(u, Normalizer.NFC);
     91             t[noCases].NFD = Normalizer.normalize(u, Normalizer.NFD);
     92 
     93             if (t[noCases].NFC.length() != t[noCases].NFD.length()
     94                 || (t[noCases].NFC.compareTo(t[noCases].NFD) != 0)
     95                 || (len != t[noCases].NFD.length())
     96                 || (comp.compareTo(t[noCases].NFD) != 0)) {
     97                 t[noCases].u = u;
     98                 if (len != t[noCases].NFD.length()
     99                     || (comp.compareTo(t[noCases].NFD) != 0)) {
    100                     t[noCases].NFC = comp;
    101                 }
    102                 noCases ++;
    103                 t[noCases] = new Tester();
    104             }
    105         }
    106 
    107         for (int u = 0; u < noCases; u ++) {
    108             if (!coll.equals(t[u].NFC, t[u].NFD)) {
    109                 errln("Failure: codePoint \\u" + Integer.toHexString(t[u].u)
    110                       + " fails TestComposeDecompose in the UCA");
    111                 CollationTest.doTest(this, coll, t[u].NFC, t[u].NFD, 0);
    112             }
    113         }
    114 
    115         logln("Testing locales, number of cases = " + noCases);
    116         Locale loc[] = Collator.getAvailableLocales();
    117         for (int i = 0; i < loc.length; i ++) {
    118             if (hasCollationElements(loc[i])) {
    119                 logln("Testing locale " + loc[i].getDisplayName());
    120                 coll = (RuleBasedCollator)Collator.getInstance(loc[i]);
    121                 coll.setStrength(Collator.IDENTICAL);
    122 
    123                 for (int u = 0; u < noCases; u ++) {
    124                     if (!coll.equals(t[u].NFC, t[u].NFD)) {
    125                         errln("Failure: codePoint \\u"
    126                               + Integer.toHexString(t[u].u)
    127                               + " fails TestComposeDecompose for locale "
    128                               + loc[i].getDisplayName());
    129                         // this tests for the iterators too
    130                         CollationTest.doTest(this, coll, t[u].NFC, t[u].NFD,
    131                                              0);
    132                     }
    133                 }
    134             }
    135         }
    136     }
    137 
    138     @Test
    139     public void TestRuleOptions() {
    140         // values here are hardcoded and are correct for the current UCA when
    141         // the UCA changes, one might be forced to change these values.
    142 
    143         /*
    144          * These strings contain the last character before [variable top]
    145          * and the first and second characters (by primary weights) after it.
    146          * See FractionalUCA.txt. For example:
    147             [last variable [0C FE, 05, 05]] # U+10A7F OLD SOUTH ARABIAN NUMERIC INDICATOR
    148             [variable top = 0C FE]
    149             [first regular [0D 0A, 05, 05]] # U+0060 GRAVE ACCENT
    150            and
    151             00B4; [0D 0C, 05, 05]
    152          *
    153          * Note: Starting with UCA 6.0, the [variable top] collation element
    154          * is not the weight of any character or string,
    155          * which means that LAST_VARIABLE_CHAR_STRING sorts before [last variable].
    156          */
    157         String LAST_VARIABLE_CHAR_STRING = "\\U00010A7F";
    158         String FIRST_REGULAR_CHAR_STRING = "\\u0060";
    159         String SECOND_REGULAR_CHAR_STRING = "\\u00B4";
    160 
    161         /*
    162          * This string has to match the character that has the [last regular] weight
    163          * which changes with each UCA version.
    164          * See the bottom of FractionalUCA.txt which says something like
    165             [last regular [7A FE, 05, 05]] # U+1342E EGYPTIAN HIEROGLYPH AA032
    166          *
    167          * Note: Starting with UCA 6.0, the [last regular] collation element
    168          * is not the weight of any character or string,
    169          * which means that LAST_REGULAR_CHAR_STRING sorts before [last regular].
    170          */
    171         String LAST_REGULAR_CHAR_STRING = "\\U0001342E";
    172 
    173         String[] rules = {
    174             // cannot test this anymore, as [last primary ignorable] doesn't
    175             // have a  code point associated to it anymore
    176             // "&[before 3][last primary ignorable]<<<k",
    177             // - all befores here amount to zero
    178             /* "you cannot go before ...": The parser now sets an error for such nonsensical rules.
    179             "&[before 3][first tertiary ignorable]<<<a",
    180             "&[before 3][last tertiary ignorable]<<<a", */
    181             /*
    182              * However, there is a real secondary ignorable (artificial addition in FractionalUCA.txt),
    183              * and it *is* possible to "go before" that.
    184              */
    185             "&[before 3][first secondary ignorable]<<<a",
    186             "&[before 3][last secondary ignorable]<<<a",
    187             // 'normal' befores
    188             /*
    189              * Note: With a "SPACE first primary" boundary CE in FractionalUCA.txt,
    190              * it is not possible to tailor &[first primary ignorable]<a or &[last primary ignorable]<a
    191              * because there is no tailoring space before that boundary.
    192              * Made the tests work by tailoring to a space instead.
    193              */
    194             "&[before 3][first primary ignorable]<<<c<<<b &' '<a",  /* was &[first primary ignorable]<a */
    195             // we don't have a code point that corresponds to the last primary
    196             // ignorable
    197             "&[before 3][last primary ignorable]<<<c<<<b &' '<a",  /* was &[last primary ignorable]<a */
    198             "&[before 3][first variable]<<<c<<<b &[first variable]<a",
    199             "&[last variable]<a &[before 3][last variable]<<<c<<<b ",
    200             "&[first regular]<a &[before 1][first regular]<b",
    201             "&[before 1][last regular]<b &[last regular]<a",
    202             "&[before 1][first implicit]<b &[first implicit]<a",
    203             /* The current builder does not support tailoring to unassigned-implicit CEs (seems unnecessary, adds complexity).
    204             "&[before 1][last implicit]<b &[last implicit]<a", */
    205             "&[last variable]<z" +
    206             "&' '<x" +  /* was &[last primary ignorable]<x, see above */
    207             "&[last secondary ignorable]<<y&[last tertiary ignorable]<<<w&[top]<u",
    208         };
    209         String[][] data = {
    210             // {"k", "\u20e3"},
    211             /* "you cannot go before ...": The parser now sets an error for such nonsensical rules.
    212             {"\\u0000", "a"}, // you cannot go before first tertiary ignorable
    213             {"\\u0000", "a"}, // you cannot go before last tertiary ignorable */
    214             /*
    215              * However, there is a real secondary ignorable (artificial addition in FractionalUCA.txt),
    216              * and it *is* possible to "go before" that.
    217              */
    218             {"\\u0000", "a"},
    219             {"\\u0000", "a"},
    220             /*
    221              * Note: With a "SPACE first primary" boundary CE in FractionalUCA.txt,
    222              * it is not possible to tailor &[first primary ignorable]<a or &[last primary ignorable]<a
    223              * because there is no tailoring space before that boundary.
    224              * Made the tests work by tailoring to a space instead.
    225              */
    226             {"c", "b", "\\u0332", "a"},
    227             {"\\u0332", "\\u20e3", "c", "b", "a"},
    228             {"c", "b", "\\u0009", "a", "\\u000a"},
    229             {LAST_VARIABLE_CHAR_STRING, "c", "b", /* [last variable] */ "a", FIRST_REGULAR_CHAR_STRING},
    230             {"b", FIRST_REGULAR_CHAR_STRING, "a", SECOND_REGULAR_CHAR_STRING},
    231             // The character in the second ordering test string
    232             // has to match the character that has the [last regular] weight
    233             // which changes with each UCA version.
    234             // See the bottom of FractionalUCA.txt which says something like
    235             // [last regular [CE 27, 05, 05]] # U+1342E EGYPTIAN HIEROGLYPH AA032
    236             {LAST_REGULAR_CHAR_STRING, "b", /* [last regular] */ "a", "\\u4e00"},
    237             {"b", "\\u4e00", "a", "\\u4e01"},
    238             /* The current builder does not support tailoring to unassigned-implicit CEs (seems unnecessary, adds complexity).
    239             {"b", "\\U0010FFFD", "a"}, */
    240             {"\ufffb",  "w", "y", "\u20e3", "x", LAST_VARIABLE_CHAR_STRING, "z", "u"},
    241         };
    242 
    243         for (int i = 0; i< rules.length; i++) {
    244             logln(String.format("rules[%d] = \"%s\"", i, rules[i]));
    245             genericRulesStarter(rules[i], data[i]);
    246         }
    247     }
    248 
    249     void genericRulesStarter(String rules, String[] s) {
    250         genericRulesStarterWithResult(rules, s, -1);
    251     }
    252 
    253     void genericRulesStarterWithResult(String rules, String[] s, int result) {
    254 
    255         RuleBasedCollator coll = null;
    256         try {
    257             coll = new RuleBasedCollator(rules);
    258             // logln("Rules starter for " + rules);
    259             genericOrderingTestWithResult(coll, s, result);
    260         } catch (Exception e) {
    261             warnln("Unable to open collator with rules " + rules + ": " + e);
    262         }
    263     }
    264 
    265     void genericRulesStarterWithOptionsAndResult(String rules, String[] s, String[] atts, Object[] attVals, int result) {
    266         RuleBasedCollator coll = null;
    267         try {
    268             coll = new RuleBasedCollator(rules);
    269             genericOptionsSetter(coll, atts, attVals);
    270             genericOrderingTestWithResult(coll, s, result);
    271         } catch (Exception e) {
    272             warnln("Unable to open collator with rules " + rules);
    273         }
    274     }
    275     void genericOrderingTestWithResult(Collator coll, String[] s, int result) {
    276         String t1 = "";
    277         String t2 = "";
    278 
    279         for(int i = 0; i < s.length - 1; i++) {
    280             for(int j = i+1; j < s.length; j++) {
    281                 t1 = Utility.unescape(s[i]);
    282                 t2 = Utility.unescape(s[j]);
    283                 // System.out.println(i + " " + j);
    284                 CollationTest.doTest(this, (RuleBasedCollator)coll, t1, t2,
    285                                      result);
    286             }
    287         }
    288     }
    289 
    290     void reportCResult(String source, String target, CollationKey sourceKey, CollationKey targetKey,
    291                        int compareResult, int keyResult, int incResult, int expectedResult ) {
    292         if (expectedResult < -1 || expectedResult > 1) {
    293             errln("***** invalid call to reportCResult ****");
    294             return;
    295         }
    296         boolean ok1 = (compareResult == expectedResult);
    297         boolean ok2 = (keyResult == expectedResult);
    298         boolean ok3 = (incResult == expectedResult);
    299         if (ok1 && ok2 && ok3 /* synwee to undo && !isVerbose()*/) {
    300             return;
    301         } else {
    302             String msg1 = ok1? "Ok: compare(\"" : "FAIL: compare(\"";
    303             String msg2 = "\", \"";
    304             String msg3 = "\") returned ";
    305             String msg4 = "; expected ";
    306             String sExpect = new String("");
    307             String sResult = new String("");
    308             sResult = CollationTest.appendCompareResult(compareResult, sResult);
    309             sExpect = CollationTest.appendCompareResult(expectedResult, sExpect);
    310             if (ok1) {
    311                 // logln(msg1 + source + msg2 + target + msg3 + sResult);
    312             } else {
    313                 errln(msg1 + source + msg2 + target + msg3 + sResult + msg4 + sExpect);
    314             }
    315             msg1 = ok2 ? "Ok: key(\"" : "FAIL: key(\"";
    316             msg2 = "\").compareTo(key(\"";
    317             msg3 = "\")) returned ";
    318             sResult = CollationTest.appendCompareResult(keyResult, sResult);
    319             if (ok2) {
    320                 // logln(msg1 + source + msg2 + target + msg3 + sResult);
    321             } else {
    322                 errln(msg1 + source + msg2 + target + msg3 + sResult + msg4 + sExpect);
    323                 msg1 = "  ";
    324                 msg2 = " vs. ";
    325                 errln(msg1 + CollationTest.prettify(sourceKey) + msg2 + CollationTest.prettify(targetKey));
    326             }
    327             msg1 = ok3 ? "Ok: incCompare(\"" : "FAIL: incCompare(\"";
    328             msg2 = "\", \"";
    329             msg3 = "\") returned ";
    330             sResult = CollationTest.appendCompareResult(incResult, sResult);
    331             if (ok3) {
    332                 // logln(msg1 + source + msg2 + target + msg3 + sResult);
    333             } else {
    334                 errln(msg1 + source + msg2 + target + msg3 + sResult + msg4 + sExpect);
    335             }
    336         }
    337     }
    338 
    339     @Test
    340     public void TestBeforePrefixFailure() {
    341         String[] rules = {
    342             "&g <<< a&[before 3]\uff41 <<< x",
    343             "&\u30A7=\u30A7=\u3047=\uff6a&\u30A8=\u30A8=\u3048=\uff74&[before 3]\u30a7<<<\u30a9",
    344             "&[before 3]\u30a7<<<\u30a9&\u30A7=\u30A7=\u3047=\uff6a&\u30A8=\u30A8=\u3048=\uff74",
    345         };
    346         String[][] data = {
    347             {"x", "\uff41"},
    348             {"\u30a9", "\u30a7"},
    349             {"\u30a9", "\u30a7"},
    350         };
    351 
    352         for(int i = 0; i< rules.length; i++) {
    353             genericRulesStarter(rules[i], data[i]);
    354         }
    355     }
    356 
    357     @Test
    358     public void TestContractionClosure() {
    359         // Note: This was also ported to the data-driven test, see collationtest.txt.
    360         String[] rules = {
    361             "&b=\u00e4\u00e4",
    362             "&b=\u00C5",
    363         };
    364         String[][] data = {
    365             { "b", "\u00e4\u00e4", "a\u0308a\u0308", "\u00e4a\u0308", "a\u0308\u00e4" },
    366             { "b", "\u00C5", "A\u030A", "\u212B" },
    367         };
    368 
    369         for(int i = 0; i< rules.length; i++) {
    370             genericRulesStarterWithResult(rules[i], data[i], 0);
    371         }
    372     }
    373 
    374     @Test
    375     public void TestPrefixCompose() {
    376         String rule1 = "&\u30a7<<<\u30ab|\u30fc=\u30ac|\u30fc";
    377 
    378         String string = rule1;
    379         try {
    380             RuleBasedCollator coll = new RuleBasedCollator(string);
    381             logln("rule:" + coll.getRules());
    382         } catch (Exception e) {
    383             warnln("Error open RuleBasedCollator rule = " + string);
    384         }
    385     }
    386 
    387     @Test
    388     public void TestStrCollIdenticalPrefix() {
    389         String rule = "&\ud9b0\udc70=\ud9b0\udc71";
    390         String test[] = {
    391             "ab\ud9b0\udc70",
    392             "ab\ud9b0\udc71"
    393         };
    394         genericRulesStarterWithResult(rule, test, 0);
    395     }
    396 
    397     @Test
    398     public void TestPrefix() {
    399         String[] rules = {
    400             "&z <<< z|a",
    401             "&z <<< z|   a",
    402             "[strength I]&a=\ud900\udc25&z<<<\ud900\udc25|a",
    403         };
    404         String[][] data = {
    405             {"zz", "za"},
    406             {"zz", "za"},
    407             {"aa", "az", "\ud900\udc25z", "\ud900\udc25a", "zz"},
    408         };
    409 
    410         for(int i = 0; i<rules.length; i++) {
    411             genericRulesStarter(rules[i], data[i]);
    412         }
    413     }
    414 
    415     @Test
    416     public void TestNewJapanese() {
    417 
    418         String test1[] = {
    419             "\u30b7\u30e3\u30fc\u30ec",
    420             "\u30b7\u30e3\u30a4",
    421             "\u30b7\u30e4\u30a3",
    422             "\u30b7\u30e3\u30ec",
    423             "\u3061\u3087\u3053",
    424             "\u3061\u3088\u3053",
    425             "\u30c1\u30e7\u30b3\u30ec\u30fc\u30c8",
    426             "\u3066\u30fc\u305f",
    427             "\u30c6\u30fc\u30bf",
    428             "\u30c6\u30a7\u30bf",
    429             "\u3066\u3048\u305f",
    430             "\u3067\u30fc\u305f",
    431             "\u30c7\u30fc\u30bf",
    432             "\u30c7\u30a7\u30bf",
    433             "\u3067\u3048\u305f",
    434             "\u3066\u30fc\u305f\u30fc",
    435             "\u30c6\u30fc\u30bf\u30a1",
    436             "\u30c6\u30a7\u30bf\u30fc",
    437             "\u3066\u3047\u305f\u3041",
    438             "\u3066\u3048\u305f\u30fc",
    439             "\u3067\u30fc\u305f\u30fc",
    440             "\u30c7\u30fc\u30bf\u30a1",
    441             "\u3067\u30a7\u305f\u30a1",
    442             "\u30c7\u3047\u30bf\u3041",
    443             "\u30c7\u30a8\u30bf\u30a2",
    444             "\u3072\u3086",
    445             "\u3073\u3085\u3042",
    446             "\u3074\u3085\u3042",
    447             "\u3073\u3085\u3042\u30fc",
    448             "\u30d3\u30e5\u30a2\u30fc",
    449             "\u3074\u3085\u3042\u30fc",
    450             "\u30d4\u30e5\u30a2\u30fc",
    451             "\u30d2\u30e5\u30a6",
    452             "\u30d2\u30e6\u30a6",
    453             "\u30d4\u30e5\u30a6\u30a2",
    454             "\u3073\u3085\u30fc\u3042\u30fc",
    455             "\u30d3\u30e5\u30fc\u30a2\u30fc",
    456             "\u30d3\u30e5\u30a6\u30a2\u30fc",
    457             "\u3072\u3085\u3093",
    458             "\u3074\u3085\u3093",
    459             "\u3075\u30fc\u308a",
    460             "\u30d5\u30fc\u30ea",
    461             "\u3075\u3045\u308a",
    462             "\u3075\u30a5\u308a",
    463             "\u3075\u30a5\u30ea",
    464             "\u30d5\u30a6\u30ea",
    465             "\u3076\u30fc\u308a",
    466             "\u30d6\u30fc\u30ea",
    467             "\u3076\u3045\u308a",
    468             "\u30d6\u30a5\u308a",
    469             "\u3077\u3046\u308a",
    470             "\u30d7\u30a6\u30ea",
    471             "\u3075\u30fc\u308a\u30fc",
    472             "\u30d5\u30a5\u30ea\u30fc",
    473             "\u3075\u30a5\u308a\u30a3",
    474             "\u30d5\u3045\u308a\u3043",
    475             "\u30d5\u30a6\u30ea\u30fc",
    476             "\u3075\u3046\u308a\u3043",
    477             "\u30d6\u30a6\u30ea\u30a4",
    478             "\u3077\u30fc\u308a\u30fc",
    479             "\u3077\u30a5\u308a\u30a4",
    480             "\u3077\u3046\u308a\u30fc",
    481             "\u30d7\u30a6\u30ea\u30a4",
    482             "\u30d5\u30fd",
    483             "\u3075\u309e",
    484             "\u3076\u309d",
    485             "\u3076\u3075",
    486             "\u3076\u30d5",
    487             "\u30d6\u3075",
    488             "\u30d6\u30d5",
    489             "\u3076\u309e",
    490             "\u3076\u3077",
    491             "\u30d6\u3077",
    492             "\u3077\u309d",
    493             "\u30d7\u30fd",
    494             "\u3077\u3075",
    495         };
    496 
    497         String test2[] = {
    498             "\u306f\u309d", // H\u309d
    499             "\u30cf\u30fd", // K\u30fd
    500             "\u306f\u306f", // HH
    501             "\u306f\u30cf", // HK
    502             "\u30cf\u30cf", // KK
    503             "\u306f\u309e", // H\u309e
    504             "\u30cf\u30fe", // K\u30fe
    505             "\u306f\u3070", // HH\u309b
    506             "\u30cf\u30d0", // KK\u309b
    507             "\u306f\u3071", // HH\u309c
    508             "\u30cf\u3071", // KH\u309c
    509             "\u30cf\u30d1", // KK\u309c
    510             "\u3070\u309d", // H\u309b\u309d
    511             "\u30d0\u30fd", // K\u309b\u30fd
    512             "\u3070\u306f", // H\u309bH
    513             "\u30d0\u30cf", // K\u309bK
    514             "\u3070\u309e", // H\u309b\u309e
    515             "\u30d0\u30fe", // K\u309b\u30fe
    516             "\u3070\u3070", // H\u309bH\u309b
    517             "\u30d0\u3070", // K\u309bH\u309b
    518             "\u30d0\u30d0", // K\u309bK\u309b
    519             "\u3070\u3071", // H\u309bH\u309c
    520             "\u30d0\u30d1", // K\u309bK\u309c
    521             "\u3071\u309d", // H\u309c\u309d
    522             "\u30d1\u30fd", // K\u309c\u30fd
    523             "\u3071\u306f", // H\u309cH
    524             "\u30d1\u30cf", // K\u309cK
    525             "\u3071\u3070", // H\u309cH\u309b
    526             "\u3071\u30d0", // H\u309cK\u309b
    527             "\u30d1\u30d0", // K\u309cK\u309b
    528             "\u3071\u3071", // H\u309cH\u309c
    529             "\u30d1\u30d1", // K\u309cK\u309c
    530         };
    531 
    532         String[] att = { "strength", };
    533         Object[] val = { new Integer(Collator.QUATERNARY), };
    534 
    535         String[] attShifted = { "strength", "AlternateHandling"};
    536         Object valShifted[] = { new Integer(Collator.QUATERNARY),
    537                                 Boolean.TRUE };
    538 
    539         genericLocaleStarterWithOptions(Locale.JAPANESE, test1, att, val);
    540         genericLocaleStarterWithOptions(Locale.JAPANESE, test2, att, val);
    541 
    542         genericLocaleStarterWithOptions(Locale.JAPANESE, test1, attShifted,
    543                                         valShifted);
    544         genericLocaleStarterWithOptions(Locale.JAPANESE, test2, attShifted,
    545                                         valShifted);
    546     }
    547 
    548     void genericLocaleStarter(Locale locale, String s[]) {
    549         RuleBasedCollator coll = null;
    550         try {
    551             coll = (RuleBasedCollator)Collator.getInstance(locale);
    552 
    553         } catch (Exception e) {
    554             warnln("Unable to open collator for locale " + locale);
    555             return;
    556         }
    557         // logln("Locale starter for " + locale);
    558         genericOrderingTest(coll, s);
    559     }
    560 
    561     void genericLocaleStarterWithOptions(Locale locale, String[] s, String[] attrs, Object[] values) {
    562         genericLocaleStarterWithOptionsAndResult(locale, s, attrs, values, -1);
    563     }
    564 
    565     private void genericOptionsSetter(RuleBasedCollator coll, String[] attrs, Object[] values) {
    566         for(int i = 0; i < attrs.length; i++) {
    567             if (attrs[i].equals("strength")) {
    568                 coll.setStrength(((Integer)values[i]).intValue());
    569             }
    570             else if (attrs[i].equals("decomp")) {
    571                 coll.setDecomposition(((Integer)values[i]).intValue());
    572             }
    573             else if (attrs[i].equals("AlternateHandling")) {
    574                 coll.setAlternateHandlingShifted(((Boolean)values[i]
    575                                                   ).booleanValue());
    576             }
    577             else if (attrs[i].equals("NumericCollation")) {
    578                 coll.setNumericCollation(((Boolean)values[i]).booleanValue());
    579             }
    580             else if (attrs[i].equals("UpperFirst")) {
    581                 coll.setUpperCaseFirst(((Boolean)values[i]).booleanValue());
    582             }
    583             else if (attrs[i].equals("LowerFirst")) {
    584                 coll.setLowerCaseFirst(((Boolean)values[i]).booleanValue());
    585             }
    586             else if (attrs[i].equals("CaseLevel")) {
    587                 coll.setCaseLevel(((Boolean)values[i]).booleanValue());
    588             }
    589         }
    590     }
    591 
    592     void genericLocaleStarterWithOptionsAndResult(Locale locale, String[] s, String[] attrs, Object[] values, int result) {
    593         RuleBasedCollator coll = null;
    594         try {
    595             coll = (RuleBasedCollator)Collator.getInstance(locale);
    596         } catch (Exception e) {
    597             warnln("Unable to open collator for locale " + locale);
    598             return;
    599         }
    600         // logln("Locale starter for " +locale);
    601 
    602         // logln("Setting attributes");
    603         genericOptionsSetter(coll, attrs, values);
    604 
    605         genericOrderingTestWithResult(coll, s, result);
    606     }
    607 
    608     void genericOrderingTest(Collator coll, String[] s) {
    609         genericOrderingTestWithResult(coll, s, -1);
    610     }
    611 
    612     @Test
    613     public void TestNonChars() {
    614         String test[] = {
    615             "\u0000",  /* ignorable */
    616             "\uFFFE",  /* special merge-sort character with minimum non-ignorable weights */
    617             "\uFDD0", "\uFDEF",
    618             "\\U0001FFFE", "\\U0001FFFF",  /* UCA 6.0: noncharacters are treated like unassigned, */
    619             "\\U0002FFFE", "\\U0002FFFF",  /* not like ignorable. */
    620             "\\U0003FFFE", "\\U0003FFFF",
    621             "\\U0004FFFE", "\\U0004FFFF",
    622             "\\U0005FFFE", "\\U0005FFFF",
    623             "\\U0006FFFE", "\\U0006FFFF",
    624             "\\U0007FFFE", "\\U0007FFFF",
    625             "\\U0008FFFE", "\\U0008FFFF",
    626             "\\U0009FFFE", "\\U0009FFFF",
    627             "\\U000AFFFE", "\\U000AFFFF",
    628             "\\U000BFFFE", "\\U000BFFFF",
    629             "\\U000CFFFE", "\\U000CFFFF",
    630             "\\U000DFFFE", "\\U000DFFFF",
    631             "\\U000EFFFE", "\\U000EFFFF",
    632             "\\U000FFFFE", "\\U000FFFFF",
    633             "\\U0010FFFE", "\\U0010FFFF",
    634             "\uFFFF"  /* special character with maximum primary weight */
    635         };
    636         Collator coll = null;
    637         try {
    638             coll = Collator.getInstance(new Locale("en", "US"));
    639         } catch (Exception e) {
    640             warnln("Unable to open collator");
    641             return;
    642         }
    643         // logln("Test non characters");
    644 
    645         genericOrderingTestWithResult(coll, test, -1);
    646     }
    647 
    648     @Test
    649     public void TestExtremeCompression() {
    650         String[] test = new String[4];
    651 
    652         for(int i = 0; i<4; i++) {
    653             StringBuffer temp = new StringBuffer();
    654             for (int j = 0; j < 2047; j++) {
    655                 temp.append('a');
    656             }
    657             temp.append((char)('a' + i));
    658             test[i] = temp.toString();
    659         }
    660 
    661         genericLocaleStarter(new Locale("en", "US"), test);
    662     }
    663 
    664     /**
    665      * Tests surrogate support.
    666      */
    667     @Test
    668     public void TestSurrogates() {
    669         String test[] = {"z","\ud900\udc25", "\ud805\udc50", "\ud800\udc00y",
    670                          "\ud800\udc00r", "\ud800\udc00f", "\ud800\udc00",
    671                          "\ud800\udc00c", "\ud800\udc00b", "\ud800\udc00fa",
    672                          "\ud800\udc00fb", "\ud800\udc00a", "c", "b"};
    673 
    674         String rule = "&z < \ud900\udc25 < \ud805\udc50 < \ud800\udc00y "
    675             + "< \ud800\udc00r < \ud800\udc00f << \ud800\udc00 "
    676             + "< \ud800\udc00fa << \ud800\udc00fb < \ud800\udc00a "
    677             + "< c < b";
    678         genericRulesStarter(rule, test);
    679     }
    680 
    681     @Test
    682     public void TestBocsuCoverage() {
    683         String test = "\u0041\u0441\u4441\\U00044441\u4441\u0441\u0041";
    684         Collator coll = Collator.getInstance();
    685         coll.setStrength(Collator.IDENTICAL);
    686         CollationKey key = coll.getCollationKey(test);
    687         logln("source:" + key.getSourceString());
    688     }
    689 
    690     @Test
    691     public void TestCyrillicTailoring() {
    692         String test[] = {
    693             "\u0410b",
    694             "\u0410\u0306a",
    695             "\u04d0A"
    696         };
    697 
    698         // Most of the following are commented out because UCA 8.0
    699         // drops most of the Cyrillic contractions from the default order.
    700         // See CLDR ticket #7246 "root collation: remove Cyrillic contractions".
    701 
    702         // genericLocaleStarter(new Locale("en", ""), test);
    703         // genericRulesStarter("&\u0410 = \u0410", test);
    704         // genericRulesStarter("&Z < \u0410", test);
    705         genericRulesStarter("&\u0410 = \u0410 < \u04d0", test);
    706         genericRulesStarter("&Z < \u0410 < \u04d0", test);
    707         // genericRulesStarter("&\u0410 = \u0410 < \u0410\u0301", test);
    708         // genericRulesStarter("&Z < \u0410 < \u0410\u0301", test);
    709     }
    710 
    711     @Test
    712     public void TestSuppressContractions() {
    713         String testNoCont2[] = {
    714             "\u0410\u0302a",
    715             "\u0410\u0306b",
    716             "\u0410c"
    717         };
    718         String testNoCont[] = {
    719             "a\u0410",
    720             "A\u0410\u0306",
    721             "\uFF21\u0410\u0302"
    722         };
    723 
    724         genericRulesStarter("[suppressContractions [\u0400-\u047f]]", testNoCont);
    725         genericRulesStarter("[suppressContractions [\u0400-\u047f]]", testNoCont2);
    726     }
    727 
    728     @Test
    729     public void TestCase() {
    730         String gRules = "\u0026\u0030\u003C\u0031\u002C\u2460\u003C\u0061\u002C\u0041";
    731         String[] testCase = {
    732             "1a", "1A", "\u2460a", "\u2460A"
    733         };
    734         int[][] caseTestResults = {
    735             { -1, -1, -1, 0, -1, -1, 0, 0, -1 },
    736             { 1, -1, -1, 0, -1, -1, 0, 0, 1 },
    737             { -1, -1, -1, 0, 1, -1, 0, 0, -1 },
    738             { 1, -1, 1, 0, -1, -1, 0, 0, 1 }
    739 
    740         };
    741         boolean[][] caseTestAttributes = {
    742             { false, false},
    743             { true, false},
    744             { false, true},
    745             { true, true}
    746         };
    747 
    748         int i,j,k;
    749         Collator  myCollation;
    750         try {
    751             myCollation = Collator.getInstance(new Locale("en", "US"));
    752         } catch (Exception e) {
    753             warnln("ERROR: in creation of rule based collator ");
    754             return;
    755         }
    756         // logln("Testing different case settings");
    757         myCollation.setStrength(Collator.TERTIARY);
    758 
    759         for(k = 0; k <4; k++) {
    760             if (caseTestAttributes[k][0] == true) {
    761                 // upper case first
    762                 ((RuleBasedCollator)myCollation).setUpperCaseFirst(true);
    763             }
    764             else {
    765                 // upper case first
    766                 ((RuleBasedCollator)myCollation).setLowerCaseFirst(true);
    767             }
    768             ((RuleBasedCollator)myCollation).setCaseLevel(
    769                                                           caseTestAttributes[k][1]);
    770 
    771             // logln("Case first = " + caseTestAttributes[k][0] + ", Case level = " + caseTestAttributes[k][1]);
    772             for (i = 0; i < 3 ; i++) {
    773                 for(j = i+1; j<4; j++) {
    774                     CollationTest.doTest(this,
    775                                          (RuleBasedCollator)myCollation,
    776                                          testCase[i], testCase[j],
    777                                          caseTestResults[k][3*i+j-1]);
    778                 }
    779             }
    780         }
    781         try {
    782             myCollation = new RuleBasedCollator(gRules);
    783         } catch (Exception e) {
    784             warnln("ERROR: in creation of rule based collator");
    785             return;
    786         }
    787         // logln("Testing different case settings with custom rules");
    788         myCollation.setStrength(Collator.TERTIARY);
    789 
    790         for(k = 0; k<4; k++) {
    791             if (caseTestAttributes[k][0] == true) {
    792                 ((RuleBasedCollator)myCollation).setUpperCaseFirst(true);
    793             }
    794             else {
    795                 ((RuleBasedCollator)myCollation).setUpperCaseFirst(false);
    796             }
    797             ((RuleBasedCollator)myCollation).setCaseLevel(
    798                                                           caseTestAttributes[k][1]);
    799             for (i = 0; i < 3 ; i++) {
    800                 for(j = i+1; j<4; j++) {
    801                     CollationTest.doTest(this,
    802                                          (RuleBasedCollator)myCollation,
    803                                          testCase[i], testCase[j],
    804                                          caseTestResults[k][3*i+j-1]);
    805                 }
    806             }
    807         }
    808 
    809         {
    810             String[] lowerFirst = {
    811                 "h",
    812                 "H",
    813                 "ch",
    814                 "Ch",
    815                 "CH",
    816                 "cha",
    817                 "chA",
    818                 "Cha",
    819                 "ChA",
    820                 "CHa",
    821                 "CHA",
    822                 "i",
    823                 "I"
    824             };
    825 
    826             String[] upperFirst = {
    827                 "H",
    828                 "h",
    829                 "CH",
    830                 "Ch",
    831                 "ch",
    832                 "CHA",
    833                 "CHa",
    834                 "ChA",
    835                 "Cha",
    836                 "chA",
    837                 "cha",
    838                 "I",
    839                 "i"
    840             };
    841             // logln("mixed case test");
    842             // logln("lower first, case level off");
    843             genericRulesStarter("[caseFirst lower]&H<ch<<<Ch<<<CH", lowerFirst);
    844             // logln("upper first, case level off");
    845             genericRulesStarter("[caseFirst upper]&H<ch<<<Ch<<<CH", upperFirst);
    846             // logln("lower first, case level on");
    847             genericRulesStarter("[caseFirst lower][caseLevel on]&H<ch<<<Ch<<<CH", lowerFirst);
    848             // logln("upper first, case level on");
    849             genericRulesStarter("[caseFirst upper][caseLevel on]&H<ch<<<Ch<<<CH", upperFirst);
    850         }
    851     }
    852 
    853     @Test
    854     public void TestIncompleteCnt() {
    855         String[] cnt1 = {
    856             "AA",
    857             "AC",
    858             "AZ",
    859             "AQ",
    860             "AB",
    861             "ABZ",
    862             "ABQ",
    863             "Z",
    864             "ABC",
    865             "Q",
    866             "B"
    867         };
    868 
    869         String[] cnt2 = {
    870             "DA",
    871             "DAD",
    872             "DAZ",
    873             "MAR",
    874             "Z",
    875             "DAVIS",
    876             "MARK",
    877             "DAV",
    878             "DAVI"
    879         };
    880         RuleBasedCollator coll =  null;
    881         String temp = " & Z < ABC < Q < B";
    882         try {
    883             coll = new RuleBasedCollator(temp);
    884         } catch (Exception e) {
    885             warnln("fail to create RuleBasedCollator");
    886             return;
    887         }
    888 
    889         int size = cnt1.length;
    890         for(int i = 0; i < size-1; i++) {
    891             for(int j = i+1; j < size; j++) {
    892                 String t1 = cnt1[i];
    893                 String t2 = cnt1[j];
    894                 CollationTest.doTest(this, coll, t1, t2, -1);
    895             }
    896         }
    897 
    898         temp = " & Z < DAVIS < MARK <DAV";
    899         try {
    900             coll = new RuleBasedCollator(temp);
    901         } catch (Exception e) {
    902             warnln("fail to create RuleBasedCollator");
    903             return;
    904         }
    905 
    906         size = cnt2.length;
    907         for(int i = 0; i < size-1; i++) {
    908             for(int j = i+1; j < size; j++) {
    909                 String t1 = cnt2[i];
    910                 String t2 = cnt2[j];
    911                 CollationTest.doTest(this, coll, t1, t2, -1);
    912             }
    913         }
    914     }
    915 
    916     @Test
    917     public void TestBlackBird() {
    918         String[] shifted = {
    919             "black bird",
    920             "black-bird",
    921             "blackbird",
    922             "black Bird",
    923             "black-Bird",
    924             "blackBird",
    925             "black birds",
    926             "black-birds",
    927             "blackbirds"
    928         };
    929         int[] shiftedTert = {
    930             0,
    931             0,
    932             0,
    933             -1,
    934             0,
    935             0,
    936             -1,
    937             0,
    938             0
    939         };
    940         String[] nonignorable = {
    941             "black bird",
    942             "black Bird",
    943             "black birds",
    944             "black-bird",
    945             "black-Bird",
    946             "black-birds",
    947             "blackbird",
    948             "blackBird",
    949             "blackbirds"
    950         };
    951         int i = 0, j = 0;
    952         int size = 0;
    953         Collator coll = Collator.getInstance(new Locale("en", "US"));
    954         //ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_OFF, &status);
    955         //ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, &status);
    956         ((RuleBasedCollator)coll).setAlternateHandlingShifted(false);
    957         size = nonignorable.length;
    958         for(i = 0; i < size-1; i++) {
    959             for(j = i+1; j < size; j++) {
    960                 String t1 = nonignorable[i];
    961                 String t2 = nonignorable[j];
    962                 CollationTest.doTest(this, (RuleBasedCollator)coll, t1, t2, -1);
    963             }
    964         }
    965         ((RuleBasedCollator)coll).setAlternateHandlingShifted(true);
    966         coll.setStrength(Collator.QUATERNARY);
    967         size = shifted.length;
    968         for(i = 0; i < size-1; i++) {
    969             for(j = i+1; j < size; j++) {
    970                 String t1 = shifted[i];
    971                 String t2 = shifted[j];
    972                 CollationTest.doTest(this, (RuleBasedCollator)coll, t1, t2, -1);
    973             }
    974         }
    975         coll.setStrength(Collator.TERTIARY);
    976         size = shifted.length;
    977         for(i = 1; i < size; i++) {
    978             String t1 = shifted[i-1];
    979             String t2 = shifted[i];
    980             CollationTest.doTest(this, (RuleBasedCollator)coll, t1, t2,
    981                                  shiftedTert[i]);
    982         }
    983     }
    984 
    985     @Test
    986     public void TestFunkyA() {
    987         String[] testSourceCases = {
    988             "\u0041\u0300\u0301",
    989             "\u0041\u0300\u0316",
    990             "\u0041\u0300",
    991             "\u00C0\u0301",
    992             // this would work with forced normalization
    993             "\u00C0\u0316",
    994         };
    995 
    996         String[] testTargetCases = {
    997             "\u0041\u0301\u0300",
    998             "\u0041\u0316\u0300",
    999             "\u00C0",
   1000             "\u0041\u0301\u0300",
   1001             // this would work with forced normalization
   1002             "\u0041\u0316\u0300",
   1003         };
   1004 
   1005         int[] results = {
   1006             1,
   1007             0,
   1008             0,
   1009             1,
   1010             0
   1011         };
   1012 
   1013         Collator  myCollation;
   1014         try {
   1015             myCollation = Collator.getInstance(new Locale("en", "US"));
   1016         } catch (Exception e) {
   1017             warnln("ERROR: in creation of rule based collator");
   1018             return;
   1019         }
   1020         // logln("Testing some A letters, for some reason");
   1021         myCollation.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
   1022         myCollation.setStrength(Collator.TERTIARY);
   1023         for (int i = 0; i < 4 ; i++)
   1024             {
   1025                 CollationTest.doTest(this, (RuleBasedCollator)myCollation,
   1026                                      testSourceCases[i], testTargetCases[i],
   1027                                      results[i]);
   1028             }
   1029     }
   1030 
   1031     @Test
   1032     public void TestChMove() {
   1033         String[] chTest = {
   1034             "c",
   1035             "C",
   1036             "ca", "cb", "cx", "cy", "CZ",
   1037             "c\u030C", "C\u030C",
   1038             "h",
   1039             "H",
   1040             "ha", "Ha", "harly", "hb", "HB", "hx", "HX", "hy", "HY",
   1041             "ch", "cH", "Ch", "CH",
   1042             "cha", "charly", "che", "chh", "chch", "chr",
   1043             "i", "I", "iarly",
   1044             "r", "R",
   1045             "r\u030C", "R\u030C",
   1046             "s",
   1047             "S",
   1048             "s\u030C", "S\u030C",
   1049             "z", "Z",
   1050             "z\u030C", "Z\u030C"
   1051         };
   1052         Collator coll = null;
   1053         try {
   1054             coll = Collator.getInstance(new Locale("cs", ""));
   1055         } catch (Exception e) {
   1056             warnln("Cannot create Collator");
   1057             return;
   1058         }
   1059         int size = chTest.length;
   1060         for(int i = 0; i < size-1; i++) {
   1061             for(int j = i+1; j < size; j++) {
   1062                 String t1 = chTest[i];
   1063                 String t2 = chTest[j];
   1064                 CollationTest.doTest(this, (RuleBasedCollator)coll, t1, t2, -1);
   1065             }
   1066         }
   1067     }
   1068 
   1069     @Test
   1070     public void TestImplicitTailoring() {
   1071         String rules[] = {
   1072             /* Tailor b and c before U+4E00. */
   1073             "&[before 1]\u4e00 < b < c " +
   1074             /* Now, before U+4E00 is c; put d and e after that. */
   1075             "&[before 1]\u4e00 < d < e",
   1076             "&\u4e00 < a <<< A < b <<< B",
   1077             "&[before 1]\u4e00 < \u4e01 < \u4e02",
   1078             "&[before 1]\u4e01 < \u4e02 < \u4e03",
   1079         };
   1080         String cases[][] = {
   1081             { "b", "c", "d", "e", "\u4e00" },
   1082             { "\u4e00", "a", "A", "b", "B", "\u4e01" },
   1083             { "\u4e01", "\u4e02", "\u4e00" },
   1084             { "\u4e02", "\u4e03", "\u4e01" },
   1085         };
   1086 
   1087         int i = 0;
   1088 
   1089         for(i = 0; i < rules.length; i++) {
   1090             genericRulesStarter(rules[i], cases[i]);
   1091         }
   1092     }
   1093 
   1094     @Test
   1095     public void TestFCDProblem() {
   1096         String s1 = "\u0430\u0306\u0325";
   1097         String s2 = "\u04D1\u0325";
   1098         Collator coll = null;
   1099         try {
   1100             coll = Collator.getInstance();
   1101         } catch (Exception e) {
   1102             warnln("Can't create collator");
   1103             return;
   1104         }
   1105 
   1106         coll.setDecomposition(Collator.NO_DECOMPOSITION);
   1107         CollationTest.doTest(this, (RuleBasedCollator)coll, s1, s2, 0);
   1108         coll.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
   1109         CollationTest.doTest(this, (RuleBasedCollator)coll, s1, s2, 0);
   1110     }
   1111 
   1112     @Test
   1113     public void TestEmptyRule() {
   1114         String rulez = "";
   1115         try {
   1116             RuleBasedCollator coll = new RuleBasedCollator(rulez);
   1117             logln("rule:" + coll.getRules());
   1118         } catch (Exception e) {
   1119             warnln(e.getMessage());
   1120         }
   1121     }
   1122 
   1123     /* superseded by TestBeforePinyin, since Chinese collation rules have changed */
   1124     /*
   1125     @Test
   1126     public void TestJ784() {
   1127         String[] data = {
   1128             "A", "\u0101", "\u00e1", "\u01ce", "\u00e0",
   1129             "E", "\u0113", "\u00e9", "\u011b", "\u00e8",
   1130             "I", "\u012b", "\u00ed", "\u01d0", "\u00ec",
   1131             "O", "\u014d", "\u00f3", "\u01d2", "\u00f2",
   1132             "U", "\u016b", "\u00fa", "\u01d4", "\u00f9",
   1133             "\u00fc", "\u01d6", "\u01d8", "\u01da", "\u01dc"
   1134         };
   1135         genericLocaleStarter(new Locale("zh", ""), data);
   1136     }
   1137     */
   1138 
   1139     @Test
   1140     public void TestJ815() {
   1141         String data[] = {
   1142             "aa",
   1143             "Aa",
   1144             "ab",
   1145             "Ab",
   1146             "ad",
   1147             "Ad",
   1148             "ae",
   1149             "Ae",
   1150             "\u00e6",
   1151             "\u00c6",
   1152             "af",
   1153             "Af",
   1154             "b",
   1155             "B"
   1156         };
   1157         genericLocaleStarter(new Locale("fr", ""), data);
   1158         genericRulesStarter("[backwards 2]&A<<\u00e6/e<<<\u00c6/E", data);
   1159     }
   1160 
   1161     @Test
   1162     public void TestJ3087()
   1163     {
   1164         String rule[] = {
   1165                 "&h<H&CH=\u0427",
   1166                 /*
   1167                  * The ICU 53 builder adheres to the principle that
   1168                  * a rule is affected by previous rules but not following ones.
   1169                  * Therefore, setting CH=\u0427 and then re-tailoring H makes CH != \u0427.
   1170                 "&CH=\u0427&h<H", */
   1171                 "&CH=\u0427"
   1172         };
   1173         RuleBasedCollator rbc = null;
   1174         CollationElementIterator iter1;
   1175         CollationElementIterator iter2;
   1176         for (int i = 0; i < rule.length; i ++) {
   1177             try {
   1178                 rbc = new RuleBasedCollator(rule[i]);
   1179             } catch (Exception e) {
   1180                 warnln(e.getMessage());
   1181                 continue;
   1182             }
   1183             iter1 = rbc.getCollationElementIterator("CH");
   1184             iter2 = rbc.getCollationElementIterator("\u0427");
   1185             int ce1 = CollationElementIterator.IGNORABLE;
   1186             int ce2 = CollationElementIterator.IGNORABLE;
   1187             // The ICU 53 builder code sets the uppercase flag only on the first CE.
   1188             int mask = ~0;
   1189             while (ce1 != CollationElementIterator.NULLORDER
   1190                    && ce2 != CollationElementIterator.NULLORDER) {
   1191                 ce1 = iter1.next();
   1192                 ce2 = iter2.next();
   1193                 if ((ce1 & mask) != (ce2 & mask)) {
   1194                     errln("Error generating RuleBasedCollator with the rule "
   1195                           + rule[i]);
   1196                     errln("CH != \\u0427");
   1197                 }
   1198                 mask = ~0xc0;  // mask off case/continuation bits
   1199             }
   1200         }
   1201     }
   1202 
   1203     @Test
   1204     public void TestUpperCaseFirst() {
   1205         String[] data = {
   1206             "I",
   1207             "i",
   1208             "Y",
   1209             "y"
   1210         };
   1211         genericLocaleStarter(new Locale("da", ""), data);
   1212     }
   1213 
   1214     @Test
   1215     public void TestBefore() {
   1216         String data[] = {
   1217             "\u0101", "\u00e1", "\u01ce", "\u00e0", "A",
   1218             "\u0113", "\u00e9", "\u011b", "\u00e8", "E",
   1219             "\u012b", "\u00ed", "\u01d0", "\u00ec", "I",
   1220             "\u014d", "\u00f3", "\u01d2", "\u00f2", "O",
   1221             "\u016b", "\u00fa", "\u01d4", "\u00f9", "U",
   1222             "\u01d6", "\u01d8", "\u01da", "\u01dc", "\u00fc"
   1223         };
   1224         genericRulesStarter(
   1225                             "&[before 1]a<\u0101<\u00e1<\u01ce<\u00e0"
   1226                             + "&[before 1]e<\u0113<\u00e9<\u011b<\u00e8"
   1227                             + "&[before 1]i<\u012b<\u00ed<\u01d0<\u00ec"
   1228                             + "&[before 1]o<\u014d<\u00f3<\u01d2<\u00f2"
   1229                             + "&[before 1]u<\u016b<\u00fa<\u01d4<\u00f9"
   1230                             + "&u<\u01d6<\u01d8<\u01da<\u01dc<\u00fc", data);
   1231     }
   1232 
   1233     @Test
   1234     public void TestHangulTailoring() {
   1235         String[] koreanData = {
   1236             "\uac00", "\u4f3d", "\u4f73", "\u5047", "\u50f9", "\u52a0", "\u53ef", "\u5475",
   1237             "\u54e5", "\u5609", "\u5ac1", "\u5bb6", "\u6687", "\u67b6", "\u67b7", "\u67ef",
   1238             "\u6b4c", "\u73c2", "\u75c2", "\u7a3c", "\u82db", "\u8304", "\u8857", "\u8888",
   1239             "\u8a36", "\u8cc8", "\u8dcf", "\u8efb", "\u8fe6", "\u99d5",
   1240             "\u4EEE", "\u50A2", "\u5496", "\u54FF", "\u5777", "\u5B8A", "\u659D", "\u698E",
   1241             "\u6A9F", "\u73C8", "\u7B33", "\u801E", "\u8238", "\u846D", "\u8B0C"
   1242         };
   1243 
   1244         String rules =
   1245             "&\uac00 <<< \u4f3d <<< \u4f73 <<< \u5047 <<< \u50f9 <<< \u52a0 <<< \u53ef <<< \u5475 "
   1246             + "<<< \u54e5 <<< \u5609 <<< \u5ac1 <<< \u5bb6 <<< \u6687 <<< \u67b6 <<< \u67b7 <<< \u67ef "
   1247             + "<<< \u6b4c <<< \u73c2 <<< \u75c2 <<< \u7a3c <<< \u82db <<< \u8304 <<< \u8857 <<< \u8888 "
   1248             + "<<< \u8a36 <<< \u8cc8 <<< \u8dcf <<< \u8efb <<< \u8fe6 <<< \u99d5 "
   1249             + "<<< \u4EEE <<< \u50A2 <<< \u5496 <<< \u54FF <<< \u5777 <<< \u5B8A <<< \u659D <<< \u698E "
   1250             + "<<< \u6A9F <<< \u73C8 <<< \u7B33 <<< \u801E <<< \u8238 <<< \u846D <<< \u8B0C";
   1251 
   1252         String rlz = rules;
   1253 
   1254         Collator coll = null;
   1255         try {
   1256             coll = new RuleBasedCollator(rlz);
   1257         } catch (Exception e) {
   1258             warnln("Unable to open collator with rules" + rules);
   1259             return;
   1260         }
   1261         // logln("Using start of korean rules\n");
   1262         genericOrderingTest(coll, koreanData);
   1263 
   1264         // no such locale in icu4j
   1265         // logln("Using ko__LOTUS locale\n");
   1266         // genericLocaleStarter(new Locale("ko__LOTUS", ""), koreanData);
   1267     }
   1268 
   1269     @Test
   1270     public void TestIncrementalNormalize() {
   1271         Collator        coll = null;
   1272         // logln("Test 1 ....");
   1273         {
   1274             /* Test 1.  Run very long unnormalized strings, to force overflow of*/
   1275             /*          most buffers along the way.*/
   1276 
   1277             try {
   1278                 coll = Collator.getInstance(new Locale("en", "US"));
   1279             } catch (Exception e) {
   1280                 warnln("Cannot get default instance!");
   1281                 return;
   1282             }
   1283             char baseA     =0x41;
   1284             char ccMix[]   = {0x316, 0x321, 0x300};
   1285             int          sLen;
   1286             int          i;
   1287             StringBuffer strA = new StringBuffer();
   1288             StringBuffer strB = new StringBuffer();
   1289 
   1290             coll.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
   1291 
   1292             for (sLen = 1000; sLen<1001; sLen++) {
   1293                 strA.delete(0, strA.length());
   1294                 strA.append(baseA);
   1295                 strB.delete(0, strB.length());
   1296                 strB.append(baseA);
   1297                 for (i=1; i< sLen; i++) {
   1298                     strA.append(ccMix[i % 3]);
   1299                     strB.insert(1, ccMix[i % 3]);
   1300                 }
   1301                 coll.setStrength(Collator.TERTIARY);   // Do test with default strength, which runs
   1302                 CollationTest.doTest(this, (RuleBasedCollator)coll,
   1303                                      strA.toString(), strB.toString(), 0);    //   optimized functions in the impl
   1304                 coll.setStrength(Collator.IDENTICAL);   // Do again with the slow, general impl.
   1305                 CollationTest.doTest(this, (RuleBasedCollator)coll,
   1306                                      strA.toString(), strB.toString(), 0);
   1307             }
   1308         }
   1309         /*  Test 2:  Non-normal sequence in a string that extends to the last character*/
   1310         /*         of the string.  Checks a couple of edge cases.*/
   1311         // logln("Test 2 ....");
   1312         {
   1313             String strA = "AA\u0300\u0316";
   1314             String strB = "A\u00c0\u0316";
   1315             coll.setStrength(Collator.TERTIARY);
   1316             CollationTest.doTest(this, (RuleBasedCollator)coll, strA, strB, 0);
   1317         }
   1318         /*  Test 3:  Non-normal sequence is terminated by a surrogate pair.*/
   1319         // logln("Test 3 ....");
   1320         {
   1321             String strA = "AA\u0300\u0316\uD800\uDC01";
   1322             String strB = "A\u00c0\u0316\uD800\uDC00";
   1323             coll.setStrength(Collator.TERTIARY);
   1324             CollationTest.doTest(this, (RuleBasedCollator)coll, strA, strB, 1);
   1325         }
   1326         /*  Test 4:  Imbedded nulls do not terminate a string when length is specified.*/
   1327         // logln("Test 4 ....");
   1328         /*
   1329          * not a valid test since string are null-terminated in java{
   1330          char strA[] = {0x41, 0x00, 0x42};
   1331          char strB[] = {0x41, 0x00, 0x00};
   1332 
   1333          int result = coll.compare(new String(strA), new String(strB));
   1334          if (result != 1) {
   1335          errln("ERROR 1 in test 4\n");
   1336          }
   1337 
   1338          result = coll.compare(new String(strA, 0, 1), new String(strB, 0, 1));
   1339          if (result != 0) {
   1340          errln("ERROR 1 in test 4\n");
   1341          }
   1342 
   1343          CollationKey sortKeyA = coll.getCollationKey(new String(strA));
   1344          CollationKey sortKeyB = coll.getCollationKey(new String(strB));
   1345 
   1346          int r = sortKeyA.compareTo(sortKeyB);
   1347          if (r <= 0) {
   1348          errln("Error 4 in test 4\n");
   1349          }
   1350 
   1351          coll.setStrength(Collator.IDENTICAL);
   1352          sortKeyA = coll.getCollationKey(new String(strA));
   1353          sortKeyB = coll.getCollationKey(new String(strB));
   1354 
   1355          r = sortKeyA.compareTo(sortKeyB);
   1356          if (r <= 0) {
   1357          errln("Error 7 in test 4\n");
   1358          }
   1359 
   1360          coll.setStrength(Collator.TERTIARY);
   1361          }
   1362         */
   1363         /*  Test 5:  Null characters in non-normal source strings.*/
   1364         // logln("Test 5 ....");
   1365         /*
   1366          * not a valid test since string are null-terminated in java{
   1367          {
   1368          char strA[] = {0x41, 0x41, 0x300, 0x316, 0x00, 0x42,};
   1369          char strB[] = {0x41, 0x41, 0x300, 0x316, 0x00, 0x00,};
   1370 
   1371 
   1372          int result = coll.compare(new String(strA, 0, 6), new String(strB, 0, 6));
   1373          if (result < 0) {
   1374          errln("ERROR 1 in test 5\n");
   1375          }
   1376          result = coll.compare(new String(strA, 0, 4), new String(strB, 0, 4));
   1377          if (result != 0) {
   1378          errln("ERROR 2 in test 5\n");
   1379          }
   1380 
   1381          CollationKey sortKeyA = coll.getCollationKey(new String(strA));
   1382          CollationKey sortKeyB = coll.getCollationKey(new String(strB));
   1383          int r = sortKeyA.compareTo(sortKeyB);
   1384          if (r <= 0) {
   1385          errln("Error 4 in test 5\n");
   1386          }
   1387 
   1388          coll.setStrength(Collator.IDENTICAL);
   1389 
   1390          sortKeyA = coll.getCollationKey(new String(strA));
   1391          sortKeyB = coll.getCollationKey(new String(strB));
   1392          r = sortKeyA.compareTo(sortKeyB);
   1393          if (r <= 0) {
   1394          errln("Error 7 in test 5\n");
   1395          }
   1396 
   1397          coll.setStrength(Collator.TERTIARY);
   1398          }
   1399         */
   1400         /*  Test 6:  Null character as base of a non-normal combining sequence.*/
   1401         // logln("Test 6 ....");
   1402         /*
   1403          * not a valid test since string are null-terminated in java{
   1404          {
   1405          char strA[] = {0x41, 0x0, 0x300, 0x316, 0x41, 0x302,};
   1406          char strB[] = {0x41, 0x0, 0x302, 0x316, 0x41, 0x300,};
   1407 
   1408          int result = coll.compare(new String(strA, 0, 5), new String(strB, 0, 5));
   1409          if (result != -1) {
   1410          errln("Error 1 in test 6\n");
   1411          }
   1412          result = coll.compare(new String(strA, 0, 1), new String(strB, 0, 1));
   1413          if (result != 0) {
   1414          errln("Error 2 in test 6\n");
   1415          }
   1416          }
   1417         */
   1418     }
   1419 
   1420     @Test
   1421     public void TestContraction() {
   1422         String[] testrules = {
   1423             "&A = AB / B",
   1424             "&A = A\\u0306/\\u0306",
   1425             "&c = ch / h",
   1426         };
   1427         String[] testdata = {
   1428             "AB", "AB", "A\u0306", "ch"
   1429         };
   1430         String[] testdata2 = {
   1431             "\u0063\u0067",
   1432             "\u0063\u0068",
   1433             "\u0063\u006C",
   1434         };
   1435         /*
   1436          * These pairs of rule strings are not guaranteed to yield the very same mappings.
   1437          * In fact, LDML 24 recommends an improved way of creating mappings
   1438          * which always yields different mappings for such pairs. See
   1439          * http://www.unicode.org/reports/tr35/tr35-33/tr35-collation.html#Orderings
   1440         String[] testrules3 = {
   1441             "&z < xyz &xyzw << B",
   1442             "&z < xyz &xyz << B / w",
   1443             "&z < ch &achm << B",
   1444             "&z < ch &a << B / chm",
   1445             "&\ud800\udc00w << B",
   1446             "&\ud800\udc00 << B / w",
   1447             "&a\ud800\udc00m << B",
   1448             "&a << B / \ud800\udc00m",
   1449         }; */
   1450 
   1451         RuleBasedCollator  coll = null;
   1452         for (int i = 0; i < testrules.length; i ++) {
   1453             CollationElementIterator iter1 = null;
   1454             int j = 0;
   1455             // logln("Rule " + testrules[i] + " for testing\n");
   1456             String rule = testrules[i];
   1457             try {
   1458                 coll = new RuleBasedCollator(rule);
   1459             } catch (Exception e) {
   1460                 warnln("Collator creation failed " + testrules[i]);
   1461                 return;
   1462             }
   1463             try {
   1464                 iter1 = coll.getCollationElementIterator(testdata[i]);
   1465             } catch (Exception e) {
   1466                 errln("Collation iterator creation failed\n");
   1467                 return;
   1468             }
   1469             while (j < 2) {
   1470                 CollationElementIterator iter2;
   1471                 int ce;
   1472                 try {
   1473                     iter2 = coll.getCollationElementIterator(String.valueOf(testdata[i].charAt(j)));
   1474 
   1475                 }catch (Exception e) {
   1476                     errln("Collation iterator creation failed\n");
   1477                     return;
   1478                 }
   1479                 ce = iter2.next();
   1480                 while (ce != CollationElementIterator.NULLORDER) {
   1481                     if (iter1.next() != ce) {
   1482                         errln("Collation elements in contraction split does not match\n");
   1483                         return;
   1484                     }
   1485                     ce = iter2.next();
   1486                 }
   1487                 j ++;
   1488             }
   1489             if (iter1.next() != CollationElementIterator.NULLORDER) {
   1490                 errln("Collation elements not exhausted\n");
   1491                 return;
   1492             }
   1493         }
   1494         String rule = "& a < b < c < ch < d & c = ch / h";
   1495         try {
   1496             coll = new RuleBasedCollator(rule);
   1497         } catch (Exception e) {
   1498             errln("cannot create rulebased collator");
   1499             return;
   1500         }
   1501 
   1502         if (coll.compare(testdata2[0], testdata2[1]) != -1) {
   1503             errln("Expected " + testdata2[0] + " < " + testdata2[1]);
   1504             return;
   1505         }
   1506         if (coll.compare(testdata2[1], testdata2[2]) != -1) {
   1507             errln("Expected " + testdata2[1] + " < " + testdata2[2]);
   1508             return;
   1509         }
   1510         /* see above -- for (int i = 0; i < testrules3.length; i += 2) {
   1511             RuleBasedCollator          coll1, coll2;
   1512             CollationElementIterator iter1, iter2;
   1513             char               ch = 0x0042;
   1514             int            ce;
   1515             rule = testrules3[i];
   1516             try {
   1517                 coll1 = new RuleBasedCollator(rule);
   1518             } catch (Exception e) {
   1519                 errln("Fail: cannot create rulebased collator, rule:" + rule);
   1520                 return;
   1521             }
   1522             rule = testrules3[i + 1];
   1523             try {
   1524                 coll2 = new RuleBasedCollator(rule);
   1525             } catch (Exception e) {
   1526                 errln("Collator creation failed " + testrules[i]);
   1527                 return;
   1528             }
   1529             try {
   1530                 iter1 = coll1.getCollationElementIterator(String.valueOf(ch));
   1531                 iter2 = coll2.getCollationElementIterator(String.valueOf(ch));
   1532             } catch (Exception e) {
   1533                 errln("Collation iterator creation failed\n");
   1534                 return;
   1535             }
   1536             ce = iter1.next();
   1537 
   1538             while (ce != CollationElementIterator.NULLORDER) {
   1539                 if (ce != iter2.next()) {
   1540                     errln("CEs does not match\n");
   1541                     return;
   1542                 }
   1543                 ce = iter1.next();
   1544             }
   1545             if (iter2.next() != CollationElementIterator.NULLORDER) {
   1546                 errln("CEs not exhausted\n");
   1547                 return;
   1548             }
   1549         } */
   1550     }
   1551 
   1552     @Test
   1553     public void TestExpansion() {
   1554         String[] testrules = {
   1555             /*
   1556              * This seems to have tested that M was not mapped to an expansion.
   1557              * I believe the old builder just did that because it computed the extension CEs
   1558              * at the very end, which was a bug.
   1559              * Among other problems, it violated the core tailoring principle
   1560              * by making an earlier rule depend on a later one.
   1561              * And, of course, if M did not get an expansion, then it was primary different from K,
   1562              * unlike what the rule &K<<M says.
   1563             "&J << K / B & K << M",
   1564              */
   1565             "&J << K / B << M"
   1566         };
   1567         String[] testdata = {
   1568             "JA", "MA", "KA", "KC", "JC", "MC",
   1569         };
   1570 
   1571         Collator  coll;
   1572         for (int i = 0; i < testrules.length; i++) {
   1573             // logln("Rule " + testrules[i] + " for testing\n");
   1574             String rule = testrules[i];
   1575             try {
   1576                 coll = new RuleBasedCollator(rule);
   1577             } catch (Exception e) {
   1578                 warnln("Collator creation failed " + testrules[i]);
   1579                 return;
   1580             }
   1581 
   1582             for (int j = 0; j < 5; j ++) {
   1583                 CollationTest.doTest(this, (RuleBasedCollator)coll,
   1584                                      testdata[j], testdata[j + 1], -1);
   1585             }
   1586         }
   1587     }
   1588 
   1589     @Test
   1590     public void TestContractionEndCompare()
   1591     {
   1592         String rules = "&b=ch";
   1593         String src = "bec";
   1594         String tgt = "bech";
   1595         Collator coll = null;
   1596         try {
   1597             coll = new RuleBasedCollator(rules);
   1598         } catch (Exception e) {
   1599             warnln("Collator creation failed " + rules);
   1600             return;
   1601         }
   1602         CollationTest.doTest(this, (RuleBasedCollator)coll, src, tgt, 1);
   1603     }
   1604 
   1605     @Test
   1606     public void TestLocaleRuleBasedCollators() {
   1607         if (TestFmwk.getExhaustiveness() < 5) {
   1608             // not serious enough to run this
   1609             return;
   1610         }
   1611         Locale locale[] = Collator.getAvailableLocales();
   1612         String prevrule = null;
   1613         for (int i = 0; i < locale.length; i ++) {
   1614             Locale l = locale[i];
   1615             try {
   1616                 ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUData.ICU_COLLATION_BASE_NAME,l);
   1617                 String collkey = rb.getStringWithFallback("collations/default");
   1618                 ICUResourceBundle elements = rb.getWithFallback("collations/" + collkey);
   1619                 if (elements == null) {
   1620                     continue;
   1621                 }
   1622                 String rule = null;
   1623                 /*
   1624                   Object[][] colldata = (Object[][])elements;
   1625                   // %%CollationBin
   1626                   if (colldata[0][1] instanceof byte[]){
   1627                   rule = (String)colldata[1][1];
   1628                   }
   1629                   else {
   1630                   rule = (String)colldata[0][1];
   1631                   }
   1632                 */
   1633                 rule = elements.getString("Sequence");
   1634 
   1635                 RuleBasedCollator col1 =
   1636                     (RuleBasedCollator)Collator.getInstance(l);
   1637                 if (!rule.equals(col1.getRules())) {
   1638                     errln("Rules should be the same in the RuleBasedCollator and Locale");
   1639                 }
   1640                 if (rule != null && rule.length() > 0
   1641                     && !rule.equals(prevrule)) {
   1642                     RuleBasedCollator col2 = new RuleBasedCollator(rule);
   1643                     if (!col1.equals(col2)) {
   1644                         errln("Error creating RuleBasedCollator from " +
   1645                               "locale rules for " + l.toString());
   1646                     }
   1647                 }
   1648                 prevrule = rule;
   1649             } catch (Exception e) {
   1650                 warnln("Error retrieving resource bundle for testing: " + e.toString());
   1651             }
   1652         }
   1653     }
   1654 
   1655     @Test
   1656     public void TestOptimize() {
   1657         /* this is not really a test - just trying out
   1658          * whether copying of UCA contents will fail
   1659          * Cannot really test, since the functionality
   1660          * remains the same.
   1661          */
   1662         String rules[] = {
   1663             "[optimize [\\uAC00-\\uD7FF]]"
   1664         };
   1665         String data[][] = {
   1666             { "a", "b"}
   1667         };
   1668         int i = 0;
   1669 
   1670         for(i = 0; i<rules.length; i++) {
   1671             genericRulesStarter(rules[i], data[i]);
   1672         }
   1673     }
   1674 
   1675     @Test
   1676     public void TestIdenticalCompare()
   1677     {
   1678         try {
   1679             RuleBasedCollator coll
   1680                 = new RuleBasedCollator("& \uD800\uDC00 = \uD800\uDC01");
   1681             String strA = "AA\u0300\u0316\uD800\uDC01";
   1682             String strB = "A\u00c0\u0316\uD800\uDC00";
   1683             coll.setStrength(Collator.IDENTICAL);
   1684             CollationTest.doTest(this, coll, strA, strB, 1);
   1685         } catch (Exception e) {
   1686             warnln(e.getMessage());
   1687         }
   1688     }
   1689 
   1690     @Test
   1691     public void TestMergeSortKeys()
   1692     {
   1693         String cases[] = {"abc", "abcd", "abcde"};
   1694         String prefix = "foo";
   1695         String suffix = "egg";
   1696         CollationKey mergedPrefixKeys[] = new CollationKey[cases.length];
   1697         CollationKey mergedSuffixKeys[] = new CollationKey[cases.length];
   1698 
   1699         Collator coll = Collator.getInstance(Locale.ENGLISH);
   1700         genericLocaleStarter(Locale.ENGLISH, cases);
   1701 
   1702         int strength = Collator.PRIMARY;
   1703         while (strength <= Collator.IDENTICAL) {
   1704             coll.setStrength(strength);
   1705             CollationKey prefixKey = coll.getCollationKey(prefix);
   1706             CollationKey suffixKey = coll.getCollationKey(suffix);
   1707             for (int i = 0; i < cases.length; i ++) {
   1708                 CollationKey key = coll.getCollationKey(cases[i]);
   1709                 mergedPrefixKeys[i] = prefixKey.merge(key);
   1710                 mergedSuffixKeys[i] = suffixKey.merge(key);
   1711                 if (mergedPrefixKeys[i].getSourceString() != null
   1712                     || mergedSuffixKeys[i].getSourceString() != null) {
   1713                     errln("Merged source string error: expected null");
   1714                 }
   1715                 if (i > 0) {
   1716                     if (mergedPrefixKeys[i-1].compareTo(mergedPrefixKeys[i])
   1717                         >= 0) {
   1718                         errln("Error while comparing prefixed keys @ strength "
   1719                               + strength);
   1720                         errln(CollationTest.prettify(mergedPrefixKeys[i-1]));
   1721                         errln(CollationTest.prettify(mergedPrefixKeys[i]));
   1722                     }
   1723                     if (mergedSuffixKeys[i-1].compareTo(mergedSuffixKeys[i])
   1724                         >= 0) {
   1725                         errln("Error while comparing suffixed keys @ strength "
   1726                               + strength);
   1727                         errln(CollationTest.prettify(mergedSuffixKeys[i-1]));
   1728                         errln(CollationTest.prettify(mergedSuffixKeys[i]));
   1729                     }
   1730                 }
   1731             }
   1732             if (strength == Collator.QUATERNARY) {
   1733                 strength = Collator.IDENTICAL;
   1734             }
   1735             else {
   1736                 strength ++;
   1737             }
   1738         }
   1739     }
   1740 
   1741     @Test
   1742     public void TestVariableTop()
   1743     {
   1744         // ICU 53+: The character must be in a supported reordering group,
   1745         // and the variable top is pinned to the end of that group.
   1746         // parseNextToken is not released as public so i create my own rules
   1747         String rules = "& ' ' < b < c < de < fg & hi = j";
   1748         try {
   1749             RuleBasedCollator coll = new RuleBasedCollator(rules);
   1750             String tokens[] = {" ", "b", "c", "de", "fg", "hi", "j", "ab"};
   1751             coll.setAlternateHandlingShifted(true);
   1752             for (int i = 0; i < tokens.length; i ++) {
   1753                 int varTopOriginal = coll.getVariableTop();
   1754                 try {
   1755                     int varTop = coll.setVariableTop(tokens[i]);
   1756                     if (i > 4) {
   1757                         errln("Token " + tokens[i] + " expected to fail");
   1758                     }
   1759                     if (varTop != coll.getVariableTop()) {
   1760                         errln("Error setting and getting variable top");
   1761                     }
   1762                     CollationKey key1 = coll.getCollationKey(tokens[i]);
   1763                     for (int j = 0; j < i; j ++) {
   1764                         CollationKey key2 = coll.getCollationKey(tokens[j]);
   1765                         if (key2.compareTo(key1) < 0) {
   1766                             errln("Setting variable top shouldn't change the comparison sequence");
   1767                         }
   1768                         byte sortorder[] = key2.toByteArray();
   1769                         if (sortorder.length > 0
   1770                             && (key2.toByteArray())[0] > 1) {
   1771                             errln("Primary sort order should be 0");
   1772                         }
   1773                     }
   1774                 } catch (Exception e) {
   1775                     CollationElementIterator iter
   1776                         = coll.getCollationElementIterator(tokens[i]);
   1777                     /*int ce =*/ iter.next();
   1778                     int ce2 = iter.next();
   1779                     if (ce2 == CollationElementIterator.NULLORDER) {
   1780                         errln("Token " + tokens[i] + " not expected to fail");
   1781                     }
   1782                     if (coll.getVariableTop() != varTopOriginal) {
   1783                         errln("When exception is thrown variable top should "
   1784                               + "not be changed");
   1785                     }
   1786                 }
   1787                 coll.setVariableTop(varTopOriginal);
   1788                 if (varTopOriginal != coll.getVariableTop()) {
   1789                     errln("Couldn't restore old variable top\n");
   1790                 }
   1791             }
   1792 
   1793             // Testing calling with error set
   1794             try {
   1795                 coll.setVariableTop("");
   1796                 errln("Empty string should throw an IllegalArgumentException");
   1797             } catch (IllegalArgumentException e) {
   1798                 logln("PASS: Empty string failed as expected");
   1799             }
   1800             try {
   1801                 coll.setVariableTop(null);
   1802                 errln("Null string should throw an IllegalArgumentException");
   1803             } catch (IllegalArgumentException e) {
   1804                 logln("PASS: null string failed as expected");
   1805             }
   1806         } catch (Exception e) {
   1807             warnln("Error creating RuleBasedCollator");
   1808         }
   1809     }
   1810 
   1811     // ported from cmsccoll.c
   1812     @Test
   1813     public void TestVariableTopSetting() {
   1814         int varTopOriginal = 0, varTop1, varTop2;
   1815         Collator coll = Collator.getInstance(ULocale.ROOT);
   1816 
   1817         String empty = "";
   1818         String space = " ";
   1819         String dot = ".";  /* punctuation */
   1820         String degree = "\u00b0";  /* symbol */
   1821         String dollar = "$";  /* currency symbol */
   1822         String zero = "0";  /* digit */
   1823 
   1824         varTopOriginal = coll.getVariableTop();
   1825         logln(String.format("coll.getVariableTop(root) -> %08x", varTopOriginal));
   1826         ((RuleBasedCollator)coll).setAlternateHandlingShifted(true);
   1827 
   1828         varTop1 = coll.setVariableTop(space);
   1829         varTop2 = coll.getVariableTop();
   1830         logln(String.format("coll.setVariableTop(space) -> %08x", varTop1));
   1831         if(varTop1 != varTop2 ||
   1832                 !coll.equals(empty, space) ||
   1833                 coll.equals(empty, dot) ||
   1834                 coll.equals(empty, degree) ||
   1835                 coll.equals(empty, dollar) ||
   1836                 coll.equals(empty, zero) ||
   1837                 coll.compare(space, dot) >= 0) {
   1838             errln("coll.setVariableTop(space) did not work");
   1839         }
   1840 
   1841         varTop1 = coll.setVariableTop(dot);
   1842         varTop2 = coll.getVariableTop();
   1843         logln(String.format("coll.setVariableTop(dot) -> %08x", varTop1));
   1844         if(varTop1 != varTop2 ||
   1845                 !coll.equals(empty, space) ||
   1846                 !coll.equals(empty, dot) ||
   1847                 coll.equals(empty, degree) ||
   1848                 coll.equals(empty, dollar) ||
   1849                 coll.equals(empty, zero) ||
   1850                 coll.compare(dot, degree) >= 0) {
   1851             errln("coll.setVariableTop(dot) did not work");
   1852         }
   1853 
   1854         varTop1 = coll.setVariableTop(degree);
   1855         varTop2 = coll.getVariableTop();
   1856         logln(String.format("coll.setVariableTop(degree) -> %08x", varTop1));
   1857         if(varTop1 != varTop2 ||
   1858                 !coll.equals(empty, space) ||
   1859                 !coll.equals(empty, dot) ||
   1860                 !coll.equals(empty, degree) ||
   1861                 coll.equals(empty, dollar) ||
   1862                 coll.equals(empty, zero) ||
   1863                 coll.compare(degree, dollar) >= 0) {
   1864             errln("coll.setVariableTop(degree) did not work");
   1865         }
   1866 
   1867         varTop1 = coll.setVariableTop(dollar);
   1868         varTop2 = coll.getVariableTop();
   1869         logln(String.format("coll.setVariableTop(dollar) -> %08x", varTop1));
   1870         if(varTop1 != varTop2 ||
   1871                 !coll.equals(empty, space) ||
   1872                 !coll.equals(empty, dot) ||
   1873                 !coll.equals(empty, degree) ||
   1874                 !coll.equals(empty, dollar) ||
   1875                 coll.equals(empty, zero) ||
   1876                 coll.compare(dollar, zero) >= 0) {
   1877             errln("coll.setVariableTop(dollar) did not work");
   1878         }
   1879 
   1880         logln("Testing setting variable top to contractions");
   1881         try {
   1882             coll.setVariableTop("@P");
   1883             errln("Invalid contraction succeded in setting variable top!");
   1884         } catch(Exception expected) {
   1885         }
   1886 
   1887         logln("Test restoring variable top");
   1888         coll.setVariableTop(varTopOriginal);
   1889         if(varTopOriginal != coll.getVariableTop()) {
   1890             errln("Couldn't restore old variable top");
   1891         }
   1892     }
   1893 
   1894     // ported from cmsccoll.c
   1895     @Test
   1896     public void TestMaxVariable() {
   1897         int oldMax, max;
   1898 
   1899         String empty = "";
   1900         String space = " ";
   1901         String dot = ".";  /* punctuation */
   1902         String degree = "\u00b0";  /* symbol */
   1903         String dollar = "$";  /* currency symbol */
   1904         String zero = "0";  /* digit */
   1905 
   1906         Collator coll = Collator.getInstance(ULocale.ROOT);
   1907 
   1908         oldMax = coll.getMaxVariable();
   1909         logln(String.format("coll.getMaxVariable(root) -> %04x", oldMax));
   1910         ((RuleBasedCollator)coll).setAlternateHandlingShifted(true);
   1911 
   1912         coll.setMaxVariable(Collator.ReorderCodes.SPACE);
   1913         max = coll.getMaxVariable();
   1914         logln(String.format("coll.setMaxVariable(space) -> %04x", max));
   1915         if(max != Collator.ReorderCodes.SPACE ||
   1916                 !coll.equals(empty, space) ||
   1917                 coll.equals(empty, dot) ||
   1918                 coll.equals(empty, degree) ||
   1919                 coll.equals(empty, dollar) ||
   1920                 coll.equals(empty, zero) ||
   1921                 coll.compare(space, dot) >= 0) {
   1922             errln("coll.setMaxVariable(space) did not work");
   1923         }
   1924 
   1925         coll.setMaxVariable(Collator.ReorderCodes.PUNCTUATION);
   1926         max = coll.getMaxVariable();
   1927         logln(String.format("coll.setMaxVariable(punctuation) -> %04x", max));
   1928         if(max != Collator.ReorderCodes.PUNCTUATION ||
   1929                 !coll.equals(empty, space) ||
   1930                 !coll.equals(empty, dot) ||
   1931                 coll.equals(empty, degree) ||
   1932                 coll.equals(empty, dollar) ||
   1933                 coll.equals(empty, zero) ||
   1934                 coll.compare(dot, degree) >= 0) {
   1935             errln("coll.setMaxVariable(punctuation) did not work");
   1936         }
   1937 
   1938         coll.setMaxVariable(Collator.ReorderCodes.SYMBOL);
   1939         max = coll.getMaxVariable();
   1940         logln(String.format("coll.setMaxVariable(symbol) -> %04x", max));
   1941         if(max != Collator.ReorderCodes.SYMBOL ||
   1942                 !coll.equals(empty, space) ||
   1943                 !coll.equals(empty, dot) ||
   1944                 !coll.equals(empty, degree) ||
   1945                 coll.equals(empty, dollar) ||
   1946                 coll.equals(empty, zero) ||
   1947                 coll.compare(degree, dollar) >= 0) {
   1948             errln("coll.setMaxVariable(symbol) did not work");
   1949         }
   1950 
   1951         coll.setMaxVariable(Collator.ReorderCodes.CURRENCY);
   1952         max = coll.getMaxVariable();
   1953         logln(String.format("coll.setMaxVariable(currency) -> %04x", max));
   1954         if(max != Collator.ReorderCodes.CURRENCY ||
   1955                 !coll.equals(empty, space) ||
   1956                 !coll.equals(empty, dot) ||
   1957                 !coll.equals(empty, degree) ||
   1958                 !coll.equals(empty, dollar) ||
   1959                 coll.equals(empty, zero) ||
   1960                 coll.compare(dollar, zero) >= 0) {
   1961             errln("coll.setMaxVariable(currency) did not work");
   1962         }
   1963 
   1964         logln("Test restoring maxVariable");
   1965         coll.setMaxVariable(oldMax);
   1966         if(oldMax != coll.getMaxVariable()) {
   1967             errln("Couldn't restore old maxVariable");
   1968         }
   1969     }
   1970 
   1971     @Test
   1972     public void TestUCARules()
   1973     {
   1974         try {
   1975             // only root locale can have empty tailorings .. not English!
   1976             RuleBasedCollator coll
   1977                 = (RuleBasedCollator)Collator.getInstance(new Locale("","",""));
   1978             String rule
   1979                 = coll.getRules(false);
   1980             if (!rule.equals("")) {
   1981                 errln("Empty rule string should have empty rules " + rule);
   1982             }
   1983             rule = coll.getRules(true);
   1984             if (rule.equals("")) {
   1985                 errln("UCA rule string should not be empty");
   1986             }
   1987             coll = new RuleBasedCollator(rule);
   1988         } catch (Exception e) {
   1989             // Android patch: Add --omitCollationRules to genrb.
   1990             logln(e.getMessage());
   1991             // Android patch end.
   1992         }
   1993     }
   1994 
   1995     /**
   1996      * Jitterbug 2726
   1997      */
   1998     @Test
   1999     public void TestShifted()
   2000     {
   2001         RuleBasedCollator collator = (RuleBasedCollator) Collator.getInstance();
   2002         collator.setStrength(Collator.PRIMARY);
   2003         collator.setAlternateHandlingShifted(true);
   2004         CollationTest.doTest(this, collator, " a", "a", 0); // works properly
   2005         CollationTest.doTest(this, collator, "a", "a ", 0); // inconsistent results
   2006     }
   2007 
   2008     /**
   2009      * Test for CollationElementIterator previous and next for the whole set of
   2010      * unicode characters with normalization on.
   2011      */
   2012     @Test
   2013     public void TestNumericCollation()
   2014     {
   2015         String basicTestStrings[] = {"hello1", "hello2", "hello123456"};
   2016         String preZeroTestStrings[] = {"avery1",
   2017                                        "avery01",
   2018                                        "avery001",
   2019                                        "avery0001"};
   2020         String thirtyTwoBitNumericStrings[] = {"avery42949672960",
   2021                                                "avery42949672961",
   2022                                                "avery42949672962",
   2023                                                "avery429496729610"};
   2024 
   2025         String supplementaryDigits[] = {"\uD835\uDFCE", // 0
   2026                                         "\uD835\uDFCF", // 1
   2027                                         "\uD835\uDFD0", // 2
   2028                                         "\uD835\uDFD1", // 3
   2029                                         "\uD835\uDFCF\uD835\uDFCE", // 10
   2030                                         "\uD835\uDFCF\uD835\uDFCF", // 11
   2031                                         "\uD835\uDFCF\uD835\uDFD0", // 12
   2032                                         "\uD835\uDFD0\uD835\uDFCE", // 20
   2033                                         "\uD835\uDFD0\uD835\uDFCF", // 21
   2034                                         "\uD835\uDFD0\uD835\uDFD0" // 22
   2035         };
   2036 
   2037         String foreignDigits[] = {"\u0661",
   2038                                   "\u0662",
   2039                                   "\u0663",
   2040                                   "\u0661\u0660",
   2041                                   "\u0661\u0662",
   2042                                   "\u0661\u0663",
   2043                                   "\u0662\u0660",
   2044                                   "\u0662\u0662",
   2045                                   "\u0662\u0663",
   2046                                   "\u0663\u0660",
   2047                                   "\u0663\u0662",
   2048                                   "\u0663\u0663"
   2049         };
   2050 
   2051         //Additional tests to cover bug reported in #9476
   2052         String lastDigitDifferent[]={"2004","2005",
   2053                                      "110005", "110006",
   2054                                      "11005", "11006",
   2055                                      "100000000005","100000000006"};
   2056 
   2057         // Open our collator.
   2058         RuleBasedCollator coll
   2059             = (RuleBasedCollator)Collator.getInstance(Locale.ENGLISH);
   2060         String att[] = {"NumericCollation"};
   2061         Boolean val[] = {Boolean.TRUE};
   2062         genericLocaleStarterWithOptions(Locale.ENGLISH, basicTestStrings, att,
   2063                                         val);
   2064         genericLocaleStarterWithOptions(Locale.ENGLISH,
   2065                                         thirtyTwoBitNumericStrings, att, val);
   2066         genericLocaleStarterWithOptions(Locale.ENGLISH, foreignDigits, att,
   2067                                         val);
   2068         genericLocaleStarterWithOptions(Locale.ENGLISH, supplementaryDigits,
   2069                                         att, val);
   2070 
   2071         // Setting up our collator to do digits.
   2072         coll.setNumericCollation(true);
   2073 
   2074         // Testing that prepended zeroes still yield the correct collation
   2075         // behavior.
   2076         // We expect that every element in our strings array will be equal.
   2077         for (int i = 0; i < preZeroTestStrings.length - 1; i ++) {
   2078             for (int j = i + 1; j < preZeroTestStrings.length; j ++) {
   2079                 CollationTest.doTest(this, coll, preZeroTestStrings[i],
   2080                                      preZeroTestStrings[j],0);
   2081             }
   2082         }
   2083 
   2084         //Testing that the behavior reported in #9476 is fixed
   2085         //We expect comparisons between adjacent pairs will result in -1
   2086         for (int i=0; i < lastDigitDifferent.length -1; i=i+2 ) {
   2087             CollationTest.doTest(this, coll, lastDigitDifferent[i], lastDigitDifferent[i+1], -1);
   2088         }
   2089 
   2090 
   2091         //cover setNumericCollationDefault, getNumericCollation
   2092         assertTrue("The Numeric Collation setting is on", coll.getNumericCollation());
   2093         coll.setNumericCollationDefault();
   2094         logln("After set Numeric to default, the setting is: " + coll.getNumericCollation());
   2095     }
   2096 
   2097     @Test
   2098     public void Test3249()
   2099     {
   2100         String rule = "&x < a &z < a";
   2101         try {
   2102             RuleBasedCollator coll = new RuleBasedCollator(rule);
   2103             if(coll!=null){
   2104                 logln("Collator did not throw an exception");
   2105             }
   2106         } catch (Exception e) {
   2107             warnln("Error creating RuleBasedCollator with " + rule + " failed");
   2108         }
   2109     }
   2110 
   2111     @Test
   2112     public void TestTibetanConformance()
   2113     {
   2114         String test[] = {"\u0FB2\u0591\u0F71\u0061", "\u0FB2\u0F71\u0061"};
   2115         try {
   2116             Collator coll = Collator.getInstance();
   2117             coll.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
   2118             if (coll.compare(test[0], test[1]) != 0) {
   2119                 errln("Tibetan comparison error");
   2120             }
   2121             CollationTest.doTest(this, (RuleBasedCollator)coll,
   2122                                  test[0], test[1], 0);
   2123         } catch (Exception e) {
   2124             warnln("Error creating UCA collator");
   2125         }
   2126     }
   2127 
   2128     @Test
   2129     public void TestJ3347()
   2130     {
   2131         try {
   2132             Collator coll = Collator.getInstance(Locale.FRENCH);
   2133             ((RuleBasedCollator)coll).setAlternateHandlingShifted(true);
   2134             if (coll.compare("6", "!6") != 0) {
   2135                 errln("Jitterbug 3347 failed");
   2136             }
   2137         } catch (Exception e) {
   2138             warnln("Error creating UCA collator");
   2139         }
   2140     }
   2141 
   2142     @Test
   2143     public void TestPinyinProblem()
   2144     {
   2145         String test[] = { "\u4E56\u4E56\u7761", "\u4E56\u5B69\u5B50" };
   2146         genericLocaleStarter(new Locale("zh", "", "PINYIN"), test);
   2147     }
   2148 
   2149     /* supercedes TestJ784 */
   2150     @Test
   2151     public void TestBeforePinyin() {
   2152         String rules =
   2153             "&[before 2]A << \u0101  <<< \u0100 << \u00E1 <<< \u00C1 << \u01CE <<< \u01CD << \u00E0 <<< \u00C0" +
   2154             "&[before 2]e << \u0113 <<< \u0112 << \u00E9 <<< \u00C9 << \u011B <<< \u011A << \u00E8 <<< \u00C8" +
   2155             "&[before 2] i << \u012B <<< \u012A << \u00ED <<< \u00CD << \u01D0 <<< \u01CF << \u00EC <<< \u00CC" +
   2156             "&[before 2] o << \u014D <<< \u014C << \u00F3 <<< \u00D3 << \u01D2 <<< \u01D1 << \u00F2 <<< \u00D2" +
   2157             "&[before 2]u << \u016B <<< \u016A << \u00FA <<< \u00DA << \u01D4 <<< \u01D3 << \u00F9 <<< \u00D9" +
   2158             "&U << \u01D6 <<< \u01D5 << \u01D8 <<< \u01D7 << \u01DA <<< \u01D9 << \u01DC <<< \u01DB << \u00FC";
   2159 
   2160         String test[] = {
   2161             "l\u0101",
   2162             "la",
   2163             "l\u0101n",
   2164             "lan ",
   2165             "l\u0113",
   2166             "le",
   2167             "l\u0113n",
   2168             "len"
   2169         };
   2170 
   2171         String test2[] = {
   2172             "x\u0101",
   2173             "x\u0100",
   2174             "X\u0101",
   2175             "X\u0100",
   2176             "x\u00E1",
   2177             "x\u00C1",
   2178             "X\u00E1",
   2179             "X\u00C1",
   2180             "x\u01CE",
   2181             "x\u01CD",
   2182             "X\u01CE",
   2183             "X\u01CD",
   2184             "x\u00E0",
   2185             "x\u00C0",
   2186             "X\u00E0",
   2187             "X\u00C0",
   2188             "xa",
   2189             "xA",
   2190             "Xa",
   2191             "XA",
   2192             "x\u0101x",
   2193             "x\u0100x",
   2194             "x\u00E1x",
   2195             "x\u00C1x",
   2196             "x\u01CEx",
   2197             "x\u01CDx",
   2198             "x\u00E0x",
   2199             "x\u00C0x",
   2200             "xax",
   2201             "xAx"
   2202         };
   2203         /* TODO: port builder fixes to before */
   2204         genericRulesStarter(rules, test);
   2205         genericLocaleStarter(new Locale("zh","",""), test);
   2206         genericRulesStarter(rules, test2);
   2207         genericLocaleStarter(new Locale("zh","",""), test2);
   2208     }
   2209 
   2210     @Test
   2211     public void TestUpperFirstQuaternary()
   2212     {
   2213       String tests[] = { "B", "b", "Bb", "bB" };
   2214       String[] att = { "strength", "UpperFirst" };
   2215       Object attVals[] = { new Integer(Collator.QUATERNARY), Boolean.TRUE };
   2216       genericLocaleStarterWithOptions(new Locale("root","",""), tests, att, attVals);
   2217     }
   2218 
   2219     @Test
   2220     public void TestJ4960()
   2221     {
   2222         String tests[] = { "\\u00e2T", "aT" };
   2223         String att[] = { "strength", "CaseLevel" };
   2224         Object attVals[] = { new Integer(Collator.PRIMARY), Boolean.TRUE };
   2225         String tests2[] = { "a", "A" };
   2226         String rule = "&[first tertiary ignorable]=A=a";
   2227         String att2[] = { "CaseLevel" };
   2228         Object attVals2[] = { Boolean.TRUE };
   2229         // Test whether we correctly ignore primary ignorables on case level when
   2230         // we have only primary & case level
   2231         genericLocaleStarterWithOptionsAndResult(new Locale("root", ""), tests, att, attVals, 0);
   2232         // Test whether ICU4J will make case level for sortkeys that have primary strength
   2233         // and case level
   2234         genericLocaleStarterWithOptions(new Locale("root", ""), tests2, att, attVals);
   2235         // Test whether completely ignorable letters have case level info (they shouldn't)
   2236         genericRulesStarterWithOptionsAndResult(rule, tests2, att2, attVals2, 0);
   2237     }
   2238 
   2239     @Test
   2240     public void TestJB5298(){
   2241         ULocale[] locales = Collator.getAvailableULocales();
   2242         logln("Number of collator locales returned : " + locales.length);
   2243         // double-check keywords
   2244         String[] keywords = Collator.getKeywords();
   2245         if (keywords.length != 1 || !keywords[0].equals("collation")) {
   2246             throw new IllegalArgumentException("internal collation error");
   2247         }
   2248 
   2249         String[] values = Collator.getKeywordValues("collation");
   2250         log("Collator.getKeywordValues returned: ");
   2251         for(int i=0; i<values.length;i++){
   2252             log(values[i]+", ");
   2253         }
   2254         logln("");
   2255         logln("Number of collation keyword values returned : " + values.length);
   2256         for(int i=0; i<values.length;i++){
   2257             if (values[i].startsWith("private-")) {
   2258                 errln("Collator.getKeywordValues() returns private collation keyword: " + values[i]);
   2259             }
   2260         }
   2261 
   2262         Set foundValues = new TreeSet(Arrays.asList(values));
   2263 
   2264         for (int i = 0; i < locales.length; ++i) {
   2265           for (int j = 0; j < values.length; ++j) {
   2266             ULocale tryLocale = values[j].equals("standard")
   2267             ? locales[i] : new ULocale(locales[i] + "@collation=" + values[j]);
   2268             // only append if not standard
   2269             ULocale canon = Collator.getFunctionalEquivalent("collation",tryLocale);
   2270             if (!canon.equals(tryLocale)) {
   2271                 continue; // has a different
   2272             }else {// functional equivalent, so skip
   2273                 logln(tryLocale + " : "+canon+", ");
   2274             }
   2275             String can = canon.toString();
   2276             int idx = can.indexOf("@collation=");
   2277             String val = idx >= 0 ? can.substring(idx+11, can.length()) : "";
   2278             if(val.length()>0 && !foundValues.contains(val)){
   2279                 errln("Unknown collation found "+ can);
   2280             }
   2281           }
   2282         }
   2283         logln(" ");
   2284     }
   2285 
   2286     @Test
   2287     public void TestJ5367()
   2288     {
   2289         String[] test = { "a", "y" };
   2290         String rules = "&Ny << Y &[first secondary ignorable] <<< a";
   2291         genericRulesStarter(rules, test);
   2292     }
   2293 
   2294     @Test
   2295     public void TestVI5913()
   2296     {
   2297 
   2298         String rules[] = {
   2299                 "&a < \u00e2 <<< \u00c2",
   2300                 "&a < \u1FF3 ",  // OMEGA WITH YPOGEGRAMMENI
   2301                 "&s < \u0161 ",  // &s < s with caron
   2302                 /*
   2303                  * Note: Just tailoring &z<ae^ does not work as expected:
   2304                  * The UCA spec requires for discontiguous contractions that they
   2305                  * extend an *existing match* by one combining mark at a time.
   2306                  * Therefore, ae must be a contraction so that the builder finds
   2307                  * discontiguous contractions for ae^, for example with an intervening underdot.
   2308                  * Only then do we get the expected tail closure with a\u1EC7, a\u1EB9\u0302, etc.
   2309                  */
   2310                 "&x < ae &z < a\u00EA",  // &x < ae &z < a+e with circumflex
   2311         };
   2312         String cases[][] = {
   2313             { "\u1EAC", "A\u0323\u0302", "\u1EA0\u0302", "\u00C2\u0323", },
   2314             { "\u1FA2", "\u03C9\u0313\u0300\u0345", "\u1FF3\u0313\u0300",
   2315               "\u1F60\u0300\u0345", "\u1f62\u0345", "\u1FA0\u0300", },
   2316             { "\u1E63\u030C", "s\u0323\u030C", "s\u030C\u0323"},
   2317             { "a\u1EC7", //  a+ e with dot below and circumflex
   2318               "a\u1EB9\u0302", // a + e with dot below + combining circumflex
   2319               "a\u00EA\u0323", // a + e with circumflex + combining dot below
   2320             }
   2321         };
   2322 
   2323 
   2324         for(int i = 0; i < rules.length; i++) {
   2325 
   2326             RuleBasedCollator coll = null;
   2327             try {
   2328                 coll = new RuleBasedCollator(rules[i]);
   2329             } catch (Exception e) {
   2330                 warnln("Unable to open collator with rules " + rules[i]);
   2331             }
   2332 
   2333             logln("Test case["+i+"]:");
   2334             CollationKey expectingKey = coll.getCollationKey(cases[i][0]);
   2335             for (int j=1; j<cases[i].length; j++) {
   2336                 CollationKey key = coll.getCollationKey(cases[i][j]);
   2337                 if ( key.compareTo(expectingKey)!=0) {
   2338                     errln("Error! Test case["+i+"]:"+"source:" + key.getSourceString());
   2339                     errln("expecting:"+CollationTest.prettify(expectingKey)+ "got:"+  CollationTest.prettify(key));
   2340                 }
   2341                 logln("   Key:"+  CollationTest.prettify(key));
   2342             }
   2343         }
   2344 
   2345 
   2346         RuleBasedCollator vi_vi = null;
   2347         try {
   2348             vi_vi = (RuleBasedCollator)Collator.getInstance(
   2349                                                       new Locale("vi", ""));
   2350             logln("VI sort:");
   2351             CollationKey expectingKey = vi_vi.getCollationKey(cases[0][0]);
   2352             for (int j=1; j<cases[0].length; j++) {
   2353                 CollationKey key = vi_vi.getCollationKey(cases[0][j]);
   2354                 if ( key.compareTo(expectingKey)!=0) {
   2355                     // TODO (claireho): change the logln to errln after vi.res is up-to-date.
   2356                     // errln("source:" + key.getSourceString());
   2357                     // errln("expecting:"+prettify(expectingKey)+ "got:"+  prettify(key));
   2358                     logln("Error!! in Vietnese sort - source:" + key.getSourceString());
   2359                     logln("expecting:"+CollationTest.prettify(expectingKey)+ "got:"+  CollationTest.prettify(key));
   2360                 }
   2361                 // logln("source:" + key.getSourceString());
   2362                 logln("   Key:"+  CollationTest.prettify(key));
   2363             }
   2364         } catch (Exception e) {
   2365             warnln("Error creating Vietnese collator");
   2366             return;
   2367         }
   2368 
   2369     }
   2370 
   2371 
   2372     @Test
   2373     public void Test6179()
   2374     {
   2375         String rules[] = {
   2376                 "&[last primary ignorable]<< a  &[first primary ignorable]<<b ",
   2377                 "&[last secondary ignorable]<<< a &[first secondary ignorable]<<<b",
   2378         };
   2379         // defined in UCA5.1
   2380         String firstPrimIgn = "\u0332";
   2381         String lastPrimIgn = "\uD800\uDDFD";
   2382         String firstVariable = "\u0009";
   2383         byte[] secIgnKey = {1,1,4,0};
   2384 
   2385         int i=0;
   2386         {
   2387 
   2388             RuleBasedCollator coll = null;
   2389             try {
   2390                 coll = new RuleBasedCollator(rules[i]);
   2391             } catch (Exception e) {
   2392                 warnln("Unable to open collator with rules " + rules[i] + ": " + e);
   2393                 return;
   2394             }
   2395 
   2396             logln("Test rule["+i+"]"+rules[i]);
   2397 
   2398             CollationKey keyA = coll.getCollationKey("a");
   2399             logln("Key for \"a\":"+  CollationTest.prettify(keyA));
   2400             if (keyA.compareTo(coll.getCollationKey(lastPrimIgn))<=0) {
   2401                 CollationKey key = coll.getCollationKey(lastPrimIgn);
   2402                 logln("Collation key for 0xD800 0xDDFD: "+CollationTest.prettify(key));
   2403                 errln("Error! String \"a\" must be greater than \uD800\uDDFD -"+
   2404                       "[Last Primary Ignorable]");
   2405             }
   2406             if (keyA.compareTo(coll.getCollationKey(firstVariable))>=0) {
   2407                 CollationKey key = coll.getCollationKey(firstVariable);
   2408                 logln("Collation key for 0x0009: "+CollationTest.prettify(key));
   2409                 errln("Error! String \"a\" must be less than 0x0009 - [First Variable]");
   2410             }
   2411             CollationKey keyB = coll.getCollationKey("b");
   2412             logln("Key for \"b\":"+  CollationTest.prettify(keyB));
   2413             if (keyB.compareTo(coll.getCollationKey(firstPrimIgn))<=0) {
   2414                 CollationKey key = coll.getCollationKey(firstPrimIgn);
   2415                 logln("Collation key for 0x0332: "+CollationTest.prettify(key));
   2416                 errln("Error! String \"b\" must be greater than 0x0332 -"+
   2417                       "[First Primary Ignorable]");
   2418             }
   2419             if (keyB.compareTo(coll.getCollationKey(firstVariable))>=0) {
   2420                 CollationKey key = coll.getCollationKey(firstVariable);
   2421                 logln("Collation key for 0x0009: "+CollationTest.prettify(key));
   2422                 errln("Error! String \"b\" must be less than 0x0009 - [First Variable]");
   2423             }
   2424         }
   2425         {
   2426             i=1;
   2427             RuleBasedCollator coll = null;
   2428             try {
   2429                 coll = new RuleBasedCollator(rules[i]);
   2430             } catch (Exception e) {
   2431                 warnln("Unable to open collator with rules " + rules[i]);
   2432             }
   2433 
   2434             logln("Test rule["+i+"]"+rules[i]);
   2435 
   2436             CollationKey keyA = coll.getCollationKey("a");
   2437             logln("Key for \"a\":"+  CollationTest.prettify(keyA));
   2438             byte[] keyAInBytes = keyA.toByteArray();
   2439             for (int j=0; j<keyAInBytes.length && j<secIgnKey.length; j++) {
   2440                 if (keyAInBytes[j]!=secIgnKey[j]) {
   2441                     if ((char)keyAInBytes[j]<=(char)secIgnKey[j]) {
   2442                         logln("Error! String \"a\" must be greater than [Last Secondary Ignorable]");
   2443                     }
   2444                     break;
   2445                 }
   2446             }
   2447             if (keyA.compareTo(coll.getCollationKey(firstVariable))>=0) {
   2448                 errln("Error! String \"a\" must be less than 0x0009 - [First Variable]");
   2449                 CollationKey key = coll.getCollationKey(firstVariable);
   2450                 logln("Collation key for 0x0009: "+CollationTest.prettify(key));
   2451             }
   2452             CollationKey keyB = coll.getCollationKey("b");
   2453             logln("Key for \"b\":"+  CollationTest.prettify(keyB));
   2454             byte[] keyBInBytes = keyB.toByteArray();
   2455             for (int j=0; j<keyBInBytes.length && j<secIgnKey.length; j++) {
   2456                 if (keyBInBytes[j]!=secIgnKey[j]) {
   2457                     if ((char)keyBInBytes[j]<=(char)secIgnKey[j]) {
   2458                         errln("Error! String \"b\" must be greater than [Last Secondary Ignorable]");
   2459                     }
   2460                     break;
   2461                 }
   2462             }
   2463             if (keyB.compareTo(coll.getCollationKey(firstVariable))>=0) {
   2464                 CollationKey key = coll.getCollationKey(firstVariable);
   2465                 logln("Collation key for 0x0009: "+CollationTest.prettify(key));
   2466                 errln("Error! String \"b\" must be less than 0x0009 - [First Variable]");
   2467             }
   2468         }
   2469     }
   2470 
   2471     @Test
   2472     public void TestUCAPrecontext()
   2473     {
   2474         String rules[] = {
   2475                 "& \u00B7<a ",
   2476                 "& L\u00B7 << a", // 'a' is an expansion.
   2477         };
   2478         String cases[] = {
   2479             "\u00B7",
   2480             "\u0387",
   2481             "a",
   2482             "l",
   2483             "L\u0332",
   2484             "l\u00B7",
   2485             "l\u0387",
   2486             "L\u0387",
   2487             "la\u0387",
   2488             "La\u00b7",
   2489         };
   2490 
   2491         // Test en sort
   2492         RuleBasedCollator en = null;
   2493 
   2494         logln("EN sort:");
   2495         try {
   2496             en = (RuleBasedCollator)Collator.getInstance(
   2497                     new Locale("en", ""));
   2498             for (int j=0; j<cases.length; j++) {
   2499                 CollationKey key = en.getCollationKey(cases[j]);
   2500                 if (j>0) {
   2501                     CollationKey prevKey = en.getCollationKey(cases[j-1]);
   2502                     if (key.compareTo(prevKey)<0) {
   2503                         errln("Error! EN test["+j+"]:source:" + cases[j]+
   2504                         " is not >= previous test string.");
   2505                     }
   2506                 }
   2507                 /*
   2508                 if ( key.compareTo(expectingKey)!=0) {
   2509                     errln("Error! Test case["+i+"]:"+"source:" + key.getSourceString());
   2510                     errln("expecting:"+prettify(expectingKey)+ "got:"+  prettify(key));
   2511                 }
   2512                 */
   2513                 logln("String:"+cases[j]+"   Key:"+  CollationTest.prettify(key));
   2514             }
   2515         } catch (Exception e) {
   2516             warnln("Error creating English collator");
   2517             return;
   2518         }
   2519 
   2520         // Test ja sort
   2521         RuleBasedCollator ja = null;
   2522         logln("JA sort:");
   2523         try {
   2524             ja = (RuleBasedCollator)Collator.getInstance(
   2525                     new Locale("ja", ""));
   2526             for (int j=0; j<cases.length; j++) {
   2527                 CollationKey key = ja.getCollationKey(cases[j]);
   2528                 if (j>0) {
   2529                     CollationKey prevKey = ja.getCollationKey(cases[j-1]);
   2530                     if (key.compareTo(prevKey)<0) {
   2531                         errln("Error! JA test["+j+"]:source:" + cases[j]+
   2532                         " is not >= previous test string.");
   2533                     }
   2534                 }
   2535                 logln("String:"+cases[j]+"   Key:"+  CollationTest.prettify(key));
   2536             }
   2537         } catch (Exception e) {
   2538             warnln("Error creating Japanese collator");
   2539             return;
   2540         }
   2541         for(int i = 0; i < rules.length; i++) {
   2542 
   2543             RuleBasedCollator coll = null;
   2544             logln("Tailoring rule:"+rules[i]);
   2545             try {
   2546                 coll = new RuleBasedCollator(rules[i]);
   2547             } catch (Exception e) {
   2548                 warnln("Unable to open collator with rules " + rules[i]);
   2549                 continue;
   2550             }
   2551 
   2552             for (int j=0; j<cases.length; j++) {
   2553                 CollationKey key = coll.getCollationKey(cases[j]);
   2554                 if (j>0) {
   2555                     CollationKey prevKey = coll.getCollationKey(cases[j-1]);
   2556                     if (i==1 && j==3) {
   2557                         if (key.compareTo(prevKey)>0) {
   2558                             errln("Error! Rule:"+rules[i]+" test["+j+"]:source:"+
   2559                             cases[j]+" is not <= previous test string.");
   2560                         }
   2561                     }
   2562                     else {
   2563                         if (key.compareTo(prevKey)<0) {
   2564                             errln("Error! Rule:"+rules[i]+" test["+j+"]:source:"+
   2565                             cases[j]+" is not >= previous test string.");
   2566                         }
   2567                     }
   2568                 }
   2569                 logln("String:"+cases[j]+"   Key:"+  CollationTest.prettify(key));
   2570             }
   2571         }
   2572     }
   2573 
   2574 
   2575     /**
   2576      * Stores a test case for collation testing.
   2577      */
   2578     private class OneTestCase {
   2579         /** The first value to compare.  **/
   2580         public String m_source_;
   2581 
   2582         /** The second value to compare. **/
   2583         public String m_target_;
   2584 
   2585         /**
   2586          *  0 if the two values sort equal,
   2587          * -1 if the first value sorts before the second
   2588          *  1 if the first value sorts after the first
   2589          */
   2590         public int m_result_;
   2591 
   2592         public OneTestCase(String source, String target, int result) {
   2593             m_source_ = source;
   2594             m_target_ = target;
   2595             m_result_ = result;
   2596         }
   2597     }
   2598 
   2599     /**
   2600      * Convenient function to test collation rules.
   2601      * @param testCases
   2602      * @param rules Collation rules in ICU format.  All the strings in this
   2603      *     array represent the same rule, expressed in different forms.
   2604      */
   2605     private void doTestCollation(
   2606         OneTestCase[] testCases, String[] rules) {
   2607 
   2608         Collator  myCollation;
   2609         for (String rule : rules) {
   2610             try {
   2611                 myCollation = new RuleBasedCollator(rule);
   2612             } catch (Exception e) {
   2613                 warnln("ERROR: in creation of rule based collator: " + e);
   2614                 return;
   2615             }
   2616 
   2617             myCollation.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
   2618             myCollation.setStrength(Collator.TERTIARY);
   2619             for (OneTestCase testCase : testCases) {
   2620                 CollationTest.doTest(this, (RuleBasedCollator)myCollation,
   2621                                      testCase.m_source_,
   2622                                      testCase.m_target_,
   2623                                      testCase.m_result_);
   2624             }
   2625         }
   2626     }
   2627 
   2628      // Test cases to check whether the rules equivalent to
   2629      // "&a<b<c<d &b<<k<<l<<m &k<<<x<<<y<<<z &a=1=2=3" are working fine.
   2630     private OneTestCase[] m_rangeTestCases_ = {
   2631         //               Left                  Right             Result
   2632         new OneTestCase( "\u0061",             "\u0062",             -1 ),  // "a" < "b"
   2633         new OneTestCase( "\u0062",             "\u0063",             -1 ),  // "b" < "c"
   2634         new OneTestCase( "\u0061",             "\u0063",             -1 ),  // "a" < "c"
   2635 
   2636         new OneTestCase( "\u0062",             "\u006b",             -1 ),  // "b" << "k"
   2637         new OneTestCase( "\u006b",             "\u006c",             -1 ),  // "k" << "l"
   2638         new OneTestCase( "\u0062",             "\u006c",             -1 ),  // "b" << "l"
   2639         new OneTestCase( "\u0061",             "\u006c",             -1 ),  // "a" << "l"
   2640         new OneTestCase( "\u0061",             "\u006d",             -1 ),  // "a" << "m"
   2641 
   2642         new OneTestCase( "\u0079",             "\u006d",             -1 ),  // "y" < "f"
   2643         new OneTestCase( "\u0079",             "\u0067",             -1 ),  // "y" < "g"
   2644         new OneTestCase( "\u0061",             "\u0068",             -1 ),  // "y" < "h"
   2645         new OneTestCase( "\u0061",             "\u0065",             -1 ),  // "g" < "e"
   2646 
   2647         new OneTestCase( "\u0061",             "\u0031",              0 ),   // "a" == "1"
   2648         new OneTestCase( "\u0061",             "\u0032",              0 ),   // "a" == "2"
   2649         new OneTestCase( "\u0061",             "\u0033",              0 ),   // "a" == "3"
   2650         new OneTestCase( "\u0061",             "\u0066",             -1 ),   // "a" < "f",
   2651         new OneTestCase( "\u006c\u0061",       "\u006b\u0062",       -1 ),  // "la" < "kb"
   2652         new OneTestCase( "\u0061\u0061\u0061", "\u0031\u0032\u0033",  0 ),  // "aaa" == "123"
   2653         new OneTestCase( "\u0062",             "\u007a",             -1 ),  // "b" < "z"
   2654         new OneTestCase( "\u0061\u007a\u0062", "\u0032\u0079\u006d", -1 ),  // "azm" < "2yc"
   2655     };
   2656 
   2657      // Test cases to check whether the rules equivalent to
   2658      // "&\ufffe<\uffff<\U00010000<\U00010001<\U00010002
   2659      //  &\U00010000<<\U00020001<<\U00020002<<\U00020002
   2660      //  &\U00020001=\U0003001=\U0004001=\U0004002
   2661      //  &\U00040008<\U00030008<\UU00020008"
   2662      // are working fine.
   2663     private OneTestCase[] m_rangeTestCasesSupplemental_ = {
   2664         //               Left                Right               Result
   2665         new OneTestCase( "\u4e00",           "\ufffb",             -1 ),
   2666         new OneTestCase( "\ufffb",           "\ud800\udc00",       -1 ),  // U+FFFB < U+10000
   2667         new OneTestCase( "\ud800\udc00",    "\ud800\udc01",        -1 ),  // U+10000 < U+10001
   2668 
   2669         new OneTestCase( "\u4e00",           "\ud800\udc01",       -1 ),  // U+4E00 < U+10001
   2670         new OneTestCase( "\ud800\udc01",    "\ud800\udc02",        -1 ),  // U+10001 < U+10002
   2671         new OneTestCase( "\ud800\udc00",    "\ud840\udc02",        -1 ),  // U+10000 < U+10002
   2672         new OneTestCase( "\u4e00",           "\u0d840\udc02",      -1 ),  // U+4E00 < U+10002
   2673 
   2674     };
   2675 
   2676     // Test cases in disjoint random code points.  To test only the compact syntax.
   2677     // Rule:  &q<w<e<r &w<<t<<y<<u &t<<<i<<<o<<<p &o=a=s=d
   2678     private OneTestCase[] m_qwertCollationTestCases_ = {
   2679         new OneTestCase("q", "w" , -1),
   2680         new OneTestCase("w", "e" , -1),
   2681 
   2682         new OneTestCase("y", "u" , -1),
   2683         new OneTestCase("q", "u" , -1),
   2684 
   2685         new OneTestCase("t", "i" , -1),
   2686         new OneTestCase("o", "p" , -1),
   2687 
   2688         new OneTestCase("y", "e" , -1),
   2689         new OneTestCase("i", "u" , -1),
   2690 
   2691         new OneTestCase("quest", "were" , -1),
   2692         new OneTestCase("quack", "quest", -1)
   2693     };
   2694 
   2695     // Tests the compact list with ASCII codepoints.
   2696     @Test
   2697     public void TestSameStrengthList() {
   2698         String[] rules = new String[] {
   2699             // Normal
   2700             "&a<b<c<d &b<<k<<l<<m &k<<<x<<<y<<<z &y<f<g<h<e &a=1=2=3",
   2701 
   2702             // Lists
   2703             "&a<*bcd &b<<*klm &k<<<*xyz &y<*fghe &a=*123",
   2704 
   2705             // Lists with quoted characters
   2706             "&'\u0061'<*bcd &b<<*klm &k<<<*xyz &y<*f'\u0067\u0068'e &a=*123",
   2707         };
   2708         doTestCollation(m_rangeTestCases_, rules);
   2709     }
   2710 
   2711     @Test
   2712     public void TestSameStrengthListQuoted() {
   2713         String[] rules = new String[] {
   2714             "&'\u0061'<*bcd &b<<*klm &k<<<*xyz &y<*f'\u0067\u0068'e &a=1=2=3",
   2715             "&'\u0061'<*b'\u0063'd &b<<*klm &k<<<*xyz &'\u0079'<*fgh'\u0065' " +
   2716             "&a=*'\u0031\u0032\u0033'",
   2717 
   2718             "&'\u0061'<*'\u0062'c'\u0064' &b<<*klm &k<<<*xyz  &y<*fghe " +
   2719             "&a=*'\u0031\u0032\u0033'",
   2720         };
   2721         doTestCollation(m_rangeTestCases_, rules);
   2722     }
   2723 
   2724     // Tests the compact list with ASCII codepoints in non-codepoint order.
   2725     @Test
   2726     public void TestSameStrengthListQwerty() {
   2727         String[] rules = new String[] {
   2728             "&q<w<e<r &w<<t<<y<<u &t<<<i<<<o<<<p &o=a=s=d",   // Normal
   2729             "&q<*wer &w<<*tyu &t<<<*iop &o=*asd",             // Lists
   2730         };
   2731 
   2732         doTestCollation(m_qwertCollationTestCases_, rules);
   2733     }
   2734 
   2735     // Tests the compact list with supplemental codepoints.
   2736     @Test
   2737     public void TestSameStrengthListWithSupplementalCharacters() {
   2738         String[] rules = new String[] {
   2739             // ** Rule without compact list syntax **
   2740             // \u4e00 < \ufffb < \U00010000    < \U00010001  < \U00010002
   2741             "&\u4e00<\ufffb<'\ud800\udc00'<'\ud800\udc01'<'\ud800\udc02' " +
   2742             // \U00010000    << \U00020001   << \U00020002       \U00020002
   2743             "&'\ud800\udc00'<<'\ud840\udc01'<<'\ud840\udc02'<<'\ud840\udc02'  " +
   2744             // \U00020001   = \U0003001    = \U0004001    = \U0004002
   2745             "&'\ud840\udc01'='\ud880\udc01'='\ud8c0\udc01'='\ud8c0\udc02'",
   2746 
   2747             // ** Rule with compact list syntax **
   2748             // \u4e00 <* \ufffb\U00010000  \U00010001
   2749             "&\u4e00<*'\ufffb\ud800\udc00\ud800\udc01\ud800\udc02' " +
   2750             // \U00010000   <<* \U00020001  \U00020002
   2751             "&'\ud800\udc00'<<*'\ud840\udc01\ud840\udc02\ud840\udc03'  " +
   2752             // \U00020001   =* \U0003001   \U0003002   \U0003003   \U0004001
   2753             "&'\ud840\udc01'=*'\ud880\udc01\ud880\udc02\ud880\udc03\ud8c0\udc01' "
   2754 
   2755         };
   2756         doTestCollation(m_rangeTestCasesSupplemental_, rules);
   2757     }
   2758 
   2759 
   2760     // Tests the compact range syntax with ASCII codepoints.
   2761     @Test
   2762     public void TestSameStrengthListRanges() {
   2763         String[] rules = new String[] {
   2764             // Ranges
   2765             "&a<*b-d &b<<*k-m &k<<<*x-z &y<*f-he &a=*1-3",
   2766 
   2767             // Ranges with quoted characters
   2768             "&'\u0061'<*'\u0062'-'\u0064' &b<<*klm &k<<<*xyz " +
   2769             "&'\u0079'<*'\u0066'-'\u0068e' &a=*123",
   2770             "&'\u0061'<*'\u0062'-'\u0064' " +
   2771             "&b<<*'\u006B'-m &k<<<*x-'\u007a' " +
   2772             "&'\u0079'<*'\u0066'-h'\u0065' &a=*'\u0031\u0032\u0033'",
   2773         };
   2774 
   2775         doTestCollation(m_rangeTestCases_, rules);
   2776     }
   2777 
   2778     // Tests the compact range syntax with supplemental codepoints.
   2779     @Test
   2780     public void TestSameStrengthListRangesWithSupplementalCharacters() {
   2781         String[] rules = new String[] {
   2782             // \u4e00 <* \ufffb\U00010000  \U00010001
   2783             "&\u4e00<*'\ufffb'\ud800\udc00-'\ud800\udc02' " +
   2784             // \U00010000   <<* \U00020001   - \U00020003
   2785             "&'\ud800\udc00'<<*'\ud840\udc01'-'\ud840\udc03'  " +
   2786             // \U00020001   =* \U0003001   \U0004001
   2787             "&'\ud840\udc01'=*'\ud880\udc01'-'\ud880\udc03\ud8c0\udc01' "
   2788         };
   2789         doTestCollation(m_rangeTestCasesSupplemental_, rules);
   2790     }
   2791 
   2792     // Tests the compact range syntax with special characters used as syntax characters in rules.
   2793     @Test
   2794     public void TestSpecialCharacters() {
   2795         String rules[] = new String[] {
   2796                 // Normal
   2797                 "&';'<'+'<','<'-'<'&'<'*'",
   2798 
   2799                 // List
   2800                 "&';'<*'+,-&*'",
   2801 
   2802                 // Range
   2803                 "&';'<*'+'-'-&*'",
   2804 
   2805                 "&'\u003b'<'\u002b'<'\u002c'<'\u002d'<'\u0026'<'\u002a'",
   2806 
   2807                 "&'\u003b'<*'\u002b\u002c\u002d\u0026\u002a'",
   2808                 "&'\u003b'<*'\u002b\u002c\u002d\u0026\u002a'",
   2809                 "&'\u003b'<*'\u002b'-'\u002d\u0026\u002a'",
   2810                 "&'\u003b'<*'\u002b'-'\u002d\u0026\u002a'",
   2811         };
   2812         OneTestCase[] testCases = new OneTestCase[] {
   2813             new OneTestCase("\u003b", "\u002b", -1), // ; < +
   2814             new OneTestCase("\u002b", "\u002c", -1), // + < ,
   2815             new OneTestCase("\u002c", "\u002d", -1), // , < -
   2816             new OneTestCase("\u002d", "\u0026", -1), // - < &
   2817         };
   2818         doTestCollation(testCases, rules);
   2819     }
   2820 
   2821     @Test
   2822     public void TestInvalidListsAndRanges() {
   2823         String[] invalidRules = new String[] {
   2824             // Range not in starred expression
   2825             "&\u4e00<\ufffb-'\ud800\udc02'",
   2826 
   2827             // Range without start
   2828             "&a<*-c",
   2829 
   2830             // Range without end
   2831             "&a<*b-",
   2832 
   2833             // More than one hyphen
   2834             "&a<*b-g-l",
   2835 
   2836             // Range in the wrong order
   2837             "&a<*k-b",
   2838         };
   2839         for (String rule : invalidRules) {
   2840             try {
   2841                 Collator myCollation = new RuleBasedCollator(rule);
   2842                 warnln("ERROR: Creation of collator didn't fail for " + rule + " when it should.");
   2843                 CollationTest.doTest(this, (RuleBasedCollator)myCollation,
   2844                         "x",
   2845                         "y",
   2846                         -1);
   2847 
   2848            } catch (Exception e) {
   2849                 continue;
   2850             }
   2851            throw new IllegalArgumentException("ERROR: Invalid collator with rule " + rule + " worked fine.");
   2852         }
   2853     }
   2854 
   2855     // This is the same example above with ' and space added.
   2856     // They work a little different than expected.  Desired rules are commented out.
   2857     @Test
   2858     public void TestQuoteAndSpace() {
   2859         String rules[] = new String[] {
   2860                 // These are working as expected.
   2861                 "&';'<'+'<','<'-'<'&'<''<'*'<' '",
   2862 
   2863                 // List.  Desired rule is
   2864                 // "&';'<*'+,-&''* '",
   2865                 // but it doesn't work.  Instead, '' should be outside quotes as below.
   2866                 "&';'<*'+,-&''''* '",
   2867 
   2868                 // Range.  Similar issues here as well.  The following are working.
   2869                 //"&';'<*'+'-'-&''* '",
   2870                 //"&';'<*'+'-'-&'\\u0027'* '",
   2871                 "&';'<*'+'-'-&''''* '",
   2872                 //"&';'<*'+'-'-&'\\u0027'* '",
   2873 
   2874                 // The following rules are not working.
   2875                 // "&';'<'+'<','<'-'<'&'<\\u0027<'*'<' '",
   2876                 //"&'\u003b'<'\u002b'<'\u002c'<'\u002d'<'\u0026'<'\u0027'<\u002a'<'\u0020'",
   2877                 //"&'\u003b'<'\u002b'<'\u002c'<'\u002d'<'\u0026'<\\u0027<\u002a'<'\u0020'",
   2878         };
   2879 
   2880         OneTestCase[] testCases = new OneTestCase[] {
   2881             new OneTestCase("\u003b", "\u002b", -1), // ; < ,
   2882             new OneTestCase("\u002b", "\u002c", -1), // ; < ,
   2883             new OneTestCase("\u002c", "\u002d", -1), // , < -
   2884             new OneTestCase("\u002d", "\u0026", -1), // - < &
   2885             new OneTestCase("\u0026", "\u0027", -1), // & < '
   2886             new OneTestCase("\u0027", "\u002a", -1), // ' < *
   2887             // new OneTestCase("\u002a", "\u0020", -1), // * < <space>
   2888         };
   2889         doTestCollation(testCases, rules);
   2890     }
   2891 
   2892     /*
   2893      * Tests the method public boolean equals(Object target) in CollationKey
   2894      */
   2895     @Test
   2896     public void TestCollationKeyEquals() {
   2897         CollationKey ck = new CollationKey("", (byte[]) null);
   2898 
   2899         // Tests when "if (!(target instanceof CollationKey))" is true
   2900         if (ck.equals(new Object())) {
   2901             errln("CollationKey.equals() was not suppose to return false "
   2902                     + "since it is comparing to a non Collation Key object.");
   2903         }
   2904         if (ck.equals("")) {
   2905             errln("CollationKey.equals() was not suppose to return false "
   2906                     + "since it is comparing to a non Collation Key object.");
   2907         }
   2908         if (ck.equals(0)) {
   2909             errln("CollationKey.equals() was not suppose to return false "
   2910                     + "since it is comparing to a non Collation Key object.");
   2911         }
   2912         if (ck.equals(0.0)) {
   2913             errln("CollationKey.equals() was not suppose to return false "
   2914                     + "since it is comparing to a non Collation Key object.");
   2915         }
   2916 
   2917         // Tests when "if (target == null)" is true
   2918         if (ck.equals((CollationKey) null)) {
   2919             errln("CollationKey.equals() was not suppose to return false "
   2920                     + "since it is comparing to a null Collation Key object.");
   2921         }
   2922     }
   2923 
   2924     /*
   2925      * Tests the method public int hashCode() in CollationKey
   2926      */
   2927     @Test
   2928     public void TestCollationKeyHashCode() {
   2929         CollationKey ck = new CollationKey("", (byte[]) null);
   2930 
   2931         // Tests when "if (m_key_ == null)" is true
   2932         if (ck.hashCode() != 1) {
   2933             errln("CollationKey.hashCode() was suppose to return 1 "
   2934                     + "when m_key is null due a null parameter in the " + "constructor.");
   2935         }
   2936     }
   2937 
   2938     /*
   2939      * Tests the method public CollationKey getBound(int boundType, int noOfLevels)
   2940      */
   2941     @Test
   2942     public void TestGetBound() {
   2943         CollationKey ck = new CollationKey("", (byte[]) null);
   2944 
   2945         // Tests when "if (noOfLevels > Collator.PRIMARY)" is false
   2946         // Tests when "default: " is true for "switch (boundType)"
   2947         try {
   2948             ck.getBound(BoundMode.COUNT, -1);
   2949             errln("CollationKey.getBound(int,int) was suppose to return an "
   2950                     + "exception for an invalid boundType value.");
   2951         } catch (Exception e) {
   2952         }
   2953 
   2954         // Tests when "if (noOfLevels > 0)"
   2955         byte b[] = {};
   2956         CollationKey ck1 = new CollationKey("", b);
   2957         try {
   2958             ck1.getBound(0, 1);
   2959             errln("CollationKey.getBound(int,int) was suppose to return an "
   2960                     + "exception a value of noOfLevels that exceeds expected.");
   2961         } catch (Exception e) {
   2962         }
   2963     }
   2964 
   2965     /*
   2966      * Tests the method public CollationKey merge(CollationKey source)
   2967      */
   2968     @Test
   2969     public void TestMerge() {
   2970         byte b[] = {};
   2971         CollationKey ck = new CollationKey("", b);
   2972 
   2973         // Tests when "if (source == null || source.getLength() == 0)" is true
   2974         try {
   2975             ck.merge(null);
   2976             errln("Collationkey.merge(CollationKey) was suppose to return " + "an exception for a null parameter.");
   2977         } catch (Exception e) {
   2978         }
   2979         try {
   2980             ck.merge(ck);
   2981             errln("Collationkey.merge(CollationKey) was suppose to return " + "an exception for a null parameter.");
   2982         } catch (Exception e) {
   2983         }
   2984     }
   2985 
   2986     /* Test the method public int compareTo(RawCollationKey rhs) */
   2987     @Test
   2988     public void TestRawCollationKeyCompareTo(){
   2989         RawCollationKey rck = new RawCollationKey();
   2990         byte[] b = {(byte) 10, (byte) 20};
   2991         RawCollationKey rck100 = new RawCollationKey(b, 2);
   2992 
   2993         if(rck.compareTo(rck) != 0){
   2994             errln("RawCollatonKey.compareTo(RawCollationKey) was suppose to return 0 " +
   2995                     "for two idential RawCollationKey objects.");
   2996         }
   2997 
   2998         if(rck.compareTo(rck100) == 0){
   2999             errln("RawCollatonKey.compareTo(RawCollationKey) was not suppose to return 0 " +
   3000                     "for two different RawCollationKey objects.");
   3001         }
   3002     }
   3003 
   3004     /* Track7223: CollationElementIterator does not return correct order for Hungarian */
   3005     @Test
   3006     public void TestHungarianTailoring(){
   3007         String rules = new String("&DZ<dzs<<<Dzs<<<DZS" +
   3008                                   "&G<gy<<<Gy<<<GY" +
   3009                                   "&L<ly<<<Ly<<<LY" +
   3010                                   "&N<ny<<<Ny<<<NY" +
   3011                                   "&S<sz<<<Sz<<<SZ" +
   3012                                   "&T<ty<<<Ty<<<TY" +
   3013                                   "&Z<zs<<<Zs<<<ZS" +
   3014                                   "&O<\u00f6<<<\u00d6<<\u0151<<<\u0150" +
   3015                                   "&U<\u00fc<<<\u00dc<<\u0171<<<\u0171" +
   3016                                   "&cs<<<ccs/cs" +
   3017                                   "&Cs<<<Ccs/cs" +
   3018                                   "&CS<<<CCS/CS" +
   3019                                   "&dz<<<ddz/dz" +
   3020                                   "&Dz<<<Ddz/dz" +
   3021                                   "&DZ<<<DDZ/DZ" +
   3022                                   "&dzs<<<ddzs/dzs" +
   3023                                   "&Dzs<<<Ddzs/dzs" +
   3024                                   "&DZS<<<DDZS/DZS" +
   3025                                   "&gy<<<ggy/gy" +
   3026                                   "&Gy<<<Ggy/gy" +
   3027                                   "&GY<<<GGY/GY");
   3028         RuleBasedCollator coll;
   3029         try {
   3030             String str1 = "ggy";
   3031             String str2 = "GGY";
   3032             coll = new RuleBasedCollator(rules);
   3033             if (coll.compare("ggy", "GGY") >= 0) {
   3034                   errln("TestHungarianTailoring.compare(" + str1 + ","+ str2 +
   3035                         ") was suppose to return -1 ");
   3036             }
   3037             CollationKey sortKey1 = coll.getCollationKey(str1);
   3038             CollationKey sortKey2 = coll.getCollationKey(str2);
   3039             if (sortKey1.compareTo(sortKey2) >= 0) {
   3040                   errln("TestHungarianTailoring getCollationKey(\"" + str1 +"\") was suppose "+
   3041                         "less than getCollationKey(\""+ str2 + "\").");
   3042                   errln("  getCollationKey(\"ggy\"):" + CollationTest.prettify(sortKey1) +
   3043                         "  getCollationKey(\"GGY\"):" + CollationTest.prettify(sortKey2));
   3044             }
   3045 
   3046             CollationElementIterator iter1 = coll.getCollationElementIterator(str1);
   3047             CollationElementIterator iter2 = coll.getCollationElementIterator(str2);
   3048             int ce1, ce2;
   3049             while((ce1 = iter1.next()) != CollationElementIterator.NULLORDER &&
   3050                   (ce2 = iter2.next()) != CollationElementIterator.NULLORDER) {
   3051                 if (ce1 > ce2) {
   3052                   errln("TestHungarianTailoring.CollationElementIterator(" + str1 +
   3053                       ","+ str2 + ") was suppose to return -1 ");
   3054                 }
   3055             }
   3056           } catch (Exception e) {
   3057               e.printStackTrace();
   3058           }
   3059      }
   3060 
   3061     @Test
   3062     public void TestImport(){
   3063         try{
   3064             RuleBasedCollator vicoll = (RuleBasedCollator)Collator.getInstance(new ULocale("vi"));
   3065             RuleBasedCollator escoll = (RuleBasedCollator)Collator.getInstance(new ULocale("es"));
   3066             RuleBasedCollator viescoll = new RuleBasedCollator(vicoll.getRules() + escoll.getRules());
   3067             RuleBasedCollator importviescoll = new RuleBasedCollator("[import vi][import es]");
   3068 
   3069             UnicodeSet tailoredSet = viescoll.getTailoredSet();
   3070             UnicodeSet importTailoredSet = importviescoll.getTailoredSet();
   3071 
   3072             if(!tailoredSet.equals(importTailoredSet)){
   3073                 warnln("Tailored set not equal");
   3074             }
   3075 
   3076             for (UnicodeSetIterator it = new UnicodeSetIterator(tailoredSet); it.next();) {
   3077                 String t = it.getString();
   3078                 CollationKey sk1 = viescoll.getCollationKey(t);
   3079                 CollationKey sk2 = importviescoll.getCollationKey(t);
   3080                 if(!sk1.equals(sk2)){
   3081                     warnln("Collation key's not equal for " + t);
   3082                 }
   3083             }
   3084 
   3085         }catch(Exception e){
   3086             // Android patch: Add --omitCollationRules to genrb.
   3087             logln("ERROR: in creation of rule based collator");
   3088             // Android patch end.
   3089         }
   3090     }
   3091 
   3092     @Test
   3093     public void TestImportWithType(){
   3094         try{
   3095             RuleBasedCollator vicoll = (RuleBasedCollator)Collator.getInstance(new ULocale("vi"));
   3096             RuleBasedCollator decoll = (RuleBasedCollator)Collator.getInstance(ULocale.forLanguageTag("de-u-co-phonebk"));
   3097             RuleBasedCollator videcoll = new RuleBasedCollator(vicoll.getRules() + decoll.getRules());
   3098             RuleBasedCollator importvidecoll = new RuleBasedCollator("[import vi][import de-u-co-phonebk]");
   3099 
   3100             UnicodeSet tailoredSet = videcoll.getTailoredSet();
   3101             UnicodeSet importTailoredSet = importvidecoll.getTailoredSet();
   3102 
   3103             if(!tailoredSet.equals(importTailoredSet)){
   3104                 warnln("Tailored set not equal");
   3105             }
   3106 
   3107             for (UnicodeSetIterator it = new UnicodeSetIterator(tailoredSet); it.next();) {
   3108                 String t = it.getString();
   3109                 CollationKey sk1 = videcoll.getCollationKey(t);
   3110                 CollationKey sk2 = importvidecoll.getCollationKey(t);
   3111                 if(!sk1.equals(sk2)){
   3112                     warnln("Collation key's not equal for " + t);
   3113                 }
   3114             }
   3115 
   3116         }catch(Exception e){
   3117             // Android patch: Add --omitCollationRules to genrb.
   3118             logln("ERROR: in creation of rule based collator");
   3119             // Android patch end.
   3120         }
   3121     }
   3122 
   3123     /*
   3124      * This test ensures that characters placed before a character in a different script have the same lead byte
   3125      * in their collation key before and after script reordering.
   3126      */
   3127     @Test
   3128     public void TestBeforeRuleWithScriptReordering() throws Exception
   3129     {
   3130         /* build collator */
   3131         String rules = "&[before 1]\u03b1 < \u0e01";
   3132         int[] reorderCodes = {UScript.GREEK};
   3133         int result;
   3134 
   3135         Collator myCollation = new RuleBasedCollator(rules);
   3136         myCollation.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
   3137         myCollation.setStrength(Collator.TERTIARY);
   3138 
   3139         String base = "\u03b1"; /* base */
   3140         String before = "\u0e01"; /* ko kai */
   3141 
   3142         /* check collation results - before rule applied but not script reordering */
   3143         result = myCollation.compare(base, before);
   3144         if (!(result > 0)) {
   3145             errln("Collation result not correct before script reordering.");
   3146         }
   3147 
   3148         /* check the lead byte of the collation keys before script reordering */
   3149         CollationKey baseKey = myCollation.getCollationKey(base);
   3150         CollationKey beforeKey = myCollation.getCollationKey(before);
   3151         byte[] baseKeyBytes = baseKey.toByteArray();
   3152         byte[] beforeKeyBytes = beforeKey.toByteArray();
   3153         if (baseKeyBytes[0] != beforeKeyBytes[0]) {
   3154             errln("Different lead byte for sort keys using before rule and before script reordering. base character lead byte = "
   3155                     + baseKeyBytes[0] + ", before character lead byte = " + beforeKeyBytes[0]);
   3156        }
   3157 
   3158         /* reorder the scripts */
   3159         myCollation.setReorderCodes(reorderCodes);
   3160 
   3161         /* check collation results - before rule applied and after script reordering */
   3162         result = myCollation.compare(base, before);
   3163         if (!(result > 0)) {
   3164             errln("Collation result not correct after script reordering.");
   3165         }
   3166 
   3167         /* check the lead byte of the collation keys after script reordering */
   3168         baseKey = myCollation.getCollationKey(base);
   3169         beforeKey = myCollation.getCollationKey(before);
   3170         baseKeyBytes = baseKey.toByteArray();
   3171         beforeKeyBytes = beforeKey.toByteArray();
   3172         if (baseKeyBytes[0] != beforeKeyBytes[0]) {
   3173             errln("Different lead byte for sort keys using before rule and before script reordering. base character lead byte = "
   3174                     + baseKeyBytes[0] + ", before character lead byte = " + beforeKeyBytes[0]);
   3175        }
   3176     }
   3177 
   3178     /*
   3179      * Test that in a primary-compressed sort key all bytes except the first one are unchanged under script reordering.
   3180      */
   3181     @Test
   3182     public void TestNonLeadBytesDuringCollationReordering() throws Exception
   3183     {
   3184         Collator myCollation;
   3185         byte[] baseKey;
   3186         byte[] reorderKey;
   3187         int[] reorderCodes = {UScript.GREEK};
   3188         String testString = "\u03b1\u03b2\u03b3";
   3189 
   3190         /* build collator tertiary */
   3191         myCollation = new RuleBasedCollator("");
   3192         myCollation.setStrength(Collator.TERTIARY);
   3193         baseKey = myCollation.getCollationKey(testString).toByteArray();
   3194 
   3195         myCollation.setReorderCodes(reorderCodes);
   3196         reorderKey = myCollation.getCollationKey(testString).toByteArray();
   3197 
   3198         if (baseKey.length != reorderKey.length) {
   3199             errln("Key lengths not the same during reordering.\n");
   3200         }
   3201 
   3202         for (int i = 1; i < baseKey.length; i++) {
   3203             if (baseKey[i] != reorderKey[i]) {
   3204                 errln("Collation key bytes not the same at position " + i);
   3205             }
   3206         }
   3207 
   3208         /* build collator tertiary */
   3209         myCollation = new RuleBasedCollator("");
   3210         myCollation.setStrength(Collator.QUATERNARY);
   3211         baseKey = myCollation.getCollationKey(testString).toByteArray();
   3212 
   3213         myCollation.setReorderCodes(reorderCodes);
   3214         reorderKey = myCollation.getCollationKey(testString).toByteArray();
   3215 
   3216         if (baseKey.length != reorderKey.length) {
   3217             errln("Key lengths not the same during reordering.\n");
   3218         }
   3219 
   3220         for (int i = 1; i < baseKey.length; i++) {
   3221             if (baseKey[i] != reorderKey[i]) {
   3222                 errln("Collation key bytes not the same at position " + i);
   3223             }
   3224         }
   3225     }
   3226 
   3227     /*
   3228      * Test reordering API.
   3229      */
   3230     @Test
   3231     public void TestReorderingAPI() throws Exception
   3232     {
   3233         Collator myCollation;
   3234         int[] reorderCodes = {UScript.GREEK, UScript.HAN, ReorderCodes.PUNCTUATION};
   3235         int[] duplicateReorderCodes = {UScript.HIRAGANA, UScript.GREEK, ReorderCodes.CURRENCY, UScript.KATAKANA};
   3236         int[] reorderCodesStartingWithDefault = {ReorderCodes.DEFAULT, UScript.GREEK, UScript.HAN, ReorderCodes.PUNCTUATION};
   3237         int[] retrievedReorderCodes;
   3238         String greekString = "\u03b1";
   3239         String punctuationString = "\u203e";
   3240 
   3241         /* build collator tertiary */
   3242         myCollation = new RuleBasedCollator("");
   3243         myCollation.setStrength(Collator.TERTIARY);
   3244 
   3245         /* set the reorderding */
   3246         myCollation.setReorderCodes(reorderCodes);
   3247 
   3248         retrievedReorderCodes = myCollation.getReorderCodes();
   3249         if (!Arrays.equals(reorderCodes, retrievedReorderCodes)) {
   3250             errln("ERROR: retrieved reorder codes do not match set reorder codes.");
   3251         }
   3252         if (!(myCollation.compare(greekString, punctuationString) < 0)) {
   3253             errln("ERROR: collation result should have been less.");
   3254         }
   3255 
   3256         /* clear the reordering */
   3257         myCollation.setReorderCodes(null);
   3258         retrievedReorderCodes = myCollation.getReorderCodes();
   3259         if (retrievedReorderCodes.length != 0) {
   3260             errln("ERROR: retrieved reorder codes was not null.");
   3261         }
   3262 
   3263         if (!(myCollation.compare(greekString, punctuationString) > 0)) {
   3264             errln("ERROR: collation result should have been greater.");
   3265         }
   3266 
   3267         // do it again with an empty but non-null array
   3268 
   3269         /* set the reorderding */
   3270         myCollation.setReorderCodes(reorderCodes);
   3271 
   3272         retrievedReorderCodes = myCollation.getReorderCodes();
   3273         if (!Arrays.equals(reorderCodes, retrievedReorderCodes)) {
   3274             errln("ERROR: retrieved reorder codes do not match set reorder codes.");
   3275         }
   3276         if (!(myCollation.compare(greekString, punctuationString) < 0)) {
   3277             errln("ERROR: collation result should have been less.");
   3278         }
   3279 
   3280         /* clear the reordering */
   3281         myCollation.setReorderCodes(new int[]{});
   3282         retrievedReorderCodes = myCollation.getReorderCodes();
   3283         if (retrievedReorderCodes.length != 0) {
   3284             errln("ERROR: retrieved reorder codes was not null.");
   3285         }
   3286 
   3287         if (!(myCollation.compare(greekString, punctuationString) > 0)) {
   3288             errln("ERROR: collation result should have been greater.");
   3289         }
   3290 
   3291         /* clear the reordering using [NONE] */
   3292         myCollation.setReorderCodes(new int[]{ ReorderCodes.NONE });
   3293         retrievedReorderCodes = myCollation.getReorderCodes();
   3294         if (retrievedReorderCodes.length != 0) {
   3295             errln("ERROR: [NONE] retrieved reorder codes was not null.");
   3296         }
   3297 
   3298         boolean gotException = false;
   3299         /* set duplicates in the reorder codes */
   3300         try {
   3301             myCollation.setReorderCodes(duplicateReorderCodes);
   3302         } catch (IllegalArgumentException e) {
   3303             // expect exception on illegal arguments
   3304             gotException = true;
   3305         }
   3306         if (!gotException) {
   3307             errln("ERROR: exception was not thrown for illegal reorder codes argument.");
   3308         }
   3309 
   3310         /* set duplicate reorder codes */
   3311         gotException = false;
   3312         try {
   3313             myCollation.setReorderCodes(reorderCodesStartingWithDefault);
   3314         } catch (IllegalArgumentException e) {
   3315             gotException = true;
   3316         }
   3317         if (!gotException) {
   3318             errln("ERROR: reorder codes following a 'default' code should have thrown an exception but did not.");
   3319         }
   3320     }
   3321 
   3322     /*
   3323      * Test reordering API.
   3324      */
   3325     @Test
   3326     public void TestReorderingAPIWithRuleCreatedCollator() throws Exception
   3327     {
   3328         Collator myCollation;
   3329         String rules = "[reorder Hani Grek]";
   3330         int[] rulesReorderCodes = {UScript.HAN, UScript.GREEK};
   3331         int[] reorderCodes = {UScript.GREEK, UScript.HAN, ReorderCodes.PUNCTUATION};
   3332         int[] retrievedReorderCodes;
   3333 
   3334 
   3335         /* build collator tertiary */
   3336         myCollation = new RuleBasedCollator(rules);
   3337         myCollation.setStrength(Collator.TERTIARY);
   3338 
   3339         retrievedReorderCodes = myCollation.getReorderCodes();
   3340         if (!Arrays.equals(rulesReorderCodes, retrievedReorderCodes)) {
   3341             errln("ERROR: retrieved reorder codes do not match set reorder codes.");
   3342         }
   3343 
   3344         /* clear the reordering */
   3345         myCollation.setReorderCodes(null);
   3346         retrievedReorderCodes = myCollation.getReorderCodes();
   3347         if (retrievedReorderCodes.length != 0) {
   3348             errln("ERROR: retrieved reorder codes was not null.");
   3349         }
   3350 
   3351         /* set the reorderding */
   3352         myCollation.setReorderCodes(reorderCodes);
   3353 
   3354         retrievedReorderCodes = myCollation.getReorderCodes();
   3355         if (!Arrays.equals(reorderCodes, retrievedReorderCodes)) {
   3356             errln("ERROR: retrieved reorder codes do not match set reorder codes.");
   3357         }
   3358 
   3359         /* reset the reordering */
   3360         myCollation.setReorderCodes(ReorderCodes.DEFAULT);
   3361         retrievedReorderCodes = myCollation.getReorderCodes();
   3362         if (!Arrays.equals(rulesReorderCodes, retrievedReorderCodes)) {
   3363             errln("ERROR: retrieved reorder codes do not match set reorder codes.");
   3364         }
   3365     }
   3366 
   3367     static boolean containsExpectedScript(int[] scripts, int expectedScript) {
   3368         for (int i = 0; i < scripts.length; ++i) {
   3369             if (expectedScript == scripts[i]) { return true; }
   3370         }
   3371         return false;
   3372     }
   3373 
   3374     @Test
   3375     public void TestEquivalentReorderingScripts() {
   3376         // Beginning with ICU 55, collation reordering moves single scripts
   3377         // rather than groups of scripts,
   3378         // except where scripts share a range and sort primary-equal.
   3379         final int[] expectedScripts = {
   3380                 UScript.HIRAGANA,
   3381                 UScript.KATAKANA,
   3382                 UScript.KATAKANA_OR_HIRAGANA
   3383         };
   3384 
   3385         int[] equivalentScripts = RuleBasedCollator.getEquivalentReorderCodes(UScript.GOTHIC);
   3386         if (equivalentScripts.length != 1 || equivalentScripts[0] != UScript.GOTHIC) {
   3387             errln(String.format("ERROR/Gothic: retrieved equivalent scripts wrong: " +
   3388                     "length expected 1, was = %d; expected [%d] was [%d]",
   3389                     equivalentScripts.length, UScript.GOTHIC, equivalentScripts[0]));
   3390         }
   3391 
   3392         equivalentScripts = RuleBasedCollator.getEquivalentReorderCodes(UScript.HIRAGANA);
   3393         if (equivalentScripts.length != expectedScripts.length) {
   3394             errln(String.format("ERROR/Hiragana: retrieved equivalent script length wrong: " +
   3395                     "expected %d, was = %d",
   3396                     expectedScripts.length, equivalentScripts.length));
   3397         }
   3398         int prevScript = -1;
   3399         for (int i = 0; i < equivalentScripts.length; ++i) {
   3400             int script = equivalentScripts[i];
   3401             if (script <= prevScript) {
   3402                 errln("ERROR/Hiragana: equivalent scripts out of order at index " + i);
   3403             }
   3404             prevScript = script;
   3405         }
   3406         for (int code : expectedScripts) {
   3407             if (!containsExpectedScript(equivalentScripts, code)) {
   3408                 errln("ERROR/Hiragana: equivalent scripts do not contain " + code);
   3409             }
   3410         }
   3411 
   3412         equivalentScripts = RuleBasedCollator.getEquivalentReorderCodes(UScript.KATAKANA);
   3413         if (equivalentScripts.length != expectedScripts.length) {
   3414             errln(String.format("ERROR/Katakana: retrieved equivalent script length wrong: " +
   3415                     "expected %d, was = %d",
   3416                     expectedScripts.length, equivalentScripts.length));
   3417         }
   3418         for (int code : expectedScripts) {
   3419             if (!containsExpectedScript(equivalentScripts, code)) {
   3420                 errln("ERROR/Katakana: equivalent scripts do not contain " + code);
   3421             }
   3422         }
   3423 
   3424         equivalentScripts = RuleBasedCollator.getEquivalentReorderCodes(UScript.KATAKANA_OR_HIRAGANA);
   3425         if (equivalentScripts.length != expectedScripts.length) {
   3426             errln(String.format("ERROR/Hrkt: retrieved equivalent script length wrong: " +
   3427                     "expected %d, was = %d",
   3428                     expectedScripts.length, equivalentScripts.length));
   3429         }
   3430 
   3431         equivalentScripts = RuleBasedCollator.getEquivalentReorderCodes(UScript.HAN);
   3432         if (equivalentScripts.length != 3) {
   3433             errln("ERROR/Hani: retrieved equivalent script length wrong: " +
   3434                     "expected 3, was = " + equivalentScripts.length);
   3435         }
   3436         equivalentScripts = RuleBasedCollator.getEquivalentReorderCodes(UScript.SIMPLIFIED_HAN);
   3437         if (equivalentScripts.length != 3) {
   3438             errln("ERROR/Hans: retrieved equivalent script length wrong: " +
   3439                     "expected 3, was = " + equivalentScripts.length);
   3440         }
   3441         equivalentScripts = RuleBasedCollator.getEquivalentReorderCodes(UScript.TRADITIONAL_HAN);
   3442         if (equivalentScripts.length != 3) {
   3443             errln("ERROR/Hant: retrieved equivalent script length wrong: " +
   3444                     "expected 3, was = " + equivalentScripts.length);
   3445         }
   3446 
   3447         equivalentScripts = RuleBasedCollator.getEquivalentReorderCodes(UScript.MEROITIC_CURSIVE);
   3448         if (equivalentScripts.length != 2) {
   3449             errln("ERROR/Merc: retrieved equivalent script length wrong: " +
   3450                     "expected 2, was = " + equivalentScripts.length);
   3451         }
   3452         equivalentScripts = RuleBasedCollator.getEquivalentReorderCodes(UScript.MEROITIC_HIEROGLYPHS);
   3453         if (equivalentScripts.length != 2) {
   3454             errln("ERROR/Mero: retrieved equivalent script length wrong: " +
   3455                     "expected 2, was = " + equivalentScripts.length);
   3456         }
   3457     }
   3458 
   3459     @Test
   3460     public void TestGreekFirstReorderCloning() {
   3461         String[] testSourceCases = {
   3462             "\u0041",
   3463             "\u03b1\u0041",
   3464             "\u0061",
   3465             "\u0041\u0061",
   3466             "\u0391",
   3467         };
   3468 
   3469         String[] testTargetCases = {
   3470             "\u03b1",
   3471             "\u0041\u03b1",
   3472             "\u0391",
   3473             "\u0391\u03b1",
   3474             "\u0391",
   3475         };
   3476 
   3477         int[] results = {
   3478             1,
   3479             -1,
   3480             1,
   3481             1,
   3482             0
   3483         };
   3484 
   3485         Collator  originalCollation;
   3486         Collator  myCollation;
   3487         String rules = "[reorder Grek]";
   3488         try {
   3489             originalCollation = new RuleBasedCollator(rules);
   3490         } catch (Exception e) {
   3491             warnln("ERROR: in creation of rule based collator");
   3492             return;
   3493         }
   3494         try {
   3495             myCollation = (Collator) originalCollation.clone();
   3496         } catch (Exception e) {
   3497             warnln("ERROR: in creation of rule based collator");
   3498             return;
   3499         }
   3500         myCollation.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
   3501         myCollation.setStrength(Collator.TERTIARY);
   3502         for (int i = 0; i < testSourceCases.length ; i++)
   3503         {
   3504             CollationTest.doTest(this, (RuleBasedCollator)myCollation,
   3505                                  testSourceCases[i], testTargetCases[i],
   3506                                  results[i]);
   3507         }
   3508     }
   3509 
   3510     /*
   3511      * Utility function to test one collation reordering test case.
   3512      * @param testcases Array of test cases.
   3513      * @param n_testcases Size of the array testcases.
   3514      * @param str_rules Array of rules.  These rules should be specifying the same rule in different formats.
   3515      * @param n_rules Size of the array str_rules.
   3516      */
   3517     private void doTestOneReorderingAPITestCase(OneTestCase testCases[], int reorderTokens[])
   3518     {
   3519         Collator myCollation = Collator.getInstance(ULocale.ENGLISH);
   3520         myCollation.setReorderCodes(reorderTokens);
   3521 
   3522         for (OneTestCase testCase : testCases) {
   3523             CollationTest.doTest(this, (RuleBasedCollator)myCollation,
   3524                     testCase.m_source_,
   3525                     testCase.m_target_,
   3526                     testCase.m_result_);
   3527         }
   3528     }
   3529 
   3530     @Test
   3531     public void TestGreekFirstReorder()
   3532     {
   3533         String[] strRules = {
   3534             "[reorder Grek]"
   3535         };
   3536 
   3537         int[] apiRules = {
   3538             UScript.GREEK
   3539         };
   3540 
   3541         OneTestCase[] privateUseCharacterStrings = {
   3542             new OneTestCase("\u0391", "\u0391", 0),
   3543             new OneTestCase("\u0041", "\u0391", 1),
   3544             new OneTestCase("\u03B1\u0041", "\u03B1\u0391", 1),
   3545             new OneTestCase("\u0060", "\u0391", -1),
   3546             new OneTestCase("\u0391", "\ue2dc", -1),
   3547             new OneTestCase("\u0391", "\u0060", 1),
   3548         };
   3549 
   3550         /* Test rules creation */
   3551         doTestCollation(privateUseCharacterStrings, strRules);
   3552 
   3553         /* Test collation reordering API */
   3554         doTestOneReorderingAPITestCase(privateUseCharacterStrings, apiRules);
   3555     }
   3556 
   3557     @Test
   3558     public void TestGreekLastReorder()
   3559     {
   3560         String[] strRules = {
   3561             "[reorder Zzzz Grek]"
   3562         };
   3563 
   3564         int[] apiRules = {
   3565             UScript.UNKNOWN, UScript.GREEK
   3566         };
   3567 
   3568         OneTestCase[] privateUseCharacterStrings = {
   3569             new OneTestCase("\u0391", "\u0391", 0),
   3570             new OneTestCase("\u0041", "\u0391", -1),
   3571             new OneTestCase("\u03B1\u0041", "\u03B1\u0391", -1),
   3572             new OneTestCase("\u0060", "\u0391", -1),
   3573             new OneTestCase("\u0391", "\ue2dc", 1),
   3574         };
   3575 
   3576         /* Test rules creation */
   3577         doTestCollation(privateUseCharacterStrings, strRules);
   3578 
   3579         /* Test collation reordering API */
   3580         doTestOneReorderingAPITestCase(privateUseCharacterStrings, apiRules);
   3581     }
   3582 
   3583     @Test
   3584     public void TestNonScriptReorder()
   3585     {
   3586         String[] strRules = {
   3587             "[reorder Grek Symbol DIGIT Latn Punct space Zzzz cURRENCy]"
   3588         };
   3589 
   3590         int[] apiRules = {
   3591             UScript.GREEK, ReorderCodes.SYMBOL, ReorderCodes.DIGIT, UScript.LATIN,
   3592             ReorderCodes.PUNCTUATION, ReorderCodes.SPACE, UScript.UNKNOWN,
   3593             ReorderCodes.CURRENCY
   3594         };
   3595 
   3596         OneTestCase[] privateUseCharacterStrings = {
   3597             new OneTestCase("\u0391", "\u0041", -1),
   3598             new OneTestCase("\u0041", "\u0391", 1),
   3599             new OneTestCase("\u0060", "\u0041", -1),
   3600             new OneTestCase("\u0060", "\u0391", 1),
   3601             new OneTestCase("\u0024", "\u0041", 1),
   3602         };
   3603 
   3604         /* Test rules creation */
   3605         doTestCollation(privateUseCharacterStrings, strRules);
   3606 
   3607         /* Test collation reordering API */
   3608         doTestOneReorderingAPITestCase(privateUseCharacterStrings, apiRules);
   3609     }
   3610 
   3611     @Test
   3612     public void TestHaniReorder()
   3613     {
   3614         String[] strRules = {
   3615             "[reorder Hani]"
   3616         };
   3617         int[] apiRules = {
   3618             UScript.HAN
   3619         };
   3620 
   3621         OneTestCase[] privateUseCharacterStrings = {
   3622             new OneTestCase("\u4e00", "\u0041", -1),
   3623             new OneTestCase("\u4e00", "\u0060", 1),
   3624             new OneTestCase("\uD86D\uDF40", "\u0041", -1),
   3625             new OneTestCase("\uD86D\uDF40", "\u0060", 1),
   3626             new OneTestCase("\u4e00", "\uD86D\uDF40", -1),
   3627             new OneTestCase("\ufa27", "\u0041", -1),
   3628             new OneTestCase("\uD869\uDF00", "\u0041", -1),
   3629         };
   3630 
   3631         /* Test rules creation */
   3632         doTestCollation(privateUseCharacterStrings, strRules);
   3633 
   3634         /* Test collation reordering API */
   3635         doTestOneReorderingAPITestCase(privateUseCharacterStrings, apiRules);
   3636     }
   3637 
   3638     @Test
   3639     public void TestHaniReorderWithOtherRules()
   3640     {
   3641         String[] strRules = {
   3642             "[reorder Hani]  &b<a"
   3643         };
   3644 
   3645         OneTestCase[] privateUseCharacterStrings = {
   3646             new OneTestCase("\u4e00", "\u0041", -1),
   3647             new OneTestCase("\u4e00", "\u0060", 1),
   3648             new OneTestCase("\uD86D\uDF40", "\u0041", -1),
   3649             new OneTestCase("\uD86D\uDF40", "\u0060", 1),
   3650             new OneTestCase("\u4e00", "\uD86D\uDF40", -1),
   3651             new OneTestCase("\ufa27", "\u0041", -1),
   3652             new OneTestCase("\uD869\uDF00", "\u0041", -1),
   3653             new OneTestCase("b", "a", -1),
   3654         };
   3655 
   3656         /* Test rules creation */
   3657         doTestCollation(privateUseCharacterStrings, strRules);
   3658     }
   3659 
   3660     @Test
   3661     public void TestMultipleReorder()
   3662     {
   3663         String[] strRules = {
   3664             "[reorder Grek Zzzz DIGIT Latn Hani]"
   3665         };
   3666 
   3667         int[] apiRules = {
   3668             UScript.GREEK, UScript.UNKNOWN, ReorderCodes.DIGIT, UScript.LATIN, UScript.HAN
   3669         };
   3670 
   3671         OneTestCase[] collationTestCases = {
   3672             new OneTestCase("\u0391", "\u0041", -1),
   3673             new OneTestCase("\u0031", "\u0041", -1),
   3674             new OneTestCase("u0041", "\u4e00", -1),
   3675         };
   3676 
   3677         /* Test rules creation */
   3678         doTestCollation(collationTestCases, strRules);
   3679 
   3680         /* Test collation reordering API */
   3681         doTestOneReorderingAPITestCase(collationTestCases, apiRules);
   3682     }
   3683 
   3684     @Test
   3685     public void TestFrozeness()
   3686     {
   3687         Collator myCollation = Collator.getInstance(ULocale.CANADA);
   3688         boolean exceptionCaught = false;
   3689 
   3690         myCollation.freeze();
   3691         assertTrue("Collator not frozen.", myCollation.isFrozen());
   3692 
   3693         try {
   3694             myCollation.setStrength(Collator.SECONDARY);
   3695         } catch (UnsupportedOperationException e) {
   3696             // expected
   3697             exceptionCaught = true;
   3698         }
   3699         assertTrue("Frozen collator allowed change.", exceptionCaught);
   3700         exceptionCaught = false;
   3701 
   3702         try {
   3703             myCollation.setReorderCodes(ReorderCodes.DEFAULT);
   3704         } catch (UnsupportedOperationException e) {
   3705             // expected
   3706             exceptionCaught = true;
   3707         }
   3708         assertTrue("Frozen collator allowed change.", exceptionCaught);
   3709         exceptionCaught = false;
   3710 
   3711         try {
   3712             myCollation.setVariableTop(12);
   3713         } catch (UnsupportedOperationException e) {
   3714             // expected
   3715             exceptionCaught = true;
   3716         }
   3717         assertTrue("Frozen collator allowed change.", exceptionCaught);
   3718         exceptionCaught = false;
   3719 
   3720         Collator myClone = null;
   3721         try {
   3722             myClone = (Collator) myCollation.clone();
   3723         } catch (CloneNotSupportedException e) {
   3724             // should not happen - clone is implemented in Collator
   3725             errln("ERROR: unable to clone collator.");
   3726         }
   3727         assertTrue("Clone not frozen as expected.", myClone.isFrozen());
   3728 
   3729         myClone = myClone.cloneAsThawed();
   3730         assertFalse("Clone not thawed as expected.", myClone.isFrozen());
   3731     }
   3732 
   3733     // Test case for Ticket#9409
   3734     // Unknown collation type should be ignored, without printing stack trace
   3735     @Test
   3736     public void TestUnknownCollationKeyword() {
   3737         Collator coll1 = Collator.getInstance(new ULocale("en_US@collation=bogus"));
   3738         Collator coll2 = Collator.getInstance(new ULocale("en_US"));
   3739         assertEquals("Unknown collation keyword 'bogus' should be ignored", coll1, coll2);
   3740     }
   3741 }
   3742