text: /*
   * 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.
   */
  
  #include <log4cxx/helpers/cacheddateformat.h>
  #include "../logunit.h"
  #include <log4cxx/helpers/absolutetimedateformat.h>
  #include <log4cxx/helpers/iso8601dateformat.h>
  #include <log4cxx/helpers/relativetimedateformat.h>
  #include <log4cxx/helpers/pool.h>
  #include <locale>
  #include "../insertwide.h"
  #include <apr.h>
  #include <apr_time.h>
  #include "localechanger.h"
  
  using namespace log4cxx;
  using namespace log4cxx::helpers;
  using namespace log4cxx::pattern;
  
  #define LOCALE_US "C"
  #if defined(_WIN32)
  	#define LOCALE_JP "Japanese_japan"
  #else
  	#define LOCALE_JP "ja_JP"
  #endif
  
  
  //Define INT64_C for compilers that don't have it
  #if (!defined(INT64_C))
  	#define INT64_C(value)  value ##LL
  #endif
  
  #define LOG4CXX_TEST 1
  #include <log4cxx/private/log4cxx_private.h>
  
  
  /**
   * Unit test {@link CachedDateFormat}.
   */
  LOGUNIT_CLASS(CachedDateFormatTestCase)
  {
  	LOGUNIT_TEST_SUITE( CachedDateFormatTestCase );
  	LOGUNIT_TEST(test1);
  	LOGUNIT_TEST(test2);
  	LOGUNIT_TEST(test3);
  	LOGUNIT_TEST(test4);
  #if LOG4CXX_HAS_STD_LOCALE
  	LOGUNIT_TEST(test5);
  #endif
  	LOGUNIT_TEST(test6);
  	LOGUNIT_TEST(test8);
  	//   Gump doesn't like this test
  	//     LOGUNIT_TEST(test9);
  	LOGUNIT_TEST(test10);
  	LOGUNIT_TEST(test11);
  	LOGUNIT_TEST(test12);
  	LOGUNIT_TEST(test13);
  	LOGUNIT_TEST(test14);
  	LOGUNIT_TEST(test15);
  	LOGUNIT_TEST(test16);
  	LOGUNIT_TEST(test17);
  	LOGUNIT_TEST(test18);
  	LOGUNIT_TEST(test19);
  	LOGUNIT_TEST(test20);
  	LOGUNIT_TEST(test21);
  	LOGUNIT_TEST(test22);
  	LOGUNIT_TEST_SUITE_END();
  
  #define MICROSECONDS_PER_DAY APR_INT64_C(86400000000)
  
  public:
  
  	/**
  	 * Test multiple calls in close intervals.
  	 */
  	void test1()
  	{
  		//   subsequent calls within one minute
  		//     are optimized to reuse previous formatted value
  		//     make a couple of nearly spaced calls
  		DateFormatPtr baseFormatter(new AbsoluteTimeDateFormat());
  		CachedDateFormat gmtFormat(baseFormatter, 1000000);
  		gmtFormat.setTimeZone(TimeZone::getGMT());
  
  		apr_time_t jul1 = MICROSECONDS_PER_DAY * 12601L;
  		Pool p;
  
  		LogString actual;
  
  		gmtFormat.format(actual, jul1, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,000"), actual);
  		actual.erase(actual.begin(), actual.end());
  
  		gmtFormat.format(actual, jul1 + 8000, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,008"), actual);
  		actual.erase(actual.begin(), actual.end());
  
  		gmtFormat.format(actual, jul1 + 17000, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,017"), actual);
  		actual.erase(actual.begin(), actual.end());
  
  		gmtFormat.format(actual, jul1 + 237000, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,237"), actual);
  		actual.erase(actual.begin(), actual.end());
  
  		gmtFormat.format(actual, jul1 + 1415000, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:01,415"), actual);
  		actual.erase(actual.begin(), actual.end());
  
  	}
  
  	/**
  	 *  Check for interaction between caches.
  	 */
  
  	void test2()
  	{
  		apr_time_t jul2 = MICROSECONDS_PER_DAY * 12602;
  		DateFormatPtr baseFormatter(new AbsoluteTimeDateFormat());
  		CachedDateFormat gmtFormat(baseFormatter, 1000000);
  		gmtFormat.setTimeZone(TimeZone::getGMT());
  
  		DateFormatPtr chicagoBase(new AbsoluteTimeDateFormat());
  		CachedDateFormat chicagoFormat(chicagoBase, 1000000);
  		chicagoFormat.setTimeZone(TimeZone::getTimeZone(LOG4CXX_STR("GMT-5")));
  
  		Pool p;
  		LogString actual;
  		gmtFormat.format(actual, jul2, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,000"), actual);
  
  		actual.erase(actual.begin(), actual.end());
  		chicagoFormat.format(actual, jul2, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("19:00:00,000"), actual);
  
  		actual.erase(actual.begin(), actual.end());
  		gmtFormat.format(actual, jul2, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,000"), actual);
  	}
  
  	/**
  	 * Test multiple calls in close intervals prior to 1 Jan 1970.
  	 */
  	void test3()
  	{
  		//   subsequent calls within one minute
  		//     are optimized to reuse previous formatted value
  		//     make a couple of nearly spaced calls
  		DateFormatPtr baseFormatter(new AbsoluteTimeDateFormat());
  		CachedDateFormat gmtFormat(baseFormatter, 1000000);
  		gmtFormat.setTimeZone(TimeZone::getGMT());
  
  		apr_time_t ticks = MICROSECONDS_PER_DAY * -7;
  
  		Pool p;
  
  		LogString actual;
  
  
  		gmtFormat.format(actual, ticks, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,000"), actual);
  		actual.erase(actual.begin(), actual.end());
  
  		//
  		//   APR's explode_time method does not properly calculate tm_usec
  		//     prior to 1 Jan 1970 on Unix
  		gmtFormat.format(actual, ticks + 8000, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,008"), actual);
  		actual.erase(actual.begin(), actual.end());
  
  		gmtFormat.format(actual, ticks + 17000, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,017"), actual);
  		actual.erase(actual.begin(), actual.end());
  
  		gmtFormat.format(actual, ticks + 237000, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,237"), actual);
  		actual.erase(actual.begin(), actual.end());
  
  		gmtFormat.format(actual, ticks + 1423000, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:01,423"), actual);
  	}
  
  	void assertFormattedEquals(
  		const DateFormatPtr & baseFormat,
  		const CachedDateFormat & cachedFormat,
  		apr_time_t date,
  		Pool & p)
  	{
  		LogString expected;
  		LogString actual;
  
  		baseFormat->format(expected, date, p);
  		cachedFormat.format(actual, date, p);
  
  
  		LOGUNIT_ASSERT_EQUAL(expected, actual);
  	}
  
  	void test4()
  	{
  		//   subsequent calls within one minute
  		//     are optimized to reuse previous formatted value
  		//     make a couple of nearly spaced calls
  #if LOG4CXX_HAS_STD_LOCALE
  		std::locale loco(LOCALE_US);
  		std::locale* localeEN = &loco;
  #else
  		std::locale* localeEN = NULL;
  #endif
  		DateFormatPtr baseFormat(
  			new SimpleDateFormat(LOG4CXX_STR("EEE, MMM dd, HH:mm:ss.SSS Z"), localeEN));
  		CachedDateFormat cachedFormat(baseFormat, 1000000);
  		//
  		//   use a date in 2000 to attempt to confuse the millisecond locator
  		apr_time_t ticks = MICROSECONDS_PER_DAY * 11141;
  
  		Pool p;
  
  		assertFormattedEquals(baseFormat, cachedFormat, ticks, p);
  		assertFormattedEquals(baseFormat, cachedFormat, ticks + 8000, p);
  		assertFormattedEquals(baseFormat, cachedFormat, ticks + 17000, p);
  		assertFormattedEquals(baseFormat, cachedFormat, ticks + 237000, p);
  		assertFormattedEquals(baseFormat, cachedFormat, ticks + 1415000, p);
  	}
  
  
  #if LOG4CXX_HAS_STD_LOCALE
  	void test5()
  	{
  		//   subsequent calls within one minute
  		//     are optimized to reuse previous formatted value
  		//     make a couple of nearly spaced calls
  		LocaleChanger localeChange(LOCALE_JP);
  
  		if (localeChange.isEffective())
  		{
  			DateFormatPtr baseFormat(new SimpleDateFormat(
  					LOG4CXX_STR("EEE, MMM dd, HH:mm:ss.SSS Z")));
  			CachedDateFormat cachedFormat(baseFormat, 1000000);
  			//
  			//   use a date in 2000 to attempt to confuse the millisecond locator
  			apr_time_t ticks = MICROSECONDS_PER_DAY * 11141;
  
  			Pool p;
  
  			assertFormattedEquals(baseFormat, cachedFormat, ticks, p);
  			assertFormattedEquals(baseFormat, cachedFormat, ticks + 8000, p);
  			assertFormattedEquals(baseFormat, cachedFormat, ticks + 17000, p);
  			assertFormattedEquals(baseFormat, cachedFormat, ticks + 237000, p);
  			assertFormattedEquals(baseFormat, cachedFormat, ticks + 1415000, p);
  		}
  	}
  #endif
  
  	/**
  	 * Checks that numberFormat works as expected.
  	 */
  	void test6()
  	{
  		LogString numb;
  		Pool p;
  		AbsoluteTimeDateFormat formatter;
  		formatter.numberFormat(numb, 87, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("87"), numb);
  	}
  
  
  	/**
  	 * Set time zone on cached and check that it is effective.
  	 */
  	void test8()
  	{
  		DateFormatPtr baseFormat(new SimpleDateFormat(LOG4CXX_STR("yyyy-MM-dd HH:mm:ss,SSS")));
  		baseFormat->setTimeZone(TimeZone::getGMT());
  		CachedDateFormat cachedFormat(baseFormat, 1000000);
  		apr_time_t jul4 = MICROSECONDS_PER_DAY * 12603;
  
  		Pool p;
  
  		LogString actual;
  		cachedFormat.format(actual, jul4, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("2004-07-04 00:00:00,000"), actual);
  
  		cachedFormat.setTimeZone(TimeZone::getTimeZone(LOG4CXX_STR("GMT-6")));
  		actual.erase(actual.begin(), actual.end());
  		cachedFormat.format(actual, jul4, p);
  
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("2004-07-03 18:00:00,000"), actual);
  	}
  
  
  	/**
  	 * Test of caching when less than three millisecond digits are specified.
  	 */
  	void test9()
  	{
  		std::locale localeUS(LOCALE_US);
  
  		DateFormatPtr baseFormat = new SimpleDateFormat(
  			LOG4CXX_STR("yyyy-MMMM-dd HH:mm:ss,SS Z"), &localeUS);
  		DateFormatPtr cachedFormat = new CachedDateFormat(baseFormat, 1000000);
  		TimeZonePtr cet = TimeZone::getTimeZone(LOG4CXX_STR("GMT+1"));
  		cachedFormat->setTimeZone(cet);
  
  
  		apr_time_exp_t c;
  		memset(&c, 0, sizeof(c));
  		c.tm_year = 104;
  		c.tm_mon = 11;
  		c.tm_mday = 12;
  		c.tm_hour = 19;
  		c.tm_sec = 37;
  		c.tm_usec = 23000;
  
  		apr_time_t dec12;
  		apr_status_t stat = apr_time_exp_gmt_get(&dec12, &c);
  		const apr_status_t statOK = 0;
  		LOGUNIT_ASSERT_EQUAL(statOK, stat);
  
  		Pool p;
  
  		LogString s;
  		cachedFormat->format(s, dec12, p);
  
  		LOGUNIT_ASSERT_EQUAL(
  			(LogString) LOG4CXX_STR("2004-December-12 20:00:37,23 +0100"), s);
  
  		memset(&c, 0, sizeof(c));
  		c.tm_year = 104;
  		c.tm_mon = 11;
  		c.tm_mday = 31;
  		c.tm_hour = 23;
  		c.tm_sec = 13;
  		c.tm_usec = 905000;
  
  		apr_time_t jan1;
  		stat = apr_time_exp_gmt_get(&jan1, &c);
  		LOGUNIT_ASSERT_EQUAL(statOK, stat);
  
  		s.erase(s.begin(), s.end());
  		cachedFormat->format(s, jan1, p);
  
  		LOGUNIT_ASSERT_EQUAL(
  			(LogString) LOG4CXX_STR("2005-January-01 00:00:13,905 +0100"), s);
  	}
  
  
  	/**
  	 * Test when millisecond position moves but length remains constant.
  	 */
  	void test10()
  	{
  #if LOG4CXX_HAS_STD_LOCALE
  		std::locale loco("C");
  		std::locale* localeUS = &loco;
  #else
  		std::locale* localeUS = NULL;
  #endif
  		DateFormatPtr baseFormat = new SimpleDateFormat(
  			LOG4CXX_STR("MMMM SSS EEEEEE"), localeUS);
  		DateFormatPtr cachedFormat = new CachedDateFormat(baseFormat, 1000000);
  		TimeZonePtr cet = TimeZone::getTimeZone(LOG4CXX_STR("GMT+1"));
  		cachedFormat->setTimeZone(cet);
  
  		apr_time_exp_t c;
  		memset(&c, 0, sizeof(c));
  		c.tm_year = 104;
  		c.tm_mon = 9;
  		c.tm_mday = 5;
  		c.tm_hour = 21;
  		c.tm_sec = 37;
  		c.tm_usec = 23000;
  
  		apr_time_t oct5;
  		apr_status_t stat = apr_time_exp_gmt_get(&oct5, &c);
  		const apr_status_t statOK = 0;
  		LOGUNIT_ASSERT_EQUAL(statOK, stat);
  
  		Pool p;
  
  		LogString s;
  		cachedFormat->format(s, oct5, p);
  
  		LOGUNIT_ASSERT_EQUAL(
  			(LogString) LOG4CXX_STR("October 023 Tuesday"), s);
  
  		memset(&c, 0, sizeof(c));
  		c.tm_year = 104;
  		c.tm_mon = 10;
  		c.tm_mday = 1;
  		c.tm_usec = 23000;
  
  		apr_time_t nov1;
  		stat = apr_time_exp_gmt_get(&nov1, &c);
  		LOGUNIT_ASSERT_EQUAL(statOK, stat);
  
  		s.erase(s.begin(), s.end());
  		cachedFormat->format(s, nov1, p);
  
  		LOGUNIT_ASSERT_EQUAL(
  			(LogString) LOG4CXX_STR("November 023 Monday"), s);
  
  		nov1 += 961000;
  		s.erase(s.begin(), s.end());
  		cachedFormat->format(s, nov1, p);
  
  		LOGUNIT_ASSERT_EQUAL(
  			(LogString) LOG4CXX_STR("November 984 Monday"), s);
  	}
  
  	/**
  	 * Test that tests if caching is skipped if only "SS"
  	 *     is specified.
  	 */
  	void test11()
  	{
  		//
  		//   Earlier versions could be tricked by "SS0" patterns.
  		//
  		LogString badPattern(LOG4CXX_STR("ss,SS0"));
  		DateFormatPtr simpleFormat = new SimpleDateFormat(badPattern);
  		DateFormatPtr gmtFormat = new CachedDateFormat(simpleFormat, 1000000);
  		gmtFormat->setTimeZone(TimeZone::getGMT());
  
  		//
  		// The first request has to 100 ms after an ordinal second
  		//    to push the literal zero out of the pattern check
  		apr_time_t ticks = MICROSECONDS_PER_DAY * 11142L;
  		apr_time_t jul2 = ticks + 120000;
  
  		Pool p;
  
  		LogString s;
  		gmtFormat->format(s, jul2, p);
  
  		LOGUNIT_ASSERT_EQUAL(
  			(LogString) LOG4CXX_STR("00,1200"), s);
  
  		jul2 = ticks + 87000;
  
  		s.erase(s.begin(), s.end());
  		gmtFormat->format(s, jul2, p);
  
  		LOGUNIT_ASSERT_EQUAL(
  			(LogString) LOG4CXX_STR("00,870"), s);
  	}
  
  	/**
  	 * Check pattern location for ISO8601
  	 */
  	void test12()
  	{
  		DateFormatPtr df    = new SimpleDateFormat(LOG4CXX_STR("yyyy-MM-dd HH:mm:ss,SSS"));
  		apr_time_t    ticks = 11142L * MICROSECONDS_PER_DAY;
  		Pool p;
  		LogString formatted;
  
  		df->format(formatted, ticks, p);
  		int msStart = CachedDateFormat::findMillisecondStart(ticks, formatted, df, p);
  		LOGUNIT_ASSERT_EQUAL(20, msStart);
  
  		// Test for for milliseconds overlapping with the magic ones as per LOGCXX-420.
  		apr_time_exp_t c;
  		memset(&c, 0, sizeof(c));
  		c.tm_year = 110;
  		c.tm_mon  = 7;
  		c.tm_mday = 12;
  		c.tm_hour = 9;
  		c.tm_min  = 4;
  		c.tm_sec  = 50;
  		c.tm_usec = 406000;
  
  		LOGUNIT_ASSERT_EQUAL(0, apr_time_exp_gmt_get(&ticks, &c));
  
  		formatted.clear();
  		df->format(formatted, ticks, p);
  		msStart = CachedDateFormat::findMillisecondStart(ticks, formatted, df, p);
  		LOGUNIT_ASSERT_EQUAL(20, msStart);
  
  		c.tm_usec = 609000;
  		LOGUNIT_ASSERT_EQUAL(0, apr_time_exp_gmt_get(&ticks, &c));
  
  		formatted.clear();
  		df->format(formatted, ticks, p);
  		msStart = CachedDateFormat::findMillisecondStart(ticks, formatted, df, p);
  		LOGUNIT_ASSERT_EQUAL(20, msStart);
  	}
  
  	/**
  	 * Check pattern location for DATE
  	 */
  	void test13()
  	{
  		DateFormatPtr df = new SimpleDateFormat(LOG4CXX_STR("yyyy-MM-dd"));
  		apr_time_t ticks = 11142L * MICROSECONDS_PER_DAY;
  
  		Pool p;
  
  		LogString formatted;
  		df->format(formatted, ticks, p);
  
  		int millisecondStart = CachedDateFormat::findMillisecondStart(ticks,
  				formatted, df, p);
  		LOGUNIT_ASSERT_EQUAL((int) CachedDateFormat::NO_MILLISECONDS, millisecondStart);
  	}
  
  	/**
  	 * Check pattern location for ABSOLUTE
  	 */
  	void test14()
  	{
  		DateFormatPtr df = new SimpleDateFormat(LOG4CXX_STR("HH:mm:ss,SSS"));
  		apr_time_t ticks = 11142L * MICROSECONDS_PER_DAY;
  
  		Pool p;
  		LogString formatted;
  		df->format(formatted, ticks, p);
  
  		int millisecondStart = CachedDateFormat::findMillisecondStart(ticks,
  				formatted, df, p);
  		LOGUNIT_ASSERT_EQUAL(9, millisecondStart);
  	}
  
  	/**
  	 * Check pattern location for single S
  	 */
  	void test15()
  	{
  		DateFormatPtr df = new SimpleDateFormat(LOG4CXX_STR("HH:mm:ss,S"));
  		apr_time_t ticks = 11142L * MICROSECONDS_PER_DAY;
  
  		Pool p;
  		LogString formatted;
  		df->format(formatted, ticks, p);
  
  		int millisecondStart = CachedDateFormat::findMillisecondStart(ticks,
  				formatted, df, p);
  		LOGUNIT_ASSERT_EQUAL((int) CachedDateFormat::UNRECOGNIZED_MILLISECONDS, millisecondStart);
  	}
  
  	/**
  	 * Check pattern location for single SS
  	 */
  	void test16()
  	{
  		DateFormatPtr df = new SimpleDateFormat(LOG4CXX_STR("HH:mm:ss,SS"));
  		apr_time_t ticks = 11142L * MICROSECONDS_PER_DAY;
  
  		Pool p;
  		LogString formatted;
  		df->format(formatted, ticks, p);
  
  		int millisecondStart =
  			CachedDateFormat::findMillisecondStart(ticks, formatted, df, p);
  		LOGUNIT_ASSERT_EQUAL((int) CachedDateFormat::UNRECOGNIZED_MILLISECONDS, millisecondStart);
  	}
  
  	/**
  	 * Check caching when multiple SSS appear in pattern
  	 */
  	void test17()
  	{
  		apr_time_t jul2 = 12602L * MICROSECONDS_PER_DAY;
  		LogString badPattern(LOG4CXX_STR("HH:mm:ss,SSS HH:mm:ss,SSS"));
  		DateFormatPtr simpleFormat = new SimpleDateFormat(badPattern);
  		simpleFormat->setTimeZone(TimeZone::getGMT());
  		DateFormatPtr cachedFormat = new CachedDateFormat(simpleFormat, 1000000);
  
  		Pool p;
  		LogString s;
  		cachedFormat->format(s, jul2, p);
  
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,000 00:00:00,000"), s);
  		jul2 += 120000;
  
  		s.erase(s.begin(), s.end());
  		simpleFormat->format(s, jul2, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,120 00:00:00,120"), s);
  
  		s.erase(s.begin(), s.end());
  		int msStart = CachedDateFormat::findMillisecondStart(jul2, s, simpleFormat, p);
  		LOGUNIT_ASSERT_EQUAL((int) CachedDateFormat::UNRECOGNIZED_MILLISECONDS, msStart);
  
  		cachedFormat->format(s, jul2, p);
  		LOGUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,120 00:00:00,120"), s) ;
  
  		int maxValid = CachedDateFormat::getMaximumCacheValidity(badPattern);
  		LOGUNIT_ASSERT_EQUAL(1000, maxValid);
  
  		// Test overlapping millis with a magic string from CachedDateFormat for LOGCXX-420.
  		s.clear();
  		jul2 += 286000;
  		cachedFormat->format(s, jul2, p);
  		msStart = CachedDateFormat::findMillisecondStart(jul2, s, simpleFormat, p);
  		LOGUNIT_ASSERT_EQUAL((int) CachedDateFormat::UNRECOGNIZED_MILLISECONDS, msStart);
  
  		s.clear();
  		jul2 += 203000;
  		cachedFormat->format(s, jul2, p);
  		msStart = CachedDateFormat::findMillisecondStart(jul2, s, simpleFormat, p);
  		LOGUNIT_ASSERT_EQUAL((int) CachedDateFormat::UNRECOGNIZED_MILLISECONDS, msStart);
  	}
  
  	/**
  	 * Check that patterns not containing microseconds
  	 * are reported as being able to be cached for a full second.
  	 */
  	void test18()
  	{
  
  		int maxValid =
  			CachedDateFormat::getMaximumCacheValidity(
  				LOG4CXX_STR("yyyy-MM-dd"));
  		LOGUNIT_ASSERT_EQUAL(1000000, maxValid);
  	}
  
  	/**
  	 * Check that patterns not containing 3 microseconds
  	 * are reported as being able to be cached for a full second.
  	 */
  	void test19()
  	{
  
  		int maxValid =
  			CachedDateFormat::getMaximumCacheValidity(
  				LOG4CXX_STR("yyyy-MM-dd SSS"));
  		LOGUNIT_ASSERT_EQUAL(1000000, maxValid);
  	}
  
  	/**
  	 * Check that patterns not containing 2 S's
  	 * are reported as being able to be cached for only a millisecond.
  	 */
  	void test20()
  	{
  
  		int maxValid =
  			CachedDateFormat::getMaximumCacheValidity(
  				LOG4CXX_STR("yyyy-MM-dd SS"));
  		LOGUNIT_ASSERT_EQUAL(1000, maxValid);
  	}
  
  	/**
  	 * Check that patterns not containing multi S groups
  	 * are reported as being able to be cached for only a millisecond.
  	 */
  	void test21()
  	{
  
  		int maxValid =
  			CachedDateFormat::getMaximumCacheValidity(
  				LOG4CXX_STR("yyyy-MM-dd SSS SSS"));
  		LOGUNIT_ASSERT_EQUAL(1000, maxValid);
  	}
  
  	/**
  	 * Check that findMillisecondStart correctly handles timestamps
  	 * which use the magic millisecond value 654.
  	 */
  	void test22()
  	{
  		DateFormatPtr baseFormatter(new ISO8601DateFormat());
  		CachedDateFormat isoFormat(baseFormatter, 1000000);
  		isoFormat.setTimeZone(TimeZone::getGMT());
  
  		Pool p;
  		LogString formatted;
  
  		isoFormat.format(formatted, 654000, p);
  		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("1970-01-01 00:00:00,654"), formatted);
  
  		formatted.clear();
  		isoFormat.format(formatted, 999000, p);
  		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("1970-01-01 00:00:00,999"), formatted);
  
  		formatted.clear();
  		isoFormat.format(formatted, 1654010, p);
  		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("1970-01-01 00:00:01,654"), formatted);
  
  		formatted.clear();
  		isoFormat.format(formatted, 1999010, p);
  		LOGUNIT_ASSERT_EQUAL(LOG4CXX_STR("1970-01-01 00:00:01,999"), formatted);
  	}
  
  };
  
  LOGUNIT_TEST_SUITE_REGISTRATION(CachedDateFormatTestCase);
  