2 *******************************************************************************
\r
3 * Copyright (C) 2001-2006, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.dev.test.collator;
\r
9 import java.util.Iterator;
\r
10 import java.util.Locale;
\r
11 import java.util.MissingResourceException;
\r
12 import java.util.Vector;
\r
14 import com.ibm.icu.dev.test.ModuleTest;
\r
15 import com.ibm.icu.dev.test.TestFmwk;
\r
16 import com.ibm.icu.dev.test.TestDataModule.DataMap;
\r
17 import com.ibm.icu.impl.LocaleUtility;
\r
18 import com.ibm.icu.impl.Utility;
\r
19 import com.ibm.icu.lang.UCharacter;
\r
20 import com.ibm.icu.text.CollationElementIterator;
\r
21 import com.ibm.icu.text.CollationKey;
\r
22 import com.ibm.icu.text.Collator;
\r
23 import com.ibm.icu.text.RawCollationKey;
\r
24 import com.ibm.icu.text.RuleBasedCollator;
\r
25 import com.ibm.icu.text.UTF16;
\r
27 public class CollationTest extends ModuleTest{
\r
28 // public methods --------------------------------------------------------
\r
30 public static void main(String[] args) throws Exception{
\r
31 new CollationTest().run(args);
\r
34 public CollationTest() {
\r
35 super("com/ibm/icu/dev/data/testdata/", "DataDrivenCollationTest");
\r
38 public void processModules() {
\r
39 for (Iterator iter = t.getSettingsIterator(); iter.hasNext();) {
\r
40 DataMap setting = (DataMap) iter.next();
\r
41 processSetting(setting);
\r
45 // package private methods ----------------------------------------------
\r
47 static void doTest(TestFmwk test, RuleBasedCollator col, String source,
\r
48 String target, int result)
\r
50 doTestVariant(test, col, source, target, result);
\r
52 doTestVariant(test, col, target, source, 1);
\r
54 else if (result == 1) {
\r
55 doTestVariant(test, col, target, source, -1);
\r
58 doTestVariant(test, col, target, source, 0);
\r
61 CollationElementIterator iter = col.getCollationElementIterator(source);
\r
62 backAndForth(test, iter);
\r
63 iter.setText(target);
\r
64 backAndForth(test, iter);
\r
68 * Return an integer array containing all of the collation orders
\r
69 * returned by calls to next on the specified iterator
\r
71 static int[] getOrders(CollationElementIterator iter)
\r
75 int[] orders = new int[maxSize];
\r
78 while ((order = iter.next()) != CollationElementIterator.NULLORDER) {
\r
79 if (size == maxSize) {
\r
81 int[] temp = new int[maxSize];
\r
82 System.arraycopy(orders, 0, temp, 0, size);
\r
85 orders[size++] = order;
\r
88 if (maxSize > size) {
\r
89 int[] temp = new int[size];
\r
90 System.arraycopy(orders, 0, temp, 0, size);
\r
96 static void backAndForth(TestFmwk test, CollationElementIterator iter)
\r
98 // Run through the iterator forwards and stick it into an array
\r
100 int[] orders = getOrders(iter);
\r
102 // Now go through it backwards and make sure we get the same values
\r
103 int index = orders.length;
\r
106 // reset the iterator
\r
109 while ((o = iter.previous()) != CollationElementIterator.NULLORDER) {
\r
110 if (o != orders[--index]) {
\r
114 while (index > 0 && orders[index] == 0) {
\r
117 if (o != orders[index]) {
\r
118 test.errln("Mismatch at index " + index + ": 0x"
\r
119 + Integer.toHexString(orders[index]) + " vs 0x" + Integer.toHexString(o));
\r
126 while (index != 0 && orders[index - 1] == 0) {
\r
131 String msg = "Didn't get back to beginning - index is ";
\r
132 test.errln(msg + index);
\r
135 test.err("next: ");
\r
136 while ((o = iter.next()) != CollationElementIterator.NULLORDER) {
\r
137 String hexString = "0x" + Integer.toHexString(o) + " ";
\r
138 test.err(hexString);
\r
141 test.err("prev: ");
\r
142 while ((o = iter.previous()) != CollationElementIterator.NULLORDER) {
\r
143 String hexString = "0x" + Integer.toHexString(o) + " ";
\r
144 test.err(hexString);
\r
150 // private data members --------------------------------------------------
\r
152 private String m_sequence_;
\r
153 private int m_sequenceIndex_;
\r
154 private String m_source_;
\r
155 private StringBuffer m_target_ = new StringBuffer();
\r
156 private int m_nextRelation_;
\r
157 private int m_relation_;
\r
159 // private methods -------------------------------------------------------
\r
161 private void processSetting(DataMap settings) {
\r
162 RuleBasedCollator col = null;
\r
163 // ok i have to be careful here since it seems like we can have
\r
164 // multiple locales for each test
\r
165 String locale = settings.getString("TestLocale");
\r
167 if (locale != null) {
\r
168 // this is a case where we have locale
\r
170 Locale l = LocaleUtility.getLocaleFromName(locale);
\r
171 col = (RuleBasedCollator)Collator.getInstance(l);
\r
172 }catch (MissingResourceException e){
\r
173 warnln("Could not load the locale data for locale " + locale);
\r
174 }catch (Exception e) {
\r
175 errln("Error creating collator for locale " + locale);
\r
177 logln("Testing collator for locale " + locale);
\r
178 processSetting2(settings, col);
\r
180 String rules = settings.getString("Rules");
\r
181 // ok i have to be careful here since it seems like we can have
\r
182 // multiple rules for each test
\r
183 if (rules != null) {
\r
184 // here we deal with rules
\r
186 col = new RuleBasedCollator(rules);
\r
187 }catch (MissingResourceException e){
\r
188 warnln("Could not load the locale data: " + e.getMessage());
\r
189 } catch (Exception e) {
\r
190 errln("Error creating collator for rules " + rules);
\r
192 processSetting2(settings, col);
\r
196 private void processSetting2(DataMap settings,RuleBasedCollator col)
\r
199 // ok i have to be careful here since it seems like we can have
\r
200 // multiple rules for each test
\r
201 String arguments = settings.getString("Arguments");
\r
202 if (arguments != null) {
\r
203 handleArguments(col, arguments);
\r
205 processTestCases(col);
\r
209 * Reads the options string and sets appropriate attributes in collator
\r
211 private void handleArguments(RuleBasedCollator col, String argument) {
\r
213 boolean printInfo = false;
\r
214 while (i < argument.length()) {
\r
215 if (!UCharacter.isWhitespace(argument.charAt(i))) {
\r
221 while (i < argument.length()) {
\r
222 // skip opening '['
\r
223 if (argument.charAt(i) == '[') {
\r
227 if(!isModularBuild()){
\r
228 errln("Error in collation arguments, missing ["); // no opening '['
\r
230 // !!! following line has no effect
\r
235 int value = argument.indexOf(' ', i);
\r
236 String option = argument.substring(i, value);
\r
237 i = argument.indexOf(']', value);
\r
238 String optionvalue = argument.substring(value + 1, i);
\r
240 // some options are not added because they have no public apis yet
\r
241 // TODO add the rest of the options
\r
242 if (option.equalsIgnoreCase("alternate")) {
\r
243 if (optionvalue.equalsIgnoreCase("non-ignorable")) {
\r
244 col.setAlternateHandlingShifted(false);
\r
247 col.setAlternateHandlingShifted(true);
\r
250 else if (option.equals("strength")) {
\r
251 if (optionvalue.equalsIgnoreCase("1")) {
\r
252 col.setStrength(Collator.PRIMARY);
\r
254 else if (optionvalue.equalsIgnoreCase("2")) {
\r
255 col.setStrength(Collator.SECONDARY);
\r
257 else if (optionvalue.equalsIgnoreCase("3")) {
\r
258 col.setStrength(Collator.TERTIARY);
\r
260 else if (optionvalue.equalsIgnoreCase("4")) {
\r
261 col.setStrength(Collator.QUATERNARY);
\r
266 warnln("Could not load the locale data. Skipping...");
\r
268 // !!! effect is odd, if no modular build, this emits no
\r
269 // message at all. How come? Hmmm. printInfo is never
\r
270 // true if we get here, so this code is never executed.
\r
272 if(printInfo == true && isModularBuild()){
\r
273 infoln("Could not load the locale data. Skipping...");
\r
278 private void processTestCases(RuleBasedCollator col) {
\r
279 for (Iterator iter = t.getDataIterator(); iter.hasNext();) {
\r
280 DataMap e1 = (DataMap) iter.next();
\r
281 processSequence(col, e1.getString("sequence"));
\r
285 private void processSequence(RuleBasedCollator col, String sequence) {
\r
286 // TODO: have a smarter tester that remembers the sequence and ensures
\r
287 // that the complete sequence is in order. That is why I have made a
\r
288 // constraint in the sequence format.
\r
289 m_sequence_ = sequence;
\r
290 m_sequenceIndex_ = 0;
\r
291 m_nextRelation_ = -1;
\r
292 m_target_.delete(0, m_target_.length());
\r
293 Vector vector = new Vector();
\r
294 int lastsmallerthanindex = -1;
\r
295 getNextInSequence();
\r
296 while (getNextInSequence()) {
\r
297 String target = m_target_.toString();
\r
298 doTest(this, col, m_source_, target, m_relation_);
\r
299 int vsize = vector.size();
\r
300 for (int i = vsize - 1; i >= 0; i --) {
\r
301 String source = (String)vector.elementAt(i);
\r
302 if (i > lastsmallerthanindex) {
\r
303 doTest(this, col, source, target, m_relation_);
\r
306 doTest(this, col, source, target, -1);
\r
309 vector.addElement(target);
\r
310 if (m_relation_ < 0) {
\r
311 lastsmallerthanindex = vsize - 1;
\r
317 * Parses the sequence to be tested
\r
319 private boolean getNextInSequence() {
\r
320 if (m_sequenceIndex_ >= m_sequence_.length()) {
\r
324 boolean quoted = false;
\r
325 boolean quotedsingle = false;
\r
326 boolean done = false;
\r
327 int i = m_sequenceIndex_;
\r
329 m_source_ = m_target_.toString();
\r
330 m_relation_ = m_nextRelation_;
\r
331 m_target_.delete(0, m_target_.length());
\r
332 while (i < m_sequence_.length() && !done) {
\r
333 int ch = UTF16.charAt(m_sequence_, i);
\r
334 if (UCharacter.isSupplementary(ch)) {
\r
341 if (UCharacter.isWhitespace(ch)) {
\r
346 m_nextRelation_ = -1;
\r
350 m_nextRelation_ = 0;
\r
354 m_nextRelation_ = 1;
\r
357 case 0x0027 : // ' very basic quoting
\r
359 quotedsingle = false;
\r
361 case 0x005c : // \ single quote
\r
363 quotedsingle = true;
\r
366 UTF16.insert(m_target_, offset, ch);
\r
367 if (UCharacter.isSupplementary(ch)) {
\r
376 if (ch == 0x0027) {
\r
380 UTF16.insert(m_target_, offset, ch);
\r
381 if (UCharacter.isSupplementary(ch)) {
\r
388 if (quotedsingle) {
\r
393 if (quoted == true) {
\r
394 errln("Quote in sequence not closed!");
\r
399 m_sequenceIndex_ = i;
\r
403 private static void doTestVariant(TestFmwk test,
\r
404 RuleBasedCollator myCollation,
\r
405 String source, String target, int result)
\r
407 boolean printInfo = false;
\r
408 int compareResult = myCollation.compare(source, target);
\r
409 if (compareResult != result) {
\r
411 // !!! if not mod build, error, else nothing.
\r
412 // warnln if not build, error, else always print warning.
\r
413 // do we need a 'quiet warning?' (err or log). Hmmm,
\r
414 // would it work to have the 'verbose' flag let you
\r
415 // suppress warnings? Are there ever some warnings you
\r
416 // want to suppress, and others you don't?
\r
417 if(!test.isModularBuild()){
\r
418 test.errln("Comparing \"" + Utility.hex(source) + "\" with \""
\r
419 + Utility.hex(target) + "\" expected " + result
\r
420 + " but got " + compareResult);
\r
425 CollationKey ssk = myCollation.getCollationKey(source);
\r
426 CollationKey tsk = myCollation.getCollationKey(target);
\r
427 compareResult = ssk.compareTo(tsk);
\r
428 if (compareResult != result) {
\r
430 if(!test.isModularBuild()){
\r
431 test.errln("Comparing CollationKeys of \"" + Utility.hex(source)
\r
432 + "\" with \"" + Utility.hex(target)
\r
433 + "\" expected " + result + " but got "
\r
439 RawCollationKey srsk = new RawCollationKey();
\r
440 myCollation.getRawCollationKey(source, srsk);
\r
441 RawCollationKey trsk = new RawCollationKey();
\r
442 myCollation.getRawCollationKey(target, trsk);
\r
443 compareResult = ssk.compareTo(tsk);
\r
444 if (compareResult != result) {
\r
446 if(!test.isModularBuild()){
\r
447 test.errln("Comparing RawCollationKeys of \""
\r
448 + Utility.hex(source)
\r
449 + "\" with \"" + Utility.hex(target)
\r
450 + "\" expected " + result + " but got "
\r
456 // hmmm, but here we issue a warning
\r
457 // only difference is, one warning or two, and detailed info or not?
\r
458 // hmmm, does seem preferable to omit detail if we know it is due to missing resource data.
\r
459 // well, if we label the errors as warnings, we can let people know the details, but
\r
460 // also know they may be due to missing resource data. basically this code is asserting
\r
461 // that the errors are due to missing resource data, which may or may not be true.
\r
463 test.warnln("Could not load locale data skipping.");
\r