001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.beanutils.converters;
019:
020: import java.text.DateFormat;
021: import java.text.SimpleDateFormat;
022: import java.util.Calendar;
023: import java.util.Date;
024: import java.util.GregorianCalendar;
025: import java.util.Locale;
026:
027: import junit.framework.TestCase;
028: import org.apache.commons.beanutils.Converter;
029: import org.apache.commons.beanutils.ConversionException;
030:
031: /**
032: * Abstract base for <Date>Converter classes.
033: *
034: * @version $Revision: 471689 $ $Date: 2006-11-06 10:52:49 +0000 (Mon, 06 Nov 2006) $
035: */
036:
037: public abstract class DateConverterTestBase extends TestCase {
038:
039: // ------------------------------------------------------------------------
040:
041: /**
042: * Construtc a new test case.
043: * @param name Name of the test
044: */
045: public DateConverterTestBase(String name) {
046: super (name);
047: }
048:
049: // ------------------------------------------------------------------------
050:
051: /**
052: * Create the Converter with no default value.
053: * @return A new Converter
054: */
055: protected abstract DateTimeConverter makeConverter();
056:
057: /**
058: * Create the Converter with a default value.
059: * @param defaultValue The default value
060: * @return A new Converter
061: */
062: protected abstract DateTimeConverter makeConverter(
063: Object defaultValue);
064:
065: /**
066: * Return the expected type
067: * @return The expected type
068: */
069: protected abstract Class getExpectedType();
070:
071: /**
072: * Convert from a Calendar to the appropriate Date type
073: *
074: * @param value The Calendar value to convert
075: * @return The converted value
076: */
077: protected abstract Object toType(Calendar value);
078:
079: // ------------------------------------------------------------------------
080:
081: /**
082: * Assumes ConversionException in response to covert(getExpectedType(), null).
083: */
084: public void testConvertNull() {
085: try {
086: makeConverter().convert(getExpectedType(), null);
087: fail("Expected ConversionException");
088: } catch (ConversionException e) {
089: // expected
090: }
091: }
092:
093: /**
094: * Assumes convert() returns some non-null
095: * instance of getExpectedType().
096: */
097: public void testConvertDate() {
098: String[] message = { "from Date", "from Calendar",
099: "from SQL Date", "from SQL Time", "from SQL Timestamp" };
100:
101: long now = System.currentTimeMillis();
102:
103: Object[] date = { new Date(now),
104: new java.util.GregorianCalendar(),
105: new java.sql.Date(now), new java.sql.Time(now),
106: new java.sql.Timestamp(now) };
107:
108: // Initialize calendar also with same ms to avoid a failing test in a new time slice
109: ((GregorianCalendar) date[1]).setTime(new Date(now));
110:
111: for (int i = 0; i < date.length; i++) {
112: Object val = makeConverter().convert(getExpectedType(),
113: date[i]);
114: assertNotNull("Convert " + message[i]
115: + " should not be null", val);
116: assertTrue("Convert " + message[i] + " should return a "
117: + getExpectedType().getName(), getExpectedType()
118: .isInstance(val));
119: assertEquals("Convert " + message[i] + " should return a "
120: + date[0], now, getTimeInMillis(val));
121: }
122: }
123:
124: /**
125: * Test Default Type conversion (i.e. don't specify target type)
126: */
127: public void testDefaultType() {
128: String pattern = "yyyy-MM-dd";
129:
130: // Create & Configure the Converter
131: DateTimeConverter converter = makeConverter();
132: converter.setPattern(pattern);
133:
134: // Valid String --> Type Conversion
135: String testString = "2006-10-29";
136: Calendar calendar = toCalendar(testString, pattern, null);
137: Object expected = toType(calendar);
138:
139: Object result = converter.convert(null, testString);
140: if (getExpectedType().equals(Calendar.class)) {
141: assertTrue("TYPE ", getExpectedType().isAssignableFrom(
142: result.getClass()));
143: } else {
144: assertEquals("TYPE ", getExpectedType(), result.getClass());
145: }
146: assertEquals("VALUE ", expected, result);
147: }
148:
149: /**
150: * Test default String to type conversion
151: *
152: * N.B. This method is overriden by test case
153: * implementations for java.sql.Date/Time/Timestamp
154: */
155: public void testDefaultStringToTypeConvert() {
156:
157: // Create & Configure the Converter
158: DateTimeConverter converter = makeConverter();
159: converter.setUseLocaleFormat(false);
160: try {
161: converter.convert(getExpectedType(), "2006-10-23");
162: fail("Expected Conversion exception");
163: } catch (ConversionException e) {
164: // expected result
165: }
166:
167: }
168:
169: /**
170: * Test Conversion to String
171: */
172: public void testStringConversion() {
173:
174: String pattern = "yyyy-MM-dd";
175:
176: // Create & Configure the Converter
177: DateTimeConverter converter = makeConverter();
178: converter.setPattern(pattern);
179:
180: // Create Values
181: String expected = "2006-10-29";
182: Calendar calendar = toCalendar(expected, pattern, null);
183:
184: // Type --> String Conversion
185: stringConversion(converter, expected, toType(calendar));
186:
187: // Calendar --> String Conversion
188: stringConversion(converter, expected, calendar);
189:
190: // java.util.Date --> String Conversion
191: stringConversion(converter, expected, toDate(calendar));
192:
193: // java.sql.Date --> String Conversion
194: stringConversion(converter, expected, toSqlDate(calendar));
195:
196: // java.sql.Timestamp --> String Conversion
197: stringConversion(converter, expected, toSqlTimestamp(calendar));
198:
199: // java.sql.Time --> String Conversion
200: stringConversion(converter, expected, toSqlTime(calendar));
201:
202: stringConversion(converter, null, null);
203: stringConversion(converter, "", "");
204:
205: }
206:
207: /**
208: * Test Converter with no default value
209: */
210: public void testPatternNoDefault() {
211:
212: String pattern = "yyyy-MM-dd";
213:
214: // Create & Configure the Converter
215: DateTimeConverter converter = makeConverter();
216: converter.setPattern(pattern);
217:
218: // Valid String --> Type Conversion
219: String testString = "2006-10-29";
220: Calendar calendar = toCalendar(testString, pattern, null);
221: Object expected = toType(calendar);
222: validConversion(converter, expected, testString);
223:
224: // Valid java.util.Date --> Type Conversion
225: validConversion(converter, expected, calendar);
226:
227: // Valid Calendar --> Type Conversion
228: validConversion(converter, expected, toDate(calendar));
229:
230: // Test java.sql.Date --> Type Conversion
231: validConversion(converter, expected, toSqlDate(calendar));
232:
233: // java.sql.Timestamp --> String Conversion
234: validConversion(converter, expected, toSqlTimestamp(calendar));
235:
236: // java.sql.Time --> String Conversion
237: validConversion(converter, expected, toSqlTime(calendar));
238:
239: // Invalid Conversions
240: invalidConversion(converter, null);
241: invalidConversion(converter, "");
242: invalidConversion(converter, "2006-10-2X");
243: invalidConversion(converter, "2006/10/01");
244: invalidConversion(converter, "02/10/2006");
245: invalidConversion(converter, "02/10/06");
246: invalidConversion(converter, new Integer(2));
247:
248: }
249:
250: /**
251: * Test Converter with no default value
252: */
253: public void testPatternDefault() {
254:
255: String pattern = "yyyy-MM-dd";
256:
257: // Create & Configure the Converter
258: Object defaultValue = toType("2000-01-01", pattern, null);
259: assertNotNull("Check default date", defaultValue);
260: DateTimeConverter converter = makeConverter(defaultValue);
261: converter.setPattern(pattern);
262:
263: // Valid String --> Type Conversion
264: String testString = "2006-10-29";
265: Object expected = toType(testString, pattern, null);
266: validConversion(converter, expected, testString);
267:
268: // Invalid Values, expect default value
269: validConversion(converter, defaultValue, null);
270: validConversion(converter, defaultValue, "");
271: validConversion(converter, defaultValue, "2006-10-2X");
272: validConversion(converter, defaultValue, "2006/10/01");
273: validConversion(converter, defaultValue, "02/10/06");
274: validConversion(converter, defaultValue, new Integer(2));
275:
276: }
277:
278: /**
279: * Test Converter with no default value
280: */
281: public void testPatternNullDefault() {
282:
283: String pattern = "yyyy-MM-dd";
284:
285: // Create & Configure the Converter
286: Object defaultValue = null;
287: DateTimeConverter converter = makeConverter(defaultValue);
288: converter.setPattern(pattern);
289:
290: // Valid String --> Type Conversion
291: String testString = "2006-10-29";
292: Object expected = toType(testString, pattern, null);
293: validConversion(converter, expected, testString);
294:
295: // Invalid Values, expect default --> null
296: validConversion(converter, defaultValue, null);
297: validConversion(converter, defaultValue, "");
298: validConversion(converter, defaultValue, "2006-10-2X");
299: validConversion(converter, defaultValue, "2006/10/01");
300: validConversion(converter, defaultValue, "02/10/06");
301: validConversion(converter, defaultValue, new Integer(2));
302:
303: }
304:
305: /**
306: * Test Converter with multiple patterns
307: */
308: public void testMultiplePatterns() {
309: String testString = null;
310: Object expected = null;
311:
312: // Create & Configure the Converter
313: String[] patterns = new String[] { "yyyy-MM-dd", "yyyy/MM/dd" };
314: DateTimeConverter converter = makeConverter();
315: converter.setPatterns(patterns);
316:
317: // First Pattern
318: testString = "2006-10-28";
319: expected = toType(testString, patterns[0], null);
320: validConversion(converter, expected, testString);
321:
322: // Second pattern
323: testString = "2006/10/18";
324: expected = toType(testString, patterns[1], null);
325: validConversion(converter, expected, testString);
326:
327: // Invalid Conversion
328: invalidConversion(converter, "17/03/2006");
329: invalidConversion(converter, "17.03.2006");
330:
331: }
332:
333: /**
334: * Test Date Converter with no default value
335: */
336: public void testLocale() {
337:
338: // Re-set the default Locale to Locale.US
339: Locale defaultLocale = Locale.getDefault();
340: Locale.setDefault(Locale.US);
341:
342: String pattern = "M/d/yy"; // SHORT style date format for US Locale
343:
344: // Create & Configure the Converter
345: DateTimeConverter converter = makeConverter();
346: converter.setUseLocaleFormat(true);
347:
348: // Valid String --> Type Conversion
349: String testString = "10/28/06";
350: Object expected = toType(testString, pattern, null);
351: validConversion(converter, expected, testString);
352:
353: // Invalid Conversions
354: invalidConversion(converter, null);
355: invalidConversion(converter, "");
356: invalidConversion(converter, "2006-10-2X");
357: invalidConversion(converter, "10.28.06");
358: invalidConversion(converter, "10-28-06");
359: invalidConversion(converter, new Integer(2));
360:
361: // Restore the default Locale
362: Locale.setDefault(defaultLocale);
363:
364: }
365:
366: /**
367: * Test Converter with types it can't handle
368: */
369: public void testInvalidType() {
370:
371: // Create & Configure the Converter
372: DateTimeConverter converter = makeConverter();
373:
374: // Invalid Class Type
375: try {
376: converter.convert(Character.class, new Date());
377: fail("Requested Character.class conversion, expected ConversionException");
378: } catch (ConversionException e) {
379: // Expected result
380: }
381: }
382:
383: /**
384: * Test Conversion to the required type
385: * @param converter The converter to use
386: * @param expected The expected result
387: * @param value The value to convert
388: */
389: void validConversion(Converter converter, Object expected,
390: Object value) {
391: String valueType = (value == null ? "null" : value.getClass()
392: .getName());
393: String msg = "Converting '" + valueType + "' value '" + value
394: + "'";
395: try {
396: Object result = converter.convert(getExpectedType(), value);
397: Class resultType = (result == null ? null : result
398: .getClass());
399: Class expectType = (expected == null ? null : expected
400: .getClass());
401: assertEquals("TYPE " + msg, expectType, resultType);
402: assertEquals("VALUE " + msg, expected, result);
403: } catch (Exception ex) {
404: fail(msg + " threw " + ex.toString());
405: }
406: }
407:
408: /**
409: * Test Conversion to String
410: * @param converter The converter to use
411: * @param expected The expected result
412: * @param value The value to convert
413: */
414: void stringConversion(Converter converter, String expected,
415: Object value) {
416: String valueType = (value == null ? "null" : value.getClass()
417: .getName());
418: String msg = "Converting '" + valueType + "' value '" + value
419: + "' to String";
420: try {
421: Object result = converter.convert(String.class, value);
422: Class resultType = (result == null ? null : result
423: .getClass());
424: Class expectType = (expected == null ? null : expected
425: .getClass());
426: assertEquals("TYPE " + msg, expectType, resultType);
427: assertEquals("VALUE " + msg, expected, result);
428: } catch (Exception ex) {
429: fail(msg + " threw " + ex.toString());
430: }
431: }
432:
433: /**
434: * Test Conversion Error
435: * @param converter The converter to use
436: * @param value The value to convert
437: */
438: void invalidConversion(Converter converter, Object value) {
439: String valueType = (value == null ? "null" : value.getClass()
440: .getName());
441: String msg = "Converting '" + valueType + "' value '" + value
442: + "'";
443: try {
444: Object result = converter.convert(getExpectedType(), value);
445: fail(msg + ", expected ConversionException, but result = '"
446: + result + "'");
447: } catch (ConversionException ex) {
448: // Expected Result
449: }
450: }
451:
452: /**
453: * Parse a String value to the required type
454: * @param value The String value to parse
455: * @param pattern The date pattern
456: * @param locale The locale to use (or null)
457: * @return parsed Calendar value
458: */
459: Object toType(String value, String pattern, Locale locale) {
460: Calendar calendar = toCalendar(value, pattern, locale);
461: return toType(calendar);
462: }
463:
464: /**
465: * Parse a String value to a Calendar
466: * @param value The String value to parse
467: * @param pattern The date pattern
468: * @param locale The locale to use (or null)
469: * @return parsed Calendar value
470: */
471: Calendar toCalendar(String value, String pattern, Locale locale) {
472: Calendar calendar = null;
473: try {
474: DateFormat format = (locale == null) ? new SimpleDateFormat(
475: pattern)
476: : new SimpleDateFormat(pattern, locale);
477: format.setLenient(false);
478: format.parse(value);
479: calendar = format.getCalendar();
480: } catch (Exception e) {
481: fail("Error creating Calendar value ='" + value
482: + ", pattern='" + pattern + "' " + e.toString());
483: }
484: return calendar;
485: }
486:
487: /**
488: * Convert a Calendar to a java.util.Date
489: * @param calendar The calendar object to convert
490: * @return The converted java.util.Date
491: */
492: Date toDate(Calendar calendar) {
493: return calendar.getTime();
494: }
495:
496: /**
497: * Convert a Calendar to a java.sql.Date
498: * @param calendar The calendar object to convert
499: * @return The converted java.sql.Date
500: */
501: java.sql.Date toSqlDate(Calendar calendar) {
502: return new java.sql.Date(getTimeInMillis(calendar));
503: }
504:
505: /**
506: * Convert a Calendar to a java.sql.Time
507: * @param calendar The calendar object to convert
508: * @return The converted java.sql.Time
509: */
510: java.sql.Time toSqlTime(Calendar calendar) {
511: return new java.sql.Time(getTimeInMillis(calendar));
512: }
513:
514: /**
515: * Convert a Calendar to a java.sql.Timestamp
516: * @param calendar The calendar object to convert
517: * @return The converted java.sql.Timestamp
518: */
519: java.sql.Timestamp toSqlTimestamp(Calendar calendar) {
520: return new java.sql.Timestamp(getTimeInMillis(calendar));
521: }
522:
523: /**
524: * Convert a Date or Calendar objects to the time in millisconds
525: * @param date The date or calendar object
526: * @return The time in milliseconds
527: */
528: long getTimeInMillis(Object date) {
529:
530: if (date instanceof java.sql.Timestamp) {
531: // ---------------------- JDK 1.3 Fix ----------------------
532: // N.B. Prior to JDK 1.4 the Timestamp's getTime() method
533: // didn't include the milliseconds. The following code
534: // ensures it works consistently accross JDK versions
535: java.sql.Timestamp timestamp = (java.sql.Timestamp) date;
536: long timeInMillis = ((timestamp.getTime() / 1000) * 1000);
537: timeInMillis += timestamp.getNanos() / 1000000;
538: return timeInMillis;
539: }
540:
541: if (date instanceof Calendar) {
542: return ((Calendar) date).getTime().getTime();
543: } else {
544: return ((Date) date).getTime();
545: }
546: }
547: }
|