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