blob: eef84774aa3f498c0b992fcb7ab45d4d23806788 [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 2001, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/test/format/Attic/DateFormatRoundTripTest.java,v $
* $Date: 2001/10/19 11:43:37 $
* $Revision: 1.1 $
*
*****************************************************************************************
*/
/**
* Port From: ICU4C v1.8.1 : format : DateFormatRoundTripTest
* Source File: $ICU4CRoot/source/test/intltest/dtfmtrtts.cpp
**/
package com.ibm.icu.test.format;
import com.ibm.text.*;
import com.ibm.util.*;
import java.util.Locale;
import java.util.Date;
import java.util.Random;
import java.text.FieldPosition;
import java.text.ParseException;
/**
* Performs round-trip tests for DateFormat
**/
public class DateFormatRoundTripTest extends com.ibm.test.TestFmwk {
public boolean INFINITE = false;
public boolean quick = true;
private SimpleDateFormat dateFormat;
private Calendar getFieldCal;
private int SPARSENESS = 18;
private int TRIALS = 4;
private int DEPTH = 5;
private Random ran = new Random();
public static void main(String[] args) throws Exception {
new DateFormatRoundTripTest().run(args);
}
//The Case fail randomly, I will recreate the case soon. [Richard/GCL]
/*
public void TestDateFormatRoundTrip() {
dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss.SSS zzz yyyy G");
getFieldCal = Calendar.getInstance();
final Locale[] avail = DateFormat.getAvailableLocales();
int locCount = avail.length;
logln("DateFormat available locales: " + locCount);
if (quick) {
if (locCount > 5)
locCount = 5;
logln("Quick mode: only testing first 5 Locales");
}
TimeZone tz = TimeZone.getDefault();
logln("Default TimeZone: " + tz.getID());
if (INFINITE) {
// Special infinite loop test mode for finding hard to reproduce errors
Locale loc = Locale.getDefault();
logln("ENTERING INFINITE TEST LOOP FOR Locale: " + loc.getDisplayName());
for (;;) {
_test(loc);
}
} else {
_test(Locale.getDefault());
for (int i = 0; i < locCount; ++i) {
_test(avail[i]);
}
}
}*/
public String styleName(int s) {
switch (s) {
case DateFormat.SHORT :
return "SHORT";
case DateFormat.MEDIUM :
return "MEDIUM";
case DateFormat.LONG :
return "LONG";
case DateFormat.FULL :
return "FULL";
default :
return "Unknown";
}
}
public void _test(Locale loc) {
if (!INFINITE) {
logln("Locale: " + loc.getDisplayName());
}
// Total possibilities = 24
// 4 date
// 4 time
// 16 date-time
boolean[] TEST_TABLE = new boolean[24];
int i = 0;
for (i = 0; i < 24; ++i)
TEST_TABLE[i] = true;
// If we have some sparseness, implement it here. Sparseness decreases
// test time by eliminating some tests, up to 23.
for (i = 0; i < SPARSENESS; i++) {
int random = (int) (ran.nextDouble() * 24);
if (random >= 0 && random < 24 && TEST_TABLE[i]) {
TEST_TABLE[random] = false;
}
}
int itable = 0;
int style = 0;
for (style = DateFormat.FULL; style <= DateFormat.SHORT; ++style) {
if (TEST_TABLE[itable++]) {
logln("Testing style " + styleName(style));
DateFormat df = DateFormat.getDateInstance(style, loc);
_test(df, false);
}
}
for (style = DateFormat.FULL; style <= DateFormat.SHORT; ++style) {
if (TEST_TABLE[itable++]) {
logln("Testing style " + styleName(style));
DateFormat df = DateFormat.getTimeInstance(style, loc);
_test(df, true);
}
}
for (int dstyle = DateFormat.FULL; dstyle <= DateFormat.SHORT; ++dstyle) {
for (int tstyle = DateFormat.FULL; tstyle <= DateFormat.SHORT; ++tstyle) {
if (TEST_TABLE[itable++]) {
logln("Testing dstyle " + styleName(dstyle) + ", tstyle " + styleName(tstyle));
DateFormat df = DateFormat.getDateTimeInstance(dstyle, tstyle, loc);
_test(df, false);
}
}
}
}
public void _test(DateFormat fmt, boolean timeOnly) {
if (!(fmt instanceof SimpleDateFormat)) {
errln("DateFormat wasn't a SimpleDateFormat");
return;
}
String pat = ((SimpleDateFormat) fmt).toPattern();
logln(pat);
// NOTE TO MAINTAINER
// This indexOf check into the pattern needs to be refined to ignore
// quoted characters. Currently, this isn't a problem with the locale
// patterns we have, but it may be a problem later.
boolean hasEra = (pat.indexOf("G") != -1);
boolean hasZone = (pat.indexOf("z") != -1);
// Because patterns contain incomplete data representing the Date,
// we must be careful of how we do the roundtrip. We start with
// a randomly generated Date because they're easier to generate.
// From this we get a string. The string is our real starting point,
// because this string should parse the same way all the time. Note
// that it will not necessarily parse back to the original date because
// of incompleteness in patterns. For example, a time-only pattern won't
// parse back to the same date.
try {
for (int i = 0; i < TRIALS; ++i) {
Date[] d = new Date[DEPTH];
String[] s = new String[DEPTH];
d[0] = generateDate();
// We go through this loop until we achieve a match or until
// the maximum loop count is reached. We record the points at
// which the date and the string starts to match. Once matching
// starts, it should continue.
int loop;
int dmatch = 0; // d[dmatch].getTime() == d[dmatch-1].getTime()
int smatch = 0; // s[smatch].equals(s[smatch-1])
for (loop = 0; loop < DEPTH; ++loop) {
if (loop > 0) {
d[loop] = fmt.parse(s[loop - 1]);
}
s[loop] = fmt.format(d[loop]);
if (loop > 0) {
if (smatch == 0) {
boolean match = s[loop].equals(s[loop - 1]);
if (smatch == 0) {
if (match)
smatch = loop;
} else
if (!match)
errln("FAIL: String mismatch after match");
}
if (dmatch == 0) {
// {sfb} watch out here, this might not work
boolean match = d[loop].getTime() == d[loop - 1].getTime();
if (dmatch == 0) {
if (match)
dmatch = loop;
} else
if (!match)
errln("FAIL: Date mismatch after match");
}
if (smatch != 0 && dmatch != 0)
break;
}
}
// At this point loop == DEPTH if we've failed, otherwise loop is the
// max(smatch, dmatch), that is, the index at which we have string and
// date matching.
// Date usually matches in 2. Exceptions handled below.
int maxDmatch = 2;
int maxSmatch = 1;
if (dmatch > maxDmatch) {
// Time-only pattern with zone information and a starting date in PST.
if (timeOnly && hasZone && (fmt.getTimeZone().inDaylightTime(d[0]))) {
maxDmatch = 3;
maxSmatch = 2;
}
if ((pat.indexOf("yyyy") == -1)) {
maxDmatch = 3;
maxSmatch = 2;
}
if (!hasEra && getField(d[0], Calendar.ERA) == GregorianCalendar.BC) {
maxDmatch = 3;
maxSmatch = 2;
}
}
// String usually matches in 1. Exceptions are checked for here.
if (smatch > maxSmatch) { // Don't compute unless necessary
// Starts in BC, with no era in pattern
if (!hasEra && getField(d[0], Calendar.ERA) == GregorianCalendar.BC)
maxSmatch = 2;
// Starts in DST, no year in pattern
else
if (fmt.getTimeZone().inDaylightTime(d[0]) && pat.indexOf("yyyy") == -1)
maxSmatch = 2;
// Two digit year with zone and year change and zone in pattern
else
if (hasZone
&& fmt.getTimeZone().inDaylightTime(d[0])
!= fmt.getTimeZone().inDaylightTime(d[dmatch])
&& getField(d[0], Calendar.YEAR) != getField(d[dmatch], Calendar.YEAR)
&& pat.indexOf("y") != -1
&& pat.indexOf("yyyy") == -1)
maxSmatch = 2;
else
if ((fmt.getTimeZone().inDaylightTime(d[0])) && (pat.indexOf("z") != -1)) {
maxSmatch = 2;
}
else
if ((pat.indexOf("yyyy") == -1)) {
maxSmatch = 2;
}
}
if (dmatch > maxDmatch || smatch > maxSmatch) {
logln("date = " + d[0] + "getTime = " + d[0].getTime());
logln(" Date " + dmatch + " String " + smatch);
logln("dmatch: " + dmatch + " maxD: " + maxDmatch+ " smatch:" + smatch
+ " maxS:" + maxSmatch);
errln("Pattern: " + pat + " failed to match");
for (int j = 0; j <= loop && j < DEPTH; ++j) {
StringBuffer temp = new StringBuffer("");
FieldPosition pos = new FieldPosition(0);
logln((j > 0 ? " P> " : " ")+ dateFormat.format(d[j], temp, pos)
+ " F> "+ s[j]+ (j > 0 && d[j] /*.getTime()*/ == d[j - 1] /*.getTime()*/ ? " d==" : "")
+ (j > 0 && s[j] == s[j - 1] ? " s==" : ""));
}
}
}
} catch (ParseException e) {
errln("Exception: " + e.getMessage());
logln(e.toString());
}
}
public int getField(Date d, int f) {
getFieldCal.setTime(d);
int ret = getFieldCal.get(f);
return ret;
}
public Date generateDate() {
double a = ran.nextDouble();
// Now 'a' ranges from 0..1; scale it to range from 0 to 8000 years
a *= 8000;
// Range from (4000-1970) BC to (8000-1970) AD
a -= 4000;
// Now scale up to ms
a *= 365.25 * 24 * 60 * 60 * 1000;
return new Date((long)a);
}
}