]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/dev/test/ResourceModule.java
go
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / dev / test / ResourceModule.java
1 //##header J2SE15
2 /*
3  **********************************************************************
4  * Copyright (c) 2006-2009, International Business Machines
5  * Corporation and others.  All Rights Reserved.
6  **********************************************************************
7  * Created on 2006-4-21
8  */
9 package com.ibm.icu.dev.test;
10
11 import java.util.Arrays;
12 import java.util.HashMap;
13 import java.util.Iterator;
14 import java.util.Map;
15 import java.util.MissingResourceException;
16 import java.util.NoSuchElementException;
17
18 import com.ibm.icu.impl.ICUResourceBundle;
19 import com.ibm.icu.util.UResourceBundle;
20 import com.ibm.icu.util.UResourceBundleIterator;
21 import com.ibm.icu.util.UResourceTypeMismatchException;
22
23 /**
24  * Represents a collection of test data described in a UResourceBoundle file. 
25  * 
26  * The root of the UResourceBoundle file is a table resource, and it has one 
27  * Info and one TestData sub-resources. The Info describes the data module
28  * itself. The TestData, which is a table resource, has a collection of test 
29  * data.
30  * 
31  * The test data is a named table resource which has Info, Settings, Headers,
32  * and Cases sub-resources. 
33  * 
34  * <pre>
35  * DataModule:table(nofallback){ 
36  *   Info:table {} 
37  *   TestData:table {
38  *     entry_name:table{
39  *       Info:table{}
40  *       Settings:array{}
41  *       Headers:array{}
42  *       Cases:array{}
43  *     }
44  *   } 
45  * }
46  * </pre>
47  * 
48  * The test data is expected to be fed to test code by following sequence 
49  *
50  *   for each setting in Setting{
51  *       prepare the setting
52  *     for each test data in Cases{
53  *       perform the test
54  *     }
55  *   }
56  * 
57  * For detail of the specification, please refer to the code. The code is 
58  * initially ported from "icu4c/source/tools/ctestfw/unicode/tstdtmod.h"
59  * and should be maintained parallelly.
60  * 
61  * @author Raymond Yang
62  */
63 class ResourceModule implements TestDataModule {
64     private static final String INFO = "Info";
65 //    private static final String DESCRIPTION = "Description";
66 //    private static final String LONG_DESCRIPTION = "LongDescription";
67     private static final String TEST_DATA = "TestData";
68     private static final String SETTINGS = "Settings";
69     private static final String HEADER = "Headers";
70     private static final String DATA = "Cases";
71
72     
73     UResourceBundle res;
74     UResourceBundle info;
75     UResourceBundle defaultHeader;
76     UResourceBundle testData;
77     
78     ResourceModule(String baseName, String localeName) throws DataModuleFormatError{
79
80         res = (UResourceBundle) UResourceBundle.getBundleInstance(baseName, localeName);
81         info = getFromTable(res, INFO, UResourceBundle.TABLE);
82         testData = getFromTable(res, TEST_DATA, UResourceBundle.TABLE);
83
84         try {
85             // unfortunately, actually, data can be either ARRAY or STRING
86             defaultHeader = getFromTable(info, HEADER, new int[]{UResourceBundle.ARRAY, UResourceBundle.STRING});
87         } catch (MissingResourceException e){
88             defaultHeader = null;
89         }
90     }
91
92     public String getName() {
93         return res.getKey();
94     }
95
96     public DataMap getInfo() {
97         return new UTableResource(info);
98     }
99
100     public TestData getTestData(String testName) throws DataModuleFormatError {
101         return new UResourceTestData(defaultHeader, testData.get(testName));
102     }
103
104     public Iterator getTestDataIterator() {
105         return new IteratorAdapter(testData){
106             protected Object prepareNext(UResourceBundle nextRes) throws DataModuleFormatError {
107                 return new UResourceTestData(defaultHeader, nextRes);
108             }
109         };
110     }
111
112     /**
113      * To make UResourceBundleIterator works like Iterator
114      * and return various data-driven test object for next() call
115      * 
116      * @author Raymond Yang
117      */
118     private abstract static class IteratorAdapter implements Iterator{
119         private UResourceBundle res;
120         private UResourceBundleIterator itr;
121         private Object preparedNextElement = null;
122         // fix a strange behavior for UResourceBundleIterator for 
123         // UResourceBundle.STRING. It support hasNext(), but does 
124         // not support next() now. 
125         // 
126         // Use the iterated resource itself as the result from next() call
127         private boolean isStrRes = false;
128         private boolean isStrResPrepared = false; // for STRING resouce, we only prepare once
129
130         IteratorAdapter(UResourceBundle theRes) {
131             assert_not (theRes == null);
132             res = theRes;
133             itr = ((ICUResourceBundle)res).getIterator();
134             isStrRes = res.getType() == UResourceBundle.STRING;
135         }
136         
137         public void remove() {
138             // do nothing
139         }
140
141         private boolean hasNextForStrRes(){
142             assert_is (isStrRes);
143             assert_not (!isStrResPrepared && preparedNextElement != null);
144             if (isStrResPrepared && preparedNextElement != null) return true;
145             if (isStrResPrepared && preparedNextElement == null) return false; // only prepare once
146             assert_is (!isStrResPrepared && preparedNextElement == null);
147             
148             try {
149                 preparedNextElement = prepareNext(res);
150                 assert_not (preparedNextElement == null, "prepareNext() should not return null");
151                 isStrResPrepared = true; // toggle the tag
152                 return true;
153             } catch (DataModuleFormatError e) {
154 //#if defined(FOUNDATION10) || defined(J2SE13)
155 //##                throw new RuntimeException(e.getMessage());
156 //#else
157                 throw new RuntimeException(e.getMessage(),e);
158 //#endif
159             }            
160         }
161         public boolean hasNext() {
162             if (isStrRes) return hasNextForStrRes();
163             
164             if (preparedNextElement != null) return true;
165             UResourceBundle t = null;
166             if (itr.hasNext()) {
167                 // Notice, other RuntimeException may be throwed
168                 t = itr.next();
169             } else {
170                 return false;
171             }
172
173             try {
174                 preparedNextElement = prepareNext(t);
175                 assert_not (preparedNextElement == null, "prepareNext() should not return null");
176                 return true;
177             } catch (DataModuleFormatError e) {
178                 // Sadly, we throw RuntimeException also
179 //#if defined(FOUNDATION10) || defined(J2SE13)
180 //##                throw new RuntimeException(e.getMessage());
181 //#else
182                 throw new RuntimeException(e.getMessage(),e);
183 //#endif
184             }
185         }
186
187         public Object next(){
188             if (hasNext()) {
189                 Object t = preparedNextElement;
190                 preparedNextElement = null;
191                 return t;
192             } else {
193                 throw new NoSuchElementException();
194             }
195         }
196         /**
197          * To prepare data-driven test object for next() call, should not return null
198          */
199         abstract protected Object prepareNext(UResourceBundle nextRes) throws DataModuleFormatError;
200     }
201     
202     
203     /**
204      * Avoid use Java 1.4 language new assert keyword 
205      */
206     static void assert_is(boolean eq, String msg){
207         if (!eq) throw new Error("test code itself has error: " + msg);
208     }
209     static void assert_is(boolean eq){
210         if (!eq) throw new Error("test code itself has error.");
211     }
212     static void assert_not(boolean eq, String msg){
213         assert_is(!eq, msg);
214     }
215     static void assert_not(boolean eq){
216         assert_is(!eq);
217     }
218             
219     /**
220      * Internal helper function to get resource with following add-on 
221      * 
222      * 1. Assert the returned resource is never null.
223      * 2. Check the type of resource. 
224      * 
225      * The UResourceTypeMismatchException for various get() method is a 
226      * RuntimeException which can be silently bypassed. This behavior is a 
227      * trouble. One purpose of the class is to enforce format checking for 
228      * resource file. We don't want to the exceptions are silently bypassed 
229      * and spreaded to our customer's code. 
230      * 
231      * Notice, the MissingResourceException for get() method is also a
232      * RuntimeException. The caller functions should avoid sepread the execption
233      * silently also. The behavior is modified because some resource are 
234      * optional and can be missed.
235      */
236     static UResourceBundle getFromTable(UResourceBundle res, String key, int expResType) throws DataModuleFormatError{
237         return getFromTable(res, key, new int[]{expResType});
238     }
239     
240     static UResourceBundle getFromTable(UResourceBundle res, String key, int[] expResTypes) throws DataModuleFormatError{
241         assert_is (res != null && key != null && res.getType() == UResourceBundle.TABLE);
242         UResourceBundle t = res.get(key); 
243       
244         assert_not (t ==null);
245         int type = t.getType();
246         Arrays.sort(expResTypes);
247         if (Arrays.binarySearch(expResTypes, type) >= 0) {
248             return t;
249         } else {
250 //#if defined(FOUNDATION10) || defined(J2SE13)
251 //##            throw new DataModuleFormatError("Actual type " + t.getType() + " != expected types " + expResTypes + ".");
252 //#else
253             throw new DataModuleFormatError(new UResourceTypeMismatchException("Actual type " + t.getType() + " != expected types " + expResTypes + "."));
254 //#endif
255         }
256     }
257     
258     /**
259      * Unfortunately, UResourceBundle is unable to treat one string as string array.
260      * This function return a String[] from UResourceBundle, regardless it is an array or a string 
261      */
262     static String[] getStringArrayHelper(UResourceBundle res, String key) throws DataModuleFormatError{
263         UResourceBundle t = getFromTable(res, key, new int[]{UResourceBundle.ARRAY, UResourceBundle.STRING});
264         return getStringArrayHelper(t);
265     }
266
267     static String[] getStringArrayHelper(UResourceBundle res) throws DataModuleFormatError{
268         try{
269             int type = res.getType();
270             switch (type) {
271             case UResourceBundle.ARRAY:
272                 return res.getStringArray();
273             case UResourceBundle.STRING:
274                 return new String[]{res.getString()};
275             default:
276                 throw new UResourceTypeMismatchException("Only accept ARRAY and STRING types.");
277             }
278         } catch (UResourceTypeMismatchException e){
279 //#if defined(FOUNDATION10) || defined(J2SE13)
280 //##            throw new DataModuleFormatError(e.getMessage());
281 //#else
282             throw new DataModuleFormatError(e);
283 //#endif
284         }
285     }
286     
287     public static void main(String[] args){
288         try {
289             TestDataModule m = new ResourceModule("com/ibm/icu/dev/data/testdata/","DataDrivenCollationTest");
290         System.out.println("hello: " + m.getName());
291         m.getInfo();
292         m.getTestDataIterator();
293         } catch (DataModuleFormatError e) {
294             // TODO Auto-generated catch block
295             System.out.println("???");
296             e.printStackTrace();
297         }
298     }
299
300     private static class UResourceTestData implements TestData{
301         private UResourceBundle res;
302         private UResourceBundle info;
303         private UResourceBundle settings; 
304         private UResourceBundle header;
305         private UResourceBundle data;
306
307         UResourceTestData(UResourceBundle defaultHeader, UResourceBundle theRes) throws DataModuleFormatError{
308             
309             assert_is (theRes != null && theRes.getType() == UResourceBundle.TABLE);
310             res = theRes;
311             // unfortunately, actually, data can be either ARRAY or STRING
312             data = getFromTable(res, DATA, new int[]{UResourceBundle.ARRAY, UResourceBundle.STRING});
313        
314
315             
316             try {
317                 // unfortunately, actually, data can be either ARRAY or STRING
318                 header = getFromTable(res, HEADER, new int[]{UResourceBundle.ARRAY, UResourceBundle.STRING});
319             } catch (MissingResourceException e){
320                 if (defaultHeader == null) {
321                     throw new DataModuleFormatError("Unable to find a header for test data '" + res.getKey() + "' and no default header exist.");
322                 } else {
323                     header = defaultHeader;
324                 }
325             }
326          try{
327                 settings = getFromTable(res, SETTINGS, UResourceBundle.ARRAY);
328                 info = getFromTable(res, INFO, UResourceBundle.TABLE);
329             } catch (MissingResourceException e){
330                 // do nothing, left them null;
331                 settings = data;
332             }
333         }
334         
335         public String getName() {
336             return res.getKey();
337         }
338
339         public DataMap getInfo() {
340             return info == null ? null : new UTableResource(info);
341         }
342
343         public Iterator getSettingsIterator() {
344             assert_is (settings.getType() == UResourceBundle.ARRAY);
345             return new IteratorAdapter(settings){
346                 protected Object prepareNext(UResourceBundle nextRes) throws DataModuleFormatError {
347                     return new UTableResource(nextRes);
348                 }
349             };
350         }
351
352         public Iterator getDataIterator() {
353             // unfortunately,
354             assert_is (data.getType() == UResourceBundle.ARRAY 
355                  || data.getType() == UResourceBundle.STRING);
356             return new IteratorAdapter(data){
357                 protected Object prepareNext(UResourceBundle nextRes) throws DataModuleFormatError {
358                     return new UArrayResource(header, nextRes);
359                 }
360             };
361         }
362     }
363         
364     private static class UTableResource implements DataMap{
365         private UResourceBundle res;
366
367         UTableResource(UResourceBundle theRes){
368             res = theRes;
369         }
370         public String getString(String key) {
371             String t;
372             try{
373                 t = res.getString(key);
374             } catch (MissingResourceException e){
375                 t = null;
376             }
377             return t;
378         }
379          public Object getObject(String key) {
380             
381             return res.get(key);
382         }
383     }
384     
385     private static class UArrayResource implements DataMap{
386         private Map theMap; 
387         UArrayResource(UResourceBundle theHeader, UResourceBundle theData) throws DataModuleFormatError{
388             assert_is (theHeader != null && theData != null);
389             String[] header;
390          
391             header = getStringArrayHelper(theHeader);
392             if (theData.getSize() != header.length) 
393                 throw new DataModuleFormatError("The count of Header and Data is mismatch.");
394             theMap = new HashMap();
395             for (int i = 0; i < header.length; i++) {
396                 if(theData.getType()==UResourceBundle.ARRAY){
397                     theMap.put(header[i], theData.get(i));
398                 }else if(theData.getType()==UResourceBundle.STRING){
399                     theMap.put(header[i], theData.getString());
400                 }else{
401                     throw new DataModuleFormatError("Did not get the expected data!");                   
402                 }
403             }
404             
405         }
406         
407         public String getString(String key) {
408             Object o = theMap.get(key);
409             UResourceBundle rb;
410             if(o instanceof UResourceBundle) {
411                 // unpack ResourceBundle strings
412                 rb = (UResourceBundle)o;
413                 return rb.getString();
414             }
415             return (String)o;
416         }
417         public Object getObject(String key) {
418             return theMap.get(key);
419         }
420     }
421 }