• 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         // Android patch: Add --omitCollationRules to genrb.
500         // RuleBasedCollator rcol = (RuleBasedCollator)Collator.getInstance(new Locale("da", "DK"));
501         // doAssert(rcol.getRules().length() != 0, "da_DK rules does not have length 0");
502         // Android patch end.
503 
504         try {
505             col = Collator.getInstance(Locale.FRENCH);
506         } catch (Exception e) {
507             errln("Creating French collation failed.");
508             return;
509         }
510 
511         col.setStrength(Collator.PRIMARY);
512         logln("testing Collator.getStrength() method again ...");
513         doAssert((col.getStrength() != Collator.TERTIARY), "collation object has the wrong strength");
514         doAssert((col.getStrength() == Collator.PRIMARY), "collation object's strength is not primary difference");
515 
516         logln("testing French Collator.setStrength() method ...");
517         col.setStrength(Collator.TERTIARY);
518         doAssert((col.getStrength() == Collator.TERTIARY), "collation object's strength is not tertiary difference");
519         doAssert((col.getStrength() != Collator.PRIMARY), "collation object's strength is primary difference");
520         doAssert((col.getStrength() != Collator.SECONDARY), "collation object's strength is secondary difference");
521 
522     }
523 
524     @Test
525     public void TestJunkCollator(){
526         logln("Create junk collation: ");
527         Locale abcd = new Locale("ab", "CD", "");
528 
529         Collator junk = Collator.getInstance(abcd);
530         Collator col = Collator.getInstance();
531 
532 
533         String colrules = ((RuleBasedCollator)col).getRules();
534         String junkrules = ((RuleBasedCollator)junk).getRules();
535         doAssert(colrules == junkrules || colrules.equals(junkrules),
536                    "The default collation should be returned.");
537         Collator frCol = null;
538         try {
539             frCol = Collator.getInstance(Locale.CANADA_FRENCH);
540         } catch (Exception e) {
541             errln("Creating fr_CA collator failed.");
542             return;
543         }
544 
545         doAssert(!(frCol.equals(junk)), "The junk is the same as the fr_CA collator.");
546         logln("Collator property test ended.");
547 
548     }
549 
550     /**
551     * This tests the RuleBasedCollator
552     * - constructor/destructor
553     * - getRules
554     */
555     @Test
556     public void TestRuleBasedColl() {
557         RuleBasedCollator col1 = null, col2 = null, col3 = null, col4 = null;
558 
559         String ruleset1 = "&9 < a, A < b, B < c, C; ch, cH, Ch, CH < d, D, e, E";
560         String ruleset2 = "&9 < a, A < b, B < c, C < d, D, e, E";
561         String ruleset3 = "&";
562 
563         try {
564             col1 = new RuleBasedCollator(ruleset1);
565         } catch (Exception e) {
566             // only first error needs to be a warning since we exit function
567             warnln("RuleBased Collator creation failed.");
568             return;
569         }
570 
571         try {
572             col2 = new RuleBasedCollator(ruleset2);
573         } catch (Exception e) {
574             errln("RuleBased Collator creation failed.");
575             return;
576         }
577 
578         try {
579             // empty rules fail
580             col3 = new RuleBasedCollator(ruleset3);
581             errln("Failure: Empty rules for the collator should fail");
582             return;
583         } catch (MissingResourceException e) {
584             warnln(e.getMessage());
585         } catch (Exception e) {
586             logln("PASS: Empty rules for the collator failed as expected");
587         }
588 
589         Locale locale = new Locale("aa", "AA");
590         try {
591             col3 = (RuleBasedCollator)Collator.getInstance(locale);
592         } catch (Exception e) {
593             errln("Fallback Collator creation failed.: %s");
594             return;
595         }
596 
597         try {
598             col3 = (RuleBasedCollator)Collator.getInstance();
599         } catch (Exception e) {
600             errln("Default Collator creation failed.: %s");
601             return;
602         }
603 
604         String rule1 = col1.getRules();
605         String rule2 = col2.getRules();
606         String rule3 = col3.getRules();
607 
608         doAssert(!rule1.equals(rule2), "Default collator getRules failed");
609         doAssert(!rule2.equals(rule3), "Default collator getRules failed");
610         doAssert(!rule1.equals(rule3), "Default collator getRules failed");
611 
612         try {
613             col4 = new RuleBasedCollator(rule2);
614         } catch (Exception e) {
615             errln("RuleBased Collator creation failed.");
616             return;
617         }
618 
619         String rule4 = col4.getRules();
620         doAssert(rule2.equals(rule4), "Default collator getRules failed");
621         // tests that modifier ! is always ignored
622         String exclamationrules = "!&a<b";
623         // java does not allow ! to be the start of the rule
624         String thaistr = "\u0e40\u0e01\u0e2d";
625         try {
626             RuleBasedCollator col5 = new RuleBasedCollator(exclamationrules);
627             RuleBasedCollator encol = (RuleBasedCollator)
628                                         Collator.getInstance(Locale.ENGLISH);
629             CollationElementIterator col5iter
630                                    = col5.getCollationElementIterator(thaistr);
631             CollationElementIterator encoliter
632                                    = encol.getCollationElementIterator(
633                                                                       thaistr);
634             while (true) {
635                 // testing with en since thai has its own tailoring
636                 int ce = col5iter.next();
637                 int ce2 = encoliter.next();
638                 if (ce2 != ce) {
639                     errln("! modifier test failed");
640                 }
641                 if (ce == CollationElementIterator.NULLORDER) {
642                     break;
643                 }
644             }
645         } catch (Exception e) {
646             errln("RuleBased Collator creation failed for ! modifier.");
647             return;
648         }
649     }
650 
651     /**
652     * This tests the RuleBasedCollator
653     * - getRules
654     */
655     @Test
656     public void TestRules() {
657         RuleBasedCollator coll = (RuleBasedCollator)Collator.getInstance(new Locale("","","")); //root
658             // logln("PASS: RuleBased Collator creation passed");
659 
660 
661         String rules = coll.getRules();
662         if (rules != null && rules.length() != 0) {
663             errln("Root tailored rules failed");
664         }
665     }
666 
667     @Test
668     public void TestSafeClone() {
669         String test1 = "abCda";
670         String test2 = "abcda";
671 
672         // one default collator & two complex ones
673         RuleBasedCollator someCollators[] = {
674             (RuleBasedCollator)Collator.getInstance(Locale.ENGLISH),
675             (RuleBasedCollator)Collator.getInstance(Locale.KOREA),
676             (RuleBasedCollator)Collator.getInstance(Locale.JAPAN)
677         };
678         RuleBasedCollator someClonedCollators[] = new RuleBasedCollator[3];
679 
680         // change orig & clone & make sure they are independent
681 
682         for (int index = 0; index < someCollators.length; index ++)
683         {
684             try {
685                 someClonedCollators[index]
686                             = (RuleBasedCollator)someCollators[index].clone();
687             } catch (CloneNotSupportedException e) {
688                 errln("Error cloning collator");
689             }
690 
691             someClonedCollators[index].setStrength(Collator.TERTIARY);
692             someCollators[index].setStrength(Collator.PRIMARY);
693             someClonedCollators[index].setCaseLevel(false);
694             someCollators[index].setCaseLevel(false);
695 
696             doAssert(someClonedCollators[index].compare(test1, test2) > 0,
697                      "Result should be \"abCda\" >>> \"abcda\" ");
698             doAssert(someCollators[index].compare(test1, test2) == 0,
699                      "Result should be \"abCda\" == \"abcda\" ");
700         }
701     }
702 
703     @Test
704     public void TestGetTailoredSet()
705     {
706         logln("testing getTailoredSet...");
707         String rules[] = {
708             "&a < \u212b",
709             "& S < \u0161 <<< \u0160",
710         };
711         String data[][] = {
712             { "\u212b", "A\u030a", "\u00c5" },
713             { "\u0161", "s\u030C", "\u0160", "S\u030C" }
714         };
715 
716         int i = 0, j = 0;
717 
718         RuleBasedCollator coll;
719         UnicodeSet set;
720 
721         for(i = 0; i < rules.length; i++) {
722             try {
723                 logln("Instantiating a collator from "+rules[i]);
724                 coll = new RuleBasedCollator(rules[i]);
725                 set = coll.getTailoredSet();
726                 logln("Got set: "+set.toPattern(true));
727                 if(set.size() < data[i].length) {
728                     errln("Tailored set size smaller ("+set.size()+") than expected ("+data[i].length+")");
729                 }
730                 for(j = 0; j < data[i].length; j++) {
731                     logln("Checking to see whether "+data[i][j]+" is in set");
732                     if(!set.contains(data[i][j])) {
733                         errln("Tailored set doesn't contain "+data[i][j]+"... It should");
734                     }
735                 }
736             } catch (Exception e) {
737                 warnln("Couldn't open collator with rules "+ rules[i]);
738             }
739         }
740     }
741 
742     /**
743      * Simple test to see if Collator is subclassable.
744      * Also test coverage of base class methods that are overridden by RuleBasedCollator.
745      */
746     @Test
747     public void TestSubClass()
748     {
749         class TestCollator extends Collator
750         {
751             @Override
752             public boolean equals(Object that) {
753                 return this == that;
754             }
755 
756             @Override
757             public int hashCode() {
758                 return 0;
759             }
760 
761             @Override
762             public int compare(String source, String target) {
763                 return source.compareTo(target);
764             }
765 
766             @Override
767             public CollationKey getCollationKey(String source)
768             {   return new CollationKey(source,
769                           getRawCollationKey(source, new RawCollationKey()));
770             }
771 
772             @Override
773             public RawCollationKey getRawCollationKey(String source,
774                                                       RawCollationKey key)
775             {
776                 byte temp1[] = source.getBytes();
777                 byte temp2[] = new byte[temp1.length + 1];
778                 System.arraycopy(temp1, 0, temp2, 0, temp1.length);
779                 temp2[temp1.length] = 0;
780                 if (key == null) {
781                     key = new RawCollationKey();
782                 }
783                 key.bytes = temp2;
784                 key.size = temp2.length;
785                 return key;
786             }
787 
788             @Override
789             public void setVariableTop(int ce)
790             {
791                 if (isFrozen()) {
792                     throw new UnsupportedOperationException("Attempt to modify frozen object");
793                 }
794             }
795 
796             @Override
797             public int setVariableTop(String str)
798             {
799                 if (isFrozen()) {
800                     throw new UnsupportedOperationException("Attempt to modify frozen object");
801                 }
802 
803                 return 0;
804             }
805 
806             @Override
807             public int getVariableTop()
808             {
809                 return 0;
810             }
811             @Override
812             public VersionInfo getVersion()
813             {
814                 return VersionInfo.getInstance(0);
815             }
816             @Override
817             public VersionInfo getUCAVersion()
818             {
819                 return VersionInfo.getInstance(0);
820             }
821         }
822 
823         Collator col1 = new TestCollator();
824         Collator col2 = new TestCollator();
825         if (col1.equals(col2)) {
826             errln("2 different instance of TestCollator should fail");
827         }
828         if (col1.hashCode() != col2.hashCode()) {
829             errln("Every TestCollator has the same hashcode");
830         }
831         String abc = "abc";
832         String bcd = "bcd";
833         if (col1.compare(abc, bcd) != abc.compareTo(bcd)) {
834             errln("TestCollator compare should be the same as the default " +
835                   "string comparison");
836         }
837         CollationKey key = col1.getCollationKey(abc);
838         byte temp1[] = abc.getBytes();
839         byte temp2[] = new byte[temp1.length + 1];
840         System.arraycopy(temp1, 0, temp2, 0, temp1.length);
841         temp2[temp1.length] = 0;
842         if (!java.util.Arrays.equals(key.toByteArray(), temp2)
843                 || !key.getSourceString().equals(abc)) {
844             errln("TestCollator collationkey API is returning wrong values");
845         }
846         UnicodeSet set = col1.getTailoredSet();
847         if (!set.equals(new UnicodeSet(0, 0x10FFFF))) {
848             errln("Error getting default tailored set");
849         }
850 
851         // Base class code coverage.
852         // Most of these methods are dummies;
853         // they are overridden by any subclass that supports their features.
854 
855         assertEquals("compare(strings as Object)", 0,
856                 col1.compare(new StringBuilder("abc"), new StringBuffer("abc")));
857 
858         col1.setStrength(Collator.SECONDARY);
859         assertNotEquals("getStrength()", Collator.PRIMARY, col1.getStrength());
860 
861         // setStrength2() is @internal and returns this.
862         // The base class getStrength() always returns the same value,
863         // since the base class does not have a field to store the strength.
864         assertNotEquals("setStrength2().getStrength()", Collator.PRIMARY,
865                 col1.setStrength2(Collator.IDENTICAL).getStrength());
866 
867         // (base class).setDecomposition() may or may not be implemented.
868         try {
869             col1.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
870         } catch (UnsupportedOperationException expected) {
871         }
872         assertNotEquals("getDecomposition()", -1, col1.getDecomposition());  // don't care about the value
873 
874         // (base class).setMaxVariable() may or may not be implemented.
875         try {
876             col1.setMaxVariable(Collator.ReorderCodes.CURRENCY);
877         } catch (UnsupportedOperationException expected) {
878         }
879         assertNotEquals("getMaxVariable()", -1, col1.getMaxVariable());  // don't care about the value
880 
881         // (base class).setReorderCodes() may or may not be implemented.
882         try {
883             col1.setReorderCodes(0, 1, 2);
884         } catch (UnsupportedOperationException expected) {
885         }
886         try {
887             col1.getReorderCodes();
888         } catch (UnsupportedOperationException expected) {
889         }
890 
891         assertFalse("getDisplayName()", Collator.getDisplayName(Locale.GERMAN).isEmpty());
892         assertFalse("getDisplayName()", Collator.getDisplayName(Locale.GERMAN, Locale.ITALIAN).isEmpty());
893 
894         assertNotEquals("getLocale()", ULocale.GERMAN, col1.getLocale(ULocale.ACTUAL_LOCALE));
895 
896         // Cover Collator.setLocale() which is only package-visible.
897         Object token = Collator.registerInstance(new TestCollator(), new ULocale("de-Japn-419"));
898         Collator.unregister(token);
899 
900         // Freezable default implementations. freeze() may or may not be implemented.
901         assertFalse("not yet frozen", col2.isFrozen());
902         try {
903             col2.freeze();
904             assertTrue("now frozen", col2.isFrozen());
905         } catch (UnsupportedOperationException expected) {
906         }
907         try {
908             col2.setStrength(Collator.PRIMARY);
909             if (col2.isFrozen()) {
910                 fail("(frozen Collator).setStrength() should throw an exception");
911             }
912         } catch (UnsupportedOperationException expected) {
913         }
914         try {
915             Collator col3 = col2.cloneAsThawed();
916             assertFalse("!cloneAsThawed().isFrozen()", col3.isFrozen());
917         } catch (UnsupportedOperationException expected) {
918         }
919     }
920 
921     /**
922      * Simple test the collator setter and getters.
923      * Similar to C++ apicoll.cpp TestAttribute().
924      */
925     @Test
926     public void TestSetGet()
927     {
928         RuleBasedCollator collator = (RuleBasedCollator)Collator.getInstance();
929         int decomp = collator.getDecomposition();
930         int strength = collator.getStrength();
931         boolean alt = collator.isAlternateHandlingShifted();
932         boolean caselevel = collator.isCaseLevel();
933         boolean french = collator.isFrenchCollation();
934         boolean hquart = collator.isHiraganaQuaternary();
935         boolean lowercase = collator.isLowerCaseFirst();
936         boolean uppercase = collator.isUpperCaseFirst();
937 
938         collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
939         if (collator.getDecomposition() != Collator.CANONICAL_DECOMPOSITION) {
940             errln("Setting decomposition failed");
941         }
942         collator.setStrength(Collator.QUATERNARY);
943         if (collator.getStrength() != Collator.QUATERNARY) {
944             errln("Setting strength failed");
945         }
946         collator.setAlternateHandlingShifted(!alt);
947         if (collator.isAlternateHandlingShifted() == alt) {
948             errln("Setting alternate handling failed");
949         }
950         collator.setCaseLevel(!caselevel);
951         if (collator.isCaseLevel() == caselevel) {
952             errln("Setting case level failed");
953         }
954         collator.setFrenchCollation(!french);
955         if (collator.isFrenchCollation() == french) {
956             errln("Setting french collation failed");
957         }
958         collator.setHiraganaQuaternary(!hquart);
959         if (collator.isHiraganaQuaternary() != hquart) {
960             errln("Setting hiragana quartenary worked but should be a no-op since ICU 50");
961         }
962         collator.setLowerCaseFirst(!lowercase);
963         if (collator.isLowerCaseFirst() == lowercase) {
964             errln("Setting lower case first failed");
965         }
966         collator.setUpperCaseFirst(!uppercase);
967         if (collator.isUpperCaseFirst() == uppercase) {
968             errln("Setting upper case first failed");
969         }
970         collator.setDecompositionDefault();
971         if (collator.getDecomposition() != decomp) {
972             errln("Setting decomposition default failed");
973         }
974         collator.setStrengthDefault();
975         if (collator.getStrength() != strength) {
976             errln("Setting strength default failed");
977         }
978         collator.setAlternateHandlingDefault();
979         if (collator.isAlternateHandlingShifted() != alt) {
980             errln("Setting alternate handling default failed");
981         }
982         collator.setCaseLevelDefault();
983         if (collator.isCaseLevel() != caselevel) {
984             errln("Setting case level default failed");
985         }
986         collator.setFrenchCollationDefault();
987         if (collator.isFrenchCollation() != french) {
988             errln("Setting french handling default failed");
989         }
990         collator.setHiraganaQuaternaryDefault();
991         if (collator.isHiraganaQuaternary() != hquart) {
992             errln("Setting Hiragana Quartenary default failed");
993         }
994         collator.setCaseFirstDefault();
995         if (collator.isLowerCaseFirst() != lowercase
996             || collator.isUpperCaseFirst() != uppercase) {
997             errln("Setting case first handling default failed");
998         }
999     }
1000 
1001     @Test
1002     public void TestVariableTopSetting() {
1003         // Use the root collator, not the default collator.
1004         // This test fails with en_US_POSIX which tailors the dollar sign after 'A'.
1005         RuleBasedCollator coll = (RuleBasedCollator)Collator.getInstance(ULocale.ROOT);
1006 
1007         int oldVarTop = coll.getVariableTop();
1008 
1009         // ICU 53+: The character must be in a supported reordering group,
1010         // and the variable top is pinned to the end of that group.
1011         try {
1012             coll.setVariableTop("A");
1013             errln("setVariableTop(letter) did not detect illegal argument");
1014         } catch(IllegalArgumentException expected) {
1015         }
1016 
1017         // dollar sign (currency symbol)
1018         int newVarTop = coll.setVariableTop("$");
1019 
1020         if(newVarTop != coll.getVariableTop()) {
1021             errln("setVariableTop(dollar sign) != following getVariableTop()");
1022         }
1023 
1024         String dollar = "$";
1025         String euro = "\u20AC";
1026         int newVarTop2 = coll.setVariableTop(euro);
1027         assertEquals("setVariableTop(Euro sign) == following getVariableTop()",
1028                      newVarTop2, coll.getVariableTop());
1029         assertEquals("setVariableTop(Euro sign) == setVariableTop(dollar sign) (should pin to top of currency group)",
1030                      newVarTop2, newVarTop);
1031 
1032         coll.setAlternateHandlingShifted(true);
1033         assertEquals("empty==dollar", 0, coll.compare("", dollar));  // UCOL_EQUAL
1034         assertEquals("empty==euro", 0, coll.compare("", euro));  // UCOL_EQUAL
1035         assertEquals("dollar<zero", -1, coll.compare(dollar, "0"));  // UCOL_LESS
1036 
1037         coll.setVariableTop(oldVarTop);
1038 
1039         int newerVarTop = coll.setVariableTop("$");
1040 
1041         if(newVarTop != newerVarTop) {
1042           errln("Didn't set vartop properly from String!\n");
1043         }
1044     }
1045 
1046     @Test
1047     public void TestMaxVariable() {
1048         RuleBasedCollator coll = (RuleBasedCollator)Collator.getInstance(ULocale.ROOT);
1049 
1050         try {
1051             coll.setMaxVariable(Collator.ReorderCodes.OTHERS);
1052             errln("setMaxVariable(others) did not detect illegal argument");
1053         } catch(IllegalArgumentException expected) {
1054         }
1055 
1056         coll.setMaxVariable(Collator.ReorderCodes.CURRENCY);
1057 
1058         if(Collator.ReorderCodes.CURRENCY != coll.getMaxVariable()) {
1059           errln("setMaxVariable(currency) != following getMaxVariable()");
1060         }
1061 
1062         coll.setAlternateHandlingShifted(true);
1063         assertEquals("empty==dollar", 0, coll.compare("", "$"));  // UCOL_EQUAL
1064         assertEquals("empty==euro", 0, coll.compare("", "\u20AC"));  // UCOL_EQUAL
1065         assertEquals("dollar<zero", -1, coll.compare("$", "0"));  // UCOL_LESS
1066     }
1067 
1068     @Test
1069     public void TestGetLocale() {
1070         String rules = "&a<x<y<z";
1071 
1072         Collator coll = Collator.getInstance(new ULocale("root"));
1073         ULocale locale = coll.getLocale(ULocale.ACTUAL_LOCALE);
1074         if(!locale.equals(ULocale.ROOT)) {
1075           errln("Collator.getInstance(\"root\").getLocale(actual) != ULocale.ROOT; " +
1076                 "getLocale().getName() = \"" + locale.getName() + "\"");
1077         }
1078 
1079         coll = Collator.getInstance(new ULocale(""));
1080         locale = coll.getLocale(ULocale.ACTUAL_LOCALE);
1081         if(!locale.equals(ULocale.ROOT)) {
1082             errln("Collator.getInstance(\"\").getLocale(actual) != ULocale.ROOT; " +
1083                   "getLocale().getName() = \"" + locale.getName() + "\"");
1084         }
1085 
1086         int i = 0;
1087 
1088         String[][] testStruct = {
1089           // requestedLocale, validLocale, actualLocale
1090           // Note: ULocale.ROOT.getName() == "" not "root".
1091           { "de_DE", "de", "" },
1092           { "sr_RS", "sr_Cyrl_RS", "sr" },
1093           { "en_US_CALIFORNIA", "en_US", "" },
1094           { "fr_FR_NONEXISTANT", "fr", "" },
1095           // pinyin is the default, therefore suppressed.
1096           { "zh_CN", "zh_Hans_CN", "zh" },
1097           // zh_Hant has default=stroke but the data is in zh.
1098           { "zh_TW", "zh_Hant_TW", "zh@collation=stroke" },
1099           { "zh_TW@collation=pinyin", "zh_Hant_TW@collation=pinyin", "zh" },
1100           { "zh_CN@collation=stroke", "zh_Hans_CN@collation=stroke", "zh@collation=stroke" },
1101           // yue/yue_Hant aliased to zh_Hant, yue_Hans aliased to zh_Hans.
1102           { "yue", "zh_Hant", "zh@collation=stroke" },
1103           { "yue_HK", "zh_Hant", "zh@collation=stroke" },
1104           { "yue_Hant", "zh_Hant", "zh@collation=stroke" },
1105           { "yue_Hant_HK", "zh_Hant", "zh@collation=stroke" },
1106           { "yue@collation=pinyin", "zh_Hant@collation=pinyin", "zh" },
1107           { "yue_HK@collation=pinyin", "zh_Hant@collation=pinyin", "zh" },
1108           { "yue_CN", "zh_Hans", "zh" },
1109           { "yue_Hans", "zh_Hans", "zh" },
1110           { "yue_Hans_CN", "zh_Hans", "zh" },
1111           { "yue_Hans@collation=stroke", "zh_Hans@collation=stroke", "zh@collation=stroke" },
1112           { "yue_CN@collation=stroke", "zh_Hans@collation=stroke", "zh@collation=stroke" }
1113         };
1114 
1115         /* test opening collators for different locales */
1116         for(i = 0; i<testStruct.length; i++) {
1117             String requestedLocale = testStruct[i][0];
1118             String validLocale = testStruct[i][1];
1119             String actualLocale = testStruct[i][2];
1120             try {
1121                 coll = Collator.getInstance(new ULocale(requestedLocale));
1122             } catch(Exception e) {
1123                 errln(String.format("Failed to open collator for %s with %s", requestedLocale, e));
1124                 continue;
1125             }
1126             // Note: C++ getLocale() recognizes ULOC_REQUESTED_LOCALE
1127             // which does not exist in Java.
1128             locale = coll.getLocale(ULocale.VALID_LOCALE);
1129             if(!locale.equals(new ULocale(validLocale))) {
1130               errln(String.format("[Coll %s]: Error in valid locale, expected %s, got %s",
1131                     requestedLocale, validLocale, locale.getName()));
1132             }
1133             locale = coll.getLocale(ULocale.ACTUAL_LOCALE);
1134             if(!locale.equals(new ULocale(actualLocale))) {
1135               errln(String.format("[Coll %s]: Error in actual locale, expected %s, got %s",
1136                     requestedLocale, actualLocale, locale.getName()));
1137             }
1138             // If we open a collator for the actual locale, we should get an equivalent one again.
1139             Collator coll2;
1140             try {
1141                 coll2 = Collator.getInstance(locale);
1142             } catch(Exception e) {
1143                 errln(String.format("Failed to open collator for actual locale \"%s\" with %s",
1144                         locale.getName(), e));
1145                 continue;
1146             }
1147             ULocale actual2 = coll2.getLocale(ULocale.ACTUAL_LOCALE);
1148             if(!actual2.equals(locale)) {
1149               errln(String.format("[Coll actual \"%s\"]: Error in actual locale, got different one: \"%s\"",
1150                     locale.getName(), actual2.getName()));
1151             }
1152             if(!coll2.equals(coll)) {
1153               errln(String.format("[Coll actual \"%s\"]: Got different collator than before",
1154                       locale.getName()));
1155             }
1156         }
1157 
1158         /* completely non-existent locale for collator should get a root collator */
1159         {
1160             try {
1161                 coll = Collator.getInstance(new ULocale("blahaha"));
1162             } catch(Exception e) {
1163                 errln("Failed to open collator with " + e);
1164                 return;
1165             }
1166             ULocale valid = coll.getLocale(ULocale.VALID_LOCALE);
1167             String name = valid.getName();
1168             if(name.length() != 0 && !name.equals("root")) {
1169                 errln("Valid locale for nonexisting locale collator is \"" + name + "\" not root");
1170             }
1171             ULocale actual = coll.getLocale(ULocale.ACTUAL_LOCALE);
1172             name = actual.getName();
1173             if(name.length() != 0 && !name.equals("root")) {
1174                 errln("Actual locale for nonexisting locale collator is \"" + name + "\" not root");
1175             }
1176         }
1177 
1178         /* collator instantiated from rules should have all locales null */
1179         try {
1180             coll = new RuleBasedCollator(rules);
1181         } catch (Exception e) {
1182             errln("RuleBasedCollator(" + rules + ") failed: " + e);
1183             return;
1184         }
1185         locale = coll.getLocale(ULocale.VALID_LOCALE);
1186         if(locale != null) {
1187             errln(String.format("For collator instantiated from rules, valid locale %s is not bogus",
1188                     locale.getName()));
1189         }
1190         locale = coll.getLocale(ULocale.ACTUAL_LOCALE);
1191         if(locale != null) {
1192             errln(String.format("For collator instantiated from rules, actual locale %s is not bogus",
1193                     locale.getName()));
1194         }
1195     }
1196 
1197     @Test
1198     public void TestBounds()
1199     {
1200         Collator coll = Collator.getInstance(new Locale("sh", ""));
1201 
1202         String test[] = { "John Smith", "JOHN SMITH",
1203                           "john SMITH", "j\u00F6hn sm\u00EFth",
1204                           "J\u00F6hn Sm\u00EFth", "J\u00D6HN SM\u00CFTH",
1205                           "john smithsonian", "John Smithsonian",
1206         };
1207 
1208         String testStr[] = {
1209                           "\u010CAKI MIHALJ",
1210                           "\u010CAKI MIHALJ",
1211                           "\u010CAKI PIRO\u0160KA",
1212                           "\u010CABAI ANDRIJA",
1213                           "\u010CABAI LAJO\u0160",
1214                           "\u010CABAI MARIJA",
1215                           "\u010CABAI STEVAN",
1216                           "\u010CABAI STEVAN",
1217                           "\u010CABARKAPA BRANKO",
1218                           "\u010CABARKAPA MILENKO",
1219                           "\u010CABARKAPA MIROSLAV",
1220                           "\u010CABARKAPA SIMO",
1221                           "\u010CABARKAPA STANKO",
1222                           "\u010CABARKAPA TAMARA",
1223                           "\u010CABARKAPA TOMA\u0160",
1224                           "\u010CABDARI\u0106 NIKOLA",
1225                           "\u010CABDARI\u0106 ZORICA",
1226                           "\u010CABI NANDOR",
1227                           "\u010CABOVI\u0106 MILAN",
1228                           "\u010CABRADI AGNEZIJA",
1229                           "\u010CABRADI IVAN",
1230                           "\u010CABRADI JELENA",
1231                           "\u010CABRADI LJUBICA",
1232                           "\u010CABRADI STEVAN",
1233                           "\u010CABRDA MARTIN",
1234                           "\u010CABRILO BOGDAN",
1235                           "\u010CABRILO BRANISLAV",
1236                           "\u010CABRILO LAZAR",
1237                           "\u010CABRILO LJUBICA",
1238                           "\u010CABRILO SPASOJA",
1239                           "\u010CADE\u0160 ZDENKA",
1240                           "\u010CADESKI BLAGOJE",
1241                           "\u010CADOVSKI VLADIMIR",
1242                           "\u010CAGLJEVI\u0106 TOMA",
1243                           "\u010CAGOROVI\u0106 VLADIMIR",
1244                           "\u010CAJA VANKA",
1245                           "\u010CAJI\u0106 BOGOLJUB",
1246                           "\u010CAJI\u0106 BORISLAV",
1247                           "\u010CAJI\u0106 RADOSLAV",
1248                           "\u010CAK\u0160IRAN MILADIN",
1249                           "\u010CAKAN EUGEN",
1250                           "\u010CAKAN EVGENIJE",
1251                           "\u010CAKAN IVAN",
1252                           "\u010CAKAN JULIJAN",
1253                           "\u010CAKAN MIHAJLO",
1254                           "\u010CAKAN STEVAN",
1255                           "\u010CAKAN VLADIMIR",
1256                           "\u010CAKAN VLADIMIR",
1257                           "\u010CAKAN VLADIMIR",
1258                           "\u010CAKARA ANA",
1259                           "\u010CAKAREVI\u0106 MOMIR",
1260                           "\u010CAKAREVI\u0106 NEDELJKO",
1261                           "\u010CAKI \u0160ANDOR",
1262                           "\u010CAKI AMALIJA",
1263                           "\u010CAKI ANDRA\u0160",
1264                           "\u010CAKI LADISLAV",
1265                           "\u010CAKI LAJO\u0160",
1266                           "\u010CAKI LASLO" };
1267 
1268         CollationKey testKey[] = new CollationKey[testStr.length];
1269         for (int i = 0; i < testStr.length; i ++) {
1270             testKey[i] = coll.getCollationKey(testStr[i]);
1271         }
1272 
1273         Arrays.sort(testKey);
1274         for(int i = 0; i < testKey.length - 1; i ++) {
1275             CollationKey lower
1276                            = testKey[i].getBound(CollationKey.BoundMode.LOWER,
1277                                                  Collator.SECONDARY);
1278             for (int j = i + 1; j < testKey.length; j ++) {
1279                 CollationKey upper
1280                            = testKey[j].getBound(CollationKey.BoundMode.UPPER,
1281                                                  Collator.SECONDARY);
1282                 for (int k = i; k <= j; k ++) {
1283                     if (lower.compareTo(testKey[k]) > 0) {
1284                         errln("Problem with lower bound at i = " + i + " j = "
1285                               + j + " k = " + k);
1286                     }
1287                     if (upper.compareTo(testKey[k]) <= 0) {
1288                         errln("Problem with upper bound at i = " + i + " j = "
1289                               + j + " k = " + k);
1290                     }
1291                 }
1292             }
1293         }
1294 
1295         for (int i = 0; i < test.length; i ++)
1296         {
1297             CollationKey key = coll.getCollationKey(test[i]);
1298             CollationKey lower = key.getBound(CollationKey.BoundMode.LOWER,
1299                                               Collator.SECONDARY);
1300             CollationKey upper = key.getBound(CollationKey.BoundMode.UPPER_LONG,
1301                                               Collator.SECONDARY);
1302             for (int j = i + 1; j < test.length; j ++) {
1303                 key = coll.getCollationKey(test[j]);
1304                 if (lower.compareTo(key) > 0) {
1305                     errln("Problem with lower bound i = " + i + " j = " + j);
1306                 }
1307                 if (upper.compareTo(key) <= 0) {
1308                     errln("Problem with upper bound i = " + i + " j = " + j);
1309                 }
1310             }
1311         }
1312     }
1313 
1314     @Test
1315     public final void TestGetAll() {
1316         Locale[] list = Collator.getAvailableLocales();
1317         int errorCount = 0;
1318         for (int i = 0; i < list.length; ++i) {
1319             log("Locale name: ");
1320             log(list[i].toString());
1321             log(" , the display name is : ");
1322             logln(list[i].getDisplayName());
1323             try{
1324                 logln("     ...... Or display as: " + Collator.getDisplayName(list[i]));
1325                 logln("     ...... and display in Chinese: " +
1326                       Collator.getDisplayName(list[i],Locale.CHINA));
1327             }catch(MissingResourceException ex){
1328                 errorCount++;
1329                 logln("could not get displayName for " + list[i]);
1330             }
1331         }
1332         if(errorCount>0){
1333           warnln("Could not load the locale data.");
1334         }
1335     }
1336 
1337     private boolean
1338     doSetsTest(UnicodeSet ref, UnicodeSet set, String inSet, String outSet) {
1339         boolean ok = true;
1340         set.clear();
1341         set.applyPattern(inSet);
1342 
1343         if(!ref.containsAll(set)) {
1344             err("Some stuff from "+inSet+" is not present in the set.\nMissing:"+
1345                 set.removeAll(ref).toPattern(true)+"\n");
1346             ok = false;
1347         }
1348 
1349         set.clear();
1350         set.applyPattern(outSet);
1351         if(!ref.containsNone(set)) {
1352             err("Some stuff from "+outSet+" is present in the set.\nUnexpected:"+
1353                 set.retainAll(ref).toPattern(true)+"\n");
1354             ok = false;
1355         }
1356         return ok;
1357     }
1358 
1359     // capitst.c/TestGetContractionsAndUnsafes()
1360     @Test
1361     public void TestGetContractions() throws Exception {
1362         /*        static struct {
1363          const char* locale;
1364          const char* inConts;
1365          const char* outConts;
1366          const char* inExp;
1367          const char* outExp;
1368          const char* unsafeCodeUnits;
1369          const char* safeCodeUnits;
1370          }
1371          */
1372         String tests[][] = {
1373                 { "ru",
1374                     "[{\u0418\u0306}{\u0438\u0306}]",
1375                     "[\u0439\u0457]",
1376                     "[\u00e6]",
1377                     "[ae]",
1378                     "[\u0418\u0438]",
1379                     "[aAbBxv]"
1380                 },
1381                 { "uk",
1382                     "[{\u0406\u0308}{\u0456\u0308}{\u0418\u0306}{\u0438\u0306}]",
1383                     "[\u0407\u0419\u0439\u0457]",
1384                     "[\u00e6]",
1385                     "[ae]",
1386                     "[\u0406\u0456\u0418\u0438]",
1387                     "[aAbBxv]"
1388                 },
1389                 { "sh",
1390                     "[{C\u0301}{C\u030C}{C\u0341}{DZ\u030C}{Dz\u030C}{D\u017D}{D\u017E}{lj}{nj}]",
1391                     "[{\u309d\u3099}{\u30fd\u3099}]",
1392                     "[\u00e6]",
1393                     "[a]",
1394                     "[nlcdzNLCDZ]",
1395                     "[jabv]"
1396                 },
1397                 { "ja",
1398                     /*
1399                      * The "collv2" builder omits mappings if the collator maps their
1400                      * character sequences to the same CEs.
1401                      * For example, it omits Japanese contractions for NFD forms
1402                      * of the voiced iteration mark (U+309E = U+309D + U+3099), such as
1403                      * {\u3053\u3099\u309D\u3099}{\u3053\u309D\u3099}
1404                      * {\u30B3\u3099\u30FD\u3099}{\u30B3\u30FD\u3099}.
1405                      * It does add mappings for the precomposed forms.
1406                      */
1407                     "[{\u3053\u3099\u309D}{\u3053\u3099\u309E}{\u3053\u3099\u30FC}" +
1408                      "{\u3053\u309D}{\u3053\u309E}{\u3053\u30FC}" +
1409                      "{\u30B3\u3099\u30FC}{\u30B3\u3099\u30FD}{\u30B3\u3099\u30FE}" +
1410                      "{\u30B3\u30FC}{\u30B3\u30FD}{\u30B3\u30FE}]",
1411                     "[{\u30FD\u3099}{\u309D\u3099}{\u3053\u3099}{\u30B3\u3099}{lj}{nj}]",
1412                     "[\u30FE\u00e6]",
1413                     "[a]",
1414                     "[\u3099]",
1415                     "[]"
1416                 }
1417         };
1418 
1419         RuleBasedCollator coll = null;
1420         int i = 0;
1421         UnicodeSet conts = new UnicodeSet();
1422         UnicodeSet exp = new UnicodeSet();
1423         UnicodeSet set = new UnicodeSet();
1424 
1425         for(i = 0; i < tests.length; i++) {
1426             logln("Testing locale: "+ tests[i][0]);
1427             coll = (RuleBasedCollator)Collator.getInstance(new ULocale(tests[i][0]));
1428             coll.getContractionsAndExpansions(conts, exp, true);
1429             boolean ok = true;
1430             logln("Contractions "+conts.size()+":\n"+conts.toPattern(true));
1431             ok &= doSetsTest(conts, set, tests[i][1], tests[i][2]);
1432             logln("Expansions "+exp.size()+":\n"+exp.toPattern(true));
1433             ok &= doSetsTest(exp, set, tests[i][3], tests[i][4]);
1434             if(!ok) {
1435                 // In case of failure, log the rule string for better diagnostics.
1436                 String rules = coll.getRules(false);
1437                 logln("Collation rules (getLocale()="+
1438                         coll.getLocale(ULocale.ACTUAL_LOCALE).toString()+"): "+
1439                         Utility.escape(rules));
1440             }
1441 
1442             // No unsafe set in ICU4J
1443             //noConts = ucol_getUnsafeSet(coll, conts, &status);
1444             //doSetsTest(conts, set, tests[i][5], tests[i][6]);
1445             //log_verbose("Unsafes "+conts.size()+":\n"+conts.toPattern(true)+"\n");
1446         }
1447     }
1448     private static final String bigone = "One";
1449     private static final String littleone = "one";
1450 
1451     @Test
1452     public void TestClone() {
1453         logln("\ninit c0");
1454         RuleBasedCollator c0 = (RuleBasedCollator)Collator.getInstance();
1455         c0.setStrength(Collator.TERTIARY);
1456         dump("c0", c0);
1457 
1458         logln("\ninit c1");
1459         RuleBasedCollator c1 = (RuleBasedCollator)Collator.getInstance();
1460         c1.setStrength(Collator.TERTIARY);
1461         c1.setUpperCaseFirst(!c1.isUpperCaseFirst());
1462         dump("c0", c0);
1463         dump("c1", c1);
1464         try{
1465             logln("\ninit c2");
1466             RuleBasedCollator c2 = (RuleBasedCollator)c1.clone();
1467             c2.setUpperCaseFirst(!c2.isUpperCaseFirst());
1468             dump("c0", c0);
1469             dump("c1", c1);
1470             dump("c2", c2);
1471             if(c1.equals(c2)){
1472                 errln("The cloned objects refer to same data");
1473             }
1474         }catch(CloneNotSupportedException ex){
1475             errln("Could not clone the collator");
1476         }
1477     }
1478 
1479     private void dump(String msg, RuleBasedCollator c) {
1480         logln(msg + " " + c.compare(bigone, littleone) +
1481                            " s: " + c.getStrength() +
1482                            " u: " + c.isUpperCaseFirst());
1483     }
1484 
1485     @Test
1486     public void TestIterNumeric() throws Exception {  // misnomer for Java, but parallel with C++ test
1487         // Regression test for ticket #9915.
1488         // The collation code sometimes masked the continuation marker away
1489         // but later tested the result for isContinuation().
1490         // This test case failed because the third bytes of the computed numeric-collation primaries
1491         // were permutated with the script reordering table.
1492         // It should have been possible to reproduce this with the root collator
1493         // and characters with appropriate 3-byte primary weights.
1494         // The effectiveness of this test depends completely on the collation elements
1495         // and on the implementation code.
1496         RuleBasedCollator coll = new RuleBasedCollator("[reorder Hang Hani]");
1497         coll.setNumericCollation(true);
1498         int result = coll.compare("40", "72");
1499         assertTrue("40<72", result < 0);
1500     }
1501 
1502     /*
1503      * Tests the method public void setStrength(int newStrength)
1504      */
1505     @Test
1506     public void TestSetStrength() {
1507         // Tests when if ((newStrength != PRIMARY) && ... ) is true
1508         int[] cases = { -1, 4, 5 };
1509         for (int i = 0; i < cases.length; i++) {
1510             try {
1511                 // Assuming -1 is not one of the values
1512                 Collator c = Collator.getInstance();
1513                 c.setStrength(cases[i]);
1514                 errln("Collator.setStrength(int) is suppose to return "
1515                         + "an exception for an invalid newStrength value of " + cases[i]);
1516             } catch (Exception e) {
1517             }
1518         }
1519     }
1520 
1521     /*
1522      * Tests the method public void setDecomposition(int decomposition)
1523      */
1524     @Test
1525     public void TestSetDecomposition() {
1526         // Tests when if ((decomposition != NO_DECOMPOSITION) && ...) is true
1527         int[] cases = { 0, 1, 14, 15, 18, 19 };
1528         for (int i = 0; i < cases.length; i++) {
1529             try {
1530                 // Assuming -1 is not one of the values
1531                 Collator c = Collator.getInstance();
1532                 c.setDecomposition(cases[i]);
1533                 errln("Collator.setDecomposition(int) is suppose to return "
1534                         + "an exception for an invalid decomposition value of " + cases[i]);
1535             } catch (Exception e) {
1536             }
1537         }
1538     }
1539 
1540     /*
1541      * Tests the class CollatorFactory
1542      */
1543     @Test
1544     public void TestCreateCollator() {
1545         // The following class override public Collator createCollator(Locale loc)
1546         class TestCreateCollator extends CollatorFactory {
1547             @Override
1548             public Set<String> getSupportedLocaleIDs() {
1549                 return new HashSet<String>();
1550             }
1551 
1552             public TestCreateCollator() {
1553                 super();
1554             }
1555 
1556             @Override
1557             public Collator createCollator(ULocale c) {
1558                 return null;
1559             }
1560         }
1561         // The following class override public Collator createCollator(ULocale loc)
1562         class TestCreateCollator1 extends CollatorFactory {
1563             @Override
1564             public Set<String> getSupportedLocaleIDs() {
1565                 return new HashSet<String>();
1566             }
1567 
1568             public TestCreateCollator1() {
1569                 super();
1570             }
1571 
1572             @Override
1573             public Collator createCollator(Locale c) {
1574                 return null;
1575             }
1576             @Override
1577             public boolean visible(){
1578                 return false;
1579             }
1580         }
1581 
1582         /*
1583          * Tests the method public Collator createCollator(Locale loc) using TestCreateCollator1 class
1584          */
1585         try {
1586             TestCreateCollator tcc = new TestCreateCollator();
1587             tcc.createCollator(new Locale("en", "US"));
1588         } catch (Exception e) {
1589             errln("Collator.createCollator(Locale) was not suppose to " + "return an exception.");
1590         }
1591 
1592         /*
1593          * Tests the method public Collator createCollator(ULocale loc) using TestCreateCollator1 class
1594          */
1595         try {
1596             TestCreateCollator1 tcc = new TestCreateCollator1();
1597             tcc.createCollator(new ULocale("en_US"));
1598         } catch (Exception e) {
1599             errln("Collator.createCollator(ULocale) was not suppose to " + "return an exception.");
1600         }
1601 
1602         /*
1603          * Tests the method public String getDisplayName(Locale objectLocale, Locale displayLocale) using TestCreateCollator1 class
1604          */
1605         try {
1606             TestCreateCollator tcc = new TestCreateCollator();
1607             tcc.getDisplayName(new Locale("en", "US"), new Locale("jp", "JP"));
1608         } catch (Exception e) {
1609             errln("Collator.getDisplayName(Locale,Locale) was not suppose to return an exception.");
1610         }
1611 
1612         /*
1613          * Tests the method public String getDisplayName(ULocale objectLocale, ULocale displayLocale) using TestCreateCollator1 class
1614          */
1615         try {
1616             TestCreateCollator1 tcc = new TestCreateCollator1();
1617             tcc.getDisplayName(new ULocale("en_US"), new ULocale("jp_JP"));
1618         } catch (Exception e) {
1619             errln("Collator.getDisplayName(ULocale,ULocale) was not suppose to return an exception.");
1620         }
1621     }
1622     /* Tests the method
1623      * public static final String[] getKeywordValues(String keyword)
1624      */
1625     @SuppressWarnings("static-access")
1626     @Test
1627     public void TestGetKeywordValues(){
1628         // Tests when "if (!keyword.equals(KEYWORDS[0]))" is true
1629         String[] cases = {"","dummy"};
1630         for(int i=0; i<cases.length; i++){
1631             try{
1632                 Collator c = Collator.getInstance();
1633                 @SuppressWarnings("unused")
1634                 String[] s = c.getKeywordValues(cases[i]);
1635                 errln("Collator.getKeywordValues(String) is suppose to return " +
1636                         "an exception for an invalid keyword.");
1637             } catch(Exception e){}
1638         }
1639     }
1640 
1641     @Test
1642     public void TestBadKeywords() {
1643         // Test locale IDs with errors.
1644         // Valid locale IDs are tested via data-driven tests.
1645         // Note: ICU4C tests with a bogus Locale. There is no such thing in ICU4J.
1646 
1647         // Unknown value.
1648         String localeID = "it-u-ks-xyz";
1649         try {
1650             Collator.getInstance(new ULocale(localeID));
1651             errln("Collator.getInstance(" + localeID + ") did not fail as expected");
1652         } catch(IllegalArgumentException expected) {
1653         } catch(Exception other) {
1654             errln("Collator.getInstance(" + localeID + ") did not fail as expected - " + other);
1655         }
1656 
1657         // Unsupported attributes.
1658         localeID = "it@colHiraganaQuaternary=true";
1659         try {
1660             Collator.getInstance(new ULocale(localeID));
1661             errln("Collator.getInstance(" + localeID + ") did not fail as expected");
1662         } catch(UnsupportedOperationException expected) {
1663         } catch(Exception other) {
1664             errln("Collator.getInstance(" + localeID + ") did not fail as expected - " + other);
1665         }
1666 
1667         localeID = "it-u-vt-u24";
1668         try {
1669             Collator.getInstance(new ULocale(localeID));
1670             errln("Collator.getInstance(" + localeID + ") did not fail as expected");
1671         } catch(UnsupportedOperationException expected) {
1672         } catch(Exception other) {
1673             errln("Collator.getInstance(" + localeID + ") did not fail as expected - " + other);
1674         }
1675     }
1676 
1677     @Test
1678     public void TestGapTooSmall() {
1679         // Try to tailor >20k characters into a too-small primary gap between symbols
1680         // that have 3-byte primary weights.
1681         // In FractionalUCA.txt:
1682         // 263A; [0C BA D0, 05, 05]  # Zyyy So  [084A.0020.0002]  * WHITE SMILING FACE
1683         // 263B; [0C BA D7, 05, 05]  # Zyyy So  [084B.0020.0002]  * BLACK SMILING FACE
1684         try {
1685             new RuleBasedCollator("&☺<*\u4E00-\u9FFF");
1686             errln("no exception for primary-gap overflow");
1687         } catch (UnsupportedOperationException e) {
1688             assertTrue("exception message mentions 'gap'", e.getMessage().contains("gap"));
1689         } catch (Exception e) {
1690             errln("unexpected exception for primary-gap overflow: " + e);
1691         }
1692 
1693         // CLDR 32/ICU 60 FractionalUCA.txt makes room at the end of the symbols range
1694         // for several 2-byte primaries, or a large number of 3-byters.
1695         // The reset point is primary-before what should be
1696         // the special currency-first-primary contraction,
1697         // which is hopefully fairly stable, but not guaranteed stable.
1698         // In FractionalUCA.txt:
1699         // FDD1 20AC; [0D 70 02, 05, 05]  # CURRENCY first primary
1700         try {
1701             Collator coll = new RuleBasedCollator("&[before 1]\uFDD1€<*\u4E00-\u9FFF");
1702             assertTrue("tailored Han before currency", coll.compare("\u4E00", "$") < 0);
1703         } catch (Exception e) {
1704             errln("unexpected exception for tailoring many characters at the end of symbols: " + e);
1705         }
1706     }
1707 
1708     @Test
1709     public void TestBogusLocaleID() {
1710         try {
1711             Collator c1 = Collator.getInstance(new ULocale("en-US-u-kn-true"));
1712             Collator c2 = Collator.getInstance(new ULocale("en_US-u-kn-true"));
1713 
1714             assertTrue("Comparison using \"normal\" collator failed", c1.compare("2", "10") < 0);
1715             assertTrue("Comparison using \"bad\" collator failed", c2.compare("2", "10") < 0);
1716         } catch (Exception e) {
1717             errln("Exception creating collators: " + e);
1718         }
1719     }
1720 }
1721