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