Return-Path: Delivered-To: apmail-jakarta-commons-dev-archive@www.apache.org Received: (qmail 20211 invoked from network); 13 Jul 2004 20:51:53 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur-2.apache.org with SMTP; 13 Jul 2004 20:51:53 -0000 Received: (qmail 42796 invoked by uid 500); 13 Jul 2004 20:51:46 -0000 Delivered-To: apmail-jakarta-commons-dev-archive@jakarta.apache.org Received: (qmail 42728 invoked by uid 500); 13 Jul 2004 20:51:46 -0000 Mailing-List: contact commons-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Jakarta Commons Developers List" Reply-To: "Jakarta Commons Developers List" Delivered-To: mailing list commons-dev@jakarta.apache.org Received: (qmail 42715 invoked by uid 500); 13 Jul 2004 20:51:46 -0000 Received: (qmail 42711 invoked by uid 99); 13 Jul 2004 20:51:46 -0000 X-ASF-Spam-Status: No, hits=0.5 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.27.1) with SMTP; Tue, 13 Jul 2004 13:51:45 -0700 Received: (qmail 20157 invoked by uid 1289); 13 Jul 2004 20:51:44 -0000 Date: 13 Jul 2004 20:51:44 -0000 Message-ID: <20040713205144.20156.qmail@minotaur.apache.org> From: rdonkin@apache.org To: jakarta-commons-cvs@apache.org Subject: cvs commit: jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/locale/converters BaseLocaleConverterTestCase.java DateLocaleConverterTestCase.java X-Virus-Checked: Checked X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N rdonkin 2004/07/13 13:51:44 Modified: beanutils/src/java/org/apache/commons/beanutils/locale/converters DateLocaleConverter.java beanutils/src/test/org/apache/commons/beanutils/locale/converters BaseLocaleConverterTestCase.java DateLocaleConverterTestCase.java Log: Committed patch related to bug #29772 submitted by Niall Pemberton. This patch actually fixes the more complex issue of working round a problem with some 1.4 JVMs rather than the reported bug (which had been fixed earlier). Revision Changes Path 1.10 +96 -27 jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/locale/converters/DateLocaleConverter.java Index: DateLocaleConverter.java =================================================================== RCS file: /home/cvs/jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/locale/converters/DateLocaleConverter.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- DateLocaleConverter.java 28 Feb 2004 13:18:35 -0000 1.9 +++ DateLocaleConverter.java 13 Jul 2004 20:51:44 -0000 1.10 @@ -17,12 +17,14 @@ package org.apache.commons.beanutils.locale.converters; import org.apache.commons.beanutils.locale.BaseLocaleConverter; +import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.Log; import java.text.ParseException; -import java.text.ParsePosition; import java.text.SimpleDateFormat; +import java.text.DateFormat; +import java.text.DateFormatSymbols; import java.util.Locale; @@ -48,6 +50,9 @@ /** Should the date conversion be lenient? */ boolean isLenient = false; + /** Default Pattern Characters */ + public static String defaultChars; + // ----------------------------------------------------------- Constructors /** @@ -244,36 +249,100 @@ * @param value The input object to be converted * @param pattern The pattern is used for the convertion * - * @exception org.apache.commons.beanutils.ConversionException if conversion cannot be performed - * successfully + * @exception org.apache.commons.beanutils.ConversionException + * if conversion cannot be performed successfully */ protected Object parse(Object value, String pattern) throws ParseException { - SimpleDateFormat formatter = getFormatter(pattern, locale); - if (locPattern) { - formatter.applyLocalizedPattern(pattern); - } - else { - formatter.applyPattern(pattern); + + if (locPattern) { + pattern = convertLocalizedPattern(pattern, locale); + } + + // Create Formatter - use default if pattern is null + DateFormat formatter = pattern == null ? DateFormat.getDateInstance(DateFormat.SHORT, locale) + : new SimpleDateFormat(pattern, locale); + formatter.setLenient(isLenient); + + + // Parse the Date + return formatter.parse((String) value); + } + + /** + * Convert a pattern from a localized format to the default format. + * + * @param locale The locale + * @param pattern The pattern in 'local' symbol format + * @return pattern in 'default' symbol format + */ + private String convertLocalizedPattern(String localizedPattern, Locale locale) { + + if (localizedPattern == null) + return null; + + // Note that this is a little obtuse. + // However, it is the best way that anyone can come up with + // that works with some 1.4 series JVM. + + // Initialize the default symbols + if (defaultChars == null) { + DateFormatSymbols defaultSymbols = new DateFormatSymbols(Locale.US); + defaultChars = defaultSymbols.getLocalPatternChars(); + } + + // Get the symbols for the localized pattern + DateFormatSymbols localizedSymbols = new DateFormatSymbols(locale); + String localChars = localizedSymbols.getLocalPatternChars(); + + if (defaultChars.equals(localChars)) { + return localizedPattern; + } + + // Convert the localized pattern to default + String convertedPattern = null; + try { + convertedPattern = convertPattern(localizedPattern, + localChars, + defaultChars); + } catch (Exception ex) { + log.warn("Converting pattern '" + localizedPattern + "' for " + locale, ex); + } + return convertedPattern; + } + + /** + *

Converts a Pattern from one character set to another.

+ */ + private String convertPattern(String pattern, String fromChars, String toChars) { + + StringBuffer converted = new StringBuffer(); + boolean quoted = false; + + for (int i = 0; i < pattern.length(); ++i) { + char thisChar = pattern.charAt(i); + if (quoted) { + if (thisChar == '\'') { + quoted = false; + } + } else { + if (thisChar == '\'') { + quoted = true; + } else if ((thisChar >= 'a' && thisChar <= 'z') || + (thisChar >= 'A' && thisChar <= 'Z')) { + int index = fromChars.indexOf(thisChar ); + if (index == -1) + throw new IllegalArgumentException( + "Illegal pattern character '" + thisChar + "'"); + thisChar = toChars.charAt(index); + } + } + converted.append(thisChar); } - return formatter.parse((String) value); - } - /** - * Gets an appropriate SimpleDateFormat for given locale, - * default Date format pattern is not provided. - */ - private SimpleDateFormat getFormatter(String pattern, Locale locale) { - // This method is a fix for null pattern, which would cause - // Null pointer exception when applied - // Note: that many constructors default the pattern to null, - // so it only makes sense to handle nulls gracefully - if(pattern == null) { - pattern = locPattern ? - new SimpleDateFormat().toLocalizedPattern() : new SimpleDateFormat().toPattern(); - log.warn("Null pattern was provided, defaulting to: " + pattern); + if (quoted) { + throw new IllegalArgumentException("Unfinished quote in pattern"); } - SimpleDateFormat format = new SimpleDateFormat(pattern, locale); - format.setLenient(isLenient); - return format; + + return converted.toString(); } } 1.2 +3 -11 jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/locale/converters/BaseLocaleConverterTestCase.java Index: BaseLocaleConverterTestCase.java =================================================================== RCS file: /home/cvs/jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/locale/converters/BaseLocaleConverterTestCase.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- BaseLocaleConverterTestCase.java 8 Jul 2004 13:12:06 -0000 1.1 +++ BaseLocaleConverterTestCase.java 13 Jul 2004 20:51:44 -0000 1.2 @@ -18,8 +18,8 @@ import junit.framework.TestCase; import java.util.Locale; -import org.apache.commons.beanutils.locale.BaseLocaleConverter -; +import java.text.DateFormatSymbols; +import org.apache.commons.beanutils.locale.BaseLocaleConverter; /** * Base Test Case for the DecimalLocaleConverter classes. @@ -45,19 +45,15 @@ protected Locale localizedLocale; protected String localizedDecimalPattern; protected String localizedIntegerPattern; - protected String localizedDatePattern; protected String localizedDecimalValue; protected String localizedIntegerValue; - protected String localizedDateValue; // Locale values protected Locale defaultLocale; protected String defaultDecimalPattern; protected String defaultIntegerPattern; - protected String defaultDatePattern; protected String defaultDecimalValue; protected String defaultIntegerValue; - protected String defaultDateValue; // Expected values @@ -81,19 +77,15 @@ defaultLocale = Locale.US; defaultDecimalPattern = "#,###.00"; defaultIntegerPattern = "#,###"; - defaultDatePattern = "d MMMM yyyy"; defaultDecimalValue = "1,234.56"; defaultIntegerValue = "1,234"; - defaultDateValue = "1 October 2004"; // Use German Locale (uses different separators to US) localizedLocale = Locale.GERMAN; localizedDecimalPattern = "#.###,00"; localizedIntegerPattern = "#.###"; - localizedDatePattern = "t MMMM uuuu"; localizedDecimalValue = "1.234,56"; localizedIntegerValue = "1.234"; - localizedDateValue = "1 Oktober 2004"; // Expected Values expectedDecimalValue = "1234.56"; 1.5 +302 -8 jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/locale/converters/DateLocaleConverterTestCase.java Index: DateLocaleConverterTestCase.java =================================================================== RCS file: /home/cvs/jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/locale/converters/DateLocaleConverterTestCase.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- DateLocaleConverterTestCase.java 28 Feb 2004 13:18:37 -0000 1.4 +++ DateLocaleConverterTestCase.java 13 Jul 2004 20:51:44 -0000 1.5 @@ -16,16 +16,17 @@ package org.apache.commons.beanutils.locale.converters; -import junit.framework.TestSuite; -import junit.framework.TestCase; - import java.text.SimpleDateFormat; import java.text.ParseException; +import java.text.DateFormatSymbols; import java.util.Locale; import org.apache.commons.beanutils.Converter; import org.apache.commons.beanutils.ConversionException; +import org.apache.commons.beanutils.locale.BaseLocaleConverter; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.logging.Log; /** * Test Case for the DateLocaleConverter class. @@ -34,7 +35,21 @@ * @version $Revision$ $Date$ */ -public class DateLocaleConverterTestCase extends TestCase { +public class DateLocaleConverterTestCase extends BaseLocaleConverterTestCase { + + /** All logging goes through this logger */ + private static Log log = LogFactory.getLog(DateLocaleConverterTestCase.class); + + protected String localizedDatePattern; + protected String localizedDateValue; + protected String localizedShortDateValue; + protected String defaultDatePattern; + protected String defaultDateValue; + protected String defaultShortDateValue; + + protected Object expectedValue; + + protected boolean validLocalDateSymbols; // ------------------------------------------------------------------------ @@ -42,10 +57,61 @@ super(name); } - // ------------------------------------------------------------------------ + // -------------------------------------------------- Overall Test Methods + + /** + * Set up instance variables required by this test case. + */ + public void setUp() throws Exception { + + super.setUp(); + + String version = System.getProperty("java.specification.version"); + log.warn("JDK Version "+version); + + + try { + SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd"); + expectedValue = format.parse("20041001"); + defaultValue = format.parse("19670316"); + } catch (Exception ex) { + log.error("Error creating expected/default dates", ex); + } + + // Default Locale (Use US) + defaultLocale = Locale.US; + defaultDatePattern = "d MMMM yyyy"; + defaultDateValue = "1 October 2004"; + defaultShortDateValue = "10/01/04"; + + // Use German Locale +// localizedLocale = Locale.GERMAN; // N.B. doesn't work for dates +// localizedLocale = Locale.GERMANY; // N.B. doesn't work for dates + localizedLocale = new Locale("de", "AT"); // Austria/German works + localizedDatePattern = "t MMMM uuuu"; + localizedDateValue = "1 Oktober 2004"; + localizedShortDateValue = "01.10.04"; + + // Test whether the "local pattern characters" are what we + // are expecting - Locale.GERMAN and Locale.GERMANY, Locale.FRENCH all + // returned the standard "English" pattern characters on my machine + // for JDK 1.4 (JDK 1.3 was OK). The Austria/German locale was OK though + String expectedChars = "GuMtkHmsSEDFwWahKzZ"; + DateFormatSymbols localizedSymbols = new DateFormatSymbols(localizedLocale); + String localChars = localizedSymbols.getLocalPatternChars(); + + // different JDK versions seem to have different numbers of pattern characters + int lth = localChars.length() > expectedChars.length() ? expectedChars.length() : + localChars.length() < expectedChars.length() ? localChars.length() : expectedChars.length(); + validLocalDateSymbols = expectedChars.substring(0, lth).equals(localChars.substring(0, lth)); - public static TestSuite suite() { - return new TestSuite(DateLocaleConverterTestCase.class); + } + + /** + * Tear down instance variables required by this test case. + */ + public void tearDown() { + super.tearDown(); } @@ -139,5 +205,233 @@ fail("Could not parse date (6) - " + e.getMessage()); } } + + /** + * Test Converter(defaultValue, locale, pattern, localizedPattern) constructor + */ + public void testConstructorMain() { + + // Skip this test if no valid symbols for the locale + if (!validLocalDateSymbols) { + log.error("Invalid locale symbols *** skipping testConstructorMain() **"); + return; + } + + // ------------- Construct with localized pattern ------------ + converter = new DateLocaleConverter(defaultValue, + localizedLocale, + localizedDatePattern, + true); + + + convertValueNoPattern(converter, "(A)", localizedDateValue, expectedValue); + convertValueWithPattern(converter, "(A)", localizedDateValue, localizedDatePattern, expectedValue); + convertInvalid(converter, "(A)", defaultValue); + convertNull(converter, "(A)", defaultValue); + + + // Convert value in the wrong format - should return default value + convertValueNoPattern(converter, "(B)", defaultDateValue, defaultValue); + + // Convert with non-localized pattern - should return default value + convertValueWithPattern(converter, "(B)", localizedDateValue, defaultDatePattern, defaultValue); + + // ************************************************************************** + // Convert with specified type + // + // BaseLocaleConverter completely ignores the type - so even if we specify + // Double.class here it still returns a Date. + // **** SHOULD IMPLEMENT THIS BEHAVIOUR **** + // ************************************************************************** + convertValueToType(converter, "(B)", String.class, localizedDateValue, localizedDatePattern, expectedValue); + + + // ------------- Construct with non-localized pattern ------------ + converter = new DateLocaleConverter(defaultValue, + localizedLocale, + defaultDatePattern, + false); + + + convertValueNoPattern(converter, "(C)", localizedDateValue, expectedValue); + convertValueWithPattern(converter, "(C)", localizedDateValue, defaultDatePattern, expectedValue); + convertInvalid(converter, "(C)", defaultValue); + convertNull(converter, "(C)", defaultValue); + + } + + /** + * Test Converter() constructor + * + * Uses the default locale, no default value + * + */ + public void testConstructor_2() { + + // ------------- Construct using default pattern & default locale ------------ + converter = new DateLocaleConverter(); + + // Perform Tests + convertValueNoPattern(converter, defaultShortDateValue, expectedValue); + convertValueWithPattern(converter, defaultDateValue, defaultDatePattern, expectedValue); + convertInvalid(converter, null); + convertNull(converter, null); + + } + + /** + * Test Converter(locPattern) constructor + * + * Uses the default locale, no default value + * + */ + public void testConstructor_3() { + + // ------------- Construct using default pattern & default locale -------- + converter = new DateLocaleConverter(true); + + // Perform Tests + convertValueNoPattern(converter, defaultShortDateValue, expectedValue); + convertValueWithPattern(converter, defaultDateValue, defaultDatePattern, expectedValue); + convertInvalid(converter, null); + convertNull(converter, null); + + + } + + /** + * Test Converter(Locale) constructor + */ + public void testConstructor_4() { + + // ------------- Construct using specified Locale -------- + converter = new DateLocaleConverter(localizedLocale); + + // Perform Tests + convertValueNoPattern(converter, localizedShortDateValue, expectedValue); + convertValueWithPattern(converter, localizedDateValue, defaultDatePattern, expectedValue); + convertInvalid(converter, null); + convertNull(converter, null); + + + } + + + /** + * Test Converter(Locale, locPattern) constructor + */ + public void testConstructor_5() { + + // Skip this test if no valid symbols for the locale + if (!validLocalDateSymbols) { + log.error("Invalid locale symbols *** skipping testConstructor_5() **"); + return; + } + + // ------------- Construct using specified Locale -------- + converter = new DateLocaleConverter(localizedLocale, true); + + // Perform Tests + convertValueNoPattern(converter, localizedShortDateValue, expectedValue); + convertValueWithPattern(converter, localizedDateValue, localizedDatePattern, expectedValue); + convertInvalid(converter, null); + convertNull(converter, null); + + + } + + /** + * Test Converter(Locale, pattern) constructor + */ + public void testConstructor_6() { + + // ------------- Construct using specified Locale -------- + converter = new DateLocaleConverter(localizedLocale, defaultDatePattern); + + // Perform Tests + convertValueNoPattern(converter, localizedDateValue, expectedValue); + convertValueWithPattern(converter, localizedDateValue, defaultDatePattern, expectedValue); + convertInvalid(converter, null); + convertNull(converter, null); + + } + + /** + * Test Converter(Locale, pattern, locPattern) constructor + */ + public void testConstructor_7() { + + // Skip this test if no valid symbols for the locale + if (!validLocalDateSymbols) { + log.error("Invalid locale symbols *** skipping testConstructor_7() **"); + return; + } + + // ------------- Construct using specified Locale -------- + converter = new DateLocaleConverter(localizedLocale, localizedDatePattern, true); + + // Perform Tests + convertValueNoPattern(converter, localizedDateValue, expectedValue); + convertValueWithPattern(converter, localizedDateValue, localizedDatePattern, expectedValue); + convertInvalid(converter, null); + convertNull(converter, null); + + } + + /** + * Test Converter(defaultValue) constructor + */ + public void testConstructor_8() { + + // ------------- Construct using specified Locale -------- + converter = new DateLocaleConverter(defaultValue); + + // Perform Tests + convertValueNoPattern(converter, defaultShortDateValue, expectedValue); + convertValueWithPattern(converter, defaultDateValue, defaultDatePattern, expectedValue); + convertInvalid(converter, defaultValue); + convertNull(converter, defaultValue); + + } + + /** + * Test Converter(defaultValue, locPattern) constructor + */ + public void testConstructor_9() { + + // ------------- Construct using specified Locale -------- + converter = new DateLocaleConverter(defaultValue, true); + + // Perform Tests + convertValueNoPattern(converter, defaultShortDateValue, expectedValue); + convertValueWithPattern(converter, defaultDateValue, defaultDatePattern, expectedValue); + convertInvalid(converter, defaultValue); + convertNull(converter, defaultValue); + + } + + /** + * Test Converting an invalid value. + */ + protected void convertInvalid(BaseLocaleConverter converter, String msgId, Object expectedValue) { + + // Convert value with no pattern + try { + result = converter.convert("xyz"); + if (expectedValue == null) { + fail("Expected ConversionException if no default value " + msgId); + } + } catch (Exception e) { + if (expectedValue != null) { + fail("Expected default value " + msgId + " threw " + e); + } + } + + if (expectedValue != null) { + assertEquals("Check invalid conversion is default " + msgId, expectedValue, result); + } + + } + } --------------------------------------------------------------------- To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org For additional commands, e-mail: commons-dev-help@jakarta.apache.org