]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/tests/core/src/com/ibm/icu/dev/test/lang/UnicodeSetTest.java
Clean up imports.
[Dictionary.git] / jars / icu4j-52_1 / main / tests / core / src / com / ibm / icu / dev / test / lang / UnicodeSetTest.java
1 /*
2  *******************************************************************************
3  * Copyright (C) 1996-2012, International Business Machines Corporation and
4  * others. All Rights Reserved.
5  *******************************************************************************
6  */
7 package com.ibm.icu.dev.test.lang;
8
9 import java.text.NumberFormat;
10 import java.text.ParsePosition;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.Comparator;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.LinkedHashSet;
19 import java.util.List;
20 import java.util.Set;
21 import java.util.SortedSet;
22 import java.util.TreeSet;
23
24 import com.ibm.icu.dev.test.TestFmwk;
25 import com.ibm.icu.impl.SortedSetRelation;
26 import com.ibm.icu.impl.Utility;
27 import com.ibm.icu.lang.UCharacter;
28 import com.ibm.icu.lang.UCharacterEnums.ECharacterCategory;
29 import com.ibm.icu.lang.UProperty;
30 import com.ibm.icu.lang.UScript;
31 import com.ibm.icu.text.SymbolTable;
32 import com.ibm.icu.text.UTF16;
33 import com.ibm.icu.text.UnicodeMatcher;
34 import com.ibm.icu.text.UnicodeSet;
35 import com.ibm.icu.text.UnicodeSet.ComparisonStyle;
36 import com.ibm.icu.text.UnicodeSetIterator;
37
38 /**
39  * @test
40  * @summary General test of UnicodeSet
41  */
42 public class UnicodeSetTest extends TestFmwk {
43
44     static final String NOT = "%%%%";
45
46     public static void main(String[] args) throws Exception {
47         new UnicodeSetTest().run(args);
48     }
49
50     private static final boolean isCccValue(int ccc) {
51         switch (ccc) {
52         case 0:
53         case 1:
54         case 7:
55         case 8:
56         case 9:
57         case 200:
58         case 202:
59         case 216:
60         case 218:
61         case 220:
62         case 222:
63         case 224:
64         case 226:
65         case 228:
66         case 230:
67         case 232:
68         case 233:
69         case 234:
70         case 240:
71             return true;
72         default:
73             return false;
74         }
75     }
76
77     public void TestPropertyAccess() {
78         int count = 0; 
79         // test to see that all of the names work
80         for (int propNum = UProperty.BINARY_START; propNum < UProperty.INT_LIMIT; ++propNum) {
81             count++;
82             //Skipping tests in the non-exhaustive mode to shorten the test time ticket#6475
83             if(getInclusion()<=5 && count%5!=0){
84                 continue;
85             }
86             if (propNum >= UProperty.BINARY_LIMIT && propNum < UProperty.INT_START) { // skip the gap
87                 propNum = UProperty.INT_START;
88             }
89             for (int nameChoice = UProperty.NameChoice.SHORT; nameChoice <= UProperty.NameChoice.LONG; ++nameChoice) {
90                 String propName;
91                 try {
92                     propName = UCharacter.getPropertyName(propNum, nameChoice);
93                     if (propName == null) {
94                         if (nameChoice == UProperty.NameChoice.SHORT) continue; // allow non-existent short names
95                         throw new NullPointerException();
96                     }
97                 } catch (RuntimeException e1) {
98                     errln("Can't get property name for: "
99                             + "Property (" + propNum + ")"
100                             + ", NameChoice: " + nameChoice + ", "
101                             + e1.getClass().getName());
102                     continue;
103                 }
104                 logln("Property (" + propNum + "): " + propName);
105                 for (int valueNum = UCharacter.getIntPropertyMinValue(propNum); valueNum <= UCharacter.getIntPropertyMaxValue(propNum); ++valueNum) {
106                     String valueName;
107                     try {
108                         valueName = UCharacter.getPropertyValueName(propNum, valueNum, nameChoice);
109                         if (valueName == null) {
110                             if (nameChoice == UProperty.NameChoice.SHORT) continue; // allow non-existent short names
111                             if ((propNum == UProperty.CANONICAL_COMBINING_CLASS ||
112                                     propNum == UProperty.LEAD_CANONICAL_COMBINING_CLASS ||
113                                     propNum == UProperty.TRAIL_CANONICAL_COMBINING_CLASS) &&
114                                     !isCccValue(valueNum)) {
115                                 // Only a few of the canonical combining classes have names.
116                                 // Otherwise they are just integer values.
117                                 continue;
118                             } else {
119                                 throw new NullPointerException();
120                             }
121                         }
122                     } catch (RuntimeException e1) {
123                         errln("Can't get property value name for: "
124                                 + "Property (" + propNum + "): " + propName + ", " 
125                                 + "Value (" + valueNum + ") "
126                                 + ", NameChoice: " + nameChoice + ", "
127                                 + e1.getClass().getName());
128                         continue;
129                     }
130                     logln("Value (" + valueNum + "): " + valueName);
131                     UnicodeSet testSet;
132                     try {
133                         testSet = new UnicodeSet("[:" + propName + "=" + valueName + ":]");
134                     } catch (RuntimeException e) {
135                         errln("Can't create UnicodeSet for: "
136                                 + "Property (" + propNum + "): " + propName + ", " 
137                                 + "Value (" + valueNum + "): " + valueName + ", "
138                                 + e.getClass().getName());
139                         continue;
140                     }
141                     UnicodeSet collectedErrors = new UnicodeSet();
142                     for (UnicodeSetIterator it = new UnicodeSetIterator(testSet); it.next();) {
143                         int value = UCharacter.getIntPropertyValue(it.codepoint, propNum);
144                         if (value != valueNum) {
145                             collectedErrors.add(it.codepoint);
146                         }
147                     }
148                     if (collectedErrors.size() != 0) {
149                         errln("Property Value Differs: " 
150                                 + "Property (" + propNum + "): " + propName + ", " 
151                                 + "Value (" + valueNum + "): " + valueName + ", "
152                                 + "Differing values: " + collectedErrors.toPattern(true));
153                     }
154                 }
155             } 
156         }
157     }
158
159
160     /**
161      * Test toPattern().
162      */
163     public void TestToPattern() throws Exception {
164         // Test that toPattern() round trips with syntax characters
165         // and whitespace.
166         for (int i = 0; i < OTHER_TOPATTERN_TESTS.length; ++i) {
167             checkPat(OTHER_TOPATTERN_TESTS[i], new UnicodeSet(OTHER_TOPATTERN_TESTS[i]));
168         }
169         for (int i = 0; i <= 0x10FFFF; ++i) {
170             if ((i <= 0xFF && !UCharacter.isLetter(i)) || UCharacter.isWhitespace(i)) {
171                 // check various combinations to make sure they all work.
172                 if (i != 0 && !toPatternAux(i, i)) continue;
173                 if (!toPatternAux(0, i)) continue;
174                 if (!toPatternAux(i, 0xFFFF)) continue;
175             }
176         } 
177
178         // Test pattern behavior of multicharacter strings.
179         UnicodeSet s = new UnicodeSet("[a-z {aa} {ab}]");
180         expectToPattern(s, "[a-z{aa}{ab}]",
181                 new String[] {"aa", "ab", NOT, "ac"});
182         s.add("ac");
183         expectToPattern(s, "[a-z{aa}{ab}{ac}]",
184                 new String[] {"aa", "ab", "ac", NOT, "xy"});
185
186         s.applyPattern("[a-z {\\{l} {r\\}}]");
187         expectToPattern(s, "[a-z{r\\}}{\\{l}]",
188                 new String[] {"{l", "r}", NOT, "xy"});
189         s.add("[]");
190         expectToPattern(s, "[a-z{\\[\\]}{r\\}}{\\{l}]",
191                 new String[] {"{l", "r}", "[]", NOT, "xy"});
192
193         s.applyPattern("[a-z {\u4E01\u4E02}{\\n\\r}]");
194         expectToPattern(s, "[a-z{\\u000A\\u000D}{\\u4E01\\u4E02}]",
195                 new String[] {"\u4E01\u4E02", "\n\r"});
196
197         s.clear();
198         s.add("abc");
199         s.add("abc");
200         expectToPattern(s, "[{abc}]",
201                 new String[] {"abc", NOT, "ab"});
202
203         // JB#3400: For 2 character ranges prefer [ab] to [a-b]
204         s.clear(); 
205         s.add('a', 'b');
206         expectToPattern(s, "[ab]", null);
207
208         // Cover applyPattern, applyPropertyAlias
209         s.clear();
210         s.applyPattern("[ab ]", true);
211         expectToPattern(s, "[ab]", new String[] {"a", NOT, "ab", " "});
212         s.clear();
213         s.applyPattern("[ab ]", false);
214         expectToPattern(s, "[\\ ab]", new String[] {"a", "\u0020", NOT, "ab"});
215
216         s.clear();
217         s.applyPropertyAlias("nv", "0.5");
218         expectToPattern(s, "[\\u00BD\\u0B73\\u0D74\\u0F2A\\u2CFD\\uA831\\U00010141\\U00010175\\U00010176\\U00010E7B]", null);
219         // Unicode 5.1 adds Malayalam 1/2 (\u0D74)
220         // Unicode 5.2 adds U+A831 NORTH INDIC FRACTION ONE HALF and U+10E7B RUMI FRACTION ONE HALF
221         // Unicode 6.0 adds U+0B73 ORIYA FRACTION ONE HALF
222
223         s.clear();
224         s.applyPropertyAlias("gc", "Lu");
225         // TODO expectToPattern(s, what?)
226
227         // RemoveAllStrings()
228         s.clear();
229         s.applyPattern("[a-z{abc}{def}]");
230         expectToPattern(s, "[a-z{abc}{def}]", null);
231         s.removeAllStrings();
232         expectToPattern(s, "[a-z]", null);
233     }
234
235     static String[] OTHER_TOPATTERN_TESTS = {
236         "[[:latin:]&[:greek:]]", 
237         "[[:latin:]-[:greek:]]",
238         "[:nonspacing mark:]"
239     };
240
241
242     public boolean toPatternAux(int start, int end) {
243         // use Integer.toString because Utility.hex doesn't handle ints
244         String source = "0x" + Integer.toString(start,16).toUpperCase();
245         if (start != end) source += "..0x" + Integer.toString(end,16).toUpperCase();
246         UnicodeSet testSet = new UnicodeSet();
247         testSet.add(start, end);
248         return checkPat(source, testSet);
249     }
250
251     boolean checkPat (String source, UnicodeSet testSet) {
252         String pat = "";
253         try {
254             // What we want to make sure of is that a pattern generated
255             // by toPattern(), with or without escaped unprintables, can
256             // be passed back into the UnicodeSet constructor.
257             String pat0 = testSet.toPattern(true);
258             if (!checkPat(source + " (escaped)", testSet, pat0)) return false;
259
260             //String pat1 = unescapeLeniently(pat0);
261             //if (!checkPat(source + " (in code)", testSet, pat1)) return false;
262
263             String pat2 = testSet.toPattern(false);
264             if (!checkPat(source, testSet, pat2)) return false;
265
266             //String pat3 = unescapeLeniently(pat2);
267             //if (!checkPat(source + " (in code)", testSet, pat3)) return false;
268
269             //logln(source + " => " + pat0 + ", " + pat1 + ", " + pat2 + ", " + pat3);
270             logln(source + " => " + pat0 + ", " + pat2);
271         } catch (Exception e) {
272             errln("EXCEPTION in toPattern: " + source + " => " + pat);
273             return false;
274         }
275         return true;
276     }
277
278     boolean checkPat (String source, UnicodeSet testSet, String pat) {
279         UnicodeSet testSet2 = new UnicodeSet(pat);
280         if (!testSet2.equals(testSet)) {
281             errln("Fail toPattern: " + source + "; " + pat + " => " +
282                     testSet2.toPattern(false) + ", expected " +
283                     testSet.toPattern(false));
284             return false;
285         }
286         return true;
287     }
288
289     // NOTE: copied the following from Utility. There ought to be a version in there with a flag
290     // that does the Java stuff
291
292     public static int unescapeAt(String s, int[] offset16) {
293         int c;
294         int result = 0;
295         int n = 0;
296         int minDig = 0;
297         int maxDig = 0;
298         int bitsPerDigit = 4;
299         int dig;
300         int i;
301
302         /* Check that offset is in range */
303         int offset = offset16[0];
304         int length = s.length();
305         if (offset < 0 || offset >= length) {
306             return -1;
307         }
308
309         /* Fetch first UChar after '\\' */
310         c = UTF16.charAt(s, offset);
311         offset += UTF16.getCharCount(c);
312
313         /* Convert hexadecimal and octal escapes */
314         switch (c) {
315         case 'u':
316             minDig = maxDig = 4;
317             break;
318             /*
319          case 'U':
320          minDig = maxDig = 8;
321          break;
322          case 'x':
323          minDig = 1;
324          maxDig = 2;
325          break;
326              */
327         default:
328             dig = UCharacter.digit(c, 8);
329             if (dig >= 0) {
330                 minDig = 1;
331                 maxDig = 3;
332                 n = 1; /* Already have first octal digit */
333                 bitsPerDigit = 3;
334                 result = dig;
335             }
336             break;
337         }
338         if (minDig != 0) {
339             while (offset < length && n < maxDig) {
340                 // TEMPORARY
341                 // TODO: Restore the char32-based code when UCharacter.digit
342                 // is working (Bug 66).
343
344                 //c = UTF16.charAt(s, offset);
345                 //dig = UCharacter.digit(c, (bitsPerDigit == 3) ? 8 : 16);
346                 c = s.charAt(offset);
347                 dig = Character.digit((char)c, (bitsPerDigit == 3) ? 8 : 16);
348                 if (dig < 0) {
349                     break;
350                 }
351                 result = (result << bitsPerDigit) | dig;
352                 //offset += UTF16.getCharCount(c);
353                 ++offset;
354                 ++n;
355             }
356             if (n < minDig) {
357                 return -1;
358             }
359             offset16[0] = offset;
360             return result;
361         }
362
363         /* Convert C-style escapes in table */
364         for (i=0; i<UNESCAPE_MAP.length; i+=2) {
365             if (c == UNESCAPE_MAP[i]) {
366                 offset16[0] = offset;
367                 return UNESCAPE_MAP[i+1];
368             } else if (c < UNESCAPE_MAP[i]) {
369                 break;
370             }
371         }
372
373         /* If no special forms are recognized, then consider
374          * the backslash to generically escape the next character. */
375         offset16[0] = offset;
376         return c;
377     }
378
379     /* This map must be in ASCENDING ORDER OF THE ESCAPE CODE */
380     static private final char[] UNESCAPE_MAP = {
381         /*"   0x22, 0x22 */
382         /*'   0x27, 0x27 */
383         /*?   0x3F, 0x3F */
384         /*\   0x5C, 0x5C */
385         /*a*/ 0x61, 0x07,
386         /*b*/ 0x62, 0x08,
387         /*f*/ 0x66, 0x0c,
388         /*n*/ 0x6E, 0x0a,
389         /*r*/ 0x72, 0x0d,
390         /*t*/ 0x74, 0x09,
391         /*v*/ 0x76, 0x0b
392     };
393
394     /**
395      * Convert all escapes in a given string using unescapeAt().
396      * Leave invalid escape sequences unchanged.
397      */
398     public static String unescapeLeniently(String s) {
399         StringBuffer buf = new StringBuffer();
400         int[] pos = new int[1];
401         for (int i=0; i<s.length(); ) {
402             char c = s.charAt(i++);
403             if (c == '\\') {
404                 pos[0] = i;
405                 int e = unescapeAt(s, pos);
406                 if (e < 0) {
407                     buf.append(c);
408                 } else {
409                     UTF16.append(buf, e);
410                     i = pos[0];
411                 }
412             } else {
413                 buf.append(c);
414             }
415         }
416         return buf.toString();
417     }
418
419     public void TestPatterns() {
420         UnicodeSet set = new UnicodeSet();
421         expectPattern(set, "[[a-m]&[d-z]&[k-y]]",  "km");
422         expectPattern(set, "[[a-z]-[m-y]-[d-r]]",  "aczz");
423         expectPattern(set, "[a\\-z]",  "--aazz");
424         expectPattern(set, "[-az]",  "--aazz");
425         expectPattern(set, "[az-]",  "--aazz");
426         expectPattern(set, "[[[a-z]-[aeiou]i]]", "bdfnptvz");
427
428         // Throw in a test of complement
429         set.complement();
430         String exp = '\u0000' + "aeeoouu" + (char)('z'+1) + '\uFFFF';
431         expectPairs(set, exp);
432     }
433
434     public void TestCategories() {
435         int failures = 0;
436         UnicodeSet set = new UnicodeSet("[:Lu:]");
437         expectContainment(set, "ABC", "abc");
438
439         // Make sure generation of L doesn't pollute cached Lu set
440         // First generate L, then Lu
441         // not used int TOP = 0x200; // Don't need to go over the whole range:
442         set = new UnicodeSet("[:L:]");
443         for (int i=0; i<0x200; ++i) {
444             boolean l = UCharacter.isLetter(i);
445             if (l != set.contains((char)i)) {
446                 errln("FAIL: L contains " + (char)i + " = " + 
447                         set.contains((char)i));
448                 if (++failures == 10) break;
449             }
450         }
451
452         set = new UnicodeSet("[:Lu:]");
453         for (int i=0; i<0x200; ++i) {
454             boolean lu = (UCharacter.getType(i) == ECharacterCategory.UPPERCASE_LETTER);
455             if (lu != set.contains((char)i)) {
456                 errln("FAIL: Lu contains " + (char)i + " = " + 
457                         set.contains((char)i));
458                 if (++failures == 20) break;
459             }
460         }
461     }
462
463     public void TestAddRemove() {
464         UnicodeSet set = new UnicodeSet();
465         set.add('a', 'z');
466         expectPairs(set, "az");
467         set.remove('m', 'p');
468         expectPairs(set, "alqz");
469         set.remove('e', 'g');
470         expectPairs(set, "adhlqz");
471         set.remove('d', 'i');
472         expectPairs(set, "acjlqz");
473         set.remove('c', 'r');
474         expectPairs(set, "absz");
475         set.add('f', 'q');
476         expectPairs(set, "abfqsz");
477         set.remove('a', 'g');
478         expectPairs(set, "hqsz");
479         set.remove('a', 'z');
480         expectPairs(set, "");
481
482         // Try removing an entire set from another set
483         expectPattern(set, "[c-x]", "cx");
484         UnicodeSet set2 = new UnicodeSet();
485         expectPattern(set2, "[f-ky-za-bc[vw]]", "acfkvwyz");
486         set.removeAll(set2);
487         expectPairs(set, "deluxx");
488
489         // Try adding an entire set to another set
490         expectPattern(set, "[jackiemclean]", "aacceein");
491         expectPattern(set2, "[hitoshinamekatajamesanderson]", "aadehkmort");
492         set.addAll(set2);
493         expectPairs(set, "aacehort");
494
495         // Test commutativity
496         expectPattern(set, "[hitoshinamekatajamesanderson]", "aadehkmort");
497         expectPattern(set2, "[jackiemclean]", "aacceein");
498         set.addAll(set2);
499         expectPairs(set, "aacehort");
500     }
501
502     /**
503      * Make sure minimal representation is maintained.
504      */
505     public void TestMinimalRep() {
506         // This is pretty thoroughly tested by checkCanonicalRep()
507         // run against the exhaustive operation results.  Use the code
508         // here for debugging specific spot problems.
509
510         // 1 overlap against 2
511         UnicodeSet set = new UnicodeSet("[h-km-q]");
512         UnicodeSet set2 = new UnicodeSet("[i-o]");
513         set.addAll(set2);
514         expectPairs(set, "hq");
515         // right
516         set.applyPattern("[a-m]");
517         set2.applyPattern("[e-o]");
518         set.addAll(set2);
519         expectPairs(set, "ao");
520         // left
521         set.applyPattern("[e-o]");
522         set2.applyPattern("[a-m]");
523         set.addAll(set2);
524         expectPairs(set, "ao");
525         // 1 overlap against 3
526         set.applyPattern("[a-eg-mo-w]");
527         set2.applyPattern("[d-q]");
528         set.addAll(set2);
529         expectPairs(set, "aw");
530     }
531
532     public void TestAPI() {
533         // default ct
534         UnicodeSet set = new UnicodeSet();
535         if (!set.isEmpty() || set.getRangeCount() != 0) {
536             errln("FAIL, set should be empty but isn't: " +
537                     set);
538         }
539
540         // clear(), isEmpty()
541         set.add('a');
542         if (set.isEmpty()) {
543             errln("FAIL, set shouldn't be empty but is: " +
544                     set);
545         }
546         set.clear();
547         if (!set.isEmpty()) {
548             errln("FAIL, set should be empty but isn't: " +
549                     set);
550         }
551
552         // size()
553         set.clear();
554         if (set.size() != 0) {
555             errln("FAIL, size should be 0, but is " + set.size() +
556                     ": " + set);
557         }
558         set.add('a');
559         if (set.size() != 1) {
560             errln("FAIL, size should be 1, but is " + set.size() +
561                     ": " + set);
562         }
563         set.add('1', '9');
564         if (set.size() != 10) {
565             errln("FAIL, size should be 10, but is " + set.size() +
566                     ": " + set);
567         }
568         set.clear();
569         set.complement();
570         if (set.size() != 0x110000) {
571             errln("FAIL, size should be 0x110000, but is" + set.size());
572         }
573
574         // contains(first, last)
575         set.clear();
576         set.applyPattern("[A-Y 1-8 b-d l-y]");
577         for (int i = 0; i<set.getRangeCount(); ++i) {
578             int a = set.getRangeStart(i);
579             int b = set.getRangeEnd(i);
580             if (!set.contains(a, b)) {
581                 errln("FAIL, should contain " + (char)a + '-' + (char)b +
582                         " but doesn't: " + set);
583             }
584             if (set.contains((char)(a-1), b)) {
585                 errln("FAIL, shouldn't contain " +
586                         (char)(a-1) + '-' + (char)b +
587                         " but does: " + set);
588             }
589             if (set.contains(a, (char)(b+1))) {
590                 errln("FAIL, shouldn't contain " +
591                         (char)a + '-' + (char)(b+1) +
592                         " but does: " + set);
593             }
594         }
595
596         // Ported InversionList test.
597         UnicodeSet a = new UnicodeSet((char)3,(char)10);
598         UnicodeSet b = new UnicodeSet((char)7,(char)15);
599         UnicodeSet c = new UnicodeSet();
600
601         logln("a [3-10]: " + a);
602         logln("b [7-15]: " + b);
603         c.set(a); c.addAll(b);
604         UnicodeSet exp = new UnicodeSet((char)3,(char)15);
605         if (c.equals(exp)) {
606             logln("c.set(a).add(b): " + c);
607         } else {
608             errln("FAIL: c.set(a).add(b) = " + c + ", expect " + exp);
609         }
610         c.complement();
611         exp.set((char)0, (char)2);
612         exp.add((char)16, UnicodeSet.MAX_VALUE);
613         if (c.equals(exp)) {
614             logln("c.complement(): " + c);
615         } else {
616             errln(Utility.escape("FAIL: c.complement() = " + c + ", expect " + exp));
617         }
618         c.complement();
619         exp.set((char)3, (char)15);
620         if (c.equals(exp)) {
621             logln("c.complement(): " + c);
622         } else {
623             errln("FAIL: c.complement() = " + c + ", expect " + exp);
624         }
625         c.set(a); c.complementAll(b);
626         exp.set((char)3,(char)6);
627         exp.add((char)11,(char) 15);
628         if (c.equals(exp)) {
629             logln("c.set(a).complement(b): " + c);
630         } else {
631             errln("FAIL: c.set(a).complement(b) = " + c + ", expect " + exp);
632         }
633
634         exp.set(c);
635         c = bitsToSet(setToBits(c));
636         if (c.equals(exp)) {
637             logln("bitsToSet(setToBits(c)): " + c);
638         } else {
639             errln("FAIL: bitsToSet(setToBits(c)) = " + c + ", expect " + exp);
640         } 
641
642         // Additional tests for coverage JB#2118
643         //UnicodeSet::complement(class UnicodeString const &)
644         //UnicodeSet::complementAll(class UnicodeString const &)
645         //UnicodeSet::containsNone(class UnicodeSet const &)
646         //UnicodeSet::containsNone(long,long)
647         //UnicodeSet::containsSome(class UnicodeSet const &)
648         //UnicodeSet::containsSome(long,long)
649         //UnicodeSet::removeAll(class UnicodeString const &)
650         //UnicodeSet::retain(long)
651         //UnicodeSet::retainAll(class UnicodeString const &)
652         //UnicodeSet::serialize(unsigned short *,long,enum UErrorCode &)
653         //UnicodeSetIterator::getString(void)
654         set.clear();
655         set.complement("ab");
656         exp.applyPattern("[{ab}]");
657         if (!set.equals(exp)) { errln("FAIL: complement(\"ab\")"); return; }
658
659         UnicodeSetIterator iset = new UnicodeSetIterator(set);
660         if (!iset.next() || iset.codepoint != UnicodeSetIterator.IS_STRING) {
661             errln("FAIL: UnicodeSetIterator.next/IS_STRING");
662         } else if (!iset.string.equals("ab")) {
663             errln("FAIL: UnicodeSetIterator.string");
664         }
665
666         set.add((char)0x61, (char)0x7A);
667         set.complementAll("alan");
668         exp.applyPattern("[{ab}b-kmo-z]");
669         if (!set.equals(exp)) { errln("FAIL: complementAll(\"alan\")"); return; }
670
671         exp.applyPattern("[a-z]");
672         if (set.containsNone(exp)) { errln("FAIL: containsNone(UnicodeSet)"); }
673         if (!set.containsSome(exp)) { errln("FAIL: containsSome(UnicodeSet)"); }
674         exp.applyPattern("[aln]");
675         if (!set.containsNone(exp)) { errln("FAIL: containsNone(UnicodeSet)"); }
676         if (set.containsSome(exp)) { errln("FAIL: containsSome(UnicodeSet)"); }
677
678         if (set.containsNone((char)0x61, (char)0x7A)) {
679             errln("FAIL: containsNone(char, char)");
680         }
681         if (!set.containsSome((char)0x61, (char)0x7A)) {
682             errln("FAIL: containsSome(char, char)");
683         }
684         if (!set.containsNone((char)0x41, (char)0x5A)) {
685             errln("FAIL: containsNone(char, char)");
686         }
687         if (set.containsSome((char)0x41, (char)0x5A)) {
688             errln("FAIL: containsSome(char, char)");
689         }
690
691         set.removeAll("liu");
692         exp.applyPattern("[{ab}b-hj-kmo-tv-z]");
693         if (!set.equals(exp)) { errln("FAIL: removeAll(\"liu\")"); return; }
694
695         set.retainAll("star");
696         exp.applyPattern("[rst]");
697         if (!set.equals(exp)) { errln("FAIL: retainAll(\"star\")"); return; }
698
699         set.retain((char)0x73);
700         exp.applyPattern("[s]");
701         if (!set.equals(exp)) { errln("FAIL: retain('s')"); return; }
702
703         // ICU 2.6 coverage tests
704         // public final UnicodeSet retain(String s);
705         // public final UnicodeSet remove(int c);
706         // public final UnicodeSet remove(String s);
707         // public int hashCode();
708         set.applyPattern("[a-z{ab}{cd}]");
709         set.retain("cd");
710         exp.applyPattern("[{cd}]");
711         if (!set.equals(exp)) { errln("FAIL: retain(\"cd\")"); return; }
712
713         set.applyPattern("[a-z{ab}{cd}]");
714         set.remove((char)0x63);
715         exp.applyPattern("[abd-z{ab}{cd}]");
716         if (!set.equals(exp)) { errln("FAIL: remove('c')"); return; }
717
718         set.remove("cd");
719         exp.applyPattern("[abd-z{ab}]");
720         if (!set.equals(exp)) { errln("FAIL: remove(\"cd\")"); return; }
721
722         if (set.hashCode() != exp.hashCode()) {
723             errln("FAIL: hashCode() unequal");
724         }
725         exp.clear();
726         if (set.hashCode() == exp.hashCode()) {
727             errln("FAIL: hashCode() equal");
728         }
729
730         {
731             //Cover addAll(Collection) and addAllTo(Collection)  
732             //  Seems that there is a bug in addAll(Collection) operation
733             //    Ram also add a similar test to UtilityTest.java
734             logln("Testing addAll(Collection) ... ");  
735             String[] array = {"a", "b", "c", "de"};
736             List list = Arrays.asList(array);
737             Set aset = new HashSet(list);
738             logln(" *** The source set's size is: " + aset.size());
739
740             set.clear();
741             set.addAll(aset);
742             if (set.size() != aset.size()) {
743                 errln("FAIL: After addAll, the UnicodeSet size expected " + aset.size() +
744                         ", " + set.size() + " seen instead!");
745             } else {
746                 logln("OK: After addAll, the UnicodeSet size got " + set.size());
747             }
748
749             List list2 = new ArrayList();
750             set.addAllTo(list2);
751
752             //verify the result
753             log(" *** The elements are: ");
754             String s = set.toPattern(true);
755             logln(s);
756             Iterator myiter = list2.iterator();
757             while(myiter.hasNext()) {
758                 log(myiter.next().toString() + "  ");
759             }
760             logln("");  // a new line
761         }
762
763     }
764
765     public void TestStrings() {
766         //  Object[][] testList = {
767         //  {I_EQUALS,  UnicodeSet.fromAll("abc"),
768         //  new UnicodeSet("[a-c]")},
769         //  
770         //  {I_EQUALS,  UnicodeSet.from("ch").add('a','z').add("ll"),
771         //  new UnicodeSet("[{ll}{ch}a-z]")},
772         //  
773         //  {I_EQUALS,  UnicodeSet.from("ab}c"),  
774         //  new UnicodeSet("[{ab\\}c}]")},
775         //  
776         //  {I_EQUALS,  new UnicodeSet('a','z').add('A', 'Z').retain('M','m').complement('X'), 
777         //  new UnicodeSet("[[a-zA-Z]&[M-m]-[X]]")},
778         //  };
779         //  
780         //  for (int i = 0; i < testList.length; ++i) {
781         //  expectRelation(testList[i][0], testList[i][1], testList[i][2], "(" + i + ")");
782         //  }        
783
784         UnicodeSet[][] testList = {
785                 {UnicodeSet.fromAll("abc"),
786                     new UnicodeSet("[a-c]")},
787
788                     {UnicodeSet.from("ch").add('a','z').add("ll"),
789                         new UnicodeSet("[{ll}{ch}a-z]")},
790
791                         {UnicodeSet.from("ab}c"),  
792                             new UnicodeSet("[{ab\\}c}]")},
793
794                             {new UnicodeSet('a','z').add('A', 'Z').retain('M','m').complement('X'), 
795                                 new UnicodeSet("[[a-zA-Z]&[M-m]-[X]]")},
796         };
797
798         for (int i = 0; i < testList.length; ++i) {
799             if (!testList[i][0].equals(testList[i][1])) {
800                 errln("FAIL: sets unequal; see source code (" + i + ")");
801             }
802         }        
803     }
804
805     static final Integer 
806     I_ANY = new Integer(SortedSetRelation.ANY),
807     I_CONTAINS = new Integer(SortedSetRelation.CONTAINS),
808     I_DISJOINT = new Integer(SortedSetRelation.DISJOINT),
809     I_NO_B = new Integer(SortedSetRelation.NO_B),
810     I_ISCONTAINED = new Integer(SortedSetRelation.ISCONTAINED),
811     I_EQUALS = new Integer(SortedSetRelation.EQUALS),
812     I_NO_A = new Integer(SortedSetRelation.NO_A),
813     I_NONE = new Integer(SortedSetRelation.NONE);
814
815     public void TestSetRelation() {
816
817         String[] choices = {"a", "b", "cd", "ef"};
818         int limit = 1 << choices.length;
819
820         SortedSet iset = new TreeSet();
821         SortedSet jset = new TreeSet();
822
823         for (int i = 0; i < limit; ++i) {
824             pick(i, choices, iset);
825             for (int j = 0; j < limit; ++j) {
826                 pick(j, choices, jset);
827                 checkSetRelation(iset, jset, "(" + i + ")");
828             }
829         }
830     }
831
832     public void TestSetSpeed() {
833         // skip unless verbose
834         if (!isVerbose()) return;
835
836         SetSpeed2(100);
837         SetSpeed2(1000);
838     }
839
840     public void SetSpeed2(int size) {
841
842         SortedSet iset = new TreeSet();
843         SortedSet jset = new TreeSet();
844
845         for (int i = 0; i < size*2; i += 2) { // only even values
846             iset.add(new Integer(i));
847             jset.add(new Integer(i));
848         }
849
850         int iterations = 1000000 / size;
851
852         logln("Timing comparison of Java vs Utility");
853         logln("For about " + size + " objects that are almost all the same.");
854
855         CheckSpeed(iset, jset, "when a = b", iterations);
856
857         iset.add(new Integer(size + 1));    // add odd value in middle
858
859         CheckSpeed(iset, jset, "when a contains b", iterations);        
860         CheckSpeed(jset, iset, "when b contains a", iterations);
861
862         jset.add(new Integer(size - 1));    // add different odd value in middle
863
864         CheckSpeed(jset, iset, "when a, b are disjoint", iterations);        
865     }
866
867     void CheckSpeed(SortedSet iset, SortedSet jset, String message, int iterations) {
868         CheckSpeed2(iset, jset, message, iterations);
869         CheckSpeed3(iset, jset, message, iterations);
870     }
871
872     void CheckSpeed2(SortedSet iset, SortedSet jset, String message, int iterations) {
873         boolean x;
874         boolean y;
875
876         // make sure code is loaded:
877         x = iset.containsAll(jset);
878         y = SortedSetRelation.hasRelation(iset, SortedSetRelation.CONTAINS, jset);
879         if (x != y) errln("FAIL contains comparison");
880
881         double start = System.currentTimeMillis();
882         for (int i = 0; i < iterations; ++i) {
883             x |= iset.containsAll(jset);
884         }
885         double middle = System.currentTimeMillis();
886         for (int i = 0; i < iterations; ++i) {
887             y |= SortedSetRelation.hasRelation(iset, SortedSetRelation.CONTAINS, jset);
888         }
889         double end = System.currentTimeMillis();
890
891         double jtime = (middle - start)/iterations;
892         double utime = (end - middle)/iterations;
893
894         NumberFormat nf = NumberFormat.getPercentInstance();
895         logln("Test contains: " + message + ": Java: " + jtime
896                 + ", Utility: " + utime + ", u:j: " + nf.format(utime/jtime));
897     }
898
899     void CheckSpeed3(SortedSet iset, SortedSet jset, String message, int iterations) {
900         boolean x;
901         boolean y;
902
903         // make sure code is loaded:
904         x = iset.equals(jset);
905         y = SortedSetRelation.hasRelation(iset, SortedSetRelation.EQUALS, jset);
906         if (x != y) errln("FAIL equality comparison");
907
908
909         double start = System.currentTimeMillis();
910         for (int i = 0; i < iterations; ++i) {
911             x |= iset.equals(jset);
912         }
913         double middle = System.currentTimeMillis();
914         for (int i = 0; i < iterations; ++i) {
915             y |= SortedSetRelation.hasRelation(iset, SortedSetRelation.EQUALS, jset);
916         }
917         double end = System.currentTimeMillis();
918
919         double jtime = (middle - start)/iterations;
920         double utime = (end - middle)/iterations;
921
922         NumberFormat nf = NumberFormat.getPercentInstance();
923         logln("Test equals:   " + message + ": Java: " + jtime
924                 + ", Utility: " + utime + ", u:j: " + nf.format(utime/jtime));
925     }
926
927     void pick(int bits, Object[] examples, SortedSet output) {
928         output.clear();
929         for (int k = 0; k < 32; ++k) {
930             if (((1<<k) & bits) != 0) output.add(examples[k]);
931         }
932     }
933
934     public static final String[] RELATION_NAME = {
935         "both-are-null",
936         "a-is-null", 
937         "equals", 
938         "is-contained-in",
939         "b-is-null",
940         "is-disjoint_with",
941         "contains", 
942         "any", };
943
944     boolean dumbHasRelation(Collection A, int filter, Collection B) {
945         Collection ab = new TreeSet(A);
946         ab.retainAll(B);
947         if (ab.size() > 0 && (filter & SortedSetRelation.A_AND_B) == 0) return false; 
948
949         // A - B size == A.size - A&B.size
950         if (A.size() > ab.size() && (filter & SortedSetRelation.A_NOT_B) == 0) return false; 
951
952         // B - A size == B.size - A&B.size
953         if (B.size() > ab.size() && (filter & SortedSetRelation.B_NOT_A) == 0) return false; 
954
955
956         return true;
957     }    
958
959     void checkSetRelation(SortedSet a, SortedSet b, String message) {
960         for (int i = 0; i < 8; ++i) {
961
962             boolean hasRelation = SortedSetRelation.hasRelation(a, i, b);
963             boolean dumbHasRelation = dumbHasRelation(a, i, b);
964
965             logln(message + " " + hasRelation + ":\t" + a + "\t" + RELATION_NAME[i] + "\t" + b);
966
967             if (hasRelation != dumbHasRelation) {
968                 errln("FAIL: " + 
969                         message + " " + dumbHasRelation + ":\t" + a + "\t" + RELATION_NAME[i] + "\t" + b);
970             }
971         }
972         logln("");
973     }
974
975     /**
976      * Test the [:Latin:] syntax.
977      */
978     public void TestScriptSet() {
979
980         expectContainment("[:Latin:]", "aA", CharsToUnicodeString("\\u0391\\u03B1"));
981
982         expectContainment("[:Greek:]", CharsToUnicodeString("\\u0391\\u03B1"), "aA");
983
984         /* Jitterbug 1423 */
985         expectContainment("[[:Common:][:Inherited:]]", CharsToUnicodeString("\\U00003099\\U0001D169\\u0000"), "aA");
986
987     }
988
989     /**
990      * Test the [:Latin:] syntax.
991      */
992     public void TestPropertySet() {
993         String[] DATA = {
994                 // Pattern, Chars IN, Chars NOT in
995
996                 "[:Latin:]",
997                 "aA",
998                 "\u0391\u03B1",
999
1000                 "[\\p{Greek}]",
1001                 "\u0391\u03B1",
1002                 "aA",
1003
1004                 "\\P{ GENERAL Category = upper case letter }",
1005                 "abc",
1006                 "ABC",
1007
1008                 // Combining class: @since ICU 2.2
1009                 // Check both symbolic and numeric
1010                 "\\p{ccc=Nukta}",
1011                 "\u0ABC",
1012                 "abc",
1013
1014                 "\\p{Canonical Combining Class = 11}",
1015                 "\u05B1",
1016                 "\u05B2",
1017
1018                 "[:c c c = iota subscript :]",
1019                 "\u0345",
1020                 "xyz",
1021
1022                 // Bidi class: @since ICU 2.2
1023                 "\\p{bidiclass=lefttoright}",
1024                 "abc",
1025                 "\u0671\u0672",
1026
1027                 // Binary properties: @since ICU 2.2
1028                 "\\p{ideographic}",
1029                 "\u4E0A",
1030                 "x",
1031
1032                 "[:math=false:]",
1033                 "q)*(", // )(and * were removed from math in Unicode 4.0.1
1034                 "+<>^",
1035
1036                 // JB#1767 \N{}, \p{ASCII}
1037                 "[:Ascii:]",
1038                 "abc\u0000\u007F",
1039                 "\u0080\u4E00",
1040
1041                 "[\\N{ latin small letter  a  }[:name= latin small letter z:]]",
1042                 "az",
1043                 "qrs",
1044
1045                 // JB#2015
1046                 "[:any:]",
1047                 "a\\U0010FFFF",
1048                 "",
1049
1050                 "[:nv=0.5:]",
1051                 "\u00BD\u0F2A",
1052                 "\u00BC",
1053
1054                 // JB#2653: Age
1055                 "[:Age=1.1:]",
1056                 "\u03D6", // 1.1
1057                 "\u03D8\u03D9", // 3.2
1058
1059                 "[:Age=3.1:]", 
1060                 "\\u1800\\u3400\\U0002f800", 
1061                 "\\u0220\\u034f\\u30ff\\u33ff\\ufe73\\U00010000\\U00050000", 
1062
1063                 // JB#2350: Case_Sensitive
1064                 "[:Case Sensitive:]",
1065                 "A\u1FFC\\U00010410",
1066                 ";\u00B4\\U00010500",
1067
1068
1069                 // Regex compatibility test
1070                 "[-b]", // leading '-' is literal
1071                 "-b",
1072                 "ac",
1073
1074                 "[^-b]", // leading '-' is literal
1075                 "ac",
1076                 "-b",
1077
1078                 "[b-]", // trailing '-' is literal
1079                 "-b",
1080                 "ac",
1081
1082                 "[^b-]", // trailing '-' is literal
1083                 "ac",
1084                 "-b",
1085
1086                 "[a-b-]", // trailing '-' is literal
1087                 "ab-",
1088                 "c=",
1089
1090                 "[[a-q]&[p-z]-]", // trailing '-' is literal
1091                 "pq-",
1092                 "or=",
1093
1094                 "[\\s|\\)|:|$|\\>]", // from regex tests
1095                 "s|):$>",
1096                 "\\abc",
1097
1098                 "[\uDC00cd]", // JB#2906: isolated trail at start
1099                 "cd\uDC00",
1100                 "ab\uD800\\U00010000",
1101
1102                 "[ab\uD800]", // JB#2906: isolated trail at start
1103                 "ab\uD800",
1104                 "cd\uDC00\\U00010000",
1105
1106                 "[ab\uD800cd]", // JB#2906: isolated lead in middle
1107                 "abcd\uD800",
1108                 "ef\uDC00\\U00010000",
1109
1110                 "[ab\uDC00cd]", // JB#2906: isolated trail in middle
1111                 "abcd\uDC00",
1112                 "ef\uD800\\U00010000",
1113
1114                 "[:^lccc=0:]", // Lead canonical class
1115                 "\u0300\u0301",
1116                 "abcd\u00c0\u00c5",
1117
1118                 "[:^tccc=0:]", // Trail canonical class
1119                 "\u0300\u0301\u00c0\u00c5",
1120                 "abcd",
1121
1122                 "[[:^lccc=0:][:^tccc=0:]]", // Lead and trail canonical class
1123                 "\u0300\u0301\u00c0\u00c5",
1124                 "abcd",
1125
1126                 "[[:^lccc=0:]-[:^tccc=0:]]", // Stuff that starts with an accent but ends with a base (none right now)
1127                 "",
1128                 "abcd\u0300\u0301\u00c0\u00c5",
1129
1130                 "[[:ccc=0:]-[:lccc=0:]-[:tccc=0:]]", // Weirdos. Complete canonical class is zero, but both lead and trail are not
1131                 "\u0F73\u0F75\u0F81",
1132                 "abcd\u0300\u0301\u00c0\u00c5",
1133
1134                 "[:Assigned:]",
1135                 "A\\uE000\\uF8FF\\uFDC7\\U00010000\\U0010FFFD",
1136                 "\\u0888\\uFDD3\\uFFFE\\U00050005",
1137
1138                 // Script_Extensions, new in Unicode 6.0
1139                 "[:scx=Arab:]",
1140                 "\\u061E\\u061F\\u0620\\u0621\\u063F\\u0640\\u0650\\u065E\\uFDF1\\uFDF2\\uFDF3",
1141                 "\\u061D\\uFDEF\\uFDFE",
1142
1143                 // U+FDF2 has Script=Arabic and also Arab in its Script_Extensions,
1144                 // so scx-sc is missing U+FDF2.
1145                 "[[:Script_Extensions=Arabic:]-[:Arab:]]",
1146                 "\\u0640\\u064B\\u0650\\u0655\\uFDFD",
1147                 "\\uFDF2"
1148         };
1149
1150         for (int i=0; i<DATA.length; i+=3) {  
1151             expectContainment(DATA[i], DATA[i+1], DATA[i+2]);
1152         }
1153     }
1154
1155     public void TestUnicodeSetStrings() {
1156         UnicodeSet uset = new UnicodeSet("[a{bc}{cd}pqr\u0000]");
1157         logln(uset + " ~ " + uset.getRegexEquivalent());
1158         String[][] testStrings = {{"x", "none"},
1159                 {"bc", "all"},
1160                 {"cdbca", "all"},
1161                 {"a", "all"},
1162                 {"bcx", "some"},
1163                 {"ab", "some"},
1164                 {"acb", "some"},
1165                 {"bcda", "some"},
1166                 {"dccbx", "none"},
1167         };
1168         for (int i = 0; i < testStrings.length; ++i) {
1169             check(uset, testStrings[i][0], testStrings[i][1]);
1170         }
1171     }
1172
1173
1174     private void check(UnicodeSet uset, String string, String desiredStatus) {
1175         boolean shouldContainAll = desiredStatus.equals("all");
1176         boolean shouldContainNone = desiredStatus.equals("none");
1177         if (uset.containsAll(string) != shouldContainAll) {
1178             errln("containsAll " +  string + " should be " + shouldContainAll);
1179         } else {
1180             logln("containsAll " +  string + " = " + shouldContainAll);
1181         }
1182         if (uset.containsNone(string) != shouldContainNone) {
1183             errln("containsNone " +  string + " should be " + shouldContainNone);
1184         } else {
1185             logln("containsNone " +  string + " = " + shouldContainNone);
1186         }
1187     }
1188
1189     /**
1190      * Test cloning of UnicodeSet
1191      */
1192     public void TestClone() {
1193         UnicodeSet s = new UnicodeSet("[abcxyz]");
1194         UnicodeSet t = (UnicodeSet) s.clone();
1195         expectContainment(t, "abc", "def");
1196     }
1197
1198     /**
1199      * Test the indexOf() and charAt() methods.
1200      */
1201     public void TestIndexOf() {
1202         UnicodeSet set = new UnicodeSet("[a-cx-y3578]");
1203         for (int i=0; i<set.size(); ++i) {
1204             int c = set.charAt(i);
1205             if (set.indexOf(c) != i) {
1206                 errln("FAIL: charAt(" + i + ") = " + c +
1207                         " => indexOf() => " + set.indexOf(c));
1208             }
1209         }
1210         int c = set.charAt(set.size());
1211         if (c != -1) {
1212             errln("FAIL: charAt(<out of range>) = " +
1213                     Utility.escape(String.valueOf(c)));
1214         }
1215         int j = set.indexOf('q');
1216         if (j != -1) {
1217             errln("FAIL: indexOf('q') = " + j);
1218         }
1219     }
1220
1221     public void TestContainsString() {
1222         UnicodeSet x = new UnicodeSet("[a{bc}]");
1223         if (x.contains("abc")) errln("FAIL");
1224     }
1225
1226     public void TestExhaustive() {
1227         // exhaustive tests. Simulate UnicodeSets with integers.
1228         // That gives us very solid tests (except for large memory tests).
1229
1230         char limit = (char)128;
1231
1232         for (char i = 0; i < limit; ++i) {
1233             logln("Testing " + i + ", " + bitsToSet(i));
1234             _testComplement(i);
1235
1236             // AS LONG AS WE ARE HERE, check roundtrip
1237             checkRoundTrip(bitsToSet(i));
1238
1239             for (char j = 0; j < limit; ++j) {
1240                 _testAdd(i,j);
1241                 _testXor(i,j);
1242                 _testRetain(i,j);
1243                 _testRemove(i,j);
1244             }
1245         }
1246     }
1247
1248     /**
1249      * Make sure each script name and abbreviated name can be used
1250      * to construct a UnicodeSet.
1251      */
1252     public void TestScriptNames() {
1253         for (int i=0; i<UScript.CODE_LIMIT; ++i) {
1254             for (int j=0; j<2; ++j) {
1255                 String pat = "";
1256                 try {
1257                     String name =
1258                         (j==0) ? UScript.getName(i) : UScript.getShortName(i);
1259                         pat = "[:" + name + ":]";
1260                         UnicodeSet set = new UnicodeSet(pat);
1261                         logln("Ok: " + pat + " -> " + set.toPattern(false));
1262                 } catch (IllegalArgumentException e) {
1263                     if (pat.length() == 0) {
1264                         errln("FAIL (in UScript): No name for script " + i);
1265                     } else {
1266                         errln("FAIL: Couldn't create " + pat);
1267                     }
1268                 }
1269             }
1270         }
1271     }
1272
1273     /**
1274      * Test closure API.
1275      */
1276     public void TestCloseOver() {
1277         String CASE = String.valueOf(UnicodeSet.CASE);
1278         String[] DATA = {
1279                 // selector, input, output
1280                 CASE,
1281                 "[aq\u00DF{Bc}{bC}{Fi}]",
1282                 "[aAqQ\u00DF\u1E9E\uFB01{ss}{bc}{fi}]", // U+1E9E LATIN CAPITAL LETTER SHARP S is new in Unicode 5.1
1283
1284                 CASE,
1285                 "[\u01F1]", // 'DZ'
1286                 "[\u01F1\u01F2\u01F3]",
1287
1288                 CASE,
1289                 "[\u1FB4]",
1290                 "[\u1FB4{\u03AC\u03B9}]",
1291
1292                 CASE,
1293                 "[{F\uFB01}]",
1294                 "[\uFB03{ffi}]",            
1295
1296                 CASE,
1297                 "[a-z]","[A-Za-z\u017F\u212A]",
1298                 CASE,
1299                 "[abc]","[A-Ca-c]",
1300                 CASE,
1301                 "[ABC]","[A-Ca-c]",
1302         };
1303
1304         UnicodeSet s = new UnicodeSet();
1305         UnicodeSet t = new UnicodeSet();
1306         for (int i=0; i<DATA.length; i+=3) {
1307             int selector = Integer.parseInt(DATA[i]);
1308             String pat = DATA[i+1];
1309             String exp = DATA[i+2];
1310             s.applyPattern(pat);
1311             s.closeOver(selector);
1312             t.applyPattern(exp);
1313             if (s.equals(t)) {
1314                 logln("Ok: " + pat + ".closeOver(" + selector + ") => " + exp);
1315             } else {
1316                 errln("FAIL: " + pat + ".closeOver(" + selector + ") => " +
1317                         s.toPattern(true) + ", expected " + exp);
1318             }
1319         }
1320
1321         // Test the pattern API
1322         s.applyPattern("[abc]", UnicodeSet.CASE);
1323         expectContainment(s, "abcABC", "defDEF");
1324         s = new UnicodeSet("[^abc]", UnicodeSet.CASE);
1325         expectContainment(s, "defDEF", "abcABC");
1326     }
1327
1328     public void TestEscapePattern() {
1329         // The following pattern must contain at least one range "c-d"
1330         // where c or d is a Pattern_White_Space.
1331         String pattern =
1332             "[\\uFEFF \\u200E-\\u20FF \\uFFF9-\\uFFFC \\U0001D173-\\U0001D17A \\U000F0000-\\U000FFFFD ]";
1333         String exp =
1334             "[\\u200E-\\u20FF\\uFEFF\\uFFF9-\\uFFFC\\U0001D173-\\U0001D17A\\U000F0000-\\U000FFFFD]";
1335         // We test this with two passes; in the second pass we
1336         // pre-unescape the pattern.  Since U+200E is Pattern_White_Space,
1337         // this fails -- which is what we expect.
1338         for (int pass=1; pass<=2; ++pass) {
1339             String pat = pattern;
1340             if (pass==2) {
1341                 pat = Utility.unescape(pat);
1342             }
1343             // Pattern is only good for pass 1
1344             boolean isPatternValid = (pass==1);
1345
1346             UnicodeSet set = null;
1347             try {
1348                 set = new UnicodeSet(pat);
1349             } catch (IllegalArgumentException e) {
1350                 set = null;
1351             }
1352             if ((set != null) != isPatternValid){
1353                 errln("FAIL: applyPattern(" +
1354                         Utility.escape(pat) + ") => " + set);
1355                 continue;
1356             }
1357             if (set == null) {
1358                 continue;
1359             }
1360             if (set.contains((char)0x0644)){
1361                 errln("FAIL: " + Utility.escape(pat) + " contains(U+0664)");
1362             }
1363
1364             String newpat = set.toPattern(true);
1365             if (newpat.equals(exp)) {
1366                 logln(Utility.escape(pat) + " => " + newpat);
1367             } else {
1368                 errln("FAIL: " + Utility.escape(pat) + " => " + newpat);
1369             }
1370
1371             for (int i=0; i<set.getRangeCount(); ++i) {
1372                 StringBuffer str = new StringBuffer("Range ");
1373                 str.append((char)(0x30 + i))
1374                 .append(": ");
1375                 UTF16.append(str, set.getRangeStart(i));
1376                 str.append(" - ");
1377                 UTF16.append(str, set.getRangeEnd(i));
1378                 String s = Utility.escape(str.toString() + " (" + set.getRangeStart(i) + " - " +
1379                         set.getRangeEnd(i) + ")");
1380                 if (set.getRangeStart(i) < 0) {
1381                     errln("FAIL: " + s);
1382                 } else {
1383                     logln(s);
1384                 }
1385             }
1386         }
1387     }
1388
1389     public void TestSymbolTable() {
1390         // Multiple test cases can be set up here.  Each test case
1391         // is terminated by null:
1392         // var, value, var, value,..., input pat., exp. output pat., null
1393         String DATA[] = {
1394                 "us", "a-z", "[0-1$us]", "[0-1a-z]", null,
1395                 "us", "[a-z]", "[0-1$us]", "[0-1[a-z]]", null,
1396                 "us", "\\[a\\-z\\]", "[0-1$us]", "[-01\\[\\]az]", null
1397         };
1398
1399         for (int i=0; i<DATA.length; ++i) {
1400             TokenSymbolTable sym = new TokenSymbolTable();
1401
1402             // Set up variables
1403             while (DATA[i+2] != null) {
1404                 sym.add(DATA[i], DATA[i+1]);
1405                 i += 2;
1406             }
1407
1408             // Input pattern and expected output pattern
1409             String inpat = DATA[i], exppat = DATA[i+1];
1410             i += 2;
1411
1412             ParsePosition pos = new ParsePosition(0);
1413             UnicodeSet us = new UnicodeSet(inpat, pos, sym);
1414
1415             // results
1416             if (pos.getIndex() != inpat.length()) {
1417                 errln("Failed to read to end of string \""
1418                         + inpat + "\": read to "
1419                         + pos.getIndex() + ", length is "
1420                         + inpat.length());
1421             }
1422
1423             UnicodeSet us2 = new UnicodeSet(exppat);
1424             if (!us.equals(us2)) {
1425                 errln("Failed, got " + us + ", expected " + us2);
1426             } else {
1427                 logln("Ok, got " + us);
1428             }
1429
1430             //cover Unicode(String,ParsePosition,SymbolTable,int)
1431             ParsePosition inpos = new ParsePosition(0);
1432             UnicodeSet inSet = new UnicodeSet(inpat, inpos, sym, UnicodeSet.IGNORE_SPACE);
1433             UnicodeSet expSet = new UnicodeSet(exppat);
1434             if (!inSet.equals(expSet)) {
1435                 errln("FAIL: Failed, got " + inSet + ", expected " + expSet);
1436             } else {
1437                 logln("OK: got " + inSet);
1438             }
1439         }
1440     }
1441
1442     /**
1443      * Test that Posix style character classes [:digit:], etc.
1444      *   have the Unicode definitions from TR 18.
1445      */
1446     public void TestPosixClasses() {
1447         expectEqual("POSIX alpha", "[:alpha:]", "\\p{Alphabetic}");
1448         expectEqual("POSIX lower", "[:lower:]", "\\p{lowercase}");
1449         expectEqual("POSIX upper", "[:upper:]", "\\p{Uppercase}");
1450         expectEqual("POSIX punct", "[:punct:]", "\\p{gc=Punctuation}");
1451         expectEqual("POSIX digit", "[:digit:]", "\\p{gc=DecimalNumber}");
1452         expectEqual("POSIX xdigit", "[:xdigit:]", "[\\p{DecimalNumber}\\p{HexDigit}]");
1453         expectEqual("POSIX alnum", "[:alnum:]", "[\\p{Alphabetic}\\p{DecimalNumber}]");
1454         expectEqual("POSIX space", "[:space:]", "\\p{Whitespace}");
1455         expectEqual("POSIX blank", "[:blank:]", "[\\p{Whitespace}-[\\u000a\\u000B\\u000c\\u000d\\u0085\\p{LineSeparator}\\p{ParagraphSeparator}]]");
1456         expectEqual("POSIX cntrl", "[:cntrl:]", "\\p{Control}");
1457         expectEqual("POSIX graph", "[:graph:]", "[^\\p{Whitespace}\\p{Control}\\p{Surrogate}\\p{Unassigned}]");
1458         expectEqual("POSIX print", "[:print:]", "[[:graph:][:blank:]-[\\p{Control}]]");
1459     }
1460
1461     public void TestHangulSyllable() {
1462         final UnicodeSet lvt = new UnicodeSet("[:Hangul_Syllable_Type=LVT_Syllable:]");
1463         assertNotEquals("LVT count", new UnicodeSet(), lvt);
1464         logln(lvt + ": " + lvt.size());
1465         final UnicodeSet lv = new UnicodeSet("[:Hangul_Syllable_Type=LV_Syllable:]");
1466         assertNotEquals("LV count", new UnicodeSet(), lv);
1467         logln(lv + ": " + lv.size());
1468     }
1469
1470     /**
1471      * Test that frozen classes disallow changes. For 4217
1472      */
1473     public void TestFrozen() {
1474         UnicodeSet test = new UnicodeSet("[[:whitespace:]A]");
1475         test.freeze();
1476         checkModification(test, true);
1477         checkModification(test, false);
1478     }
1479
1480     /**
1481      * Test Generic support
1482      */
1483     public void TestGenerics() {
1484         UnicodeSet set1 = new UnicodeSet("[a-b d-g {ch} {zh}]").freeze();
1485         UnicodeSet set2 = new UnicodeSet("[e-f {ch}]").freeze();
1486         UnicodeSet set3 = new UnicodeSet("[d m-n {dh}]").freeze();
1487         // A useful range of sets for testing, including both characters and strings
1488         // set 1 contains set2
1489         // set 1 is overlaps with set 3
1490         // set 2 is disjoint with set 3
1491
1492         //public Iterator<String> iterator() {
1493
1494         ArrayList<String> oldList = new ArrayList<String>();
1495         for (UnicodeSetIterator it = new UnicodeSetIterator(set1); it.next();) {
1496             oldList.add(it.getString());
1497         }
1498
1499         ArrayList<String> list1 = new ArrayList<String>();
1500         for (String s : set1) {
1501             list1.add(s);
1502         }
1503         assertEquals("iteration test", oldList, list1);
1504
1505         //addAllTo(Iterable<T>, U)
1506         list1.clear();
1507         set1.addAllTo(list1);
1508         assertEquals("iteration test", oldList, list1);
1509
1510         list1 = set1.addAllTo(new ArrayList<String>());
1511         assertEquals("addAllTo", oldList, list1);
1512
1513         ArrayList<String> list2 = set2.addAllTo(new ArrayList<String>());
1514         ArrayList<String> list3 = set3.addAllTo(new ArrayList<String>());
1515
1516         // put them into different order, to check that order doesn't matter
1517         TreeSet sorted1 = set1.addAllTo(new TreeSet<String>());
1518         TreeSet sorted2 = set2.addAllTo(new TreeSet<String>());
1519         TreeSet sorted3 = set3.addAllTo(new TreeSet<String>());
1520
1521         //containsAll(Collection<String> collection)
1522         assertTrue("containsAll", set1.containsAll(list1));
1523         assertTrue("containsAll", set1.containsAll(sorted1));
1524         assertTrue("containsAll", set1.containsAll(list2));
1525         assertTrue("containsAll", set1.containsAll(sorted2));
1526         assertFalse("containsAll", set1.containsAll(list3));
1527         assertFalse("containsAll", set1.containsAll(sorted3));
1528         assertFalse("containsAll", set2.containsAll(list3));
1529         assertFalse("containsAll", set2.containsAll(sorted3));
1530
1531         //containsSome(Collection<String>)
1532         assertTrue("containsSome", set1.containsSome(list1));
1533         assertTrue("containsSome", set1.containsSome(sorted1));
1534         assertTrue("containsSome", set1.containsSome(list2));
1535         assertTrue("containsSome", set1.containsSome(sorted2));
1536         assertTrue("containsSome", set1.containsSome(list3));
1537         assertTrue("containsSome", set1.containsSome(sorted3));
1538         assertFalse("containsSome", set2.containsSome(list3));
1539         assertFalse("containsSome", set2.containsSome(sorted3));
1540
1541         //containsNone(Collection<String>)
1542         assertFalse("containsNone", set1.containsNone(list1));
1543         assertFalse("containsNone", set1.containsNone(sorted1));
1544         assertFalse("containsNone", set1.containsNone(list2));
1545         assertFalse("containsNone", set1.containsNone(sorted2));
1546         assertFalse("containsNone", set1.containsNone(list3));
1547         assertFalse("containsNone", set1.containsNone(sorted3));
1548         assertTrue("containsNone", set2.containsNone(list3));
1549         assertTrue("containsNone", set2.containsNone(sorted3));
1550
1551         //addAll(String...)
1552         UnicodeSet other3 = new UnicodeSet().addAll("d", "m", "n", "dh");
1553         assertEquals("addAll", set3, other3);
1554
1555         //removeAll(Collection<String>)
1556         UnicodeSet mod1 = new UnicodeSet(set1).removeAll(set2);
1557         UnicodeSet mod2 = new UnicodeSet(set1).removeAll(list2);
1558         assertEquals("remove all", mod1, mod2);
1559
1560         //retainAll(Collection<String>)
1561         mod1 = new UnicodeSet(set1).retainAll(set2);
1562         mod2 = new UnicodeSet(set1).retainAll(set2.addAllTo(new LinkedHashSet<String>()));
1563         assertEquals("remove all", mod1, mod2);
1564     }
1565     
1566     public void TestComparison() {
1567         UnicodeSet set1 = new UnicodeSet("[a-b d-g {ch} {zh}]").freeze();
1568         UnicodeSet set2 = new UnicodeSet("[c-e {ch}]").freeze();
1569         UnicodeSet set3 = new UnicodeSet("[d m-n z {dh}]").freeze();
1570
1571         //compareTo(UnicodeSet)
1572         // do indirectly, by sorting
1573         List<UnicodeSet> unsorted = Arrays.asList(set3, set2, set1);
1574         List<UnicodeSet> goalShortest = Arrays.asList(set2, set3, set1);
1575         List<UnicodeSet> goalLongest = Arrays.asList(set1, set3, set2);
1576         List<UnicodeSet> goalLex = Arrays.asList(set1, set2, set3);
1577
1578         List<UnicodeSet> sorted = new ArrayList(new TreeSet<UnicodeSet>(unsorted));
1579         assertNotEquals("compareTo-shorter-first", unsorted, sorted);
1580         assertEquals("compareTo-shorter-first", goalShortest, sorted);
1581         
1582         TreeSet<UnicodeSet> sorted1 = new TreeSet<UnicodeSet>(new Comparator<UnicodeSet>(){
1583             public int compare(UnicodeSet o1, UnicodeSet o2) {
1584                 // TODO Auto-generated method stub
1585                 return o1.compareTo(o2, ComparisonStyle.LONGER_FIRST);
1586             }});
1587         sorted1.addAll(unsorted);
1588         sorted = new ArrayList(sorted1);
1589         assertNotEquals("compareTo-longer-first", unsorted, sorted);
1590         assertEquals("compareTo-longer-first", goalLongest, sorted);
1591
1592         sorted1 = new TreeSet<UnicodeSet>(new Comparator<UnicodeSet>(){
1593             public int compare(UnicodeSet o1, UnicodeSet o2) {
1594                 // TODO Auto-generated method stub
1595                 return o1.compareTo(o2, ComparisonStyle.LEXICOGRAPHIC);
1596             }});
1597         sorted1.addAll(unsorted);
1598         sorted = new ArrayList(sorted1);
1599         assertNotEquals("compareTo-lex", unsorted, sorted);
1600         assertEquals("compareTo-lex", goalLex, sorted);
1601
1602         //compare(String, int)
1603         // make a list of interesting combinations
1604         List<String> sources = Arrays.asList("\u0000", "a", "b", "\uD7FF", "\uD800", "\uDBFF", "\uDC00", "\uDFFF", "\uE000", "\uFFFD", "\uFFFF");
1605         TreeSet<String> target = new TreeSet<String>();
1606         for (String s : sources) {
1607             target.add(s);
1608             for (String t : sources) {
1609                 target.add(s + t);
1610                 for (String u : sources) {
1611                     target.add(s + t + u);
1612                 }
1613             }
1614         }
1615         // now compare all the combinations. If any of them is a code point, use it.
1616         int maxErrorCount = 0;
1617         compare:
1618         for (String last : target) {
1619             for (String curr : target) {
1620                 int lastCount = Character.codePointCount(last, 0, last.length());
1621                 int currCount = Character.codePointCount(curr, 0, curr.length());
1622                 int comparison;
1623                 if (lastCount == 1) {
1624                     comparison = UnicodeSet.compare(last.codePointAt(0), curr);
1625                 } else if (currCount == 1) {
1626                     comparison = UnicodeSet.compare(last, curr.codePointAt(0));
1627                 } else {
1628                     continue;
1629                 }
1630                 if (comparison != last.compareTo(curr)) {
1631                     // repeat for debugging
1632                     if (lastCount == 1) {
1633                         comparison = UnicodeSet.compare(last.codePointAt(0), curr);
1634                     } else if (currCount == 1) {
1635                         comparison = UnicodeSet.compare(last, curr.codePointAt(0));
1636                     }
1637                     if (maxErrorCount++ > 10) {
1638                         errln(maxErrorCount + " Failure in comparing " + last + " & " + curr + "\tOmitting others...");
1639                         break compare;
1640                     }
1641                     errln(maxErrorCount + " Failure in comparing " + last + " & " + curr);
1642                 }
1643             }
1644         }
1645         
1646         //compare(Iterable<T>, Iterable<T>)
1647         int max = 10;
1648         List<String> test1 = new ArrayList<String>(max);
1649         List<String> test2 = new ArrayList<String>(max);
1650         for (int i = 0; i <= max; ++i) {
1651             test1.add("a" + i);
1652             test2.add("a" + (max - i)); // add in reverse order
1653         }
1654         assertNotEquals("compare iterable test", test1, test2);
1655         TreeSet<CharSequence> sortedTest1 = new TreeSet<CharSequence>(test1);
1656         TreeSet<CharSequence> sortedTest2 = new TreeSet<CharSequence>(test2);
1657         assertEquals("compare iterable test", sortedTest1, sortedTest2);
1658     }
1659
1660     public void TestRangeConstructor() {
1661         UnicodeSet w = new UnicodeSet().addAll(3,5);
1662         UnicodeSet s = new UnicodeSet(3,5);
1663         assertEquals("new constructor", w, s);
1664
1665         w = new UnicodeSet().addAll(3,5).addAll(7,7);
1666         UnicodeSet t = new UnicodeSet(3,5, 7,7);
1667         assertEquals("new constructor", w, t);
1668         // check to make sure right exceptions are thrown
1669         Class expected = IllegalArgumentException.class;
1670         Class actual;
1671         
1672         try {
1673             actual = null;
1674             @SuppressWarnings("unused")
1675             UnicodeSet u = new UnicodeSet(5);
1676         } catch (IllegalArgumentException e) {
1677             actual = e.getClass();
1678         }
1679         assertEquals("exception if odd", expected, actual);
1680         
1681         try {
1682             actual = null;
1683             @SuppressWarnings("unused")
1684             UnicodeSet u = new UnicodeSet(3, 2, 7, 9);
1685         } catch (IllegalArgumentException e) {
1686             actual = e.getClass();
1687         }
1688         assertEquals("exception for start/end problem", expected, actual);
1689         
1690         try {
1691             actual = null;
1692             @SuppressWarnings("unused")
1693             UnicodeSet u = new UnicodeSet(3, 5, 6, 9);
1694         } catch (IllegalArgumentException e) {
1695             actual = e.getClass();
1696         }
1697         assertEquals("exception for end/start problem", expected, actual);
1698         
1699         CheckRangeSpeed(10000, new UnicodeSet("[:whitespace:]"));
1700         CheckRangeSpeed(1000, new UnicodeSet("[:letter:]"));
1701     }
1702
1703     /**
1704      * @param iterations
1705      * @param testSet
1706      */
1707     private void CheckRangeSpeed(int iterations, UnicodeSet testSet) {
1708         testSet.complement().complement();
1709         String testPattern = testSet.toString();
1710         // fill a set of pairs from the pattern
1711         int[] pairs = new int[testSet.getRangeCount()*2];
1712         int j = 0;
1713         for (UnicodeSetIterator it = new UnicodeSetIterator(testSet); it.nextRange();) {
1714             pairs[j++] = it.codepoint;
1715             pairs[j++] = it.codepointEnd;
1716         }
1717         UnicodeSet fromRange = new UnicodeSet(testSet);
1718         assertEquals("from range vs pattern", testSet, fromRange);
1719
1720         double start = System.currentTimeMillis();
1721         for (int i = 0; i < iterations; ++i) {
1722             fromRange = new UnicodeSet(testSet);
1723         }
1724         double middle = System.currentTimeMillis();
1725         for (int i = 0; i < iterations; ++i) {
1726             new UnicodeSet(testPattern);
1727         }
1728         double end = System.currentTimeMillis();
1729
1730         double rangeConstructorTime = (middle - start)/iterations;
1731         double patternConstructorTime = (end - middle)/iterations;
1732         String message = "Range constructor:\t" + rangeConstructorTime + ";\tPattern constructor:\t" + patternConstructorTime + "\t\t"
1733         + percent.format(rangeConstructorTime/patternConstructorTime-1);
1734         if (rangeConstructorTime < 2*patternConstructorTime) {
1735             logln(message);
1736         } else {
1737             errln(message);
1738         }
1739     }
1740     
1741     NumberFormat percent = NumberFormat.getPercentInstance();
1742     {
1743         percent.setMaximumFractionDigits(2);
1744     }
1745     // ****************************************
1746     // UTILITIES
1747     // ****************************************
1748
1749     public void checkModification(UnicodeSet original, boolean isFrozen) {
1750         main:
1751             for (int i = 0; ;++i) {
1752                 UnicodeSet test = (UnicodeSet) (isFrozen ? original.clone() : original.cloneAsThawed());
1753                 boolean gotException = true;
1754                 boolean checkEquals = true;
1755                 try {
1756                     switch(i) {
1757                     case 0: test.add(0); break;
1758                     case 1: test.add(0,1); break;
1759                     case 2: test.add("a"); break;
1760                     case 3: List a = new ArrayList(); a.add("a"); test.addAll(a); break;
1761                     case 4: test.addAll("ab"); break;
1762                     case 5: test.addAll(new UnicodeSet("[ab]")); break;
1763                     case 6: test.applyIntPropertyValue(0,0); break;
1764                     case 7: test.applyPattern("[ab]"); break;
1765                     case 8: test.applyPattern("[ab]", true); break;
1766                     case 9: test.applyPattern("[ab]", 0); break;
1767                     case 10: test.applyPropertyAlias("hex","true"); break;
1768                     case 11: test.applyPropertyAlias("hex", "true", null); break;
1769                     case 12: test.closeOver(UnicodeSet.CASE); break;
1770                     case 13: test.compact(); checkEquals = false; break;
1771                     case 14: test.complement(0); break;
1772                     case 15: test.complement(0,0); break;
1773                     case 16: test.complement("ab"); break;
1774                     case 17: test.complementAll("ab"); break;
1775                     case 18: test.complementAll(new UnicodeSet("[ab]")); break;
1776                     case 19: test.remove(' '); break;
1777                     case 20: test.remove(' ','a'); break;
1778                     case 21: test.remove(" "); break;
1779                     case 22: test.removeAll(" a"); break;
1780                     case 23: test.removeAll(new UnicodeSet("[\\ a]")); break;
1781                     case 24: test.retain(' '); break;
1782                     case 25: test.retain(' ','a'); break;
1783                     case 26: test.retain(" "); break;
1784                     case 27: test.retainAll(" a"); break;
1785                     case 28: test.retainAll(new UnicodeSet("[\\ a]")); break;
1786                     case 29: test.set(0,1); break;
1787                     case 30: test.set(new UnicodeSet("[ab]")); break;
1788
1789                     default: continue main; // so we don't keep having to change the endpoint, and gaps are not skipped.
1790                     case 35: return;
1791                     }
1792                     gotException = false;
1793                 } catch (UnsupportedOperationException e) {
1794                     // do nothing
1795                 }
1796                 if (isFrozen && !gotException) errln(i + ") attempt to modify frozen object didn't result in an exception");
1797                 if (!isFrozen && gotException) errln(i + ") attempt to modify thawed object did result in an exception");
1798                 if (checkEquals) {
1799                     if (test.equals(original)) {
1800                         if (!isFrozen) errln(i + ") attempt to modify thawed object didn't change the object");
1801                     } else { // unequal
1802                         if (isFrozen) errln(i + ") attempt to modify frozen object changed the object");
1803                     }
1804                 }
1805             }
1806     }
1807
1808 // Following cod block is commented out to eliminate PrettyPrinter depenencies
1809
1810 //    String[] prettyData = {
1811 //            "[\\uD7DE-\\uD90C \\uDCB5-\\uDD9F]", // special case
1812 //            "[:any:]",
1813 //            "[:whitespace:]",
1814 //            "[:linebreak=AL:]",
1815 //    };
1816 //
1817 //    public void TestPrettyPrinting() {
1818 //        try{
1819 //            PrettyPrinter pp = new PrettyPrinter();
1820 //
1821 //            int i = 0;
1822 //            for (; i < prettyData.length; ++i) {
1823 //                UnicodeSet test = new UnicodeSet(prettyData[i]);
1824 //                checkPrettySet(pp, i, test);
1825 //            }
1826 //            Random random = new Random(0);
1827 //            UnicodeSet test = new UnicodeSet();
1828 //
1829 //            // To keep runtimes under control, make the number of random test cases
1830 //            //   to try depends on the test framework exhaustive setting.
1831 //            //  params.inclusions = 5:   default exhaustive value
1832 //            //  params.inclusions = 10:  max exhaustive value.
1833 //            int iterations = 50;
1834 //            if (params.inclusion > 5) {
1835 //                iterations = (params.inclusion-5) * 200;
1836 //            }
1837 //            for (; i < iterations; ++i) {
1838 //                double start = random.nextGaussian() * 0x10000;
1839 //                if (start < 0) start = - start;
1840 //                if (start > 0x10FFFF) {
1841 //                    start = 0x10FFFF;
1842 //                }
1843 //                double end = random.nextGaussian() * 0x100;
1844 //                if (end < 0) end = -end;
1845 //                end = start + end;
1846 //                if (end > 0x10FFFF) {
1847 //                    end = 0x10FFFF;
1848 //                }
1849 //                test.complement((int)start, (int)end);
1850 //                checkPrettySet(pp, i, test);
1851 //            }
1852 //        }catch(RuntimeException ex){
1853 //            warnln("Could not load Collator");
1854 //        }
1855 //    }
1856 //
1857 //    private void checkPrettySet(PrettyPrinter pp, int i, UnicodeSet test) {
1858 //        String pretty = pp.toPattern(test);
1859 //        UnicodeSet retry = new UnicodeSet(pretty);
1860 //        if (!test.equals(retry)) {
1861 //            errln(i + ". Failed test: " + test + " != " + pretty);
1862 //        } else {
1863 //            logln(i + ". Worked for " + truncate(test.toString()) + " => " + truncate(pretty));
1864 //        }
1865 //    }
1866 //
1867 //    private String truncate(String string) {
1868 //        if (string.length() <= 100) return string;
1869 //        return string.substring(0,97) + "...";
1870 //    }
1871
1872     public class TokenSymbolTable implements SymbolTable {
1873         HashMap contents = new HashMap();
1874
1875         /**
1876          * (Non-SymbolTable API) Add the given variable and value to
1877          * the table.  Variable should NOT contain leading '$'.
1878          */
1879         public void add(String var, String value) {
1880             char[] buffer = new char[value.length()];
1881             value.getChars(0, value.length(), buffer, 0);
1882             add(var, buffer);
1883         }
1884
1885         /**
1886          * (Non-SymbolTable API) Add the given variable and value to
1887          * the table.  Variable should NOT contain leading '$'.
1888          */
1889         public void add(String var, char[] body) {
1890             logln("TokenSymbolTable: add \"" + var + "\" => \"" +
1891                     new String(body) + "\"");
1892             contents.put(var, body);
1893         }
1894
1895         /* (non-Javadoc)
1896          * @see com.ibm.icu.text.SymbolTable#lookup(java.lang.String)
1897          */
1898         public char[] lookup(String s) {
1899             logln("TokenSymbolTable: lookup \"" + s + "\" => \"" +
1900                     new String((char[]) contents.get(s)) + "\"");
1901             return (char[])contents.get(s);
1902         }
1903
1904         /* (non-Javadoc)
1905          * @see com.ibm.icu.text.SymbolTable#lookupMatcher(int)
1906          */
1907         public UnicodeMatcher lookupMatcher(int ch) {
1908             return null;
1909         }
1910
1911         /* (non-Javadoc)
1912          * @see com.ibm.icu.text.SymbolTable#parseReference(java.lang.String,
1913      java.text.ParsePosition, int)
1914          */
1915         public String parseReference(String text, ParsePosition pos, int
1916                 limit) {
1917             int cp;
1918             int start = pos.getIndex();
1919             int i;
1920             for (i = start; i < limit; i += UTF16.getCharCount(cp)) {
1921                 cp = UTF16.charAt(text, i);
1922                 if (!com.ibm.icu.lang.UCharacter.isUnicodeIdentifierPart(cp)) {
1923                     break;
1924                 }
1925             }
1926             logln("TokenSymbolTable: parse \"" + text + "\" from " +
1927                     start + " to " + i +
1928                     " => \"" + text.substring(start,i) + "\"");
1929             pos.setIndex(i);
1930             return text.substring(start,i);
1931         }
1932     }
1933
1934     public void TestSurrogate() {
1935         String DATA[] = {
1936                 // These should all behave identically
1937                 "[abc\\uD800\\uDC00]",
1938                 "[abc\uD800\uDC00]",
1939                 "[abc\\U00010000]",
1940         };
1941         for (int i=0; i<DATA.length; ++i) {
1942             logln("Test pattern " + i + " :" + Utility.escape(DATA[i]));
1943             UnicodeSet set = new UnicodeSet(DATA[i]);
1944             expectContainment(set,
1945                     CharsToUnicodeString("abc\\U00010000"),
1946             "\uD800;\uDC00"); // split apart surrogate-pair
1947             if (set.size() != 4) {
1948                 errln(Utility.escape("FAIL: " + DATA[i] + ".size() == " + 
1949                         set.size() + ", expected 4"));
1950             }
1951         }
1952     }
1953
1954     public void TestContains() {
1955         int limit = 256; // combinations to test
1956         for (int i = 0; i < limit; ++i) {
1957             logln("Trying: " + i);
1958             UnicodeSet x = bitsToSet(i);
1959             for (int j = 0; j < limit; ++j) {
1960                 UnicodeSet y = bitsToSet(j);
1961                 boolean containsNone = (i & j) == 0;
1962                 boolean containsAll = (i & j) == j;
1963                 boolean equals = i == j;
1964                 if (containsNone != x.containsNone(y)) {
1965                     x.containsNone(y); // repeat for debugging
1966                     errln("FAILED: " + x +  " containsSome " + y);
1967                 }
1968                 if (containsAll != x.containsAll(y)) {
1969                     x.containsAll(y); // repeat for debugging
1970                     errln("FAILED: " + x +  " containsAll " + y);
1971                 }
1972                 if (equals != x.equals(y)) {
1973                     x.equals(y); // repeat for debugging
1974                     errln("FAILED: " + x +  " equals " + y);
1975                 }
1976             }
1977         }
1978     }
1979
1980     void _testComplement(int a) {
1981         UnicodeSet x = bitsToSet(a);
1982         UnicodeSet z = bitsToSet(a);
1983         z.complement();
1984         int c = setToBits(z);
1985         if (c != (~a)) {
1986             errln("FAILED: add: ~" + x +  " != " + z);
1987             errln("FAILED: add: ~" + a + " != " + c);
1988         }
1989         checkCanonicalRep(z, "complement " + a);
1990     }
1991
1992     void _testAdd(int a, int b) {
1993         UnicodeSet x = bitsToSet(a);
1994         UnicodeSet y = bitsToSet(b);
1995         UnicodeSet z = bitsToSet(a);
1996         z.addAll(y);
1997         int c = setToBits(z);
1998         if (c != (a | b)) {
1999             errln(Utility.escape("FAILED: add: " + x + " | " + y + " != " + z));
2000             errln("FAILED: add: " + a + " | " + b + " != " + c);
2001         }
2002         checkCanonicalRep(z, "add " + a + "," + b);
2003     }
2004
2005     void _testRetain(int a, int b) {
2006         UnicodeSet x = bitsToSet(a);
2007         UnicodeSet y = bitsToSet(b);
2008         UnicodeSet z = bitsToSet(a);
2009         z.retainAll(y);
2010         int c = setToBits(z);
2011         if (c != (a & b)) {
2012             errln("FAILED: retain: " + x + " & " + y + " != " + z);
2013             errln("FAILED: retain: " + a + " & " + b + " != " + c);
2014         }
2015         checkCanonicalRep(z, "retain " + a + "," + b);
2016     }
2017
2018     void _testRemove(int a, int b) {
2019         UnicodeSet x = bitsToSet(a);
2020         UnicodeSet y = bitsToSet(b);
2021         UnicodeSet z = bitsToSet(a);
2022         z.removeAll(y);
2023         int c = setToBits(z);
2024         if (c != (a &~ b)) {
2025             errln("FAILED: remove: " + x + " &~ " + y + " != " + z);
2026             errln("FAILED: remove: " + a + " &~ " + b + " != " + c);
2027         }
2028         checkCanonicalRep(z, "remove " + a + "," + b);
2029     }
2030
2031     void _testXor(int a, int b) {
2032         UnicodeSet x = bitsToSet(a);
2033         UnicodeSet y = bitsToSet(b);
2034         UnicodeSet z = bitsToSet(a);
2035         z.complementAll(y);
2036         int c = setToBits(z);
2037         if (c != (a ^ b)) {
2038             errln("FAILED: complement: " + x + " ^ " + y + " != " + z);
2039             errln("FAILED: complement: " + a + " ^ " + b + " != " + c);
2040         }
2041         checkCanonicalRep(z, "complement " + a + "," + b);
2042     }
2043
2044     /**
2045      * Check that ranges are monotonically increasing and non-
2046      * overlapping.
2047      */
2048     void checkCanonicalRep(UnicodeSet set, String msg) {
2049         int n = set.getRangeCount();
2050         if (n < 0) {
2051             errln("FAIL result of " + msg +
2052                     ": range count should be >= 0 but is " +
2053                     n + " for " + Utility.escape(set.toString()));
2054             return;
2055         }
2056         int last = 0;
2057         for (int i=0; i<n; ++i) {
2058             int start = set.getRangeStart(i);
2059             int end = set.getRangeEnd(i);
2060             if (start > end) {
2061                 errln("FAIL result of " + msg +
2062                         ": range " + (i+1) +
2063                         " start > end: " + start + ", " + end +
2064                         " for " + Utility.escape(set.toString()));
2065             }
2066             if (i > 0 && start <= last) {
2067                 errln("FAIL result of " + msg +
2068                         ": range " + (i+1) +
2069                         " overlaps previous range: " + start + ", " + end +
2070                         " for " + Utility.escape(set.toString()));
2071             }
2072             last = end;
2073         }
2074     }
2075
2076     /**
2077      * Convert a bitmask to a UnicodeSet.
2078      */
2079     UnicodeSet bitsToSet(int a) {
2080         UnicodeSet result = new UnicodeSet();
2081         for (int i = 0; i < 32; ++i) {
2082             if ((a & (1<<i)) != 0) {
2083                 result.add((char)i,(char)i);
2084             }
2085         }
2086
2087         return result;
2088     }
2089
2090     /**
2091      * Convert a UnicodeSet to a bitmask.  Only the characters
2092      * U+0000 to U+0020 are represented in the bitmask.
2093      */
2094     static int setToBits(UnicodeSet x) {
2095         int result = 0;
2096         for (int i = 0; i < 32; ++i) {
2097             if (x.contains((char)i)) {
2098                 result |= (1<<i);
2099             }
2100         }
2101         return result;
2102     }
2103
2104     /**
2105      * Return the representation of an inversion list based UnicodeSet
2106      * as a pairs list.  Ranges are listed in ascending Unicode order.
2107      * For example, the set [a-zA-M3] is represented as "33AMaz".
2108      */
2109     static String getPairs(UnicodeSet set) {
2110         StringBuffer pairs = new StringBuffer();
2111         for (int i=0; i<set.getRangeCount(); ++i) {
2112             int start = set.getRangeStart(i);
2113             int end = set.getRangeEnd(i);
2114             if (end > 0xFFFF) {
2115                 end = 0xFFFF;
2116                 i = set.getRangeCount(); // Should be unnecessary
2117             }
2118             pairs.append((char)start).append((char)end);
2119         }
2120         return pairs.toString();
2121     }
2122
2123     /**
2124      * Test function. Make sure that the sets have the right relation
2125      */
2126
2127     void expectRelation(Object relationObj, Object set1Obj, Object set2Obj, String message) {
2128         int relation = ((Integer) relationObj).intValue();
2129         UnicodeSet set1 = (UnicodeSet) set1Obj;
2130         UnicodeSet set2 = (UnicodeSet) set2Obj;
2131
2132         // by-the-by, check the iterator
2133         checkRoundTrip(set1);
2134         checkRoundTrip(set2);
2135
2136         boolean contains = set1.containsAll(set2);
2137         boolean isContained = set2.containsAll(set1);
2138         boolean disjoint = set1.containsNone(set2);
2139         boolean equals = set1.equals(set2);
2140
2141         UnicodeSet intersection = new UnicodeSet(set1).retainAll(set2);
2142         UnicodeSet minus12 = new UnicodeSet(set1).removeAll(set2);
2143         UnicodeSet minus21 = new UnicodeSet(set2).removeAll(set1);
2144
2145         // test basic properties
2146
2147         if (contains != (intersection.size() == set2.size())) {
2148             errln("FAIL contains1" + set1.toPattern(true) + ", " + set2.toPattern(true));
2149         }
2150
2151         if (contains != (intersection.equals(set2))) {
2152             errln("FAIL contains2" + set1.toPattern(true) + ", " + set2.toPattern(true));
2153         }
2154
2155         if (isContained != (intersection.size() == set1.size())) {
2156             errln("FAIL isContained1" + set1.toPattern(true) + ", " + set2.toPattern(true));
2157         }
2158
2159         if (isContained != (intersection.equals(set1))) {
2160             errln("FAIL isContained2" + set1.toPattern(true) + ", " + set2.toPattern(true));
2161         }
2162
2163         if ((contains && isContained) != equals) {
2164             errln("FAIL equals" + set1.toPattern(true) + ", " + set2.toPattern(true));
2165         }
2166
2167         if (disjoint != (intersection.size() == 0)) {
2168             errln("FAIL disjoint" + set1.toPattern(true) + ", " + set2.toPattern(true));
2169         }
2170
2171         // Now see if the expected relation is true
2172         int status = (minus12.size() != 0 ? 4 : 0)
2173         | (intersection.size() != 0 ? 2 : 0)
2174         | (minus21.size() != 0 ? 1 : 0);
2175
2176         if (status != relation) {
2177             errln("FAIL relation incorrect" + message
2178                     + "; desired = " + RELATION_NAME[relation]
2179                                                      + "; found = " + RELATION_NAME[status]
2180                                                                                     + "; set1 = " + set1.toPattern(true)
2181                                                                                     + "; set2 = " + set2.toPattern(true)
2182             );
2183         }
2184     }
2185
2186     /**
2187      * Basic consistency check for a few items.
2188      * That the iterator works, and that we can create a pattern and
2189      * get the same thing back
2190      */
2191
2192     void checkRoundTrip(UnicodeSet s) {
2193         String pat = s.toPattern(false);
2194         UnicodeSet t = copyWithIterator(s, false);
2195         checkEqual(s, t, "iterator roundtrip");
2196
2197         t = copyWithIterator(s, true); // try range
2198         checkEqual(s, t, "iterator roundtrip");
2199
2200         t = new UnicodeSet(pat);
2201         checkEqual(s, t, "toPattern(false)");
2202
2203         pat = s.toPattern(true);
2204         t = new UnicodeSet(pat);
2205         checkEqual(s, t, "toPattern(true)");
2206     }
2207
2208     UnicodeSet copyWithIterator(UnicodeSet s, boolean withRange) {
2209         UnicodeSet t = new UnicodeSet();
2210         UnicodeSetIterator it = new UnicodeSetIterator(s);
2211         if (withRange) {
2212             while (it.nextRange()) {
2213                 if (it.codepoint == UnicodeSetIterator.IS_STRING) {
2214                     t.add(it.string);
2215                 } else {
2216                     t.add(it.codepoint, it.codepointEnd);
2217                 }
2218             }
2219         } else {
2220             while (it.next()) {
2221                 if (it.codepoint == UnicodeSetIterator.IS_STRING) {
2222                     t.add(it.string);
2223                 } else {
2224                     t.add(it.codepoint);
2225                 }
2226             }
2227         }
2228         return t;
2229     }
2230
2231     boolean checkEqual(UnicodeSet s, UnicodeSet t, String message) {
2232         if (!s.equals(t)) {
2233             errln("FAIL " + message
2234                     + "; source = " + s.toPattern(true)
2235                     + "; result = " + t.toPattern(true)
2236             );
2237             return false;
2238         }
2239         return true;
2240     }
2241
2242     void expectEqual(String name, String pat1, String pat2) {
2243         UnicodeSet set1, set2;
2244         try {
2245             set1 = new UnicodeSet(pat1);
2246             set2 = new UnicodeSet(pat2);
2247         } catch (IllegalArgumentException e) {
2248             errln("FAIL: Couldn't create UnicodeSet from pattern for \"" + name + "\": " + e.getMessage());
2249             return;
2250         }
2251         if(!set1.equals(set2)) {
2252             errln("FAIL: Sets built from patterns differ for \"" + name + "\"");
2253         }
2254     }
2255
2256     /**
2257      * Expect the given set to contain the characters in charsIn and
2258      * to not contain those in charsOut.
2259      */
2260     void expectContainment(String pat, String charsIn, String charsOut) {
2261         UnicodeSet set;
2262         try {
2263             set = new UnicodeSet(pat);
2264         } catch (IllegalArgumentException e) {
2265             errln("FAIL: Couldn't create UnicodeSet from pattern \"" +
2266                     pat + "\": " + e.getMessage());
2267             return;
2268         }
2269         expectContainment(set, charsIn, charsOut);
2270     }
2271
2272     /**
2273      * Expect the given set to contain the characters in charsIn and
2274      * to not contain those in charsOut.
2275      */
2276     void expectContainment(UnicodeSet set, String charsIn, String charsOut) {
2277         StringBuffer bad = new StringBuffer();
2278         if (charsIn != null) {
2279             charsIn = Utility.unescape(charsIn);
2280             for (int i=0; i<charsIn.length(); ) {
2281                 int c = UTF16.charAt(charsIn,i);
2282                 i += UTF16.getCharCount(c);
2283                 if (!set.contains(c)) {
2284                     UTF16.append(bad,c);
2285                 }
2286             }
2287             if (bad.length() > 0) {
2288                 errln(Utility.escape("FAIL: set " + set + " does not contain " + bad +
2289                         ", expected containment of " + charsIn));
2290             } else {
2291                 logln(Utility.escape("Ok: set " + set + " contains " + charsIn));
2292             }
2293         }
2294         if (charsOut != null) {
2295             charsOut = Utility.unescape(charsOut);
2296             bad.setLength(0);
2297             for (int i=0; i<charsOut.length(); ) {
2298                 int c = UTF16.charAt(charsOut,i);
2299                 i += UTF16.getCharCount(c);
2300                 if (set.contains(c)) {
2301                     UTF16.append(bad, c);
2302                 }
2303             }
2304             if (bad.length() > 0) {
2305                 errln(Utility.escape("FAIL: set " + set + " contains " + bad +
2306                         ", expected non-containment of " + charsOut));
2307             } else {
2308                 logln(Utility.escape("Ok: set " + set + " does not contain " + charsOut));
2309             }
2310         }
2311     }
2312
2313     void expectPattern(UnicodeSet set,
2314             String pattern,
2315             String expectedPairs) {
2316         set.applyPattern(pattern);
2317         if (!getPairs(set).equals(expectedPairs)) {
2318             errln("FAIL: applyPattern(\"" + pattern +
2319                     "\") => pairs \"" +
2320                     Utility.escape(getPairs(set)) + "\", expected \"" +
2321                     Utility.escape(expectedPairs) + "\"");
2322         } else {
2323             logln("Ok:   applyPattern(\"" + pattern +
2324                     "\") => pairs \"" +
2325                     Utility.escape(getPairs(set)) + "\"");
2326         }
2327     }
2328
2329     void expectToPattern(UnicodeSet set,
2330             String expPat,
2331             String[] expStrings) {
2332         String pat = set.toPattern(true);
2333         if (pat.equals(expPat)) {
2334             logln("Ok:   toPattern() => \"" + pat + "\"");
2335         } else {
2336             errln("FAIL: toPattern() => \"" + pat + "\", expected \"" + expPat + "\"");
2337             return;
2338         }
2339         if (expStrings == null) {
2340             return;
2341         }
2342         boolean in = true;
2343         for (int i=0; i<expStrings.length; ++i) {
2344             if (expStrings[i] == NOT) { // sic; pointer comparison
2345                 in = false;
2346                 continue;
2347             }
2348             boolean contained = set.contains(expStrings[i]);
2349             if (contained == in) {
2350                 logln("Ok: " + expPat + 
2351                         (contained ? " contains {" : " does not contain {") +
2352                         Utility.escape(expStrings[i]) + "}");
2353             } else {
2354                 errln("FAIL: " + expPat + 
2355                         (contained ? " contains {" : " does not contain {") +
2356                         Utility.escape(expStrings[i]) + "}");
2357             }
2358         }
2359     }
2360
2361     void expectPairs(UnicodeSet set, String expectedPairs) {
2362         if (!getPairs(set).equals(expectedPairs)) {
2363             errln("FAIL: Expected pair list \"" +
2364                     Utility.escape(expectedPairs) + "\", got \"" +
2365                     Utility.escape(getPairs(set)) + "\"");
2366         }
2367     }
2368     static final String CharsToUnicodeString(String s) {
2369         return Utility.unescape(s);
2370     }
2371
2372     /* Test the method public UnicodeSet getSet() */
2373     public void TestGetSet() {
2374         UnicodeSetIterator us = new UnicodeSetIterator();
2375         try {
2376             us.getSet();
2377         } catch (Exception e) {
2378             errln("UnicodeSetIterator.getSet() was not suppose to given an " + "an exception.");
2379         }
2380     }
2381     
2382     /* Tests the method public UnicodeSet add(Collection<?> source) */
2383     public void TestAddCollection() {
2384         UnicodeSet us = new UnicodeSet();
2385         Collection<?> s = null;
2386         try {
2387             us.add(s);
2388             errln("UnicodeSet.add(Collection<?>) was suppose to return an exception for a null parameter.");
2389         } catch (Exception e) {
2390         }
2391     }
2392     
2393     public void TestConstants() {
2394         assertEquals("Empty", new UnicodeSet(), UnicodeSet.EMPTY);
2395         assertEquals("All", new UnicodeSet(0,0x10FFFF), UnicodeSet.ALL_CODE_POINTS);
2396     }
2397 }