1 /*
  2  * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @summary test International Date Format
 27  * @bug 8008577
 28  * @run junit/othervm -Djava.locale.providers=COMPAT,SPI IntlTestDateFormat
 29  * @key randomness
 30  */
 31 /*
 32 (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
 33 (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
 34 
 35   The original version of this source code and documentation is copyrighted and
 36 owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
 37 provided under terms of a License Agreement between Taligent and Sun. This
 38 technology is protected by multiple US and International patents. This notice and
 39 attribution to Taligent may not be removed.
 40   Taligent is a registered trademark of Taligent, Inc.
 41 */
 42 
 43 import java.text.*;
 44 import java.util.*;
 45 
 46 import org.junit.jupiter.api.Test;
 47 
 48 import static org.junit.jupiter.api.Assertions.fail;
 49 
 50 public class IntlTestDateFormat {
 51     // Values in milliseconds (== Date)
 52     private static final long ONESECOND = 1000;
 53     private static final long ONEMINUTE = 60 * ONESECOND;
 54     private static final long ONEHOUR = 60 * ONEMINUTE;
 55     private static final long ONEDAY = 24 * ONEHOUR;
 56     private static final double ONEYEAR = 365.25 * ONEDAY; // Approximate
 57 
 58     // EModes
 59     private static final byte GENERIC = 0;
 60     private static final byte TIME = GENERIC + 1;
 61     private static final byte DATE = TIME + 1;
 62     private static final byte DATE_TIME = DATE + 1;
 63 
 64     private DateFormat fFormat = DateFormat.getInstance();
 65     private String fTestName = new String("getInstance");
 66     private int fLimit = 3; // How many iterations it should take to reach convergence
 67 
 68     @Test
 69     public void TestLocale() {
 70         localeTest(Locale.getDefault(), "Default Locale");
 71     }
 72 
 73     // This test does round-trip testing (format -> parse -> format -> parse -> etc.) of DateFormat.
 74     public void localeTest(final Locale locale, final String localeName) {
 75         int timeStyle, dateStyle;
 76 
 77         // For patterns including only time information and a timezone, it may take
 78         // up to three iterations, since the timezone may shift as the year number
 79         // is determined.  For other patterns, 2 iterations should suffice.
 80         fLimit = 3;
 81 
 82         for(timeStyle = 0; timeStyle < 4; timeStyle++) {
 83             fTestName = new String("Time test " + timeStyle + " (" + localeName + ")");
 84             try {
 85                 fFormat = DateFormat.getTimeInstance(timeStyle, locale);
 86             }
 87             catch(StringIndexOutOfBoundsException e) {
 88                 fail("FAIL: localeTest time getTimeInstance exception");
 89                 throw e;
 90             }
 91             TestFormat();
 92         }
 93 
 94         fLimit = 2;
 95 
 96         for(dateStyle = 0; dateStyle < 4; dateStyle++) {
 97             fTestName = new String("Date test " + dateStyle + " (" + localeName + ")");
 98             try {
 99                 fFormat = DateFormat.getDateInstance(dateStyle, locale);
100             }
101             catch(StringIndexOutOfBoundsException e) {
102                 fail("FAIL: localeTest date getTimeInstance exception");
103                 throw e;
104             }
105             TestFormat();
106         }
107 
108         for(dateStyle = 0; dateStyle < 4; dateStyle++) {
109             for(timeStyle = 0; timeStyle < 4; timeStyle++) {
110                 fTestName = new String("DateTime test " + dateStyle + "/" + timeStyle + " (" + localeName + ")");
111                 try {
112                     fFormat = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
113                 }
114                 catch(StringIndexOutOfBoundsException e) {
115                     fail("FAIL: localeTest date/time getDateTimeInstance exception");
116                     throw e;
117                 }
118                 TestFormat();
119             }
120         }
121     }
122 
123     @Test
124     public void TestFormat() {
125         if (fFormat == null) {
126             fail("FAIL: DateFormat creation failed");
127             return;
128         }
129         //        logln("TestFormat: " + fTestName);
130         Date now = new Date();
131         tryDate(new Date(0));
132         tryDate(new Date((long) 1278161801778.0));
133         tryDate(now);
134         // Shift 6 months into the future, AT THE SAME TIME OF DAY.
135         // This will test the DST handling.
136         tryDate(new Date(now.getTime() + 6*30*ONEDAY));
137 
138         Date limit = new Date(now.getTime() * 10); // Arbitrary limit
139         for (int i=0; i<2; ++i)
140             //            tryDate(new Date(floor(randDouble() * limit)));
141             tryDate(new Date((long) (randDouble() * limit.getTime())));
142     }
143 
144     private void describeTest() {
145         if (fFormat == null) {
146             fail("FAIL: no DateFormat");
147             return;
148         }
149 
150         // Assume it's a SimpleDateFormat and get some info
151         SimpleDateFormat s = (SimpleDateFormat) fFormat;
152         System.out.println(fTestName + " Pattern " + s.toPattern());
153     }
154 
155     private void tryDate(Date theDate) {
156         final int DEPTH = 10;
157         Date[] date = new Date[DEPTH];
158         StringBuffer[] string = new StringBuffer[DEPTH];
159 
160         int dateMatch = 0;
161         int stringMatch = 0;
162         boolean dump = false;
163         int i;
164         for (i=0; i<DEPTH; ++i) string[i] = new StringBuffer();
165         for (i=0; i<DEPTH; ++i) {
166             if (i == 0) date[i] = theDate;
167             else {
168                 try {
169                     date[i] = fFormat.parse(string[i-1].toString());
170                 }
171                 catch (ParseException e) {
172                     describeTest();
173                     fail("********** FAIL: Parse of " + string[i-1] + " failed.");
174                     dump = true;
175                     break;
176                 }
177             }
178             FieldPosition position = new FieldPosition(0);
179             fFormat.format(date[i], string[i], position);
180             if (i > 0) {
181                 if (dateMatch == 0 && date[i] == date[i-1]) dateMatch = i;
182                 else if (dateMatch > 0 && date[i] != date[i-1]) {
183                     describeTest();
184                     fail("********** FAIL: Date mismatch after match.");
185                     dump = true;
186                     break;
187                 }
188                 if (stringMatch == 0 && string[i] == string[i-1]) stringMatch = i;
189                 else if (stringMatch > 0 && string[i] != string[i-1]) {
190                     describeTest();
191                     fail("********** FAIL: String mismatch after match.");
192                     dump = true;
193                     break;
194                 }
195             }
196             if (dateMatch > 0 && stringMatch > 0) break;
197         }
198         if (i == DEPTH) --i;
199 
200         if (stringMatch > fLimit || dateMatch > fLimit) {
201             describeTest();
202             fail("********** FAIL: No string and/or date match within " + fLimit + " iterations.");
203             dump = true;
204         }
205 
206         if (dump) {
207             for (int k=0; k<=i; ++k) {
208                 System.out.println("" + k + ": " + date[k] + " F> " + string[k] + " P> ");
209             }
210         }
211     }
212 
213     // Return a random double from 0.01 to 1, inclusive
214     private double randDouble() {
215         // Assume 8-bit (or larger) rand values.  Also assume
216         // that the system rand() function is very poor, which it always is.
217         //        double d;
218         //        int i;
219         //        do {
220         //            for (i=0; i < sizeof(double); ++i)
221         //            {
222         //                char poke = (char*)&d;
223         //                poke[i] = (rand() & 0xFF);
224         //            }
225         //        } while (TPlatformUtilities.isNaN(d) || TPlatformUtilities.isInfinite(d));
226 
227         //        if (d < 0.0) d = -d;
228         //        if (d > 0.0)
229         //        {
230         //            double e = floor(log10(d));
231         //            if (e < -2.0) d *= pow(10.0, -e-2);
232         //            else if (e > -1.0) d /= pow(10.0, e+1);
233         //        }
234         //        return d;
235         Random rand = new Random();
236         return rand.nextDouble();
237     }
238 
239     @Test
240     public void TestAvailableLocales() {
241         final Locale[] locales = DateFormat.getAvailableLocales();
242         long count = locales.length;
243         System.out.println("" + count + " available locales");
244         if (locales != null  &&  count != 0) {
245             StringBuffer all = new StringBuffer();
246             for (int i=0; i<count; ++i) {
247                 if (i!=0) all.append(", ");
248                 all.append(locales[i].getDisplayName());
249             }
250             System.out.println(all.toString());
251         }
252         else fail("********** FAIL: Zero available locales or null array pointer");
253     }
254 
255     /* This test is too slow; we disable it for now
256     @Test
257     public void TestMonster() {
258         final Locale[] locales = DateFormat.getAvailableLocales();
259         long count = locales.length;
260         if (locales != null  &&  count != 0) {
261             for (int i=0; i<count; ++i) {
262                 String name = locales[i].getDisplayName();
263                 System.out.println("Testing " + name + "...");
264                 try {
265                     localeTest(locales[i], name);
266                 }
267                 catch(Exception e) {
268                     fail("FAIL: TestMonster localeTest exception" + e);
269                 }
270             }
271         }
272     }
273     */
274 }
275 
276 //eof