| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.net.ftp.parser; |
| |
| import java.text.Format; |
| import java.text.ParseException; |
| import java.text.SimpleDateFormat; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.GregorianCalendar; |
| import java.util.TimeZone; |
| |
| import org.apache.commons.net.ftp.FTPClientConfig; |
| |
| import junit.framework.TestCase; |
| import junit.framework.TestSuite; |
| |
| /** |
| * Test the FTPTimestampParser class. |
| * |
| * @author scohen |
| * |
| */ |
| public class FTPTimestampParserImplTest extends TestCase { |
| |
| private static final int TWO_HOURS_OF_MILLISECONDS = 2 * 60 * 60 * 1000; |
| |
| public void testParseTimestamp() { |
| Calendar cal = Calendar.getInstance(); |
| cal.add(Calendar.HOUR_OF_DAY, 1); |
| cal.set(Calendar.SECOND,0); |
| cal.set(Calendar.MILLISECOND,0); |
| Date anHourFromNow = cal.getTime(); |
| FTPTimestampParserImpl parser = new FTPTimestampParserImpl(); |
| SimpleDateFormat sdf = |
| new SimpleDateFormat(parser.getRecentDateFormatString()); |
| String fmtTime = sdf.format(anHourFromNow); |
| try { |
| Calendar parsed = parser.parseTimestamp(fmtTime); |
| // since the timestamp is ahead of now (by one hour), |
| // this must mean the file's date refers to a year ago. |
| assertEquals("test.roll.back.year", 1, cal.get(Calendar.YEAR) - parsed.get(Calendar.YEAR)); |
| } catch (ParseException e) { |
| fail("Unable to parse"); |
| } |
| } |
| |
| public void testParseTimestampWithSlop() { |
| Calendar cal = Calendar.getInstance(); |
| cal.add(Calendar.HOUR_OF_DAY, 1); |
| cal.set(Calendar.SECOND,0); |
| cal.set(Calendar.MILLISECOND,0); |
| Date anHourFromNow = cal.getTime(); |
| cal.add(Calendar.DATE, 1); |
| Date anHourFromNowTomorrow = cal.getTime(); |
| cal.add(Calendar.DATE, -1); |
| |
| FTPTimestampParserImpl parser = new FTPTimestampParserImpl(); |
| |
| // set the "slop" factor on |
| parser.setLenientFutureDates(true); |
| |
| SimpleDateFormat sdf = |
| new SimpleDateFormat(parser.getRecentDateFormatString()); |
| try { |
| String fmtTime = sdf.format(anHourFromNow); |
| Calendar parsed = parser.parseTimestamp(fmtTime); |
| // the timestamp is ahead of now (by one hour), but |
| // that's within range of the "slop" factor. |
| // so the date is still considered this year. |
| assertEquals("test.slop.no.roll.back.year", 0, cal.get(Calendar.YEAR) - parsed.get(Calendar.YEAR)); |
| |
| // add a day to get beyond the range of the slop factor. |
| // this must mean the file's date refers to a year ago. |
| fmtTime = sdf.format(anHourFromNowTomorrow); |
| parsed = parser.parseTimestamp(fmtTime); |
| assertEquals("test.slop.roll.back.year", 1, cal.get(Calendar.YEAR) - parsed.get(Calendar.YEAR)); |
| |
| } catch (ParseException e) { |
| fail("Unable to parse"); |
| } |
| } |
| |
| public void testParseTimestampAcrossTimeZones() { |
| |
| |
| Calendar cal = Calendar.getInstance(); |
| cal.set(Calendar.SECOND,0); |
| cal.set(Calendar.MILLISECOND,0); |
| |
| cal.add(Calendar.HOUR_OF_DAY, 1); |
| Date anHourFromNow = cal.getTime(); |
| |
| cal.add(Calendar.HOUR_OF_DAY, 2); |
| Date threeHoursFromNow = cal.getTime(); |
| cal.add(Calendar.HOUR_OF_DAY, -2); |
| |
| FTPTimestampParserImpl parser = new FTPTimestampParserImpl(); |
| |
| // assume we are FTPing a server in Chicago, two hours ahead of |
| // L. A. |
| FTPClientConfig config = |
| new FTPClientConfig(FTPClientConfig.SYST_UNIX); |
| config.setDefaultDateFormatStr(FTPTimestampParser.DEFAULT_SDF); |
| config.setRecentDateFormatStr(FTPTimestampParser.DEFAULT_RECENT_SDF); |
| // 2 hours difference |
| config.setServerTimeZoneId("America/Chicago"); |
| parser.configure(config); |
| |
| SimpleDateFormat sdf = (SimpleDateFormat) |
| parser.getRecentDateFormat().clone(); |
| |
| // assume we're in the US Pacific Time Zone |
| TimeZone tzla = TimeZone.getTimeZone("America/Los_Angeles"); |
| sdf.setTimeZone(tzla); |
| |
| // get formatted versions of time in L.A. |
| String fmtTimePlusOneHour = sdf.format(anHourFromNow); |
| String fmtTimePlusThreeHours = sdf.format(threeHoursFromNow); |
| |
| |
| try { |
| Calendar parsed = parser.parseTimestamp(fmtTimePlusOneHour); |
| // the only difference should be the two hours |
| // difference, no rolling back a year should occur. |
| assertEquals("no.rollback.because.of.time.zones", |
| TWO_HOURS_OF_MILLISECONDS, |
| cal.getTime().getTime() - parsed.getTime().getTime()); |
| } catch (ParseException e){ |
| fail("Unable to parse " + fmtTimePlusOneHour); |
| } |
| |
| //but if the file's timestamp is THREE hours ahead of now, that should |
| //cause a rollover even taking the time zone difference into account. |
| //Since that time is still later than ours, it is parsed as occurring |
| //on this date last year. |
| try { |
| Calendar parsed = parser.parseTimestamp(fmtTimePlusThreeHours); |
| // rollback should occur here. |
| assertEquals("rollback.even.with.time.zones", |
| 1, cal.get(Calendar.YEAR) - parsed.get(Calendar.YEAR)); |
| } catch (ParseException e){ |
| fail("Unable to parse" + fmtTimePlusThreeHours); |
| } |
| } |
| |
| |
| public void testParser() { |
| FTPTimestampParserImpl parser = new FTPTimestampParserImpl(); |
| try { |
| parser.parseTimestamp("feb 22 2002"); |
| } catch (ParseException e) { |
| fail("failed.to.parse.default"); |
| } |
| try { |
| parser.parseTimestamp("f\u00e9v 22 2002"); |
| fail("should.have.failed.to.parse.default"); |
| } catch (ParseException e) { |
| // this is the success case |
| } |
| |
| FTPClientConfig config = new FTPClientConfig(); |
| config.setDefaultDateFormatStr("d MMM yyyy"); |
| config.setRecentDateFormatStr("d MMM HH:mm"); |
| config.setServerLanguageCode("fr"); |
| parser.configure(config); |
| try { |
| parser.parseTimestamp("d\u00e9c 22 2002"); |
| fail("incorrect.field.order"); |
| } catch (ParseException e) { |
| // this is the success case |
| } |
| try { |
| parser.parseTimestamp("22 d\u00e9c 2002"); |
| } catch (ParseException e) { |
| fail("failed.to.parse.french"); |
| } |
| |
| try { |
| parser.parseTimestamp("22 dec 2002"); |
| fail("incorrect.language"); |
| } catch (ParseException e) { |
| // this is the success case |
| } |
| try { |
| parser.parseTimestamp("29 f\u00e9v 2002"); |
| fail("nonexistent.date"); |
| } catch (ParseException e) { |
| // this is the success case |
| } |
| |
| try { |
| parser.parseTimestamp("22 ao\u00fb 30:02"); |
| fail("bad.hour"); |
| } catch (ParseException e) { |
| // this is the success case |
| } |
| |
| try { |
| parser.parseTimestamp("22 ao\u00fb 20:74"); |
| fail("bad.minute"); |
| } catch (ParseException e) { |
| // this is the success case |
| } |
| try { |
| parser.parseTimestamp("28 ao\u00fb 20:02"); |
| } catch (ParseException e) { |
| fail("failed.to.parse.french.recent"); |
| } |
| } |
| |
| /* |
| * Check how short date is interpreted at a given time. |
| * Check both with and without lenient future dates |
| */ |
| private void checkShortParse(String msg, Calendar now, Calendar input) throws ParseException { |
| checkShortParse(msg, now, input, false); |
| checkShortParse(msg, now, input, true); |
| } |
| |
| /* |
| * Check how short date is interpreted at a given time |
| * Check only using specified lenient future dates setting |
| */ |
| private void checkShortParse(String msg, Calendar now, Calendar input, boolean lenient) throws ParseException { |
| FTPTimestampParserImpl parser = new FTPTimestampParserImpl(); |
| parser.setLenientFutureDates(lenient); |
| Format shortFormat = parser.getRecentDateFormat(); // It's expecting this format |
| Format longFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm"); |
| |
| final String shortDate = shortFormat.format(input.getTime()); |
| Calendar output=parser.parseTimestamp(shortDate, now); |
| int outyear = output.get(Calendar.YEAR); |
| int outdom = output.get(Calendar.DAY_OF_MONTH); |
| int outmon = output.get(Calendar.MONTH); |
| int inyear = input.get(Calendar.YEAR); |
| int indom = input.get(Calendar.DAY_OF_MONTH); |
| int inmon = input.get(Calendar.MONTH); |
| if (indom != outdom || inmon != outmon || inyear != outyear){ |
| fail("Test: '"+msg+"' Server="+longFormat.format(now.getTime()) |
| +". Failed to parse "+shortDate |
| +". Actual "+longFormat.format(output.getTime()) |
| +". Expected "+longFormat.format(input.getTime())); |
| } |
| } |
| |
| public void testParseShortPastDates1() throws Exception { |
| GregorianCalendar now = new GregorianCalendar(2001, Calendar.MAY, 30, 12, 0); |
| checkShortParse("2001-5-30",now,now); // should always work |
| GregorianCalendar target = (GregorianCalendar) now.clone(); |
| target.add(Calendar.WEEK_OF_YEAR, -1); |
| checkShortParse("2001-5-30 -1 week",now,target); |
| target.add(Calendar.WEEK_OF_YEAR, -12); |
| checkShortParse("2001-5-30 -13 weeks",now,target); |
| target.add(Calendar.WEEK_OF_YEAR, -13); |
| checkShortParse("2001-5-30 -26 weeks",now,target); |
| } |
| |
| public void testParseShortPastDates2() throws Exception { |
| GregorianCalendar now = new GregorianCalendar(2004, Calendar.AUGUST, 1, 12, 0); |
| checkShortParse("2004-8-1",now,now); // should always work |
| GregorianCalendar target = (GregorianCalendar) now.clone(); |
| target.add(Calendar.WEEK_OF_YEAR, -1); |
| checkShortParse("2004-8-1 -1 week",now,target); |
| target.add(Calendar.WEEK_OF_YEAR, -12); |
| checkShortParse("2004-8-1 -13 weeks",now,target); |
| target.add(Calendar.WEEK_OF_YEAR, -13); |
| checkShortParse("2004-8-1 -26 weeks",now,target); |
| } |
| |
| // It has not yet been decided how to handle future dates, so skip these tests for now |
| |
| // public void testParseShortFutureDates1() throws Exception { |
| // GregorianCalendar now = new GregorianCalendar(2001, Calendar.MAY, 30, 12, 0); |
| // checkShortParse("2001-5-30",now,now); // should always work |
| // GregorianCalendar target = (GregorianCalendar) now.clone(); |
| // target.add(Calendar.WEEK_OF_YEAR, 1); |
| // checkShortParse("2001-5-30 +1 week",now,target); |
| // target.add(Calendar.WEEK_OF_YEAR, 12); |
| // checkShortParse("2001-5-30 +13 weeks",now,target); |
| // target.add(Calendar.WEEK_OF_YEAR, 13); |
| // checkShortParse("2001-5-30 +26 weeks",now,target); |
| // } |
| |
| // public void testParseShortFutureDates2() throws Exception { |
| // GregorianCalendar now = new GregorianCalendar(2004, Calendar.AUGUST, 1, 12, 0); |
| // checkShortParse("2004-8-1",now,now); // should always work |
| // GregorianCalendar target = (GregorianCalendar) now.clone(); |
| // target.add(Calendar.WEEK_OF_YEAR, 1); |
| // checkShortParse("2004-8-1 +1 week",now,target); |
| // target.add(Calendar.WEEK_OF_YEAR, 12); |
| // checkShortParse("2004-8-1 +13 weeks",now,target); |
| // target.add(Calendar.WEEK_OF_YEAR, 13); |
| // checkShortParse("2004-8-1 +26 weeks",now,target); |
| // } |
| |
| // Test leap year if current year is a leap year |
| public void testFeb29IfLeapYear() throws Exception{ |
| GregorianCalendar now = new GregorianCalendar(); |
| final int thisYear = now.get(Calendar.YEAR); |
| if (now.isLeapYear(thisYear) && now.before(new GregorianCalendar(thisYear,Calendar.AUGUST,29))){ |
| GregorianCalendar target = new GregorianCalendar(thisYear,Calendar.FEBRUARY,29); |
| checkShortParse("Feb 29th",now,target); |
| } else { |
| System.out.println("Skipping Feb 29 test"); |
| } |
| } |
| |
| // Test Feb 29 for a known leap year |
| public void testFeb29LeapYear() throws Exception{ |
| int year = 2000; // Use same year for current and short date |
| GregorianCalendar now = new GregorianCalendar(year, Calendar.APRIL, 1, 12, 0); |
| checkShortParse("Feb 29th 2000",now,new GregorianCalendar(year, Calendar.FEBRUARY,29)); |
| } |
| |
| // Test Feb 29 for a known non-leap year - should fail |
| public void testFeb29NonLeapYear(){ |
| GregorianCalendar now = new GregorianCalendar(1999, Calendar.APRIL, 1, 12, 0); |
| // Note: we use a known leap year for the target date to avoid rounding up |
| try { |
| checkShortParse("Feb 29th 1999",now,new GregorianCalendar(2000, Calendar.FEBRUARY,29)); |
| fail("Should have failed to parse Feb 29th 1999"); |
| } catch (ParseException expected) { |
| } |
| } |
| |
| public void testParseDec31Lenient() throws Exception { |
| GregorianCalendar now = new GregorianCalendar(2007, Calendar.DECEMBER, 30, 12, 0); |
| checkShortParse("2007-12-30",now,now); // should always work |
| GregorianCalendar target = (GregorianCalendar) now.clone(); |
| target.add(Calendar.DAY_OF_YEAR, +1); // tomorrow |
| checkShortParse("2007-12-31",now,target, true); |
| } |
| |
| public void testParseJan01Lenient() throws Exception { |
| GregorianCalendar now = new GregorianCalendar(2007, Calendar.DECEMBER, 31, 12, 0); |
| checkShortParse("2007-12-31",now,now); // should always work |
| GregorianCalendar target = (GregorianCalendar) now.clone(); |
| target.add(Calendar.DAY_OF_YEAR, +1); // tomorrow |
| checkShortParse("2008-1-1",now,target, true); |
| } |
| |
| public void testParseJan01() throws Exception { |
| GregorianCalendar now = new GregorianCalendar(2007, Calendar.JANUARY, 1, 12, 0); |
| checkShortParse("2007-01-01",now,now); // should always work |
| GregorianCalendar target = new GregorianCalendar(2006, Calendar.DECEMBER, 31, 12, 0); |
| checkShortParse("2006-12-31",now,target, true); |
| checkShortParse("2006-12-31",now,target, false); |
| } |
| |
| /** |
| * Method suite. |
| * |
| * @return TestSuite |
| */ |
| public static TestSuite suite() |
| { |
| return(new TestSuite(FTPTimestampParserImplTest.class)); |
| } |
| |
| |
| |
| } |