]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/tests/collate/src/com/ibm/icu/dev/test/collator/CollationTest.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / tests / collate / src / com / ibm / icu / dev / test / collator / CollationTest.java
1 /**\r
2  *******************************************************************************\r
3  * Copyright (C) 2001-2006, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 package com.ibm.icu.dev.test.collator;\r
8 \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
13 \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
26 \r
27 public class CollationTest extends ModuleTest{\r
28     // public methods --------------------------------------------------------\r
29 \r
30     public static void main(String[] args) throws Exception{\r
31         new CollationTest().run(args);\r
32     }\r
33 \r
34     public CollationTest() {\r
35         super("com/ibm/icu/dev/data/testdata/", "DataDrivenCollationTest");\r
36     }\r
37     \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
42         }\r
43     }\r
44     \r
45     // package private methods ----------------------------------------------\r
46     \r
47     static void doTest(TestFmwk test, RuleBasedCollator col, String source, \r
48                        String target, int result)\r
49     {\r
50         doTestVariant(test, col, source, target, result);\r
51         if (result == -1) {\r
52             doTestVariant(test, col, target, source, 1);\r
53         } \r
54         else if (result == 1) {\r
55             doTestVariant(test, col, target, source, -1);\r
56         }\r
57         else {\r
58             doTestVariant(test, col, target, source, 0);\r
59         }\r
60 \r
61         CollationElementIterator iter = col.getCollationElementIterator(source);\r
62         backAndForth(test, iter);\r
63         iter.setText(target);\r
64         backAndForth(test, iter);\r
65     }\r
66     \r
67     /**\r
68      * Return an integer array containing all of the collation orders\r
69      * returned by calls to next on the specified iterator\r
70      */\r
71     static int[] getOrders(CollationElementIterator iter) \r
72     {\r
73         int maxSize = 100;\r
74         int size = 0;\r
75         int[] orders = new int[maxSize];\r
76         \r
77         int order;\r
78         while ((order = iter.next()) != CollationElementIterator.NULLORDER) {\r
79             if (size == maxSize) {\r
80                 maxSize *= 2;\r
81                 int[] temp = new int[maxSize];\r
82                 System.arraycopy(orders, 0, temp,  0, size);\r
83                 orders = temp;\r
84             }\r
85             orders[size++] = order;\r
86         }\r
87         \r
88         if (maxSize > size) {\r
89             int[] temp = new int[size];\r
90             System.arraycopy(orders, 0, temp,  0, size);\r
91             orders = temp;\r
92         }\r
93         return orders;\r
94     }\r
95     \r
96     static void backAndForth(TestFmwk test, CollationElementIterator iter) \r
97     {\r
98         // Run through the iterator forwards and stick it into an array\r
99         iter.reset();\r
100         int[] orders = getOrders(iter);\r
101     \r
102         // Now go through it backwards and make sure we get the same values\r
103         int index = orders.length;\r
104         int o;\r
105     \r
106         // reset the iterator\r
107         iter.reset();\r
108     \r
109         while ((o = iter.previous()) != CollationElementIterator.NULLORDER) {\r
110             if (o != orders[--index]) {\r
111                 if (o == 0) {\r
112                     index ++;\r
113                 } else {\r
114                     while (index > 0 && orders[index] == 0) {\r
115                         index --;\r
116                     } \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
120                         break;\r
121                     }\r
122                 }\r
123             }\r
124         }\r
125     \r
126         while (index != 0 && orders[index - 1] == 0) {\r
127           index --;\r
128         }\r
129     \r
130         if (index != 0) {\r
131             String msg = "Didn't get back to beginning - index is ";\r
132             test.errln(msg + index);\r
133     \r
134             iter.reset();\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
139             }\r
140             test.errln("");\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
145             }\r
146             test.errln("");\r
147         }\r
148     }\r
149     \r
150     // private data members --------------------------------------------------\r
151 \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
158 \r
159     // private methods -------------------------------------------------------\r
160 \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
166         \r
167         if (locale != null) {\r
168             // this is a case where we have locale\r
169             try {\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
176             }\r
177             logln("Testing collator for locale " + locale);\r
178             processSetting2(settings, col);\r
179         }\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
185             try {\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
191             }\r
192             processSetting2(settings, col);\r
193         }\r
194     }\r
195 \r
196     private void processSetting2(DataMap settings,RuleBasedCollator col)\r
197     {\r
198 \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
204         }\r
205         processTestCases(col);\r
206     }\r
207 \r
208     /**\r
209      * Reads the options string and sets appropriate attributes in collator\r
210      */\r
211     private void handleArguments(RuleBasedCollator col, String argument) {\r
212         int i = 0;\r
213         boolean printInfo = false;\r
214         while (i < argument.length()) {\r
215             if (!UCharacter.isWhitespace(argument.charAt(i))) {\r
216                 // eat whitespace\r
217                 break;\r
218             }\r
219             i ++;\r
220         }\r
221         while (i < argument.length()) {\r
222             // skip opening '['\r
223             if (argument.charAt(i) == '[') {\r
224                 i ++;\r
225             }\r
226             else {\r
227                 if(!isModularBuild()){\r
228                     errln("Error in collation arguments, missing ["); // no opening '['\r
229                 }\r
230                 // !!! following line has no effect\r
231                 printInfo=true;\r
232                 return;\r
233             }\r
234 \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
239             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
245                 }\r
246                 else {\r
247                     col.setAlternateHandlingShifted(true);\r
248                 }\r
249             }\r
250             else if (option.equals("strength")) {\r
251                 if (optionvalue.equalsIgnoreCase("1")) {\r
252                     col.setStrength(Collator.PRIMARY);\r
253                 }\r
254                 else if (optionvalue.equalsIgnoreCase("2")) {\r
255                     col.setStrength(Collator.SECONDARY);\r
256                 }\r
257                 else if (optionvalue.equalsIgnoreCase("3")) {\r
258                     col.setStrength(Collator.TERTIARY);\r
259                 }\r
260                 else if (optionvalue.equalsIgnoreCase("4")) {\r
261                     col.setStrength(Collator.QUATERNARY);\r
262                 }\r
263             }\r
264         }\r
265         if (printInfo) {\r
266             warnln("Could not load the locale data. Skipping...");\r
267         }\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
271         /*\r
272         if(printInfo == true && isModularBuild()){\r
273             infoln("Could not load the locale data. Skipping...");\r
274         }\r
275         */\r
276     }\r
277 \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
282      }\r
283     }\r
284 \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
304                 }\r
305                 else {\r
306                     doTest(this, col, source, target, -1);\r
307                 }\r
308             }\r
309             vector.addElement(target);\r
310             if (m_relation_ < 0) {\r
311                 lastsmallerthanindex = vsize - 1;\r
312             }\r
313         }\r
314     }\r
315 \r
316     /**\r
317      * Parses the sequence to be tested\r
318      */\r
319     private boolean getNextInSequence() {\r
320         if (m_sequenceIndex_ >= m_sequence_.length()) {\r
321             return false;\r
322         }\r
323 \r
324         boolean quoted = false;\r
325         boolean quotedsingle = false;\r
326         boolean done = false;\r
327         int i = m_sequenceIndex_;\r
328         int offset = 0;\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
335                 i += 2;\r
336             }\r
337             else {\r
338                 i ++;\r
339             }\r
340             if (!quoted) {\r
341                 if (UCharacter.isWhitespace(ch)) {\r
342                     continue;\r
343                 }\r
344                 switch (ch) {\r
345                     case 0x003C : // <\r
346                         m_nextRelation_ = -1;\r
347                         done = true;\r
348                         break;\r
349                     case 0x003D : // =\r
350                         m_nextRelation_ = 0;\r
351                         done = true;\r
352                         break;\r
353                     case 0x003E : // >\r
354                         m_nextRelation_ = 1;\r
355                         done = true;\r
356                         break;\r
357                     case 0x0027 : // ' very basic quoting\r
358                         quoted = true;\r
359                         quotedsingle = false;\r
360                         break;\r
361                     case 0x005c : // \ single quote\r
362                         quoted = true;\r
363                         quotedsingle = true;\r
364                         break;\r
365                     default:\r
366                         UTF16.insert(m_target_, offset, ch);\r
367                         if (UCharacter.isSupplementary(ch)) {\r
368                             offset += 2;\r
369                         }\r
370                         else {\r
371                             offset ++;\r
372                         }\r
373                     }\r
374                 }\r
375                 else {\r
376                       if (ch == 0x0027) {\r
377                           quoted = false;\r
378                       }\r
379                       else {\r
380                           UTF16.insert(m_target_, offset, ch);\r
381                           if (UCharacter.isSupplementary(ch)) {\r
382                               offset += 2;\r
383                           }\r
384                           else {\r
385                               offset ++;\r
386                           }\r
387                       }\r
388                       if (quotedsingle) {\r
389                           quoted = false;\r
390                       }\r
391                 }\r
392           }\r
393           if (quoted == true) {\r
394               errln("Quote in sequence not closed!");\r
395               return false;\r
396           }\r
397 \r
398 \r
399           m_sequenceIndex_ = i;\r
400           return true;\r
401     }\r
402 \r
403     private static void doTestVariant(TestFmwk test, \r
404                                       RuleBasedCollator myCollation,\r
405                                       String source, String target, int result)\r
406     {\r
407         boolean printInfo = false;\r
408         int compareResult  = myCollation.compare(source, target);\r
409         if (compareResult != result) {\r
410             \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
421             }else{\r
422                 printInfo = true;\r
423             }\r
424         }\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
429             \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
434                            + compareResult);\r
435            }else{\r
436                printInfo = true;\r
437            }\r
438         }\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
445             \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
451                            + compareResult);\r
452            }else{\r
453                printInfo = true;\r
454            }\r
455         }\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
462         if (printInfo) {\r
463             test.warnln("Could not load locale data skipping.");\r
464         }\r
465     }\r
466 }\r