| /* |
| ******************************************************************************* |
| * Copyright (C) 1996-2009, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| */ |
| package com.ibm.icu.dev.test.util; |
| |
| import java.text.NumberFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Random; |
| import java.util.Set; |
| import java.util.SortedSet; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| |
| import com.ibm.icu.dev.test.TestBoilerplate; |
| import com.ibm.icu.dev.test.TestFmwk; |
| import com.ibm.icu.impl.Utility; |
| import com.ibm.icu.lang.UCharacter; |
| import com.ibm.icu.lang.UProperty; |
| import com.ibm.icu.text.UnicodeSet; |
| |
| public class TestUtilities extends TestFmwk { |
| static final int LIMIT = 0x15; // limit to make testing more realistic in terms of collisions |
| static final int ITERATIONS = 1000000; |
| static final boolean SHOW_PROGRESS = false; |
| static final boolean DEBUG = false; |
| |
| public static void main(String[] args) throws Exception { |
| new TestUtilities().run(args); |
| } |
| |
| UnicodeMap map1 = new UnicodeMap(); |
| Map map2 = new HashMap(); |
| Map map3 = new TreeMap(); |
| SortedSet log = new TreeSet(); |
| static String[] TEST_VALUES = {null, "A", "B", "C", "D", "E", "F"}; |
| static Random random = new Random(12345); |
| |
| public void TestUnicodeMap() { |
| random.setSeed(12345); |
| // do random change to both, then compare |
| logln("Comparing against HashMap"); |
| for (int counter = 0; counter < ITERATIONS; ++counter) { |
| int start = random.nextInt(LIMIT); |
| String value = TEST_VALUES[random.nextInt(TEST_VALUES.length)]; |
| String logline = Utility.hex(start) + "\t" + value; |
| if (SHOW_PROGRESS) logln(counter + "\t" + logline); |
| log.add(logline); |
| if (DEBUG && counter == 144) { |
| System.out.println(" debug"); |
| } |
| map1.put(start, value); |
| map2.put(new Integer(start), value); |
| check(counter); |
| } |
| checkNext(LIMIT); |
| |
| logln("Setting General Category"); |
| map1 = new UnicodeMap(); |
| map2 = new TreeMap(); |
| for (int cp = 0; cp <= SET_LIMIT; ++cp) { |
| int enumValue = UCharacter.getIntPropertyValue(cp, propEnum); |
| //if (enumValue <= 0) continue; // for smaller set |
| String value = UCharacter.getPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG); |
| map1.put(cp, value); |
| map2.put(new Integer(cp), value); |
| } |
| checkNext(Integer.MAX_VALUE); |
| |
| |
| logln("Comparing General Category"); |
| check(-1); |
| logln("Comparing Values"); |
| Set values1 = (Set) map1.getAvailableValues(new TreeSet()); |
| Set values2 = new TreeSet(map2.values()); |
| if (!TestBoilerplate.verifySetsIdentical(this, values1, values2)) { |
| throw new IllegalArgumentException("Halting"); |
| } |
| logln("Comparing Sets"); |
| for (Iterator it = values1.iterator(); it.hasNext();) { |
| Object value = it.next(); |
| logln(value == null ? "null" : value.toString()); |
| UnicodeSet set1 = map1.keySet(value); |
| UnicodeSet set2 = TestBoilerplate.getSet(map2, value); |
| if (!TestBoilerplate.verifySetsIdentical(this, set1, set2)) { |
| throw new IllegalArgumentException("Halting"); |
| } |
| } |
| |
| logln("Getting Scripts"); |
| UnicodeMap scripts = ICUPropertyFactory.make().getProperty("script").getUnicodeMap_internal(); |
| UnicodeMap.Composer composer = new UnicodeMap.Composer() { |
| public Object compose(int codepoint, String string, Object a, Object b) { |
| return a.toString() + "_" + b.toString(); |
| } |
| }; |
| |
| logln("Trying Compose"); |
| UnicodeMap composed = ((UnicodeMap)scripts.cloneAsThawed()).composeWith(map1, composer); |
| Object last = ""; |
| for (int i = 0; i < 0x10FFFF; ++i) { |
| Object comp = composed.getValue(i); |
| Object gc = map1.getValue(i); |
| Object sc = scripts.getValue(i); |
| if (!comp.equals(composer.compose(i, null, gc, sc))) { |
| errln("Failed compose at: " + i); |
| } |
| if (!last.equals(comp)) { |
| logln(Utility.hex(i) + "\t" + comp); |
| last = comp; |
| } |
| } |
| |
| // check boilerplate |
| List argList = new ArrayList(); |
| argList.add("TestMain"); |
| if (params.nothrow) argList.add("-nothrow"); |
| if (params.verbose) argList.add("-verbose"); |
| String[] args = new String[argList.size()]; |
| argList.toArray(args); |
| new UnicodeMapBoilerplate().run(args); |
| // TODO: the following is not being reached |
| new UnicodeSetBoilerplate().run(args); |
| } |
| |
| public void TestCollectionUtilitySpeed() { |
| TreeSet ts1 = new TreeSet(); |
| TreeSet ts2 = new TreeSet(); |
| int size = 1000; |
| int iterations = 1000; |
| String prefix = "abc"; |
| String postfix = "nop"; |
| for (int i = 0; i < size; ++i) { |
| ts1.add(prefix + String.valueOf(i) + postfix); |
| ts2.add(prefix + String.valueOf(i) + postfix); |
| } |
| // warm up |
| CollectionUtilities.containsAll(ts1, ts2); |
| ts1.containsAll(ts2); |
| |
| timeAndCompare(ts1, ts2, iterations, true, .75); |
| // now different sets |
| ts1.add("Able"); |
| timeAndCompare(ts1, ts2, iterations, true, .75); |
| timeAndCompare(ts2, ts1, iterations*100, false, 1.05); |
| } |
| |
| private void timeAndCompare(TreeSet ts1, TreeSet ts2, int iterations, boolean expected, double factorOfStandard) { |
| double utilityTimeSorted = timeUtilityContainsAll(iterations, ts1, ts2, expected)/(double)iterations; |
| double standardTimeSorted = timeStandardContainsAll(iterations, ts1, ts2, expected)/(double)iterations; |
| |
| if (utilityTimeSorted < standardTimeSorted*factorOfStandard) { |
| logln("Sorted: Utility time (" + utilityTimeSorted + ") << Standard duration (" + standardTimeSorted + "); " + 100*(utilityTimeSorted/standardTimeSorted) + "%"); |
| } else { |
| errln("Sorted: Utility time (" + utilityTimeSorted + ") !<< Standard duration (" + standardTimeSorted + "); " + 100*(utilityTimeSorted/standardTimeSorted) + "%"); |
| } |
| } |
| |
| private long timeStandardContainsAll(int iterations, Set hs1, Set hs2, boolean expected) { |
| long standardTime; |
| { |
| long start, end; |
| boolean temp = false; |
| |
| start = System.currentTimeMillis(); |
| for (int i = 0; i < iterations; ++i) { |
| temp = hs1.containsAll(hs2); |
| if (temp != expected) { |
| errln("Bad result"); |
| } |
| } |
| end = System.currentTimeMillis(); |
| standardTime = end - start; |
| } |
| return standardTime; |
| } |
| |
| private long timeUtilityContainsAll(int iterations, Set hs1, Set hs2, boolean expected) { |
| long utilityTime; |
| { |
| long start, end; |
| boolean temp = false; |
| start = System.currentTimeMillis(); |
| for (int i = 0; i < iterations; ++i) { |
| temp = CollectionUtilities.containsAll(hs1, hs2); |
| if (temp != expected) { |
| errln("Bad result"); |
| } |
| } |
| end = System.currentTimeMillis(); |
| utilityTime = end - start; |
| } |
| return utilityTime; |
| } |
| |
| public void TestCollectionUtilities() { |
| String[][] test = {{"a", "c", "e", "g", "h", "z"}, {"b", "d", "f", "h", "w"}, { "a", "b" }, { "a", "d" }, {"d"}, {}}; // |
| int resultMask = 0; |
| for (int i = 0; i < test.length; ++i) { |
| Collection a = new TreeSet(Arrays.asList(test[i])); |
| for (int j = 0; j < test.length; ++j) { |
| Collection b = new TreeSet(Arrays.asList(test[j])); |
| int relation = CollectionUtilities.getContainmentRelation(a, b); |
| resultMask |= (1 << relation); |
| switch (relation) { |
| case CollectionUtilities.ALL_EMPTY: |
| checkContainment(a.size() == 0 && b.size() == 0, a, relation, b); |
| break; |
| case CollectionUtilities.NOT_A_SUPERSET_B: |
| checkContainment(a.size() == 0 && b.size() != 0, a, relation, b); |
| break; |
| case CollectionUtilities.NOT_A_DISJOINT_B: |
| checkContainment(a.equals(b) && a.size() != 0, a, relation, b); |
| break; |
| case CollectionUtilities.NOT_A_SUBSET_B: |
| checkContainment(a.size() != 0 && b.size() == 0, a, relation, b); |
| break; |
| case CollectionUtilities.A_PROPER_SUBSET_OF_B: |
| checkContainment(b.containsAll(a) && !a.equals(b), a, relation, b); |
| break; |
| case CollectionUtilities.NOT_A_EQUALS_B: |
| checkContainment(!CollectionUtilities.containsSome(a, b) && a.size() != 0 && b.size() != 0, a, relation, b); |
| break; |
| case CollectionUtilities.A_PROPER_SUPERSET_B: |
| checkContainment(a.containsAll(b) && !a.equals(b), a, relation, b); |
| break; |
| case CollectionUtilities.A_PROPER_OVERLAPS_B: |
| checkContainment(!b.containsAll(a) && !a.containsAll(b) && CollectionUtilities.containsSome(a, b), a, relation, b); |
| break; |
| } |
| } |
| } |
| if (resultMask != 0xFF) { |
| String missing = ""; |
| for (int i = 0; i < 8; ++i) { |
| if ((resultMask & (1 << i)) == 0) { |
| if (missing.length() != 0) missing += ", "; |
| missing += RelationName[i]; |
| } |
| } |
| errln("Not all ContainmentRelations checked: " + missing); |
| } |
| } |
| |
| static final String[] RelationName = {"ALL_EMPTY", |
| "NOT_A_SUPERSET_B", |
| "NOT_A_DISJOINT_B", |
| "NOT_A_SUBSET_B", |
| "A_PROPER_SUBSET_OF_B", |
| "A_PROPER_DISJOINT_B", |
| "A_PROPER_SUPERSET_B", |
| "A_PROPER_OVERLAPS_B"}; |
| |
| /** |
| * |
| */ |
| private void checkContainment(boolean c, Collection a, int relation, Collection b) { |
| if (!c) { |
| errln("Fails relation: " + a + " \t" + RelationName[relation] + " \t" + b); |
| } |
| } |
| |
| private void checkNext(int limit) { |
| logln("Comparing nextRange"); |
| UnicodeMapIterator mi = new UnicodeMapIterator(map1); |
| Map localMap = new TreeMap(); |
| while (mi.nextRange()) { |
| logln(Utility.hex(mi.codepoint) + ".." + Utility.hex(mi.codepointEnd) + " => " + mi.value); |
| for (int i = mi.codepoint; i <= mi.codepointEnd; ++i) { |
| if (i >= limit) continue; |
| localMap.put(new Integer(i), mi.value); |
| } |
| } |
| checkMap(map2, localMap); |
| |
| logln("Comparing next"); |
| mi.reset(); |
| localMap = new TreeMap(); |
| Object lastValue = new Object(); |
| while (mi.next()) { |
| if (!UnicodeMap.areEqual(lastValue, mi.value)) { |
| // System.out.println("Change: " + Utility.hex(mi.codepoint) + " => " + mi.value); |
| lastValue = mi.value; |
| } |
| if (mi.codepoint >= limit) continue; |
| localMap.put(new Integer(mi.codepoint), mi.value); |
| } |
| checkMap(map2, localMap); |
| } |
| |
| public void check(int counter) { |
| for (int i = 0; i < LIMIT; ++i) { |
| Object value1 = map1.getValue(i); |
| Object value2 = map2.get(new Integer(i)); |
| if (!UnicodeMap.areEqual(value1, value2)) { |
| errln(counter + " Difference at " + Utility.hex(i) |
| + "\t UnicodeMap: " + value1 |
| + "\t HashMap: " + value2); |
| errln("UnicodeMap: " + map1); |
| errln("Log: " + TestBoilerplate.show(log)); |
| errln("HashMap: " + TestBoilerplate.show(map2)); |
| } |
| } |
| } |
| |
| void checkMap(Map m1, Map m2) { |
| if (m1.equals(m2)) return; |
| StringBuffer buffer = new StringBuffer(); |
| Set m1entries = m1.entrySet(); |
| Set m2entries = m2.entrySet(); |
| getEntries("\r\nIn First, and not Second", m1entries, m2entries, buffer, 20); |
| getEntries("\r\nIn Second, and not First", m2entries, m1entries, buffer, 20); |
| errln(buffer.toString()); |
| } |
| |
| static Comparator ENTRY_COMPARATOR = new Comparator() { |
| public int compare(Object o1, Object o2) { |
| if (o1 == o2) return 0; |
| if (o1 == null) return -1; |
| if (o2 == null) return 1; |
| Map.Entry a = (Map.Entry) o1; |
| Map.Entry b = (Map.Entry) o2; |
| int result = compare2(a.getKey(), b.getKey()); |
| if (result != 0) return result; |
| return compare2(a.getValue(), b.getValue()); |
| } |
| private int compare2(Object o1, Object o2) { |
| if (o1 == o2) return 0; |
| if (o1 == null) return -1; |
| if (o2 == null) return 1; |
| return ((Comparable)o1).compareTo(o2); |
| } |
| }; |
| |
| private void getEntries(String title, Set m1entries, Set m2entries, StringBuffer buffer, int limit) { |
| Set m1_m2 = new TreeSet(ENTRY_COMPARATOR); |
| m1_m2.addAll(m1entries); |
| m1_m2.removeAll(m2entries); |
| buffer.append(title + ": " + m1_m2.size() + "\r\n"); |
| for (Iterator it = m1_m2.iterator(); it.hasNext();) { |
| if (limit-- < 0) return; |
| Map.Entry entry = (Map.Entry) it.next(); |
| buffer.append(entry.getKey()).append(" => ") |
| .append(entry.getValue()).append("\r\n"); |
| } |
| } |
| |
| static final int SET_LIMIT = 0x10FFFF; |
| static final int CHECK_LIMIT = 0xFFFF; |
| static final NumberFormat pf = NumberFormat.getPercentInstance(); |
| static final NumberFormat nf = NumberFormat.getInstance(); |
| |
| public void TestTime() { |
| double hashTime, umTime, icuTime, treeTime; |
| umTime = checkSetTime(20, 0); |
| hashTime = checkSetTime(20, 1); |
| logln("Percentage: " + pf.format(hashTime/umTime)); |
| treeTime = checkSetTime(20, 3); |
| logln("Percentage: " + pf.format(treeTime/umTime)); |
| //logln(map1.toString()); |
| |
| umTime = checkGetTime(1000, 0); |
| hashTime = checkGetTime(1000, 1); |
| logln("Percentage: " + pf.format(hashTime/umTime)); |
| icuTime = checkGetTime(1000, 2); |
| logln("Percentage: " + pf.format(icuTime/umTime)); |
| treeTime = checkGetTime(1000, 3); |
| logln("Percentage: " + pf.format(treeTime/umTime)); |
| } |
| |
| int propEnum = UProperty.GENERAL_CATEGORY; |
| |
| double checkSetTime(int iterations, int type) { |
| _checkSetTime(1,type); |
| double result = _checkSetTime(iterations, type); |
| logln((type == 0 ? "UnicodeMap" : type == 1 ? "HashMap" : type == 2 ? "ICU" : "TreeMap") + "\t" + nf.format(result)); |
| return result; |
| } |
| double _checkSetTime(int iterations, int type) { |
| map1 = new UnicodeMap(); |
| map2 = new HashMap(); |
| System.gc(); |
| double start = System.currentTimeMillis(); |
| for (int j = 0; j < iterations; ++j) |
| for (int cp = 0; cp <= SET_LIMIT; ++cp) { |
| int enumValue = UCharacter.getIntPropertyValue(cp, propEnum); |
| if (enumValue <= 0) continue; // for smaller set |
| String value = UCharacter.getPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG); |
| switch(type) { |
| case 0: map1.put(cp, value); break; |
| case 1: map2.put(new Integer(cp), value); break; |
| case 3: map3.put(new Integer(cp), value); break; |
| } |
| } |
| double end = System.currentTimeMillis(); |
| return (end-start)/1000/iterations; |
| } |
| |
| double checkGetTime(int iterations, int type) { |
| _checkGetTime(1,type); |
| double result = _checkGetTime(iterations, type); |
| logln((type == 0 ? "UnicodeMap" : type == 1 ? "HashMap" : type == 2 ? "ICU" : "TreeMap") + "\t" + nf.format(result)); |
| return result; |
| } |
| double _checkGetTime(int iterations, int type) { |
| System.gc(); |
| double start = System.currentTimeMillis(); |
| for (int j = 0; j < iterations; ++j) |
| for (int cp = 0; cp < CHECK_LIMIT; ++cp) { |
| switch (type) { |
| case 0: map1.getValue(cp); break; |
| case 1: map2.get(new Integer(cp)); break; |
| case 2: |
| int enumValue = UCharacter.getIntPropertyValue(cp, propEnum); |
| //if (enumValue <= 0) continue; |
| UCharacter.getPropertyValueName(propEnum,enumValue, UProperty.NameChoice.LONG); |
| break; |
| case 3: map3.get(new Integer(cp)); break; |
| } |
| } |
| double end = System.currentTimeMillis(); |
| return (end-start)/1000/iterations; |
| } |
| |
| static class UnicodeMapBoilerplate extends TestBoilerplate { |
| |
| /* |
| * @see com.ibm.icu.dev.test.TestBoilerplate#_hasSameBehavior(java.lang.Object, java.lang.Object) |
| */ |
| protected boolean _hasSameBehavior(Object a, Object b) { |
| // we are pretty confident in the equals method, so won't bother with this right now. |
| return true; |
| } |
| |
| /* |
| * @see com.ibm.icu.dev.test.TestBoilerplate#_createTestObject() |
| */ |
| protected boolean _addTestObject(List list) { |
| if (list.size() > 30) return false; |
| UnicodeMap result = new UnicodeMap(); |
| for (int i = 0; i < 50; ++i) { |
| int start = random.nextInt(25); |
| String value = TEST_VALUES[random.nextInt(TEST_VALUES.length)]; |
| result.put(start, value); |
| } |
| list.add(result); |
| return true; |
| } |
| } |
| |
| static class StringBoilerplate extends TestBoilerplate { |
| |
| /* |
| * @see com.ibm.icu.dev.test.TestBoilerplate#_hasSameBehavior(java.lang.Object, java.lang.Object) |
| */ |
| protected boolean _hasSameBehavior(Object a, Object b) { |
| // we are pretty confident in the equals method, so won't bother with this right now. |
| return true; |
| } |
| |
| /* |
| * @see com.ibm.icu.dev.test.TestBoilerplate#_createTestObject() |
| */ |
| protected boolean _addTestObject(List list) { |
| if (list.size() > 31) return false; |
| StringBuffer result = new StringBuffer(); |
| for (int i = 0; i < 10; ++i) { |
| result.append((char)random.nextInt(0xFF)); |
| } |
| list.add(result.toString()); |
| return true; |
| } |
| } |
| |
| static class UnicodeSetBoilerplate extends TestBoilerplate { |
| |
| /* |
| * @see com.ibm.icu.dev.test.TestBoilerplate#_hasSameBehavior(java.lang.Object, java.lang.Object) |
| */ |
| protected boolean _hasSameBehavior(Object a, Object b) { |
| // we are pretty confident in the equals method, so won't bother with this right now. |
| return true; |
| } |
| |
| /* |
| * @see com.ibm.icu.dev.test.TestBoilerplate#_createTestObject() |
| */ |
| protected boolean _addTestObject(List list) { |
| if (list.size() > 32) return false; |
| UnicodeSet result = new UnicodeSet(); |
| for (int i = 0; i < 50; ++i) { |
| result.add(random.nextInt(100)); |
| } |
| list.add(result.toString()); |
| return true; |
| } |
| } |
| |
| } |