diff --git a/icu4j/src/com/ibm/icu/dev/test/ModuleTest.java b/icu4j/src/com/ibm/icu/dev/test/ModuleTest.java index 8708568fce1..6390af9dc40 100644 --- a/icu4j/src/com/ibm/icu/dev/test/ModuleTest.java +++ b/icu4j/src/com/ibm/icu/dev/test/ModuleTest.java @@ -8,108 +8,84 @@ package com.ibm.icu.dev.test; import java.lang.reflect.Method; import java.util.Iterator; -import java.util.List; -import com.ibm.icu.dev.test.TestDataModule.TestData; import com.ibm.icu.dev.test.TestDataModule.DataMap; +import com.ibm.icu.dev.test.TestDataModule.DataModuleFormatError; +import com.ibm.icu.dev.test.TestDataModule.Factory; +import com.ibm.icu.dev.test.TestDataModule.TestData; /** - * A convenience extension of TestFmwk for use by data module-driven - * tests. Tests can implement this if they make extensive use of - * information in a TestDataModule. The module should be openable - * using TestDataModule.open() passing in the class name of this test - * + "Data". For example, a test named MyTest would have a module - * named MyTestData. Each test method should also have a - * corresponding test data in the module whose name matches the test - * method name. - * - * Subclasses can allow for test methods that don't use data from the - * modeul by overriding validateMethod to return true for these - * methods. Tests are also free to instantiate their own modules and - * run from them, though care should be taken not to interfere with - * the methods in this class. - * - * See ModuleTestSample for an example. */ -public class ModuleTest extends TestFmwk { + * Ray: An adapter class for TestDataMoule to make it like TestFmwk + * + * A convenience extension of TestFmwk for use by data module-driven tests. + * + * Tests can implement this if they make extensive use of information in a + * TestDataModule. + * + * The module should be openable using TestDataModule.open() passing in the + * class name of this test + "Data". For example, a test named MyTest would have + * a module named MyTestData. Each test method should also have a corresponding + * test data in the module whose name matches the test method name. + * + * Subclasses can allow for test methods that don't use data from the modeul by + * overriding validateMethod to return true for these methods. Tests are also + * free to instantiate their own modules and run from them, though care should + * be taken not to interfere with the methods in this class. + * + * See ModuleTestSample for an example. + */ +public abstract class ModuleTest extends TestFmwk { private TestDataModule m; - private TestData t; - private String methodName; - - protected ModuleTest() { - this(null); - } - - /** - * Pass the name of a public no-arg method in this class if - * you want use that method to run all the tests off the - * data, otherwise pass null for the typical test behavior. - */ - protected ModuleTest(String methodName) { - this.methodName = methodName; - } - - /** - * Subclasses access this after calling nextSettings and getting - * a true result. - */ - protected DataMap settings; - - /** - * Subclasses access this after calling nextCase and getting a - * true result. - */ - protected DataMap testcase; - - + protected TestData t; + + abstract protected void processModules(); + protected Target getTargets(String targetName) { - if (methodName != null && params.doMethods()) { + if (params.doMethods()) { Target target = null; - List list = getModuleNames(); - if (list != null) { + if (!validate()) { + return null; + } + Iterator testData = m.getTestDataIterator(); + if (testData != null) { try { - Method method = getClass().getMethod(methodName, null); - Iterator i = list.iterator(); - while (i.hasNext()) { - target = new MethodTarget((String)i.next(), method).setNext(target); + Method method = getClass().getMethod("processModules", null); + while (testData.hasNext()) { + target = new MethodTarget(((TestData)testData.next()).getName(), method).setNext(target); } } catch (Exception e) { + e.printStackTrace(); throw new IllegalStateException(e.getMessage()); } } return target; - } - - return super.getTargets(targetName); - } - - /* - * If we were initialized with the name of a method to run the - * data driven tests, drive tests off the data using that method. - protected Map getAvailableTests() { - if (methodName != null) { - List list = getModuleNames(); - - if (list != null) { - Map map = new HashMap(list.size()); - addNamedMethodToMap(list, methodName, map); - return map; - } - return Collections.EMPTY_MAP; } else { - return super.getAvailableTests(); + return null; } } - */ /** + * * TestFmwk calls this before trying to run a suite of tests. * The test suite if valid if a module whose name is the name of * this class + "Data" can be opened. Subclasses can override * this if there are different or additional data required. */ protected boolean validate() { - return openModule(getClass().getName()+"Data"); + t = null; + String n = getClass().getName(); + String localename = "DataDriven" + n.substring(n.lastIndexOf('.') + 1); + String baseName = "com/ibm/icu/dev/data/testdata/"; + + try { + //m = Factory.get(getClass().getName()+"Data", this); + m = Factory.get(baseName, localename); + } catch (DataModuleFormatError e) { + e.printStackTrace(); + m = null; + } + return m != null; } /** @@ -130,7 +106,7 @@ public class ModuleTest extends TestFmwk { protected String getDescription() { DataMap info = moduleInfo(); if (info != null) { - return info.getString(TestDataModule.DESCRIPTION); +// return info.getString(TestDataModule.DESCRIPTION); } return null; } @@ -143,72 +119,31 @@ public class ModuleTest extends TestFmwk { if (openTestData(methodName)) { DataMap info = testInfo(); if (info != null) { - return info.getString(TestDataModule.DESCRIPTION); +// return info.getString(TestDataModule.DESCRIPTION); } } return null; } - /** - * Opens the module with the given name, and return true if success. - * All contents are reset. - */ - protected boolean openModule(String name) { - t = null; - m = TestDataModule.open(name, this); - return m != null; - } - /** * Open the test data in the module with the given name, and return * true if success. The current test is reset. + * @throws DataModuleFormatError */ - protected boolean openTestData(String name) { - t = m == null ? null : m.createTestData(name); + protected boolean openTestData(String name){ + try { + t = m == null ? null : m.getTestData(name); + } catch (DataModuleFormatError e) { + return false; + } return t != null; } - - /** - * Return an unmodifiable List of the names of all the tests in the module. - */ - protected List getModuleNames() { - if (validate()) { - return m.getTestDataNames(); - } - return null; - } - - /** - * Utility that associates a public named function in this class - * with all the names in the provided Set. The function should be - * public and take no parameters (like a TestXXX method). You can - * use this to override getAvailableTests from TestFmwk, which by - * default associates the names TestXXX or testXXX with - * the corresponding methods in the class. ModuleTests may wish - * to use a single method to drive all the tests in the module. - * - * @param names the names to associated with the named method. - * @param methodName the name of the method in this class to associate with names - * @param dest the map to hold the name->method mapping - protected void addNamedMethodToMap(List names, String methodName, Map dest) { - try { - Method method = getClass().getMethod(methodName, null); - Iterator i = names.iterator(); - while (i.hasNext()) { - dest.put(i.next(), method); - } - } - catch (Exception e) { - throw new IllegalStateException(e.getMessage()); - } - } - */ /** * Get information on this module. Returns null if no module * open or no info for the module. */ - protected DataMap moduleInfo() { + private DataMap moduleInfo() { return m == null ? null : m.getInfo(); } @@ -216,53 +151,15 @@ public class ModuleTest extends TestFmwk { * Get information on this test. Returns null if no module * open or no test open or not info for this test. */ - protected DataMap testInfo() { + private DataMap testInfo() { return t == null ? null : t.getInfo(); } - /** - * Advance test to the next settings, and return true if - * there are more settings. The protected member variable - * 'settings' holds the new settings data. - */ - protected boolean nextSettings() { - settings = t == null ? null : t.nextSettings(); - return settings != null; - } - - /** - * Advance test to the next case, and return true if there - * is another case. The protected member variable - * 'testcase' holds the new case data. - */ - protected boolean nextCase() { - testcase = t == null ? null : t.nextCase(); - return testcase != null; - } - public void msg(String message, int level, boolean incCount, boolean newln) { if (level == ERR && t != null) { - t.stopIteration(); +// t.stopIteration(); } super.msg(message, level, incCount, newln); } - /** - * Report an error, and stop iteration of the current test. - public void err(String message) { - if (t != null) { - t.stopIteration(); - } - super.err(message); - } - - /** - * Report an error, and stop iteration of the current test. - public void errln(String message) { - if (t != null) { - t.stopIteration(); - } - super.errln(message); - } - */ } diff --git a/icu4j/src/com/ibm/icu/dev/test/ResourceModule.java b/icu4j/src/com/ibm/icu/dev/test/ResourceModule.java index 858a2e2d3c1..58fa73512a2 100644 --- a/icu4j/src/com/ibm/icu/dev/test/ResourceModule.java +++ b/icu4j/src/com/ibm/icu/dev/test/ResourceModule.java @@ -1,605 +1,388 @@ -/** - ******************************************************************************* - * Copyright (C) 2001-2004, International Business Machines Corporation and * - * others. All Rights Reserved. * - ******************************************************************************* +/* + ********************************************************************** + * Copyright (c) 2006, International Business Machines + * Corporation and others. All Rights Reserved. + ********************************************************************** + * Created on 2006-4-21 */ package com.ibm.icu.dev.test; import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.ResourceBundle; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.NoSuchElementException; + +import com.ibm.icu.impl.ICUResourceBundle; +import com.ibm.icu.impl.ICUResourceBundleIterator; +import com.ibm.icu.util.UResourceBundle; +import com.ibm.icu.util.UResourceTypeMismatchException; /** - * Resource-based module. + * Represents a collection of test data described in a UResourceBoundle file. + * + * The root of the UResourceBoundle file is a table resource, and it has one + * Info and one TestData sub-resources. The Info describes the data module + * itself. The TestData, which is a table resource, has a collection of test + * data. + * + * The test data is a named table resource which has Info, Settings, Headers, + * and Cases sub-resources. + * + *
+ * DataModule:table(nofallback){ 
+ *   Info:table {} 
+ *   TestData:table {
+ *     entry_name:table{
+ *       Info:table{}
+ *       Settings:array{}
+ *       Headers:array{}
+ *       Cases:array{}
+ *     }
+ *   } 
+ * }
+ * 
+ * + * The test data is expected to be fed to test code by following sequence + * + * for each setting in Setting{ + * prepare the setting + * for each test data in Cases{ + * perform the test + * } + * } + * + * For detail of the specification, please refer to the code. The code is + * initially ported from "icu4c/source/tools/ctestfw/unicode/tstdtmod.h" + * and should be maintained parallelly. + * + * @author Raymond Yang */ -public class ResourceModule extends TestDataModule { - private NamedArray tests; - private RBDataMap info; - private String[] defaultHeaders; +class ResourceModule implements TestDataModule { + private static final String INFO = "Info"; +// private static final String DESCRIPTION = "Description"; +// private static final String LONG_DESCRIPTION = "LongDescription"; + private static final String TEST_DATA = "TestData"; + private static final String SETTINGS = "Settings"; + private static final String HEADER = "Headers"; + private static final String DATA = "Cases"; - /** - * For internal use. - */ - static final String TESTS = "TestData"; - - /** - * For internal use. - */ - static final String INFO = "Info"; - - /** - * For internal use. - */ - static final String SETTINGS = "Settings"; - - /** - * For internal use. - */ - static final String CASES = "Cases"; - - public ResourceModule(String name, TestLog log, ResourceBundle b) { - super(name, log); - - if (b == null) { - log.errln("ResourceModule must have non-null bundle"); - return; - } - - Object[][] data = (Object[][])b.getObject(TESTS); - if (data == null) { - log.errln("ResourceModule does not contain tests!"); - return; - } - this.tests = NamedArray.create(data); - - Object[][] temp = (Object[][])b.getObject(INFO); - if (temp != null) { - NamedArray na = NamedArray.create(temp); - if (na.count() < 0) { - log.errln("Bad data for " + INFO); - } else { - this.info = new RBDataMap(log, na, false); - this.defaultHeaders = info.getStringArray(HEADERS); + + ICUResourceBundle res; + ICUResourceBundle info; + ICUResourceBundle defaultHeader; + ICUResourceBundle testData; + + ResourceModule(String baseName, String localeName) throws DataModuleFormatError{ + try{ + res = (ICUResourceBundle) UResourceBundle.getBundleInstance(baseName, localeName); + info = getFromTable(res, INFO, ICUResourceBundle.TABLE); + testData = getFromTable(res, TEST_DATA, ICUResourceBundle.TABLE); + } catch (MissingResourceException e){ + throw new DataModuleFormatError("Unable to find resource", e); + } + try { + // unfortunately, actually, data can be either ARRAY or STRING + defaultHeader = getFromTable(info, HEADER, new int[]{ICUResourceBundle.ARRAY, ICUResourceBundle.STRING}); + } catch (MissingResourceException e){ + defaultHeader = null; } } + + public String getName() { + return res.getKey(); } - /** - * Get additional data related to the module. - * Returns true if successfully got info. - */ public DataMap getInfo() { - return info; + return new UTableResource(info); + } + + public TestData getTestData(String testName) throws DataModuleFormatError { + return new UResourceTestData(defaultHeader, testData.get(testName)); + } + + public Iterator getTestDataIterator() { + return new IteratorAdapter(testData){ + protected Object prepareNext(ICUResourceBundle nextRes) throws DataModuleFormatError { + return new UResourceTestData(defaultHeader, nextRes); + } + }; } /** - * Returns the Test object corresponding to name, - * or null if name not found in this module. + * To make ICUResourceBundleIterator works like Iterator + * and return various data-driven test object for next() call + * + * @author Raymond Yang */ - public TestData createTestData(String name) { - if (tests != null) { - Object[] td = tests.getEntry(name); - if (td != null) { - return createTestData(td); + private abstract static class IteratorAdapter implements Iterator{ + private ICUResourceBundle res; + private ICUResourceBundleIterator itr; + private Object preparedNextElement = null; + // fix a strange behavior for ICUResourceBundleIterator for + // ICUResourceBundle.STRING. It support hasNext(), but does + // not support next() now. + // + // Use the iterated resource itself as the result from next() call + private boolean isStrRes = false; + private boolean isStrResPrepared = false; // for STRING resouce, we only prepare once + + IteratorAdapter(ICUResourceBundle theRes) { + assert_not (theRes == null); + res = theRes; + itr = res.getIterator(); + isStrRes = res.getType() == ICUResourceBundle.STRING; } - } - - return null; - } - - /** - * Returns the Test object corresponding to index, - * or null if index is out of range for this module. - * No error logged if index is out of bounds, the assumption is that - * iteration is being used and proceeds until a null return. - */ - public TestData createTestData(int index) { - if (tests != null) { - Object[] td = tests.getEntry(index); - if (td != null) { - return createTestData(td); + + public void remove() { + // do nothing } - } - return null; - } - /** - * Return an unmodifiable list of the test data names, in index order. - */ - public List getTestDataNames() { - if (tests != null) { - return Collections.unmodifiableList(Arrays.asList(tests.names())); + private boolean hasNextForStrRes(){ + assert_is (isStrRes); + assert_not (!isStrResPrepared && preparedNextElement != null); + if (isStrResPrepared && preparedNextElement != null) return true; + if (isStrResPrepared && preparedNextElement == null) return false; // only prepare once + assert_is (!isStrResPrepared && preparedNextElement == null); + + try { + preparedNextElement = prepareNext(res); + assert_not (preparedNextElement == null, "prepareNext() should not return null"); + isStrResPrepared = true; // toggle the tag + return true; + } catch (DataModuleFormatError e) { + throw new RuntimeException(e.getMessage(),e); + } } - return null; - } + public boolean hasNext() { + if (isStrRes) return hasNextForStrRes(); + + if (preparedNextElement != null) return true; + ICUResourceBundle t = null; + if (itr.hasNext()) { + // Notice, other RuntimeException may be throwed + t = itr.next(); + } else { + return false; + } - private TestData createTestData(Object[] d) { - return new RBTestData(this, (String)d[0], (Object[][])d[1], defaultHeaders); - } - - /** - * Provides access to values either by index or by case-insensitive search on - * the name. Poor man's Map with index. - */ - static abstract class NamedArray { - int txcache; - int count; - - static NamedArray create(Object[][] pairs) { - return new NamedArrayOfPairs(pairs); - } - - static NamedArray create(String[] names, Object[] values) { - return new NamedArrayTwoLists(names, values); - } - - protected NamedArray(int count) { - this.count = count; - } - - public final int count() { - return count; - } - - public final boolean isDefined(String name) { - int ix = nameToIndex(name); - if (ix != -1) { - txcache = (ix == 0 ? count : ix) - 1; - return true; + try { + preparedNextElement = prepareNext(t); + assert_not (preparedNextElement == null, "prepareNext() should not return null"); + return true; + } catch (DataModuleFormatError e) { + // Sadly, we throw RuntimeException also + throw new RuntimeException(e.getMessage(),e); + } } - return false; - } - public final Object[] getEntry(String name) { - return getEntry(nameToIndex(name)); - } - - public final Object getValue(String name) { - return getValue(nameToIndex(name)); + public Object next(){ + if (hasNext()) { + Object t = preparedNextElement; + preparedNextElement = null; + return t; + } else { + throw new NoSuchElementException(); + } + } + /** + * To prepare data-driven test object for next() call, should not return null + */ + abstract protected Object prepareNext(ICUResourceBundle nextRes) throws DataModuleFormatError; } - public final Object[] getEntry(int index) { - if (index >= 0 && index < count) { - return entryAtIndex(index); - } - return null; - } - - public final Object getValue(int index) { - if (index >= 0 && index < count) { - return valueAtIndex(index); - } - return null; - } - - public String[] names() { - if (count > 0) { - String[] result = new String[count]; - for (int i = 0; i < count; ++i) { - result[i] = nameAtIndex(i); - } - return result; - } - return null; - } - - public Object[] values() { - if (count > 0) { - Object[] result = new Object[count]; - for (int i = 0; i < count; ++i) { - result[i] = valueAtIndex(i); - } - return result; - } - return null; - } - - public String toString() { - StringBuffer buf = new StringBuffer(super.toString()); - buf.append("count: " + count + "{"); - for (int i = 0; i < count; ++i) { - buf.append("\n { " + nameAtIndex(i) + ", " + valueAtIndex(i) + " }"); - } - buf.append("}"); - return buf.toString(); - } - - protected int nameToIndex(String name) { - if (name != null && count > 0) { - int i = txcache; - do { - if (++i == count) { - i = 0; - } - if (name.equalsIgnoreCase(nameAtIndex(i))) { - txcache = i; - return i; - } - } while (i != txcache); - } - return -1; - } - - protected Object[] entryAtIndex(int index) { - return new Object[] { nameAtIndex(index), valueAtIndex(index) }; - } - - protected abstract String nameAtIndex(int index); - protected abstract Object valueAtIndex(int index); - } - + /** - * NamedArray implemented using an array of name/value - * pairs, represented by an Object[][]. + * Avoid use Java 1.4 language new assert keyword */ - static final class NamedArrayOfPairs extends NamedArray { - private Object[][] data; - - public NamedArrayOfPairs(Object[][] data) { - super(data == null ? -1 : data.length); - this.data = data; + static void assert_is(boolean eq, String msg){ + if (!eq) throw new Error("test code itself has error: " + msg); } - - protected Object[] entryAtIndex(int index) { - return data[index]; + static void assert_is(boolean eq){ + if (!eq) throw new Error("test code itself has error."); } - - protected String nameAtIndex(int index) { - return (String)data[index][0]; + static void assert_not(boolean eq, String msg){ + assert_is(!eq, msg); } - - protected Object valueAtIndex(int index) { - return data[index][1]; + static void assert_not(boolean eq){ + assert_is(!eq); } - } - + /** - * NamedArray implemented using two arrays, one of String and one of Object. + * Internal helper function to get resource with following add-on + * + * 1. Assert the returned resource is never null. + * 2. Check the type of resource. + * + * The UResourceTypeMismatchException for various get() method is a + * RuntimeException which can be silently bypassed. This behavior is a + * trouble. One purpose of the class is to enforce format checking for + * resource file. We don't want to the exceptions are silently bypassed + * and spreaded to our customer's code. + * + * Notice, the MissingResourceException for get() method is also a + * RuntimeException. The caller functions should avoid sepread the execption + * silently also. The behavior is modified because some resource are + * optional and can be missed. */ - static final class NamedArrayTwoLists extends NamedArray { - String[] names; - Object[] values; + static ICUResourceBundle getFromTable(ICUResourceBundle res, String key, int expResType) throws DataModuleFormatError{ + return getFromTable(res, key, new int[]{expResType}); + } + + static ICUResourceBundle getFromTable(ICUResourceBundle res, String key, int[] expResTypes) throws DataModuleFormatError{ + assert_is (res != null && key != null && res.getType() == ICUResourceBundle.TABLE); + ICUResourceBundle t = res.get(key); + assert_not (t ==null); + int type = t.getType(); + Arrays.sort(expResTypes); + if (Arrays.binarySearch(expResTypes, type) >= 0) { + return t; + } else { + throw new DataModuleFormatError(new UResourceTypeMismatchException("Actual type " + t.getType() + " != expected types " + expResTypes + ".")); + } + } + + /** + * Unfortunately, ICUResourceBundle is unable to treat one string as string array. + * This function return a String[] from ICUResourceBundle, regardless it is an array or a string + */ + static String[] getStringArrayHelper(ICUResourceBundle res, String key) throws DataModuleFormatError{ + ICUResourceBundle t = getFromTable(res, key, new int[]{ICUResourceBundle.ARRAY, ICUResourceBundle.STRING}); + return getStringArrayHelper(t); + } - public NamedArrayTwoLists(String[] names, Object[] values) { - super (values != null && names != null && names.length == values.length ? - names.length : - -1); - this.names = names; - this.values = values; + static String[] getStringArrayHelper(ICUResourceBundle res) throws DataModuleFormatError{ + try{ + int type = res.getType(); + switch (type) { + case ICUResourceBundle.ARRAY: + return res.getStringArray(); + case ICUResourceBundle.STRING: + return new String[]{res.getString()}; + default: + throw new UResourceTypeMismatchException("Only accept ARRAY and STRING types."); + } + } catch (UResourceTypeMismatchException e){ + throw new DataModuleFormatError(e); + } + } + + public static void main(String[] args){ + try { + TestDataModule m = new ResourceModule("com/ibm/icu/dev/data/testdata/","DataDrivenCollationTest"); + System.out.println("hello: " + m.getName()); + m.getInfo(); + m.getTestDataIterator(); + } catch (DataModuleFormatError e) { + // TODO Auto-generated catch block + System.out.println("???"); + e.printStackTrace(); + } + } + + private static class UResourceTestData implements TestData{ + private ICUResourceBundle res; + private ICUResourceBundle info; + private ICUResourceBundle settings; + private ICUResourceBundle header; + private ICUResourceBundle data; + + UResourceTestData(ICUResourceBundle defaultHeader, ICUResourceBundle theRes) throws DataModuleFormatError{ + try{ + assert_is (theRes != null && theRes.getType() == ICUResourceBundle.TABLE); + res = theRes; + // unfortunately, actually, data can be either ARRAY or STRING + data = getFromTable(res, DATA, new int[]{ICUResourceBundle.ARRAY, ICUResourceBundle.STRING}); + } catch (MissingResourceException e){ + throw new DataModuleFormatError("Unable to find resource", e); + } + + try{ + settings = getFromTable(res, SETTINGS, ICUResourceBundle.ARRAY); + info = getFromTable(res, INFO, ICUResourceBundle.TABLE); + } catch (MissingResourceException e){ + // do nothing, left them null; + } + + try { + // unfortunately, actually, data can be either ARRAY or STRING + header = getFromTable(res, HEADER, new int[]{ICUResourceBundle.ARRAY, ICUResourceBundle.STRING}); + } catch (MissingResourceException e){ + if (defaultHeader == null) { + throw new DataModuleFormatError("Unable to find a header for test data '" + res.getKey() + "' and no default header exist."); + } else { + header = defaultHeader; + } + } + } + + public String getName() { + return res.getKey(); + } + + public DataMap getInfo() { + return info == null ? null : new UTableResource(info); + } + + public Iterator getSettingsIterator() { + assert_is (settings.getType() == ICUResourceBundle.ARRAY); + return new IteratorAdapter(settings){ + protected Object prepareNext(ICUResourceBundle nextRes) throws DataModuleFormatError { + return new UTableResource(nextRes); + } + }; + } + + public Iterator getDataIterator() { + // unfortunately, + assert_is (data.getType() == ICUResourceBundle.ARRAY + || data.getType() == ICUResourceBundle.STRING); + return new IteratorAdapter(data){ + protected Object prepareNext(ICUResourceBundle nextRes) throws DataModuleFormatError { + return new UArrayResource(header, nextRes); + } + }; + } } - public String[] names() { - return names; - } + private static class UTableResource implements DataMap{ + private ICUResourceBundle res; - public Object[] values() { - return values; - } - - protected String nameAtIndex(int index) { - return names[index]; - } - - protected Object valueAtIndex(int index) { - return values[index]; - } - } - - static class RBTestData extends TestData { - ResourceModule m; - RBDataMap info; - Object[] settings; - /** - * changed to fit the c genrb format. this is actually Object[] {Object[]} - */ - Object[] cases; - String[] headers; - int sx; - int cx; - - RBTestData(ResourceModule m, String name, Object[][] data, String[] defaultHeaders) { - super(name); - this.m = m; - - NamedArray namedData = NamedArray.create(data); - - try { - Object[][] temp = (Object[][])namedData.getValue(INFO); - if (temp != null) { - NamedArray na = NamedArray.create(temp); - if (na.count() < 1) { - m.log.errln("Bad data for " + INFO); - } else { - this.info = new RBDataMap(m.log, na, false); + UTableResource(ICUResourceBundle theRes){ + res = theRes; + } + public String getString(String key) { + String t; + try{ + t = res.getString(key); + } catch (MissingResourceException e){ + t = null; } + return t; } - } - catch (ClassCastException e) { - m.log.errln("Test " + name + " in module " + m.getName() + " has bad type for " + INFO); - } - - try { - this.settings = (Object[])namedData.getValue(SETTINGS); - } - catch (ClassCastException e) { - m.log.errln("Test " + name + " in module " + m.getName() + " has bad type for " + SETTINGS); - } - - try { - this.cases = (Object[])namedData.getValue(CASES); - } - catch (ClassCastException e) { - m.log.errln("Test " + name + " in module " + m.getName() + " has bad type for " + CASES); - } - - if (info != null) { - this.headers = info.getStringArray(HEADERS); - } - if (this.headers == null) { - this.headers = defaultHeaders; - } - } - - /** - * Get additional data related to the test. - */ - public DataMap getInfo() { - return info; - } - - /** - * Returns DataMap with next settings and resets case iteration. - * If no more settings, terminates iteration and returns null. - */ - public DataMap nextSettings() { - if (settings != null && sx < settings.length) { - cx = 0; - NamedArray na = NamedArray.create((Object[][])settings[sx++]); - if (na.count() < 0) { - m.log.errln("Bad settings data for settings " + (sx-1)); - return null; - } else { - return new RBDataMap(m.log, na, false); - } - } - stopIteration(); - - return null; - } - - /** - * Returns DataMap with next case. If no next case, returns null. - */ - public DataMap nextCase() { - if (cases != null && cx < cases.length) { - NamedArray na = NamedArray.create(headers, (Object[])cases[cx++]); - if (na.count() < 0) { - m.log.errln("Bad cases data for case " + (cx-1)); - } else { - return new RBDataMap(m.log, na, true); - } - } - return null; - } - - /** - * Stops iteration. - */ - public void stopIteration() { - sx = cx = Integer.MAX_VALUE; - } } - static final class RBDataMap extends DataMap { - TestLog log; - NamedArray na; - boolean required; - - RBDataMap(TestLog log, NamedArray na, boolean required) { - this.log = log; - this.na = na; - this.required = required; - } - - public boolean isDefined(String key) { - return na.isDefined(key); - } - - public Object getObject(String key) { - Object result = na.getValue(key); - if (required && result == null) { - reportNullError(key); - } - return result; - } - - public String getString(String key) { - String result = null; - try { - result = (String)getObject(key); - } - catch (ClassCastException e) { - reportTypeError("String", key); - } - return result; - } - - public char getChar(String key) { - try { - String s = getString(key); - if (s != null) { - return s.charAt(0); - } - } - catch (IndexOutOfBoundsException e) { - reportTypeError("char", key); - } - return 0xffff; - } - - public int getInt(String key) { - try { - String s = getString(key); - if (s != null) { - return Integer.parseInt(s); - } - } - catch (NumberFormatException e) { - reportTypeError("int", key); - } - return -1; - } - - public byte getByte(String key) { - try { - String s = getString(key); - if (s != null) { - return Byte.parseByte(s); - } - } - catch (NumberFormatException e) { - reportTypeError("byte", key); - } - return (byte)-1; - } - - public boolean getBoolean(String key) { - String s = getString(key); - if (s != null) { - if (s.equalsIgnoreCase("true")) { - return true; - } else if (!s.equalsIgnoreCase("false")) { - reportTypeError("boolean", key); - } - } - return false; - } - - public Object[] getObjectArray(String key) { - try { - Object[] result = (Object[])na.getValue(key); - if (result == null && required) { - reportNullError(key); - } - } catch (ClassCastException e) { - reportTypeError("Object[]", key); - } - return null; - } - - public String[] getStringArray(String key) { - try { - String[] result = (String[])na.getValue(key); - if (result == null && required) { - reportNullError(key); - } - return result; - } - catch (ClassCastException e) { - reportTypeError("String[]", key); - } - return null; - } - - public char[] getCharArray(String key) { - try { - return (char[])na.getValue(key); + private static class UArrayResource implements DataMap{ + private Map theMap; + UArrayResource(ICUResourceBundle theHeader, ICUResourceBundle theData) throws DataModuleFormatError{ + assert_is (theHeader != null && theData != null); + String[] header; + String[] data; + + header = getStringArrayHelper(theHeader); + data = getStringArrayHelper(theData); + if (data.length != header.length) + throw new DataModuleFormatError("The count of Header and Data is mismatch."); + theMap = new HashMap(); + for (int i = 0; i < header.length; i++) { + theMap.put(header[i], data[i]); } - catch (ClassCastException e) { - } - try{ - String temp = (String)na.getValue(key); - if (temp == null) { - if (required) { - reportNullError(key); - } - } else { - return temp.toCharArray(); + } + + public String getString(String key) { + return (String)theMap.get(key); } - catch (ClassCastException e) { - reportTypeError("char[]", key); - } - return null; - } - - public int[] getIntArray(String key) { - try { - return (int[])na.getValue(key); - } - catch (ClassCastException e) { - } - String[] data = getStringArray(key); - if (data != null) { - try { - int[] result = new int[data.length]; - for (int i = 0; i < data.length; ++i) { - result[i] = Integer.parseInt(data[i]); - } - return result; - } - catch (NumberFormatException e) { - reportTypeError("int[]", key); - } - } - return null; - } - - public byte[] getByteArray(String key) { - try { - return (byte[])na.getValue(key); - } - catch (ClassCastException e) { - } - String[] data = getStringArray(key); - if (data != null) { - try { - byte[] result = new byte[data.length]; - for (int i = 0; i < result.length; ++i) { - result[i] = Byte.parseByte(data[i]); - } - return result; - } - catch (NumberFormatException e) { - reportTypeError("byte[]", key); - } - } - return null; - } - - public boolean[] getBooleanArray(String key) { - try { - return (boolean[])na.getValue(key); - } - catch (ClassCastException e) { - } - String[] data = getStringArray(key); - if (data != null) { - boolean[] result = new boolean[data.length]; - for (int i = 0; i < result.length; ++i) { - String s = data[i]; - if (s.equalsIgnoreCase("true")) { - result[i] = true; - } else if (s.equalsIgnoreCase("false")) { - result[i] = false; - } else { - reportTypeError("boolean[]", key); - return null; - } - } - return result; - } - return null; - } - - private void reportNullError(String key) { - log.errln("Missing required value for '" + key + "'"); - } - - private void reportTypeError(String typeName, String key) { - log.errln("Could not return value of '" + key + "' (" + getObject(key) + ") as type '" + typeName + "'"); - } } } diff --git a/icu4j/src/com/ibm/icu/dev/test/TestDataModule.java b/icu4j/src/com/ibm/icu/dev/test/TestDataModule.java index dd92793fc25..845d5f7bfb4 100644 --- a/icu4j/src/com/ibm/icu/dev/test/TestDataModule.java +++ b/icu4j/src/com/ibm/icu/dev/test/TestDataModule.java @@ -1,166 +1,103 @@ /** ******************************************************************************* - * Copyright (C) 2001-2004, International Business Machines Corporation and * + * Copyright (C) 2001-2006, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ package com.ibm.icu.dev.test; -import java.util.List; -import java.util.ResourceBundle; +import java.util.Iterator; /** * Represents a collection of test data described in a file. + * */ -public abstract class TestDataModule { - protected final String name; - protected final TestLog log; - +public interface TestDataModule { /** - * Looks for file with corresponding name, either xml or resource - * bundle. Returns module or null if not present. + * Return the name of this test data module. */ - static final TestDataModule open(String name, TestLog log) { - ResourceBundle bundle = ResourceBundle.getBundle(name); - if (bundle != null) { - return new ResourceModule(name, log, bundle); - } - return null; - } - - /** - * Subclass constructors call this. - */ - protected TestDataModule(String name, TestLog log) { - this.name = name; - this.log = log; - } - - /** - * Return the name of this test module. - */ - public final String getName() { - return name; - } - - /** - * Return the log used by this module. Errors logged to this - * log will terminate settings and cases iteration for the - * current test. - */ - public final TestLog getLog() { - return log; - } + public String getName(); /** * Get additional data related to the module, e.g. DESCRIPTION, * global settings. Might be null. */ - public abstract DataMap getInfo(); - - /** - * A standard datum that can be found in the DataMap returned by getInfo. - * DESCRIPTION provides a one-line description. The corresponding type - * is a String. - */ - public static final String DESCRIPTION = "Description"; - - /** - * A standard datum that can be found in the DataMap returned by - * getInfo. LONG_DESCRIPTION provides an extended description. - * The corresponding type is a String. - */ - public static final String LONG_DESCRIPTION = "Long_Description"; - - /** - * The names of the columns of test data. This can be found in - * either the module INFO or the test INFO. If the test INFO - * does not define the headers then they are taken from the - * module. If test cases are used by the test, then the headers - * must be defined. Most clients will not need this information, - * since it is handled by the framework. - */ - public static final String HEADERS = "Headers"; - - /** - * Returns the Test object corresponding to index, or null if - * index is out of range for this module. No error logged if - * index is out of bounds, the assumption is that iteration is - * being used. - */ - public abstract TestData createTestData(int index); + public DataMap getInfo(); /** * Returns the TestData corresponding to name, or null if name not - * found in this module. Logs error if name is not found. + * found in this module. Throw error if name is not found. + * @throws DataModuleFormatError */ - public abstract TestData createTestData(String name); + public TestData getTestData(String name) throws DataModuleFormatError; /** - * Return an unmodifiable list of the test data names, in index order. + * @return Iterator */ - public abstract List getTestDataNames(); + public Iterator getTestDataIterator(); + public static class Factory{ + + static final TestDataModule get(String baseName, String localeName) throws DataModuleFormatError { + return new ResourceModule(baseName, localeName); + } + } + + public static class DataModuleFormatError extends Exception{ + public DataModuleFormatError(String msg){ + super(msg); + } + public DataModuleFormatError(String msg, Throwable cause){ + super(msg, cause); + } + public DataModuleFormatError(Throwable cause) { + super(cause); + } + } + /** * Represents a single test in the module. */ - public abstract static class TestData { - String name; - - protected TestData(String name) { - this.name = name; - } - - public final String name() { - return name; + public static interface TestData { + public String getName(); + /** + * Get additional data related to the test data, e.g. DESCRIPTION, + * global settings. Might be null. + */ + public DataMap getInfo(); + /** + * @return Iterator + */ + public Iterator getSettingsIterator(); + /** + * @return Iterator + */ + public Iterator getDataIterator(); } /** - * Get additional data related to the test, e.g. DESCRIPTION, - * LONG_DESCRIPTION, HEADERS, or other test-specific - * information. + * Map-like interface for accessing key-value pairs by key. + * If the vaule is not found by given key, return null. + * The behavior is analogous the get() method of the Map interface. + * + * @author Raymond Yang */ - public abstract DataMap getInfo(); - - /** - * Returns new DataMap for next settings, and resets test case - * iteration. Returns null if no more settings. - */ - public abstract DataMap nextSettings(); - - /** - * Returns new DataMap for next cases. - * Returns null if no more cases. - */ - public abstract DataMap nextCase(); - - /** - * Stops iteration of the test. Usually called if some - * condition detects an error. - */ - public abstract void stopIteration(); - } - - /** - * DataMap provides named access to typed data. Lookup data by - * key and attempt to cast to indicated type. If data not found - * or cast fails, log error and return null. */ - public abstract static class DataMap { - public abstract boolean isDefined(String key); - - public abstract Object getObject(String key); + public interface DataMap { +// public abstract boolean isDefined(String key); +// +// public abstract Object getObject(String key); public abstract String getString(String key); - public abstract char getChar(String key); - public abstract int getInt(String key); - public abstract byte getByte(String key); - public abstract boolean getBoolean(String key); - - public abstract Object[] getObjectArray(String key); - public abstract String[] getStringArray(String key); - public abstract char[] getCharArray(String key); - public abstract int[] getIntArray(String key); - public abstract byte[] getByteArray(String key); - public abstract boolean[] getBooleanArray(String key); +// public abstract char getChar(String key); +// public abstract int getInt(String key); +// public abstract byte getByte(String key); +// public abstract boolean getBoolean(String key); +// +// public abstract Object[] getObjectArray(String key); +// public abstract String[] getStringArray(String key); +// public abstract char[] getCharArray(String key); +// public abstract int[] getIntArray(String key); +// public abstract byte[] getByteArray(String key); +// public abstract boolean[] getBooleanArray(String key); } } diff --git a/icu4j/src/com/ibm/icu/dev/test/collator/CollationTest.java b/icu4j/src/com/ibm/icu/dev/test/collator/CollationTest.java index 67e8b53d674..af585286c5d 100644 --- a/icu4j/src/com/ibm/icu/dev/test/collator/CollationTest.java +++ b/icu4j/src/com/ibm/icu/dev/test/collator/CollationTest.java @@ -1,26 +1,28 @@ /** ******************************************************************************* - * Copyright (C) 2001-2004, International Business Machines Corporation and * + * Copyright (C) 2001-2006, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ package com.ibm.icu.dev.test.collator; -import com.ibm.icu.dev.test.ModuleTest; -import com.ibm.icu.dev.test.TestFmwk; -import com.ibm.icu.text.RuleBasedCollator; -import com.ibm.icu.text.Collator; -import com.ibm.icu.text.CollationKey; -import com.ibm.icu.text.RawCollationKey; -import com.ibm.icu.text.CollationElementIterator; -import com.ibm.icu.text.UTF16; -import com.ibm.icu.lang.UCharacter; -import com.ibm.icu.impl.Utility; -import com.ibm.icu.impl.LocaleUtility; - -import java.util.Vector; +import java.util.Iterator; import java.util.Locale; import java.util.MissingResourceException; +import java.util.Vector; + +import com.ibm.icu.dev.test.ModuleTest; +import com.ibm.icu.dev.test.TestFmwk; +import com.ibm.icu.dev.test.TestDataModule.DataMap; +import com.ibm.icu.impl.LocaleUtility; +import com.ibm.icu.impl.Utility; +import com.ibm.icu.lang.UCharacter; +import com.ibm.icu.text.CollationElementIterator; +import com.ibm.icu.text.CollationKey; +import com.ibm.icu.text.Collator; +import com.ibm.icu.text.RawCollationKey; +import com.ibm.icu.text.RuleBasedCollator; +import com.ibm.icu.text.UTF16; public class CollationTest extends ModuleTest { @@ -35,13 +37,23 @@ public class CollationTest extends ModuleTest }*/ } - public CollationTest() { - super("processModules"); +// public CollationTest() { +// super("processModules"); +// } + + // Want to be static, why super class not? + private class DataDrivenTarget extends TestFmwk.Target{ + public DataDrivenTarget(String name) { + super(name); + } + } + public void processModules() { - while (nextSettings()) { - processTest(); + for (Iterator iter = t.getSettingsIterator(); iter.hasNext();) { + DataMap setting = (DataMap) iter.next(); + processSetting(setting); } } @@ -161,7 +173,7 @@ public class CollationTest extends ModuleTest // private methods ------------------------------------------------------- - private void processTest() { + private void processSetting(DataMap settings) { RuleBasedCollator col = null; // ok i have to be careful here since it seems like we can have // multiple locales for each test @@ -177,7 +189,7 @@ public class CollationTest extends ModuleTest errln("Error creating collator for locale " + locale); } logln("Testing collator for locale %s\n" + locale); - processCollatorTests(col); + processSetting2(settings, col); } String rules = settings.getString("Rules"); // ok i have to be careful here since it seems like we can have @@ -191,26 +203,26 @@ public class CollationTest extends ModuleTest } catch (Exception e) { errln("Error creating collator for rules " + rules); } - processCollatorTests(col); + processSetting2(settings, col); } } - private void processCollatorTests(RuleBasedCollator col) + private void processSetting2(DataMap settings,RuleBasedCollator col) { // ok i have to be careful here since it seems like we can have // multiple rules for each test String arguments = settings.getString("Arguments"); if (arguments != null) { - processArguments(col, arguments); + handleArguments(col, arguments); } - processReadyCollator(col); + processTestCases(col); } /** * Reads the options string and sets appropriate attributes in collator */ - private void processArguments(RuleBasedCollator col, String argument) { + private void handleArguments(RuleBasedCollator col, String argument) { int i = 0; boolean printInfo = false; while (i < argument.length()) { @@ -277,17 +289,11 @@ public class CollationTest extends ModuleTest */ } - private void processReadyCollator(RuleBasedCollator col) { - while (nextCase()) { - // this is very sad, it is alittle awkward to write the c rb - // to have an object array of an object array of a 1 element - // string array. so now we have an object array of a 1 element - // object array of string arrays. - String sequence[] = testcase.getStringArray("sequence"); - for (int i = 0; i < sequence.length; i ++) { - processSequence(col, sequence[i]); - } - } + private void processTestCases(RuleBasedCollator col) { + for (Iterator iter = t.getDataIterator(); iter.hasNext();) { + DataMap e1 = (DataMap) iter.next(); + processSequence(col, e1.getString("sequence")); + } } private void processSequence(RuleBasedCollator col, String sequence) { diff --git a/icu4j/src/com/ibm/icu/dev/test/sample/ModuleTestSample.java b/icu4j/src/com/ibm/icu/dev/test/sample/ModuleTestSample.java index f0cd47a4b2f..01bc6fbb60d 100644 --- a/icu4j/src/com/ibm/icu/dev/test/sample/ModuleTestSample.java +++ b/icu4j/src/com/ibm/icu/dev/test/sample/ModuleTestSample.java @@ -1,6 +1,6 @@ /** ******************************************************************************* - * Copyright (C) 2001-2004, International Business Machines Corporation and * + * Copyright (C) 2001-2006, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ @@ -15,42 +15,43 @@ public class ModuleTestSample extends ModuleTest { new ModuleTestSample().run(args); } - // standard loop, settings and cases - public void Test01() { - while (nextSettings()) { - logln("--------"); - logln("String: " + settings.getString("aString")); - if (settings.isDefined("anInt")) { - logln("Int: " + settings.getInt("anInt")); - } - logln("Boolean: " + settings.getBoolean("aBoolean")); - - while (nextCase()) { - logln(" ----"); - logln(" StringArray: " + printArray(testcase.getStringArray("aStringArray"))); - logln(" IntArray: " + printArray(testcase.getIntArray("anIntArray"))); - logln(" BooleanArray: " + printArray(testcase.getBooleanArray("aBooleanArray"))); - } - } - } - - // loop with just cases - public void Test02() { - while (nextCase()) { - logln("----"); - logln("String: " + testcase.getString("aString")); - logln("Int: " + testcase.getInt("anInt")); - logln("Boolean: " + testcase.getBoolean("aBoolean")); - } - } +// // standard loop, settings and cases +// public void Test01() { +// while (nextSettings()) { +// logln("--------"); +// logln("String: " + settings.getString("aString")); +// if (settings.isDefined("anInt")) { +// logln("Int: " + settings.getInt("anInt")); +// } +// logln("Boolean: " + settings.getBoolean("aBoolean")); +// +// while (nextCase()) { +// logln(" ----"); +// logln(" StringArray: " + printArray(testcase.getStringArray("aStringArray"))); +// logln(" IntArray: " + printArray(testcase.getIntArray("anIntArray"))); +// logln(" BooleanArray: " + printArray(testcase.getBooleanArray("aBooleanArray"))); +// } +// } +// } +// +// // loop with just cases +// public void Test02() { +// while (nextCase()) { +// logln("----"); +// logln("String: " + testcase.getString("aString")); +// logln("Int: " + testcase.getInt("anInt")); +// logln("Boolean: " + testcase.getBoolean("aBoolean")); +// } +// } // no cases, just uses info for test public void Test03() { - DataMap info = testInfo(); - if (info != null) { - logln(info.getString(TestDataModule.DESCRIPTION)); // standard - logln(info.getString("Extra")); // test-specific - } +// DataMap info = testInfo(); +// if (info != null) { +//// logln(info.getString(TestDataModule.DESCRIPTION)); // standard +// logln(info.getString("Extra")); // test-specific +// } +// return; } // no data, ModuleTest should not allow this to execute by default @@ -69,56 +70,56 @@ public class ModuleTestSample extends ModuleTest { logln("Test05 executed."); } - // The test data contains an error in the third case. When getInt("Data") is - // executed the error is logged and iteration stops. - public void Test06() { - while (nextCase()) { - logln("----"); - logln("isGood: " + testcase.getString("IsGood")); - logln(" Data: " + testcase.getInt("Data")); - } - } +// // The test data contains an error in the third case. When getInt("Data") is +// // executed the error is logged and iteration stops. +// public void Test06() { +// while (nextCase()) { +// logln("----"); +// logln("isGood: " + testcase.getString("IsGood")); +// logln(" Data: " + testcase.getInt("Data")); +// } +// } +// +// // The test using the data reports an error, which also automatically stops iteration. +// public void Test07() { +// while (nextSettings()) { +// int value = settings.getInt("Value"); +// while (nextCase()) { +// int factor = testcase.getInt("Factor"); +// float result = (float)value / factor; +// if (result != (int)result) { +// errln("the number '" + factor + "' is not a factor of the number '" + value + "'"); +// } else { +// logln("'" + factor + "' is a factor of '" + value + "'"); +// } +// } +// } +// } - // The test using the data reports an error, which also automatically stops iteration. - public void Test07() { - while (nextSettings()) { - int value = settings.getInt("Value"); - while (nextCase()) { - int factor = testcase.getInt("Factor"); - float result = (float)value / factor; - if (result != (int)result) { - errln("the number '" + factor + "' is not a factor of the number '" + value + "'"); - } else { - logln("'" + factor + "' is a factor of '" + value + "'"); - } - } - } - } - - // The number of data elements is incorrect - public void Test08() { - while (nextCase()) { - int one = testcase.getInt("One"); - int two = testcase.getInt("Two"); - int three = testcase.getInt("Three"); - logln("got: " + one + ", " + two + ", " + three); - } - } - - public void Test09() { - while (nextCase()) { - int radix = testcase.getInt("Radix"); - int[] pow = testcase.getIntArray("Power"); - int[] val = testcase.getIntArray("Value"); - logln("radix: " + radix + " pow: " + printArray(pow) + " val: " + printArray(val)); - for (int i = 0; i < pow.length; ++i) { - if (val[i] != (int)Math.pow(radix, pow[i])) { - errln("radix: " + radix + " to power " + pow[i] + " != " + val[i]); - break; - } - } - } - } +// // The number of data elements is incorrect +// public void Test08() { +// while (nextCase()) { +// int one = testcase.getInt("One"); +// int two = testcase.getInt("Two"); +// int three = testcase.getInt("Three"); +// logln("got: " + one + ", " + two + ", " + three); +// } +// } +// +// public void Test09() { +// while (nextCase()) { +// int radix = testcase.getInt("Radix"); +// int[] pow = testcase.getIntArray("Power"); +// int[] val = testcase.getIntArray("Value"); +// logln("radix: " + radix + " pow: " + printArray(pow) + " val: " + printArray(val)); +// for (int i = 0; i < pow.length; ++i) { +// if (val[i] != (int)Math.pow(radix, pow[i])) { +// errln("radix: " + radix + " to power " + pow[i] + " != " + val[i]); +// break; +// } +// } +// } +// } // utility print functions to display the data from the resource String printArray(String[] a) { @@ -156,4 +157,12 @@ public class ModuleTestSample extends ModuleTest { buf.append(" }"); return buf.toString(); } + + /* (non-Javadoc) + * @see com.ibm.icu.dev.test.ModuleTest#processModules() + */ + protected void processModules() { + // TODO Auto-generated method stub + + } }