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