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