2 *******************************************************************************
\r
3 * Copyright (C) 1996-2009, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.dev.test.util;
\r
9 import java.text.NumberFormat;
\r
10 import java.util.ArrayList;
\r
11 import java.util.Arrays;
\r
12 import java.util.Collection;
\r
13 import java.util.Comparator;
\r
14 import java.util.HashMap;
\r
15 import java.util.Iterator;
\r
16 import java.util.List;
\r
17 import java.util.Map;
\r
18 import java.util.Random;
\r
19 import java.util.Set;
\r
20 import java.util.SortedSet;
\r
21 import java.util.TreeMap;
\r
22 import java.util.TreeSet;
\r
24 import com.ibm.icu.dev.test.TestBoilerplate;
\r
25 import com.ibm.icu.dev.test.TestFmwk;
\r
26 import com.ibm.icu.impl.Utility;
\r
27 import com.ibm.icu.lang.UCharacter;
\r
28 import com.ibm.icu.lang.UProperty;
\r
29 import com.ibm.icu.text.UnicodeSet;
\r
31 public class TestUtilities extends TestFmwk {
\r
32 static final int LIMIT = 0x15; // limit to make testing more realistic in terms of collisions
\r
33 static final int ITERATIONS = 1000000;
\r
34 static final boolean SHOW_PROGRESS = false;
\r
35 static final boolean DEBUG = false;
\r
37 public static void main(String[] args) throws Exception {
\r
38 new TestUtilities().run(args);
\r
41 UnicodeMap map1 = new UnicodeMap();
\r
42 Map map2 = new HashMap();
\r
43 Map map3 = new TreeMap();
\r
44 SortedSet log = new TreeSet();
\r
45 static String[] TEST_VALUES = {null, "A", "B", "C", "D", "E", "F"};
\r
46 static Random random = new Random(12345);
\r
48 public void TestUnicodeMap() {
\r
49 random.setSeed(12345);
\r
50 // do random change to both, then compare
\r
51 logln("Comparing against HashMap");
\r
52 for (int counter = 0; counter < ITERATIONS; ++counter) {
\r
53 int start = random.nextInt(LIMIT);
\r
54 String value = TEST_VALUES[random.nextInt(TEST_VALUES.length)];
\r
55 String logline = Utility.hex(start) + "\t" + value;
\r
56 if (SHOW_PROGRESS) logln(counter + "\t" + logline);
\r
58 if (DEBUG && counter == 144) {
\r
59 System.out.println(" debug");
\r
61 map1.put(start, value);
\r
62 map2.put(new Integer(start), value);
\r
67 logln("Setting General Category");
\r
68 map1 = new UnicodeMap();
\r
69 map2 = new TreeMap();
\r
70 for (int cp = 0; cp <= SET_LIMIT; ++cp) {
\r
71 int enumValue = UCharacter.getIntPropertyValue(cp, propEnum);
\r
72 //if (enumValue <= 0) continue; // for smaller set
\r
73 String value = UCharacter.getPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG);
\r
74 map1.put(cp, value);
\r
75 map2.put(new Integer(cp), value);
\r
77 checkNext(Integer.MAX_VALUE);
\r
80 logln("Comparing General Category");
\r
82 logln("Comparing Values");
\r
83 Set values1 = (Set) map1.getAvailableValues(new TreeSet());
\r
84 Set values2 = new TreeSet(map2.values());
\r
85 if (!TestBoilerplate.verifySetsIdentical(this, values1, values2)) {
\r
86 throw new IllegalArgumentException("Halting");
\r
88 logln("Comparing Sets");
\r
89 for (Iterator it = values1.iterator(); it.hasNext();) {
\r
90 Object value = it.next();
\r
91 logln(value == null ? "null" : value.toString());
\r
92 UnicodeSet set1 = map1.keySet(value);
\r
93 UnicodeSet set2 = TestBoilerplate.getSet(map2, value);
\r
94 if (!TestBoilerplate.verifySetsIdentical(this, set1, set2)) {
\r
95 throw new IllegalArgumentException("Halting");
\r
99 logln("Getting Scripts");
\r
100 UnicodeMap scripts = ICUPropertyFactory.make().getProperty("script").getUnicodeMap_internal();
\r
101 UnicodeMap.Composer composer = new UnicodeMap.Composer() {
\r
102 public Object compose(int codepoint, String string, Object a, Object b) {
\r
103 return a.toString() + "_" + b.toString();
\r
107 logln("Trying Compose");
\r
108 UnicodeMap composed = ((UnicodeMap)scripts.cloneAsThawed()).composeWith(map1, composer);
\r
110 for (int i = 0; i < 0x10FFFF; ++i) {
\r
111 Object comp = composed.getValue(i);
\r
112 Object gc = map1.getValue(i);
\r
113 Object sc = scripts.getValue(i);
\r
114 if (!comp.equals(composer.compose(i, null, gc, sc))) {
\r
115 errln("Failed compose at: " + i);
\r
117 if (!last.equals(comp)) {
\r
118 logln(Utility.hex(i) + "\t" + comp);
\r
123 // check boilerplate
\r
124 List argList = new ArrayList();
\r
125 argList.add("TestMain");
\r
126 if (params.nothrow) argList.add("-nothrow");
\r
127 if (params.verbose) argList.add("-verbose");
\r
128 String[] args = new String[argList.size()];
\r
129 argList.toArray(args);
\r
130 new UnicodeMapBoilerplate().run(args);
\r
131 // TODO: the following is not being reached
\r
132 new UnicodeSetBoilerplate().run(args);
\r
135 public void TestCollectionUtilitySpeed() {
\r
136 TreeSet ts1 = new TreeSet();
\r
137 TreeSet ts2 = new TreeSet();
\r
139 int iterations = 1000;
\r
140 String prefix = "abc";
\r
141 String postfix = "nop";
\r
142 for (int i = 0; i < size; ++i) {
\r
143 ts1.add(prefix + String.valueOf(i) + postfix);
\r
144 ts2.add(prefix + String.valueOf(i) + postfix);
\r
147 CollectionUtilities.containsAll(ts1, ts2);
\r
148 ts1.containsAll(ts2);
\r
150 timeAndCompare(ts1, ts2, iterations, true, .75);
\r
151 // now different sets
\r
153 timeAndCompare(ts1, ts2, iterations, true, .75);
\r
154 timeAndCompare(ts2, ts1, iterations*100, false, 1.05);
\r
157 private void timeAndCompare(TreeSet ts1, TreeSet ts2, int iterations, boolean expected, double factorOfStandard) {
\r
158 double utilityTimeSorted = timeUtilityContainsAll(iterations, ts1, ts2, expected)/(double)iterations;
\r
159 double standardTimeSorted = timeStandardContainsAll(iterations, ts1, ts2, expected)/(double)iterations;
\r
161 if (utilityTimeSorted < standardTimeSorted*factorOfStandard) {
\r
162 logln("Sorted: Utility time (" + utilityTimeSorted + ") << Standard duration (" + standardTimeSorted + "); " + 100*(utilityTimeSorted/standardTimeSorted) + "%");
\r
164 errln("Sorted: Utility time (" + utilityTimeSorted + ") !<< Standard duration (" + standardTimeSorted + "); " + 100*(utilityTimeSorted/standardTimeSorted) + "%");
\r
168 private long timeStandardContainsAll(int iterations, Set hs1, Set hs2, boolean expected) {
\r
172 boolean temp = false;
\r
174 start = System.currentTimeMillis();
\r
175 for (int i = 0; i < iterations; ++i) {
\r
176 temp = hs1.containsAll(hs2);
\r
177 if (temp != expected) {
\r
178 errln("Bad result");
\r
181 end = System.currentTimeMillis();
\r
182 standardTime = end - start;
\r
184 return standardTime;
\r
187 private long timeUtilityContainsAll(int iterations, Set hs1, Set hs2, boolean expected) {
\r
191 boolean temp = false;
\r
192 start = System.currentTimeMillis();
\r
193 for (int i = 0; i < iterations; ++i) {
\r
194 temp = CollectionUtilities.containsAll(hs1, hs2);
\r
195 if (temp != expected) {
\r
196 errln("Bad result");
\r
199 end = System.currentTimeMillis();
\r
200 utilityTime = end - start;
\r
202 return utilityTime;
\r
205 public void TestCollectionUtilities() {
\r
206 String[][] test = {{"a", "c", "e", "g", "h", "z"}, {"b", "d", "f", "h", "w"}, { "a", "b" }, { "a", "d" }, {"d"}, {}}; //
\r
207 int resultMask = 0;
\r
208 for (int i = 0; i < test.length; ++i) {
\r
209 Collection a = new TreeSet(Arrays.asList(test[i]));
\r
210 for (int j = 0; j < test.length; ++j) {
\r
211 Collection b = new TreeSet(Arrays.asList(test[j]));
\r
212 int relation = CollectionUtilities.getContainmentRelation(a, b);
\r
213 resultMask |= (1 << relation);
\r
214 switch (relation) {
\r
215 case CollectionUtilities.ALL_EMPTY:
\r
216 checkContainment(a.size() == 0 && b.size() == 0, a, relation, b);
\r
218 case CollectionUtilities.NOT_A_SUPERSET_B:
\r
219 checkContainment(a.size() == 0 && b.size() != 0, a, relation, b);
\r
221 case CollectionUtilities.NOT_A_DISJOINT_B:
\r
222 checkContainment(a.equals(b) && a.size() != 0, a, relation, b);
\r
224 case CollectionUtilities.NOT_A_SUBSET_B:
\r
225 checkContainment(a.size() != 0 && b.size() == 0, a, relation, b);
\r
227 case CollectionUtilities.A_PROPER_SUBSET_OF_B:
\r
228 checkContainment(b.containsAll(a) && !a.equals(b), a, relation, b);
\r
230 case CollectionUtilities.NOT_A_EQUALS_B:
\r
231 checkContainment(!CollectionUtilities.containsSome(a, b) && a.size() != 0 && b.size() != 0, a, relation, b);
\r
233 case CollectionUtilities.A_PROPER_SUPERSET_B:
\r
234 checkContainment(a.containsAll(b) && !a.equals(b), a, relation, b);
\r
236 case CollectionUtilities.A_PROPER_OVERLAPS_B:
\r
237 checkContainment(!b.containsAll(a) && !a.containsAll(b) && CollectionUtilities.containsSome(a, b), a, relation, b);
\r
242 if (resultMask != 0xFF) {
\r
243 String missing = "";
\r
244 for (int i = 0; i < 8; ++i) {
\r
245 if ((resultMask & (1 << i)) == 0) {
\r
246 if (missing.length() != 0) missing += ", ";
\r
247 missing += RelationName[i];
\r
250 errln("Not all ContainmentRelations checked: " + missing);
\r
254 static final String[] RelationName = {"ALL_EMPTY",
\r
255 "NOT_A_SUPERSET_B",
\r
256 "NOT_A_DISJOINT_B",
\r
258 "A_PROPER_SUBSET_OF_B",
\r
259 "A_PROPER_DISJOINT_B",
\r
260 "A_PROPER_SUPERSET_B",
\r
261 "A_PROPER_OVERLAPS_B"};
\r
266 private void checkContainment(boolean c, Collection a, int relation, Collection b) {
\r
268 errln("Fails relation: " + a + " \t" + RelationName[relation] + " \t" + b);
\r
272 private void checkNext(int limit) {
\r
273 logln("Comparing nextRange");
\r
274 UnicodeMapIterator mi = new UnicodeMapIterator(map1);
\r
275 Map localMap = new TreeMap();
\r
276 while (mi.nextRange()) {
\r
277 logln(Utility.hex(mi.codepoint) + ".." + Utility.hex(mi.codepointEnd) + " => " + mi.value);
\r
278 for (int i = mi.codepoint; i <= mi.codepointEnd; ++i) {
\r
279 if (i >= limit) continue;
\r
280 localMap.put(new Integer(i), mi.value);
\r
283 checkMap(map2, localMap);
\r
285 logln("Comparing next");
\r
287 localMap = new TreeMap();
\r
288 Object lastValue = new Object();
\r
289 while (mi.next()) {
\r
290 if (!UnicodeMap.areEqual(lastValue, mi.value)) {
\r
291 // System.out.println("Change: " + Utility.hex(mi.codepoint) + " => " + mi.value);
\r
292 lastValue = mi.value;
\r
294 if (mi.codepoint >= limit) continue;
\r
295 localMap.put(new Integer(mi.codepoint), mi.value);
\r
297 checkMap(map2, localMap);
\r
300 public void check(int counter) {
\r
301 for (int i = 0; i < LIMIT; ++i) {
\r
302 Object value1 = map1.getValue(i);
\r
303 Object value2 = map2.get(new Integer(i));
\r
304 if (!UnicodeMap.areEqual(value1, value2)) {
\r
305 errln(counter + " Difference at " + Utility.hex(i)
\r
306 + "\t UnicodeMap: " + value1
\r
307 + "\t HashMap: " + value2);
\r
308 errln("UnicodeMap: " + map1);
\r
309 errln("Log: " + TestBoilerplate.show(log));
\r
310 errln("HashMap: " + TestBoilerplate.show(map2));
\r
315 void checkMap(Map m1, Map m2) {
\r
316 if (m1.equals(m2)) return;
\r
317 StringBuffer buffer = new StringBuffer();
\r
318 Set m1entries = m1.entrySet();
\r
319 Set m2entries = m2.entrySet();
\r
320 getEntries("\r\nIn First, and not Second", m1entries, m2entries, buffer, 20);
\r
321 getEntries("\r\nIn Second, and not First", m2entries, m1entries, buffer, 20);
\r
322 errln(buffer.toString());
\r
325 static Comparator ENTRY_COMPARATOR = new Comparator() {
\r
326 public int compare(Object o1, Object o2) {
\r
327 if (o1 == o2) return 0;
\r
328 if (o1 == null) return -1;
\r
329 if (o2 == null) return 1;
\r
330 Map.Entry a = (Map.Entry) o1;
\r
331 Map.Entry b = (Map.Entry) o2;
\r
332 int result = compare2(a.getKey(), b.getKey());
\r
333 if (result != 0) return result;
\r
334 return compare2(a.getValue(), b.getValue());
\r
336 private int compare2(Object o1, Object o2) {
\r
337 if (o1 == o2) return 0;
\r
338 if (o1 == null) return -1;
\r
339 if (o2 == null) return 1;
\r
340 return ((Comparable)o1).compareTo(o2);
\r
344 private void getEntries(String title, Set m1entries, Set m2entries, StringBuffer buffer, int limit) {
\r
345 Set m1_m2 = new TreeSet(ENTRY_COMPARATOR);
\r
346 m1_m2.addAll(m1entries);
\r
347 m1_m2.removeAll(m2entries);
\r
348 buffer.append(title + ": " + m1_m2.size() + "\r\n");
\r
349 for (Iterator it = m1_m2.iterator(); it.hasNext();) {
\r
350 if (limit-- < 0) return;
\r
351 Map.Entry entry = (Map.Entry) it.next();
\r
352 buffer.append(entry.getKey()).append(" => ")
\r
353 .append(entry.getValue()).append("\r\n");
\r
357 static final int SET_LIMIT = 0x10FFFF;
\r
358 static final int CHECK_LIMIT = 0xFFFF;
\r
359 static final NumberFormat pf = NumberFormat.getPercentInstance();
\r
360 static final NumberFormat nf = NumberFormat.getInstance();
\r
362 public void TestTime() {
\r
363 double hashTime, umTime, icuTime, treeTime;
\r
364 umTime = checkSetTime(20, 0);
\r
365 hashTime = checkSetTime(20, 1);
\r
366 logln("Percentage: " + pf.format(hashTime/umTime));
\r
367 treeTime = checkSetTime(20, 3);
\r
368 logln("Percentage: " + pf.format(treeTime/umTime));
\r
369 //logln(map1.toString());
\r
371 umTime = checkGetTime(1000, 0);
\r
372 hashTime = checkGetTime(1000, 1);
\r
373 logln("Percentage: " + pf.format(hashTime/umTime));
\r
374 icuTime = checkGetTime(1000, 2);
\r
375 logln("Percentage: " + pf.format(icuTime/umTime));
\r
376 treeTime = checkGetTime(1000, 3);
\r
377 logln("Percentage: " + pf.format(treeTime/umTime));
\r
380 int propEnum = UProperty.GENERAL_CATEGORY;
\r
382 double checkSetTime(int iterations, int type) {
\r
383 _checkSetTime(1,type);
\r
384 double result = _checkSetTime(iterations, type);
\r
385 logln((type == 0 ? "UnicodeMap" : type == 1 ? "HashMap" : type == 2 ? "ICU" : "TreeMap") + "\t" + nf.format(result));
\r
388 double _checkSetTime(int iterations, int type) {
\r
389 map1 = new UnicodeMap();
\r
390 map2 = new HashMap();
\r
392 double start = System.currentTimeMillis();
\r
393 for (int j = 0; j < iterations; ++j)
\r
394 for (int cp = 0; cp <= SET_LIMIT; ++cp) {
\r
395 int enumValue = UCharacter.getIntPropertyValue(cp, propEnum);
\r
396 if (enumValue <= 0) continue; // for smaller set
\r
397 String value = UCharacter.getPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG);
\r
399 case 0: map1.put(cp, value); break;
\r
400 case 1: map2.put(new Integer(cp), value); break;
\r
401 case 3: map3.put(new Integer(cp), value); break;
\r
404 double end = System.currentTimeMillis();
\r
405 return (end-start)/1000/iterations;
\r
408 double checkGetTime(int iterations, int type) {
\r
409 _checkGetTime(1,type);
\r
410 double result = _checkGetTime(iterations, type);
\r
411 logln((type == 0 ? "UnicodeMap" : type == 1 ? "HashMap" : type == 2 ? "ICU" : "TreeMap") + "\t" + nf.format(result));
\r
414 double _checkGetTime(int iterations, int type) {
\r
416 double start = System.currentTimeMillis();
\r
417 for (int j = 0; j < iterations; ++j)
\r
418 for (int cp = 0; cp < CHECK_LIMIT; ++cp) {
\r
420 case 0: map1.getValue(cp); break;
\r
421 case 1: map2.get(new Integer(cp)); break;
\r
423 int enumValue = UCharacter.getIntPropertyValue(cp, propEnum);
\r
424 //if (enumValue <= 0) continue;
\r
425 UCharacter.getPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG);
\r
427 case 3: map3.get(new Integer(cp)); break;
\r
430 double end = System.currentTimeMillis();
\r
431 return (end-start)/1000/iterations;
\r
434 static class UnicodeMapBoilerplate extends TestBoilerplate {
\r
437 * @see com.ibm.icu.dev.test.TestBoilerplate#_hasSameBehavior(java.lang.Object, java.lang.Object)
\r
439 protected boolean _hasSameBehavior(Object a, Object b) {
\r
440 // we are pretty confident in the equals method, so won't bother with this right now.
\r
445 * @see com.ibm.icu.dev.test.TestBoilerplate#_createTestObject()
\r
447 protected boolean _addTestObject(List list) {
\r
448 if (list.size() > 30) return false;
\r
449 UnicodeMap result = new UnicodeMap();
\r
450 for (int i = 0; i < 50; ++i) {
\r
451 int start = random.nextInt(25);
\r
452 String value = TEST_VALUES[random.nextInt(TEST_VALUES.length)];
\r
453 result.put(start, value);
\r
460 static class StringBoilerplate extends TestBoilerplate {
\r
463 * @see com.ibm.icu.dev.test.TestBoilerplate#_hasSameBehavior(java.lang.Object, java.lang.Object)
\r
465 protected boolean _hasSameBehavior(Object a, Object b) {
\r
466 // we are pretty confident in the equals method, so won't bother with this right now.
\r
471 * @see com.ibm.icu.dev.test.TestBoilerplate#_createTestObject()
\r
473 protected boolean _addTestObject(List list) {
\r
474 if (list.size() > 31) return false;
\r
475 StringBuffer result = new StringBuffer();
\r
476 for (int i = 0; i < 10; ++i) {
\r
477 result.append((char)random.nextInt(0xFF));
\r
479 list.add(result.toString());
\r
484 static class UnicodeSetBoilerplate extends TestBoilerplate {
\r
487 * @see com.ibm.icu.dev.test.TestBoilerplate#_hasSameBehavior(java.lang.Object, java.lang.Object)
\r
489 protected boolean _hasSameBehavior(Object a, Object b) {
\r
490 // we are pretty confident in the equals method, so won't bother with this right now.
\r
495 * @see com.ibm.icu.dev.test.TestBoilerplate#_createTestObject()
\r
497 protected boolean _addTestObject(List list) {
\r
498 if (list.size() > 32) return false;
\r
499 UnicodeSet result = new UnicodeSet();
\r
500 for (int i = 0; i < 50; ++i) {
\r
501 result.add(random.nextInt(100));
\r
503 list.add(result.toString());
\r