mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 08:53:20 +00:00
ICU-3842 fix ModuleTest
X-SVN-Rev: 19891
This commit is contained in:
parent
b1b20ec190
commit
14f3f13cd7
5 changed files with 605 additions and 973 deletions
|
@ -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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
* <pre>
|
||||
* DataModule:table(nofallback){
|
||||
* Info:table {}
|
||||
* TestData:table {
|
||||
* entry_name:table{
|
||||
* Info:table{}
|
||||
* Settings:array{}
|
||||
* Headers:array{}
|
||||
* Cases:array{}
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* 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 + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TestData>
|
||||
*/
|
||||
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<DataMap>
|
||||
*/
|
||||
public Iterator getSettingsIterator();
|
||||
/**
|
||||
* @return Iterator<DataMap>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue