]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/dev/test/format/DateFormatRoundTripTest.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / dev / test / format / DateFormatRoundTripTest.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 2001-2007, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 \r
8 /** \r
9  * Port From:   ICU4C v1.8.1 : format : DateFormatRoundTripTest\r
10  * Source File: $ICU4CRoot/source/test/intltest/dtfmtrtts.cpp\r
11  **/\r
12 \r
13 package com.ibm.icu.dev.test.format;\r
14 \r
15 import com.ibm.icu.text.*;\r
16 import com.ibm.icu.util.*;\r
17 import java.util.Locale;\r
18 import java.util.Date;\r
19 import java.util.Random;\r
20 import java.text.FieldPosition;\r
21 import java.text.ParseException;\r
22 \r
23 /** \r
24  * Performs round-trip tests for DateFormat\r
25  **/\r
26 public class DateFormatRoundTripTest extends com.ibm.icu.dev.test.TestFmwk {\r
27     public boolean INFINITE = false;\r
28     public boolean quick = true;\r
29     private SimpleDateFormat dateFormat;\r
30     private Calendar getFieldCal;\r
31     private int SPARSENESS = 18;\r
32     private int TRIALS = 4;\r
33     private int DEPTH = 5;\r
34     private Random ran;\r
35 \r
36     public static void main(String[] args) throws Exception {\r
37         new DateFormatRoundTripTest().run(args);\r
38     }\r
39     \r
40     public void TestDateFormatRoundTrip() {\r
41         dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss.SSS zzz yyyy G");\r
42         getFieldCal = Calendar.getInstance();\r
43         ran = createRandom(); // use test framework's random seed\r
44 \r
45         final Locale[] avail = DateFormat.getAvailableLocales();\r
46         int locCount = avail.length;\r
47         logln("DateFormat available locales: " + locCount);\r
48         if (quick) {\r
49             if (locCount > 5)\r
50                 locCount = 5;\r
51             logln("Quick mode: only testing first 5 Locales");\r
52         }\r
53         TimeZone tz = TimeZone.getDefault();\r
54         logln("Default TimeZone:             " + tz.getID());\r
55     \r
56         if (INFINITE) {\r
57             // Special infinite loop test mode for finding hard to reproduce errors\r
58             Locale loc = Locale.getDefault();\r
59             logln("ENTERING INFINITE TEST LOOP FOR Locale: " + loc.getDisplayName());\r
60             for (;;) {\r
61                 _test(loc);\r
62             }\r
63         } else {        \r
64             _test(Locale.getDefault());\r
65             for (int i = 0; i < locCount; ++i) {\r
66                 _test(avail[i]);\r
67             }\r
68         }\r
69     }\r
70     \r
71     public String styleName(int s) {\r
72         switch (s) {\r
73             case DateFormat.SHORT :\r
74                 return "SHORT";\r
75             case DateFormat.MEDIUM :\r
76                 return "MEDIUM";\r
77             case DateFormat.LONG :\r
78                 return "LONG";\r
79             case DateFormat.FULL :\r
80                 return "FULL";\r
81             default :\r
82                 return "Unknown";\r
83         }\r
84     }\r
85     \r
86     public void _test(Locale loc) {\r
87         if (!INFINITE) {\r
88             logln("Locale: " + loc.getDisplayName());\r
89         }\r
90         // Total possibilities = 24\r
91         //  4 date\r
92         //  4 time\r
93         //  16 date-time\r
94         boolean[] TEST_TABLE = new boolean[24];\r
95         int i = 0;\r
96         for (i = 0; i < 24; ++i)\r
97             TEST_TABLE[i] = true;\r
98     \r
99         // If we have some sparseness, implement it here.  Sparseness decreases\r
100         // test time by eliminating some tests, up to 23.\r
101         for (i = 0; i < SPARSENESS; i++) {\r
102             int random = (int) (ran.nextDouble() * 24);\r
103             if (random >= 0 && random < 24 && TEST_TABLE[i]) {\r
104                 TEST_TABLE[random] = false;\r
105             }\r
106         }    \r
107         \r
108         int itable = 0;\r
109         int style = 0;\r
110         for (style = DateFormat.FULL; style <= DateFormat.SHORT; ++style) {\r
111             if (TEST_TABLE[itable++]) {\r
112                 logln("Testing style " + styleName(style)); \r
113                 DateFormat df = DateFormat.getDateInstance(style, loc); \r
114                 _test(df, false);\r
115             }\r
116         }\r
117     \r
118         for (style = DateFormat.FULL; style <= DateFormat.SHORT; ++style) {\r
119             if (TEST_TABLE[itable++]) {\r
120                 logln("Testing style " + styleName(style));\r
121                 DateFormat  df = DateFormat.getTimeInstance(style, loc); \r
122                 _test(df, true);\r
123             }\r
124         }\r
125     \r
126         for (int dstyle = DateFormat.FULL; dstyle <= DateFormat.SHORT; ++dstyle) {\r
127             for (int tstyle = DateFormat.FULL; tstyle <= DateFormat.SHORT; ++tstyle) {\r
128                 if (TEST_TABLE[itable++]) {\r
129                     logln("Testing dstyle " + styleName(dstyle) + ", tstyle " + styleName(tstyle)); \r
130                     DateFormat df = DateFormat.getDateTimeInstance(dstyle, tstyle, loc); \r
131                     _test(df, false);\r
132                 }\r
133             }\r
134         }\r
135     }\r
136     \r
137     public void _test(DateFormat fmt, boolean timeOnly) {\r
138     \r
139         if (!(fmt instanceof SimpleDateFormat)) {\r
140             errln("DateFormat wasn't a SimpleDateFormat");\r
141             return;\r
142         }\r
143     \r
144         String pat = ((SimpleDateFormat) fmt).toPattern();\r
145         logln(pat);\r
146     \r
147         // NOTE TO MAINTAINER\r
148         // This indexOf check into the pattern needs to be refined to ignore\r
149         // quoted characters.  Currently, this isn't a problem with the locale\r
150         // patterns we have, but it may be a problem later.\r
151     \r
152         boolean hasEra = (pat.indexOf("G") != -1);\r
153         boolean hasZoneDisplayName = (pat.indexOf("z") != -1) || (pat.indexOf("v") != -1) || (pat.indexOf("V") != -1);\r
154     \r
155         // Because patterns contain incomplete data representing the Date,\r
156         // we must be careful of how we do the roundtrip.  We start with\r
157         // a randomly generated Date because they're easier to generate.\r
158         // From this we get a string.  The string is our real starting point,\r
159         // because this string should parse the same way all the time.  Note\r
160         // that it will not necessarily parse back to the original date because\r
161         // of incompleteness in patterns.  For example, a time-only pattern won't\r
162         // parse back to the same date.\r
163     \r
164         try {\r
165             for (int i = 0; i < TRIALS; ++i) {\r
166                 Date[] d = new Date[DEPTH];\r
167                 String[] s = new String[DEPTH];\r
168     \r
169                 d[0] = generateDate();\r
170                 \r
171                 // We go through this loop until we achieve a match or until\r
172                 // the maximum loop count is reached.  We record the points at\r
173                 // which the date and the string starts to match.  Once matching\r
174                 // starts, it should continue.\r
175                 int loop;\r
176                 int dmatch = 0; // d[dmatch].getTime() == d[dmatch-1].getTime()\r
177                 int smatch = 0; // s[smatch].equals(s[smatch-1])\r
178                 for (loop = 0; loop < DEPTH; ++loop) {\r
179                     if (loop > 0) {\r
180                         d[loop] = fmt.parse(s[loop - 1]);\r
181                     }\r
182     \r
183                     s[loop] = fmt.format(d[loop]);\r
184     \r
185                     if (loop > 0) {\r
186                         if (smatch == 0) {\r
187                             boolean match = s[loop].equals(s[loop - 1]);\r
188                             if (smatch == 0) {\r
189                                 if (match)\r
190                                     smatch = loop;\r
191                             } else\r
192                                 if (!match)\r
193                                     errln("FAIL: String mismatch after match");\r
194                         }\r
195     \r
196                         if (dmatch == 0) {\r
197                             // {sfb} watch out here, this might not work\r
198                             boolean match = d[loop].getTime() == d[loop - 1].getTime();\r
199                             if (dmatch == 0) {\r
200                                 if (match)\r
201                                     dmatch = loop;\r
202                             } else\r
203                                 if (!match)\r
204                                     errln("FAIL: Date mismatch after match");\r
205                         }\r
206     \r
207                         if (smatch != 0 && dmatch != 0)\r
208                             break;\r
209                     }\r
210                 }\r
211                 // At this point loop == DEPTH if we've failed, otherwise loop is the\r
212                 // max(smatch, dmatch), that is, the index at which we have string and\r
213                 // date matching.\r
214     \r
215                 // Date usually matches in 2.  Exceptions handled below.\r
216                 int maxDmatch = 2;\r
217                 int maxSmatch = 1;\r
218                 if (dmatch > maxDmatch || smatch > maxSmatch) {\r
219                     //If the Date is BC\r
220                     if (!timeOnly && !hasEra && getField(d[0], Calendar.ERA) == GregorianCalendar.BC) {\r
221                         maxDmatch = 3;\r
222                         maxSmatch = 2;\r
223                     }\r
224                     if (hasZoneDisplayName &&\r
225                             (fmt.getTimeZone().inDaylightTime(d[0])\r
226                                     || fmt.getTimeZone().inDaylightTime(d[1])\r
227                                     || d[0].getTime() < 0L /* before 1970 */)) {\r
228                         maxSmatch = 2;\r
229                         if (timeOnly) {\r
230                             maxDmatch = 3;\r
231                         }\r
232                     }\r
233                 }\r
234                     \r
235                 if (dmatch > maxDmatch || smatch > maxSmatch) {\r
236                     SimpleDateFormat sdf = new SimpleDateFormat("EEEE, MMMM d, yyyy HH:mm:ss, z G", Locale.US);\r
237                     logln("Date = " + sdf.format(d[0]) + "; ms = " + d[0].getTime());\r
238                     logln("Dmatch: " + dmatch + " maxD: " + maxDmatch + " Smatch:" + smatch + " maxS:" + maxSmatch);\r
239                     for (int j = 0; j <= loop && j < DEPTH; ++j) {\r
240                         StringBuffer temp = new StringBuffer("");\r
241                         FieldPosition pos = new FieldPosition(0);\r
242                         logln((j > 0 ? " P> " : "    ") + dateFormat.format(d[j], temp, pos) \r
243                             + " F> " + s[j] + (j > 0 && d[j].getTime() == d[j - 1].getTime() ? " d==" : "")\r
244                             + (j > 0 && s[j].equals(s[j - 1]) ? " s==" : ""));\r
245                     }\r
246                     errln("Pattern: " + pat + " failed to match" + "; ms = " + d[0].getTime());\r
247                 }\r
248             }\r
249         } catch (ParseException e) {\r
250             errln("Exception: " + e.getMessage());\r
251             logln(e.toString());\r
252         }\r
253     }\r
254     \r
255     public int getField(Date d, int f) {\r
256         getFieldCal.setTime(d);\r
257         int ret = getFieldCal.get(f);\r
258         return ret;\r
259     }\r
260     \r
261     public Date generateDate() {\r
262         double a = ran.nextDouble();\r
263         // Now 'a' ranges from 0..1; scale it to range from 0 to 8000 years\r
264         a *= 8000;\r
265         // Range from (4000-1970) BC to (8000-1970) AD\r
266         a -= 4000;\r
267         // Now scale up to ms\r
268         a *= 365.25 * 24 * 60 * 60 * 1000;\r
269         return new Date((long)a);\r
270     }\r
271 }\r