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