2 *******************************************************************************
3 * Copyright (C) 1996-2012, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
7 package com.ibm.icu.dev.test.util;
9 import java.text.NumberFormat;
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collection;
13 import java.util.Comparator;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
18 import java.util.Random;
20 import java.util.SortedSet;
21 import java.util.TreeMap;
22 import java.util.TreeSet;
24 import com.ibm.icu.dev.test.TestBoilerplate;
25 import com.ibm.icu.dev.test.TestFmwk;
26 import com.ibm.icu.dev.util.CollectionUtilities;
27 import com.ibm.icu.dev.util.ICUPropertyFactory;
28 import com.ibm.icu.dev.util.UnicodeMap;
29 import com.ibm.icu.dev.util.UnicodeMapIterator;
30 import com.ibm.icu.impl.Utility;
31 import com.ibm.icu.lang.UCharacter;
32 import com.ibm.icu.lang.UProperty;
33 import com.ibm.icu.text.UnicodeSet;
35 public class TestUtilities extends TestFmwk {
36 static final int LIMIT = 0x15; // limit to make testing more realistic in terms of collisions
37 static final int ITERATIONS = 1000000;
38 static final boolean SHOW_PROGRESS = false;
39 static final boolean DEBUG = false;
41 public static void main(String[] args) throws Exception {
42 new TestUtilities().run(args);
45 UnicodeMap map1 = new UnicodeMap();
46 Map map2 = new HashMap();
47 Map map3 = new TreeMap();
48 SortedSet log = new TreeSet();
49 static String[] TEST_VALUES = {null, "A", "B", "C", "D", "E", "F"};
50 static Random random = new Random(12345);
52 public void TestUnicodeMap() {
53 random.setSeed(12345);
54 // do random change to both, then compare
55 logln("Comparing against HashMap");
56 for (int counter = 0; counter < ITERATIONS; ++counter) {
57 int start = random.nextInt(LIMIT);
58 String value = TEST_VALUES[random.nextInt(TEST_VALUES.length)];
59 String logline = Utility.hex(start) + "\t" + value;
60 if (SHOW_PROGRESS) logln(counter + "\t" + logline);
62 if (DEBUG && counter == 144) {
63 System.out.println(" debug");
65 map1.put(start, value);
66 map2.put(new Integer(start), value);
71 logln("Setting General Category");
72 map1 = new UnicodeMap();
74 for (int cp = 0; cp <= SET_LIMIT; ++cp) {
75 int enumValue = UCharacter.getIntPropertyValue(cp, propEnum);
76 //if (enumValue <= 0) continue; // for smaller set
77 String value = UCharacter.getPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG);
79 map2.put(new Integer(cp), value);
81 checkNext(Integer.MAX_VALUE);
84 logln("Comparing General Category");
86 logln("Comparing Values");
87 Set values1 = (Set) map1.getAvailableValues(new TreeSet());
88 Set values2 = new TreeSet(map2.values());
89 if (!TestBoilerplate.verifySetsIdentical(this, values1, values2)) {
90 throw new IllegalArgumentException("Halting");
92 logln("Comparing Sets");
93 for (Iterator it = values1.iterator(); it.hasNext();) {
94 Object value = it.next();
95 logln(value == null ? "null" : value.toString());
96 UnicodeSet set1 = map1.keySet(value);
97 UnicodeSet set2 = TestBoilerplate.getSet(map2, value);
98 if (!TestBoilerplate.verifySetsIdentical(this, set1, set2)) {
99 throw new IllegalArgumentException("Halting");
103 logln("Getting Scripts");
104 UnicodeMap scripts = ICUPropertyFactory.make().getProperty("script").getUnicodeMap_internal();
105 UnicodeMap.Composer composer = new UnicodeMap.Composer() {
106 public Object compose(int codepoint, String string, Object a, Object b) {
107 return a.toString() + "_" + b.toString();
111 logln("Trying Compose");
112 UnicodeMap composed = ((UnicodeMap)scripts.cloneAsThawed()).composeWith(map1, composer);
114 for (int i = 0; i < 0x10FFFF; ++i) {
115 Object comp = composed.getValue(i);
116 Object gc = map1.getValue(i);
117 Object sc = scripts.getValue(i);
118 if (!comp.equals(composer.compose(i, null, gc, sc))) {
119 errln("Failed compose at: " + i);
121 if (!last.equals(comp)) {
122 logln(Utility.hex(i) + "\t" + comp);
128 List argList = new ArrayList();
129 argList.add("TestMain");
130 if (params.nothrow) argList.add("-nothrow");
131 if (params.verbose) argList.add("-verbose");
132 String[] args = new String[argList.size()];
133 argList.toArray(args);
134 new UnicodeMapBoilerplate().run(args);
135 // TODO: the following is not being reached
136 new UnicodeSetBoilerplate().run(args);
139 public void TestCollectionUtilitySpeed() {
140 TreeSet ts1 = new TreeSet();
141 TreeSet ts2 = new TreeSet();
143 int iterations = 1000;
144 String prefix = "abc";
145 String postfix = "nop";
146 for (int i = 0; i < size; ++i) {
147 ts1.add(prefix + String.valueOf(i) + postfix);
148 ts2.add(prefix + String.valueOf(i) + postfix);
151 CollectionUtilities.containsAll(ts1, ts2);
152 ts1.containsAll(ts2);
154 timeAndCompare(ts1, ts2, iterations, true, .75);
155 // now different sets
157 timeAndCompare(ts1, ts2, iterations, true, .75);
158 timeAndCompare(ts2, ts1, iterations*100, false, 1.05);
161 private void timeAndCompare(TreeSet ts1, TreeSet ts2, int iterations, boolean expected, double factorOfStandard) {
162 double utilityTimeSorted = timeUtilityContainsAll(iterations, ts1, ts2, expected)/(double)iterations;
163 double standardTimeSorted = timeStandardContainsAll(iterations, ts1, ts2, expected)/(double)iterations;
165 if (utilityTimeSorted < standardTimeSorted*factorOfStandard) {
166 logln("Sorted: Utility time (" + utilityTimeSorted + ") << Standard duration (" + standardTimeSorted + "); " + 100*(utilityTimeSorted/standardTimeSorted) + "%");
168 errln("Sorted: Utility time (" + utilityTimeSorted + ") !<< Standard duration (" + standardTimeSorted + "); " + 100*(utilityTimeSorted/standardTimeSorted) + "%");
172 private long timeStandardContainsAll(int iterations, Set hs1, Set hs2, boolean expected) {
176 boolean temp = false;
178 start = System.currentTimeMillis();
179 for (int i = 0; i < iterations; ++i) {
180 temp = hs1.containsAll(hs2);
181 if (temp != expected) {
185 end = System.currentTimeMillis();
186 standardTime = end - start;
191 private long timeUtilityContainsAll(int iterations, Set hs1, Set hs2, boolean expected) {
195 boolean temp = false;
196 start = System.currentTimeMillis();
197 for (int i = 0; i < iterations; ++i) {
198 temp = CollectionUtilities.containsAll(hs1, hs2);
199 if (temp != expected) {
203 end = System.currentTimeMillis();
204 utilityTime = end - start;
209 public void TestCollectionUtilities() {
210 String[][] test = {{"a", "c", "e", "g", "h", "z"}, {"b", "d", "f", "h", "w"}, { "a", "b" }, { "a", "d" }, {"d"}, {}}; //
212 for (int i = 0; i < test.length; ++i) {
213 Collection a = new TreeSet(Arrays.asList(test[i]));
214 for (int j = 0; j < test.length; ++j) {
215 Collection b = new TreeSet(Arrays.asList(test[j]));
216 int relation = CollectionUtilities.getContainmentRelation(a, b);
217 resultMask |= (1 << relation);
219 case CollectionUtilities.ALL_EMPTY:
220 checkContainment(a.size() == 0 && b.size() == 0, a, relation, b);
222 case CollectionUtilities.NOT_A_SUPERSET_B:
223 checkContainment(a.size() == 0 && b.size() != 0, a, relation, b);
225 case CollectionUtilities.NOT_A_DISJOINT_B:
226 checkContainment(a.equals(b) && a.size() != 0, a, relation, b);
228 case CollectionUtilities.NOT_A_SUBSET_B:
229 checkContainment(a.size() != 0 && b.size() == 0, a, relation, b);
231 case CollectionUtilities.A_PROPER_SUBSET_OF_B:
232 checkContainment(b.containsAll(a) && !a.equals(b), a, relation, b);
234 case CollectionUtilities.NOT_A_EQUALS_B:
235 checkContainment(!CollectionUtilities.containsSome(a, b) && a.size() != 0 && b.size() != 0, a, relation, b);
237 case CollectionUtilities.A_PROPER_SUPERSET_B:
238 checkContainment(a.containsAll(b) && !a.equals(b), a, relation, b);
240 case CollectionUtilities.A_PROPER_OVERLAPS_B:
241 checkContainment(!b.containsAll(a) && !a.containsAll(b) && CollectionUtilities.containsSome(a, b), a, relation, b);
246 if (resultMask != 0xFF) {
248 for (int i = 0; i < 8; ++i) {
249 if ((resultMask & (1 << i)) == 0) {
250 if (missing.length() != 0) missing += ", ";
251 missing += RelationName[i];
254 errln("Not all ContainmentRelations checked: " + missing);
258 static final String[] RelationName = {"ALL_EMPTY",
262 "A_PROPER_SUBSET_OF_B",
263 "A_PROPER_DISJOINT_B",
264 "A_PROPER_SUPERSET_B",
265 "A_PROPER_OVERLAPS_B"};
270 private void checkContainment(boolean c, Collection a, int relation, Collection b) {
272 errln("Fails relation: " + a + " \t" + RelationName[relation] + " \t" + b);
276 private void checkNext(int limit) {
277 logln("Comparing nextRange");
278 UnicodeMapIterator mi = new UnicodeMapIterator(map1);
279 Map localMap = new TreeMap();
280 while (mi.nextRange()) {
281 logln(Utility.hex(mi.codepoint) + ".." + Utility.hex(mi.codepointEnd) + " => " + mi.value);
282 for (int i = mi.codepoint; i <= mi.codepointEnd; ++i) {
283 if (i >= limit) continue;
284 localMap.put(new Integer(i), mi.value);
287 checkMap(map2, localMap);
289 logln("Comparing next");
291 localMap = new TreeMap();
292 Object lastValue = new Object();
294 if (!UnicodeMap.areEqual(lastValue, mi.value)) {
295 // System.out.println("Change: " + Utility.hex(mi.codepoint) + " => " + mi.value);
296 lastValue = mi.value;
298 if (mi.codepoint >= limit) continue;
299 localMap.put(new Integer(mi.codepoint), mi.value);
301 checkMap(map2, localMap);
304 public void check(int counter) {
305 for (int i = 0; i < LIMIT; ++i) {
306 Object value1 = map1.getValue(i);
307 Object value2 = map2.get(new Integer(i));
308 if (!UnicodeMap.areEqual(value1, value2)) {
309 errln(counter + " Difference at " + Utility.hex(i)
310 + "\t UnicodeMap: " + value1
311 + "\t HashMap: " + value2);
312 errln("UnicodeMap: " + map1);
313 errln("Log: " + TestBoilerplate.show(log));
314 errln("HashMap: " + TestBoilerplate.show(map2));
319 void checkMap(Map m1, Map m2) {
320 if (m1.equals(m2)) return;
321 StringBuffer buffer = new StringBuffer();
322 Set m1entries = m1.entrySet();
323 Set m2entries = m2.entrySet();
324 getEntries("\r\nIn First, and not Second", m1entries, m2entries, buffer, 20);
325 getEntries("\r\nIn Second, and not First", m2entries, m1entries, buffer, 20);
326 errln(buffer.toString());
329 static Comparator ENTRY_COMPARATOR = new Comparator() {
330 public int compare(Object o1, Object o2) {
331 if (o1 == o2) return 0;
332 if (o1 == null) return -1;
333 if (o2 == null) return 1;
334 Map.Entry a = (Map.Entry) o1;
335 Map.Entry b = (Map.Entry) o2;
336 int result = compare2(a.getKey(), b.getKey());
337 if (result != 0) return result;
338 return compare2(a.getValue(), b.getValue());
340 private int compare2(Object o1, Object o2) {
341 if (o1 == o2) return 0;
342 if (o1 == null) return -1;
343 if (o2 == null) return 1;
344 return ((Comparable)o1).compareTo(o2);
348 private void getEntries(String title, Set m1entries, Set m2entries, StringBuffer buffer, int limit) {
349 Set m1_m2 = new TreeSet(ENTRY_COMPARATOR);
350 m1_m2.addAll(m1entries);
351 m1_m2.removeAll(m2entries);
352 buffer.append(title + ": " + m1_m2.size() + "\r\n");
353 for (Iterator it = m1_m2.iterator(); it.hasNext();) {
354 if (limit-- < 0) return;
355 Map.Entry entry = (Map.Entry) it.next();
356 buffer.append(entry.getKey()).append(" => ")
357 .append(entry.getValue()).append("\r\n");
361 static final int SET_LIMIT = 0x10FFFF;
362 static final int CHECK_LIMIT = 0xFFFF;
363 static final NumberFormat pf = NumberFormat.getPercentInstance();
364 static final NumberFormat nf = NumberFormat.getInstance();
366 public void TestTime() {
367 double hashTime, umTime, icuTime, treeTime;
368 umTime = checkSetTime(20, 0);
369 hashTime = checkSetTime(20, 1);
370 logln("Percentage: " + pf.format(hashTime/umTime));
371 treeTime = checkSetTime(20, 3);
372 logln("Percentage: " + pf.format(treeTime/umTime));
373 //logln(map1.toString());
375 umTime = checkGetTime(1000, 0);
376 hashTime = checkGetTime(1000, 1);
377 logln("Percentage: " + pf.format(hashTime/umTime));
378 icuTime = checkGetTime(1000, 2);
379 logln("Percentage: " + pf.format(icuTime/umTime));
380 treeTime = checkGetTime(1000, 3);
381 logln("Percentage: " + pf.format(treeTime/umTime));
384 int propEnum = UProperty.GENERAL_CATEGORY;
386 double checkSetTime(int iterations, int type) {
387 _checkSetTime(1,type);
388 double result = _checkSetTime(iterations, type);
389 logln((type == 0 ? "UnicodeMap" : type == 1 ? "HashMap" : type == 2 ? "ICU" : "TreeMap") + "\t" + nf.format(result));
392 double _checkSetTime(int iterations, int type) {
393 map1 = new UnicodeMap();
394 map2 = new HashMap();
396 double start = System.currentTimeMillis();
397 for (int j = 0; j < iterations; ++j)
398 for (int cp = 0; cp <= SET_LIMIT; ++cp) {
399 int enumValue = UCharacter.getIntPropertyValue(cp, propEnum);
400 if (enumValue <= 0) continue; // for smaller set
401 String value = UCharacter.getPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG);
403 case 0: map1.put(cp, value); break;
404 case 1: map2.put(new Integer(cp), value); break;
405 case 3: map3.put(new Integer(cp), value); break;
408 double end = System.currentTimeMillis();
409 return (end-start)/1000/iterations;
412 double checkGetTime(int iterations, int type) {
413 _checkGetTime(1,type);
414 double result = _checkGetTime(iterations, type);
415 logln((type == 0 ? "UnicodeMap" : type == 1 ? "HashMap" : type == 2 ? "ICU" : "TreeMap") + "\t" + nf.format(result));
418 double _checkGetTime(int iterations, int type) {
420 double start = System.currentTimeMillis();
421 for (int j = 0; j < iterations; ++j)
422 for (int cp = 0; cp < CHECK_LIMIT; ++cp) {
424 case 0: map1.getValue(cp); break;
425 case 1: map2.get(new Integer(cp)); break;
427 int enumValue = UCharacter.getIntPropertyValue(cp, propEnum);
428 //if (enumValue <= 0) continue;
429 UCharacter.getPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG);
431 case 3: map3.get(new Integer(cp)); break;
434 double end = System.currentTimeMillis();
435 return (end-start)/1000/iterations;
438 static class UnicodeMapBoilerplate extends TestBoilerplate {
441 * @see com.ibm.icu.dev.test.TestBoilerplate#_hasSameBehavior(java.lang.Object, java.lang.Object)
443 protected boolean _hasSameBehavior(Object a, Object b) {
444 // we are pretty confident in the equals method, so won't bother with this right now.
449 * @see com.ibm.icu.dev.test.TestBoilerplate#_createTestObject()
451 protected boolean _addTestObject(List list) {
452 if (list.size() > 30) return false;
453 UnicodeMap result = new UnicodeMap();
454 for (int i = 0; i < 50; ++i) {
455 int start = random.nextInt(25);
456 String value = TEST_VALUES[random.nextInt(TEST_VALUES.length)];
457 result.put(start, value);
464 static class StringBoilerplate extends TestBoilerplate {
467 * @see com.ibm.icu.dev.test.TestBoilerplate#_hasSameBehavior(java.lang.Object, java.lang.Object)
469 protected boolean _hasSameBehavior(Object a, Object b) {
470 // we are pretty confident in the equals method, so won't bother with this right now.
475 * @see com.ibm.icu.dev.test.TestBoilerplate#_createTestObject()
477 protected boolean _addTestObject(List list) {
478 if (list.size() > 31) return false;
479 StringBuffer result = new StringBuffer();
480 for (int i = 0; i < 10; ++i) {
481 result.append((char)random.nextInt(0xFF));
483 list.add(result.toString());
488 static class UnicodeSetBoilerplate extends TestBoilerplate {
491 * @see com.ibm.icu.dev.test.TestBoilerplate#_hasSameBehavior(java.lang.Object, java.lang.Object)
493 protected boolean _hasSameBehavior(Object a, Object b) {
494 // we are pretty confident in the equals method, so won't bother with this right now.
499 * @see com.ibm.icu.dev.test.TestBoilerplate#_createTestObject()
501 protected boolean _addTestObject(List list) {
502 if (list.size() > 32) return false;
503 UnicodeSet result = new UnicodeSet();
504 for (int i = 0; i < 50; ++i) {
505 result.add(random.nextInt(100));
507 list.add(result.toString());