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