You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4cxx-dev@logging.apache.org by ca...@apache.org on 2005/02/19 02:59:37 UTC
cvs commit: logging-log4cxx/tests/src/helpers localechanger.cpp localechanger.h Makefile.am cacheddateformattestcase.cpp datetimedateformattestcase.cpp
carnold 2005/02/18 17:59:37
Modified: include/log4cxx/helpers cacheddateformat.h
src cacheddateformat.cpp patternparser.cpp timezone.cpp
tests/src/helpers Makefile.am cacheddateformattestcase.cpp
datetimedateformattestcase.cpp
Added: tests/src/helpers localechanger.cpp localechanger.h
Log:
LOGCXX-49: Migration of updated CachedDateFormat from log4j
Revision Changes Path
1.11 +176 -31 logging-log4cxx/include/log4cxx/helpers/cacheddateformat.h
Index: cacheddateformat.h
===================================================================
RCS file: /home/cvs/logging-log4cxx/include/log4cxx/helpers/cacheddateformat.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- cacheddateformat.h 15 Feb 2005 23:55:59 -0000 1.10
+++ cacheddateformat.h 19 Feb 2005 01:59:37 -0000 1.11
@@ -21,48 +21,193 @@
namespace log4cxx
{
- namespace helpers
+ namespace pattern
{
- class LOG4CXX_EXPORT CachedDateFormat : public DateFormat {
+ class LOG4CXX_EXPORT CachedDateFormat : public log4cxx::helpers::DateFormat {
public:
- CachedDateFormat(DateFormatPtr& baseFormatter);
+ enum {
+ /*
+ * Constant used to represent that there was no change
+ * observed when changing the millisecond count.
+ */
+ NO_MILLISECONDS = -2,
+ /*
+ * Constant used to represent that there was an
+ * observed change, but was an expected change.
+ */
+ UNRECOGNIZED_MILLISECONDS = -1
+ };
- virtual void format(LogString &s,
+ private:
+ /**
+ * Supported digit set. If the wrapped DateFormat uses
+ * a different unit set, the millisecond pattern
+ * will not be recognized and duplicate requests
+ * will use the cache.
+ */
+ static const logchar* const digits;
+
+ enum {
+ /**
+ * First magic number used to detect the millisecond position.
+ */
+ magic1 = 654000,
+ /**
+ * Second magic number used to detect the millisecond position.
+ */
+ magic2 = 987000
+ };
+
+ /**
+ * Expected representation of first magic number.
+ */
+ static const logchar* const magicString1;
+
+
+ /**
+ * Expected representation of second magic number.
+ */
+ static const logchar* const magicString2;
+
+
+ /**
+ * Expected representation of 0 milliseconds.
+ */
+ static const logchar* const zeroString;
+
+ /**
+ * Wrapped formatter.
+ */
+ log4cxx::helpers::DateFormatPtr formatter;
+
+ /**
+ * Index of initial digit of millisecond pattern or
+ * UNRECOGNIZED_MILLISECONDS or NO_MILLISECONDS.
+ */
+ mutable int millisecondStart;
+
+ /**
+ * Integral second preceding the previous convered Date.
+ */
+ mutable log4cxx_time_t slotBegin;
+
+
+ /**
+ * Cache of previous conversion.
+ */
+ mutable LogString cache;
+
+
+ /**
+ * Maximum validity period for the cache.
+ * Typically 1, use cache for duplicate requests only, or
+ * 1000000, use cache for requests within the same integral second.
+ */
+ const int expiration;
+
+ /**
+ * Date requested in previous conversion.
+ */
+ mutable log4cxx_time_t previousTime;
+
+ public:
+ /**
+ * Creates a new CachedDateFormat object.
+ * @param dateFormat Date format, may not be null.
+ * @param expiration maximum cached range in microseconds.
+ * If the dateFormat is known to be incompatible with the
+ * caching algorithm, use a value of 0 to totally disable
+ * caching or 1 to only use cache for duplicate requests.
+ */
+ CachedDateFormat(const log4cxx::helpers::DateFormatPtr& dateFormat, int expiration);
+
+ /**
+ * Finds start of millisecond field in formatted time.
+ * @param time long time, must be integral number of seconds
+ * @param formatted String corresponding formatted string
+ * @param formatter DateFormat date format
+ * @return int position in string of first digit of milliseconds,
+ * -1 indicates no millisecond field, -2 indicates unrecognized
+ * field (likely RelativeTimeDateFormat)
+ */
+ static int findMillisecondStart(
+ log4cxx_time_t time, const LogString& formatted,
+ const log4cxx::helpers::DateFormatPtr& formatter,
+ log4cxx::helpers::Pool& pool);
+
+ /**
+ * Formats a Date into a date/time string.
+ *
+ * @param date the date to format.
+ * @param sbuf the string buffer to write to.
+ * @param pool memory pool.
+ */
+ virtual void format(LogString &sbuf,
log4cxx_time_t date,
log4cxx::helpers::Pool& p) const;
- virtual void setTimeZone(const TimeZonePtr& zone);
+
+ private:
+ /**
+ * Formats a count of milliseconds (0-999) into a numeric representation.
+ * @param millis Millisecond coun between 0 and 999.
+ * @buf String buffer, may not be null.
+ * @offset Starting position in buffer, the length of the
+ * buffer must be at least offset + 3.
+ */
+ static void millisecondFormat(int millis,
+ LogString& buf,
+ int offset);
+
+
+ public:
+ /**
+ * Set timezone.
+ *
+ * @remarks Setting the timezone using getCalendar().setTimeZone()
+ * will likely cause caching to misbehave.
+ * @param timeZone TimeZone new timezone
+ */
+ virtual void setTimeZone(const log4cxx::helpers::TimeZonePtr& zone);
+
+ /**
+ * Format an integer consistent with the format method.
+ * @param s string to which the numeric string is appended.
+ * @param n integer value.
+ * @param p memory pool used during formatting.
+ */
virtual void numberFormat(LogString& s,
int n,
log4cxx::helpers::Pool& p) const;
+ /**
+ * Gets maximum cache validity for the specified SimpleDateTime
+ * conversion pattern.
+ * @param pattern conversion pattern, may not be null.
+ * @returns Duration in microseconds from an integral second
+ * that the cache will return consistent results.
+ */
+ static int getMaximumCacheValidity(const LogString& pattern);
private:
- /**
- * Finds start of millisecond field in formatted time.
- * @param time long time, must be integral number of seconds
- * @param formatted String corresponding formatted string
- * @param zeroDigit char digit used to represent zero
- * @param formatter DateFormat date format
- * @return int position in string of first digit of milliseconds,
- * -1 indicates no millisecond field, -2 indicates unrecognized
- * field (likely RelativeTimeDateFormat)
- */
- static int findMillisecondStart(const log4cxx_time_t time,
- const LogString& formatted,
- const logchar zeroDigit,
- const logchar nineDigit,
- const DateFormatPtr& formatter,
- log4cxx::helpers::Pool& p);
-
- DateFormatPtr formatter;
- mutable int millisecondStart;
- mutable LogString cache;
- mutable log4cxx_time_t previousTime;
- logchar zeroDigit;
- logchar nineDigit;
- enum {
- UNRECOGNIZED_MILLISECOND_PATTERN = -2,
- NO_MILLISECOND_PATTERN = -1 };
+ CachedDateFormat(const CachedDateFormat&);
+ CachedDateFormat& operator=(const CachedDateFormat&);
+
+ /**
+ * Tests if two string regions are equal.
+ * @param target target string.
+ * @param toffset character position in target to start comparison.
+ * @param other other string.
+ * @param ooffset character position in other to start comparison.
+ * @param len length of region.
+ * @return true if regions are equal.
+ */
+ static bool regionMatches(
+ const LogString& target,
+ size_t toffset,
+ const LogString& other,
+ size_t ooffset,
+ size_t len);
+
};
1.11 +258 -123 logging-log4cxx/src/cacheddateformat.cpp
Index: cacheddateformat.cpp
===================================================================
RCS file: /home/cvs/logging-log4cxx/src/cacheddateformat.cpp,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- cacheddateformat.cpp 15 Feb 2005 23:56:01 -0000 1.10
+++ cacheddateformat.cpp 19 Feb 2005 01:59:37 -0000 1.11
@@ -20,147 +20,282 @@
#include <apr_time.h>
#include <log4cxx/helpers/pool.h>
+#include <limits>
+#include <log4cxx/helpers/exception.h>
using namespace log4cxx;
using namespace log4cxx::helpers;
+using namespace log4cxx::pattern;
-CachedDateFormat::CachedDateFormat(DateFormatPtr& formatter) :
- formatter(formatter) {
+/**
+* Supported digit set. If the wrapped DateFormat uses
+* a different unit set, the millisecond pattern
+* will not be recognized and duplicate requests
+* will use the cache.
+*/
+const logchar* const CachedDateFormat::digits = LOG4CXX_STR("0123456789");
+
+/**
+ * Expected representation of first magic number.
+ */
+const logchar* const CachedDateFormat::magicString1 = LOG4CXX_STR("654");
+
+
+/**
+ * Expected representation of second magic number.
+ */
+const logchar* const CachedDateFormat::magicString2 = LOG4CXX_STR("987");
+
+
+/**
+ * Expected representation of 0 milliseconds.
+ */
+const logchar* const CachedDateFormat::zeroString = LOG4CXX_STR("000");
+
+
+/**
+ * Creates a new CachedDateFormat object.
+ * @param dateFormat Date format, may not be null.
+ * @param expiration maximum cached range in milliseconds.
+ * If the dateFormat is known to be incompatible with the
+ * caching algorithm, use a value of 0 to totally disable
+ * caching or 1 to only use cache for duplicate requests.
+ */
+CachedDateFormat::CachedDateFormat(const DateFormatPtr& dateFormat,
+ int expiration) :
+ formatter(dateFormat),
+ expiration(expiration),
+ millisecondStart(0),
+ previousTime(std::numeric_limits<log4cxx_time_t>::min()),
+ slotBegin(std::numeric_limits<log4cxx_time_t>::min()),
+ cache(50, LOG4CXX_STR(' ')) {
+ if (dateFormat == NULL) {
+ throw IllegalArgumentException("dateFormat cannot be null");
+ }
+ if (expiration < 0) {
+ throw IllegalArgumentException("expiration must be non-negative");
+ }
+}
+
+
+/**
+ * Finds start of millisecond field in formatted time.
+ * @param time long time, must be integral number of seconds
+ * @param formatted String corresponding formatted string
+ * @param formatter DateFormat date format
+ * @return int position in string of first digit of milliseconds,
+ * -1 indicates no millisecond field, -2 indicates unrecognized
+ * field (likely RelativeTimeDateFormat)
+ */
+int CachedDateFormat::findMillisecondStart(
+ apr_time_t time, const LogString& formatted,
+ const DateFormatPtr& formatter,
+ Pool& pool) {
+
+ apr_time_t slotBegin = (time / 1000000) * 1000000;
+ if (slotBegin > time) {
+ slotBegin -= 1000000;
+ }
+ int millis = (int) (time - slotBegin)/1000;
+
+ int magic = magic1;
+ LogString magicString(magicString1);
+ if (millis == magic1) {
+ magic = magic2;
+ magicString = magicString2;
+ }
- apr_time_t nowTime = apr_time_now();
- previousTime = (nowTime / APR_USEC_PER_SEC) * APR_USEC_PER_SEC;
- //
- // if now is before 1970 and previousTime was truncated forward
- // set cached time back one second
- if (nowTime - previousTime < 0) {
- previousTime -= APR_USEC_PER_SEC;
- }
- Pool p;
- formatter->format(cache, previousTime, p);
- LogString digits;
- formatter->numberFormat(digits, 90, p);
- nineDigit = digits[0];
- zeroDigit = digits[1];
- millisecondStart = findMillisecondStart(previousTime,
- cache,
- zeroDigit,
- nineDigit,
- formatter,
- p);
-}
-
-int CachedDateFormat::findMillisecondStart(const log4cxx_time_t time,
- const LogString& formatted,
- logchar zeroDigit,
- logchar nineDigit,
- const DateFormatPtr& formatter,
- Pool& p) {
- LogString plus987;
- formatter->format(plus987, time + 987000, p);
- //
- // find first difference between values
- //
- for (size_t i = 0; i < formatted.length(); i++) {
- if (formatted[i] != plus987[i]) {
- if (formatted[i] == zeroDigit && plus987[i] == nineDigit) {
- return i;
- } else {
- return UNRECOGNIZED_MILLISECOND_PATTERN;
+ LogString plusMagic;
+ formatter->format(plusMagic, slotBegin + magic, pool);
+
+ /**
+ * If the string lengths differ then
+ * we can't use the cache except for duplicate requests.
+ */
+ if (plusMagic.length() != formatted.length()) {
+ return UNRECOGNIZED_MILLISECONDS;
+ } else {
+ // find first difference between values
+ for (int i = 0; i < formatted.length(); i++) {
+ if (formatted[i] != plusMagic[i]) {
+ //
+ // determine the expected digits for the base time
+ LogString formattedMillis(LOG4CXX_STR("ABC"));
+ millisecondFormat(millis, formattedMillis, 0);
+
+ LogString plusZero;
+ formatter->format(plusZero, slotBegin, pool);
+
+ // If the next 3 characters match the magic
+ // strings and the remaining fragments are identical
+ //
+ //
+ if (plusZero.length() == formatted.length()
+ && regionMatches(magicString, 0, plusMagic, i, magicString.length())
+ && regionMatches(formattedMillis, 0, formatted, i, magicString.length())
+ && regionMatches(zeroString, 0, plusZero, i, 3)
+ && (formatted.length() == i + 3
+ || plusZero.compare(i + 3,
+ LogString::npos, plusMagic, i+3, LogString::npos) == 0)) {
+ return i;
+ } else {
+ return UNRECOGNIZED_MILLISECONDS;
}
}
- }
- return NO_MILLISECOND_PATTERN;
+ }
+ }
+ return NO_MILLISECONDS;
}
- /**
- * Converts a Date utilizing a previously converted
- * value if possible.
+/**
+ * Formats a millisecond count into a date/time string.
+ *
+ * @param now Number of milliseconds after midnight 1 Jan 1970 GMT.
+ * @param sbuf the string buffer to write to
+ */
+ void CachedDateFormat::format(LogString& buf, log4cxx_time_t now, Pool& p) const {
+
+ //
+ // If the current requested time is identical to the previously
+ // requested time, then append the cache contents.
+ //
+ if (now == previousTime) {
+ buf.append(cache);
+ return;
+ }
- @param date the date to format
- @param sbuf the string buffer to write to
- @param fieldPosition remains untouched
- */
-void CachedDateFormat::format(LogString& s, log4cxx_time_t date, Pool& p) const {
- if (millisecondStart == UNRECOGNIZED_MILLISECOND_PATTERN) {
- formatter->format(s, date, p);
- return;
- }
- if (date < previousTime + APR_USEC_PER_SEC && date >= previousTime) {
- if (millisecondStart >= 0) {
- cache.erase(millisecondStart, 3);
- int millis = apr_time_as_msec(date - previousTime);
- int cacheLength = cache.length();
- formatter->numberFormat(cache, millis, p);
- int milliLength = cache.length() - cacheLength;
- //
- // if it didn't belong at the end, then move it
- if (cacheLength != millisecondStart) {
- LogString milli = cache.substr(cacheLength);
- cache.erase(cache.begin() + cacheLength, cache.end());
- cache.insert(millisecondStart, milli);
- }
- if (milliLength < 3) {
- cache.insert(millisecondStart,
- 3 - milliLength, zeroDigit);
- }
- }
- } else {
- apr_time_t prev = (date / APR_USEC_PER_SEC) * APR_USEC_PER_SEC;
- //
- // if earlier than 1970 and rounded toward 1970
- // then move back one second
- if (date - prev < 0) {
- prev -= APR_USEC_PER_SEC;
- }
- previousTime = prev;
- size_t prevLength = cache.length();
- cache.erase(cache.begin(), cache.end());
- formatter->format(cache, date, p);
- //
- // if the length changed then
- // recalculate the millisecond position
- if (cache.length() != prevLength) {
- LogString formattedPreviousTime;
- formatter->format(formattedPreviousTime, previousTime, p);
- millisecondStart =
- findMillisecondStart(previousTime,
- formattedPreviousTime,
- zeroDigit,
- nineDigit,
- formatter, p);
+ //
+ // If millisecond pattern was not unrecognized
+ // (that is if it was found or milliseconds did not appear)
+ //
+ if (millisecondStart != UNRECOGNIZED_MILLISECONDS) {
+
+ // Check if the cache is still valid.
+ // If the requested time is within the same integral second
+ // as the last request and a shorter expiration was not requested.
+ if (now < slotBegin + expiration
+ && now >= slotBegin
+ && now < slotBegin + 1000000L) {
+
+ //
+ // if there was a millisecond field then update it
+ //
+ if (millisecondStart >= 0 ) {
+ millisecondFormat((int) ((now - slotBegin)/1000), cache, millisecondStart);
+ }
+ //
+ // update the previously requested time
+ // (the slot begin should be unchanged)
+ previousTime = now;
+ buf.append(cache);
+ return;
}
- }
- s.append(cache);
}
- /**
- * Set timezone.
- *
- * @remarks Setting the timezone using getCalendar().setTimeZone()
- * will likely cause caching to misbehave.
- * @param timeZone TimeZone new timezone
- */
-void CachedDateFormat::setTimeZone(const TimeZonePtr& timeZone) {
- formatter->setTimeZone(timeZone);
- size_t prevLength = cache.length();
- cache.erase(cache.begin(), cache.end());
- Pool p;
- formatter->format(cache, previousTime, p);
- //
- // if the length changed then
- // recalculate the millisecond position
- if (cache.length() != prevLength) {
- millisecondStart = findMillisecondStart(previousTime,
- cache,
- zeroDigit,
- nineDigit,
- formatter, p);
- }
+ //
+ // could not use previous value.
+ // Call underlying formatter to format date.
+ cache.erase(cache.begin(), cache.end());
+ formatter->format(cache, now, p);
+ buf.append(cache);
+ previousTime = now;
+ slotBegin = (previousTime / 1000000) * 1000000;
+ if (slotBegin > previousTime) {
+ slotBegin -= 1000000;
+ }
+
+
+ //
+ // if the milliseconds field was previous found
+ // then reevaluate in case it moved.
+ //
+ if (millisecondStart >= 0) {
+ millisecondStart = findMillisecondStart(now, cache, formatter, p);
}
+}
+
+
+/**
+ * Formats a count of milliseconds (0-999) into a numeric representation.
+ * @param millis Millisecond coun between 0 and 999.
+ * @buf String buffer, may not be null.
+ * @offset Starting position in buffer, the length of the
+ * buffer must be at least offset + 3.
+ */
+void CachedDateFormat::millisecondFormat(int millis,
+ LogString& buf,
+ int offset) {
+ buf[offset] = digits[ millis / 100];
+ buf[offset + 1] = digits[(millis / 10) % 10];
+ buf[offset + 2] = digits[millis % 10];
+ }
+
+/**
+ * Set timezone.
+ *
+ * @remarks Setting the timezone using getCalendar().setTimeZone()
+ * will likely cause caching to misbehave.
+ * @param timeZone TimeZone new timezone
+ */
+void CachedDateFormat::setTimeZone(const TimeZonePtr& timeZone) {
+ formatter->setTimeZone(timeZone);
+ previousTime = std::numeric_limits<log4cxx_time_t>::min();
+ slotBegin = std::numeric_limits<log4cxx_time_t>::min();
+}
+
void CachedDateFormat::numberFormat(LogString& s, int n, Pool& p) const {
formatter->numberFormat(s, n, p);
}
+
+
+/**
+ * Gets maximum cache validity for the specified SimpleDateTime
+ * conversion pattern.
+ * @param pattern conversion pattern, may not be null.
+ * @returns Duration in microseconds from an integral second
+ * that the cache will return consistent results.
+ */
+int CachedDateFormat::getMaximumCacheValidity(const LogString& pattern) {
+ //
+ // If there are more "S" in the pattern than just one "SSS" then
+ // (for example, "HH:mm:ss,SSS SSS"), then set the expiration to
+ // one millisecond which should only perform duplicate request caching.
+ //
+ size_t firstS = pattern.find(LOG4CXX_STR('S'));
+ size_t len = pattern.length();
+ //
+ // if there are no S's or
+ // three that start with the first S and no fourth S in the string
+ //
+ if (firstS == LogString::npos ||
+ (len >= firstS + 3 && pattern.compare(firstS, 3, LOG4CXX_STR("SSS")) == 0
+ && (len == firstS + 3 ||
+ pattern.find(LOG4CXX_STR('S'), firstS + 3) == LogString::npos))) {
+ return 1000000;
+ }
+ return 1000;
+}
+
+
+/**
+* Tests if two string regions are equal.
+* @param target target string.
+* @param toffset character position in target to start comparison.
+* @param other other string.
+* @param ooffset character position in other to start comparison.
+* @param len length of region.
+* @return true if regions are equal.
+*/
+bool CachedDateFormat::regionMatches(
+ const LogString& target,
+ size_t toffset,
+ const LogString& other,
+ size_t ooffset,
+ size_t len) {
+ return target.compare(toffset, len, other, ooffset, len) == 0;
+}
+
1.30 +17 -3 logging-log4cxx/src/patternparser.cpp
Index: patternparser.cpp
===================================================================
RCS file: /home/cvs/logging-log4cxx/src/patternparser.cpp,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- patternparser.cpp 18 Feb 2005 17:18:53 -0000 1.29
+++ patternparser.cpp 19 Feb 2005 01:59:37 -0000 1.30
@@ -27,12 +27,14 @@
#include <log4cxx/mdc.h>
#include <log4cxx/helpers/transcoder.h>
#include <sstream>
+#include <log4cxx/helpers/exception.h>
#include <apr_pools.h>
using namespace log4cxx;
using namespace log4cxx::helpers;
using namespace log4cxx::spi;
+using namespace log4cxx::pattern;
#define ESCAPE_CHAR LOG4CXX_STR('%')
@@ -209,7 +211,7 @@
while ((i < patternLength) && (pattern.at(i) == LOG4CXX_STR('{'))) {
size_t end = pattern.find(LOG4CXX_STR('}'), i);
- if (end > i) {
+ if (end != LogString::npos && end > i) {
LogString r(pattern.substr(i + 1, end - (i + 1)));
options.push_back(r);
i = end+1;
@@ -461,6 +463,7 @@
DateFormatPtr PatternParser::DatePatternConverter::createDateFormat(
const std::vector<LogString>& options) {
DateFormatPtr df;
+ int maximumCacheValidity = 1000000;
if (options.size() == 0) {
df = new ISO8601DateFormat();
} else {
@@ -478,7 +481,16 @@
df = new DateTimeDateFormat();
} else {
if (dateFormatStr.find(LOG4CXX_STR('%')) == std::string::npos) {
- df = new SimpleDateFormat(dateFormatStr);
+ try {
+ df = new SimpleDateFormat(dateFormatStr);
+ maximumCacheValidity =
+ CachedDateFormat::getMaximumCacheValidity(dateFormatStr);
+ } catch(IllegalArgumentException& e) {
+ df = new ISO8601DateFormat();
+ LogLog::warn(((LogString)
+ LOG4CXX_STR("Could not instantiate SimpleDateFormat with pattern "))
+ + dateFormatStr, e);
+ }
} else {
df = new StrftimeDateFormat(dateFormatStr);
}
@@ -490,7 +502,9 @@
}
}
}
- df = new CachedDateFormat(df);
+ if (maximumCacheValidity > 0) {
+ df = new CachedDateFormat(df, maximumCacheValidity);
+ }
return df;
}
1.13 +34 -3 logging-log4cxx/src/timezone.cpp
Index: timezone.cpp
===================================================================
RCS file: /home/cvs/logging-log4cxx/src/timezone.cpp,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- timezone.cpp 18 Feb 2005 17:18:54 -0000 1.12
+++ timezone.cpp 19 Feb 2005 01:59:37 -0000 1.13
@@ -23,6 +23,7 @@
#include <log4cxx/helpers/transcoder.h>
#include <log4cxx/helpers/stringhelper.h>
#include <log4cxx/helpers/pool.h>
+#include <log4cxx/logger.h>
using namespace log4cxx;
using namespace log4cxx::helpers;
@@ -49,7 +50,17 @@
/** Explode time to human readable form. */
log4cxx_status_t explode( apr_time_exp_t * result, log4cxx_time_t input ) const
{
- return apr_time_exp_gmt( result, input );
+ apr_status_t stat;
+ // APR 1.1 and early mishandles microseconds on dates
+ // before 1970, APR bug 32520
+ if (LOG4CXX_UNLIKELY(input < 0 && apr_time_usec(input) < 0)) {
+ apr_time_t floorTime = (apr_time_sec(input) -1) * APR_USEC_PER_SEC;
+ stat = apr_time_exp_gmt(result, floorTime);
+ result->tm_usec = input - floorTime;
+ } else {
+ stat = apr_time_exp_gmt( result, input );
+ }
+ return stat;
}
private:
@@ -74,7 +85,17 @@
/** Explode time to human readable form. */
log4cxx_status_t explode( apr_time_exp_t * result, log4cxx_time_t input ) const
{
- return apr_time_exp_lt( result, input );
+ apr_status_t stat;
+ // APR 1.1 and early mishandles microseconds on dates
+ // before 1970, APR bug 32520
+ if (LOG4CXX_UNLIKELY(input < 0 && apr_time_usec(input) < 0)) {
+ apr_time_t floorTime = (apr_time_sec(input) -1) * APR_USEC_PER_SEC;
+ stat = apr_time_exp_lt(result, floorTime);
+ result->tm_usec = input - floorTime;
+ } else {
+ stat = apr_time_exp_lt( result, input );
+ }
+ return stat;
}
@@ -112,7 +133,17 @@
/** Explode time to human readable form. */
log4cxx_status_t explode( apr_time_exp_t * result, log4cxx_time_t input ) const
{
- return apr_time_exp_tz( result, input, offset );
+ apr_status_t stat;
+ // APR 1.1 and early mishandles microseconds on dates
+ // before 1970, APR bug 32520
+ if (LOG4CXX_UNLIKELY(input < 0 && apr_time_usec(input) < 0)) {
+ apr_time_t floorTime = (apr_time_sec(input) -1) * APR_USEC_PER_SEC;
+ stat = apr_time_exp_tz(result, floorTime, offset);
+ result->tm_usec = input - floorTime;
+ } else {
+ stat = apr_time_exp_tz( result, input, offset );
+ }
+ return stat;
}
1.9 +2 -1 logging-log4cxx/tests/src/helpers/Makefile.am
Index: Makefile.am
===================================================================
RCS file: /home/cvs/logging-log4cxx/tests/src/helpers/Makefile.am,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- Makefile.am 3 Jan 2005 06:43:44 -0000 1.8
+++ Makefile.am 19 Feb 2005 01:59:37 -0000 1.9
@@ -1,4 +1,4 @@
-EXTRA_DIST = *.cpp
+EXTRA_DIST = *.cpp *.h
if TESTS
@@ -12,6 +12,7 @@
cyclicbuffertestcase.cpp\
datetimedateformattestcase.cpp \
iso8601dateformattestcase.cpp \
+ localechanger.cpp\
optionconvertertestcase.cpp \
propertiestestcase.cpp \
relativetimedateformattestcase.cpp \
1.11 +354 -53 logging-log4cxx/tests/src/helpers/cacheddateformattestcase.cpp
Index: cacheddateformattestcase.cpp
===================================================================
RCS file: /home/cvs/logging-log4cxx/tests/src/helpers/cacheddateformattestcase.cpp,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- cacheddateformattestcase.cpp 15 Feb 2005 23:56:04 -0000 1.10
+++ cacheddateformattestcase.cpp 19 Feb 2005 01:59:37 -0000 1.11
@@ -23,19 +23,21 @@
#include "../insertwide.h"
#include <apr.h>
#include <apr_time.h>
+#include "localechanger.h"
using namespace log4cxx;
using namespace log4cxx::helpers;
-
+using namespace log4cxx::pattern;
#if defined(_WIN32)
-#define LOCALE_US "us"
-#define LOCALE_JP "jpn"
+#define LOCALE_US "English_us"
+#define LOCALE_JP "Japanese_japan"
#else
#define LOCALE_US "en_US"
#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
@@ -45,7 +47,7 @@
/**
Unit test {@link CachedDateFormat}.
@author Curt Arnold
- @since 1.3.0 */
+ @since 0.9.8 */
class CachedDateFormatTestCase : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE( CachedDateFormatTestCase );
@@ -53,10 +55,22 @@
CPPUNIT_TEST( test2 );
CPPUNIT_TEST( test3 );
CPPUNIT_TEST( test4 );
-// CPPUNIT_TEST( test5 );
+ CPPUNIT_TEST( test5 );
CPPUNIT_TEST( test6 );
- CPPUNIT_TEST( test7 );
CPPUNIT_TEST( test8 );
+ CPPUNIT_TEST( test9 );
+ CPPUNIT_TEST( test10 );
+ CPPUNIT_TEST( test11);
+ CPPUNIT_TEST( test12 );
+ CPPUNIT_TEST( test13 );
+ CPPUNIT_TEST( test14 );
+ CPPUNIT_TEST( test15 );
+ CPPUNIT_TEST( test16 );
+ CPPUNIT_TEST( test17);
+ CPPUNIT_TEST( test18);
+ CPPUNIT_TEST( test19);
+ CPPUNIT_TEST( test20);
+ CPPUNIT_TEST( test21);
CPPUNIT_TEST_SUITE_END();
@@ -72,7 +86,7 @@
// are optimized to reuse previous formatted value
// make a couple of nearly spaced calls
DateFormatPtr baseFormatter(new AbsoluteTimeDateFormat());
- CachedDateFormat gmtFormat(baseFormatter);
+ CachedDateFormat gmtFormat(baseFormatter, 1000000);
gmtFormat.setTimeZone(TimeZone::getGMT());
apr_time_t jul1 = MICROSECONDS_PER_DAY * 12601L;
@@ -109,28 +123,25 @@
void test2() {
apr_time_t jul2 = MICROSECONDS_PER_DAY * 12602;
DateFormatPtr baseFormatter(new AbsoluteTimeDateFormat());
- CachedDateFormat gmtFormat(baseFormatter);
+ CachedDateFormat gmtFormat(baseFormatter, 1000000);
gmtFormat.setTimeZone(TimeZone::getGMT());
DateFormatPtr chicagoBase(new AbsoluteTimeDateFormat());
- CachedDateFormat chicagoFormat(chicagoBase);
+ CachedDateFormat chicagoFormat(chicagoBase, 1000000);
chicagoFormat.setTimeZone(TimeZone::getTimeZone(LOG4CXX_STR("GMT-5")));
Pool p;
-
LogString actual;
-
gmtFormat.format(actual, jul2, p);
CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,000"), actual);
+
actual.erase(actual.begin(), actual.end());
+ chicagoFormat.format(actual, jul2, p);
+ CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("19:00:00,000"), actual);
- chicagoFormat.format(actual, jul2, p);
- CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("19:00:00,000"), actual);
actual.erase(actual.begin(), actual.end());
-
- gmtFormat.format(actual, jul2, p);
- CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,000"), actual);
- actual.erase(actual.begin(), actual.end());
+ gmtFormat.format(actual, jul2, p);
+ CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,000"), actual);
}
/**
@@ -141,7 +152,7 @@
// are optimized to reuse previous formatted value
// make a couple of nearly spaced calls
DateFormatPtr baseFormatter(new AbsoluteTimeDateFormat());
- CachedDateFormat gmtFormat(baseFormatter);
+ CachedDateFormat gmtFormat(baseFormatter, 1000000);
gmtFormat.setTimeZone(TimeZone::getGMT());
apr_time_t ticks = MICROSECONDS_PER_DAY * -7;
@@ -155,7 +166,6 @@
CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,000"), actual);
actual.erase(actual.begin(), actual.end());
-#if defined(_WIN32)
//
// APR's explode_time method does not properly calculate tm_usec
// prior to 1 Jan 1970 on Unix
@@ -171,11 +181,8 @@
CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,237"), actual);
actual.erase(actual.begin(), actual.end());
-// gmtFormat.format(actual, ticks + 1415000, p);
-// Fails on both Linux and Win32
-// CPPUNIT_ASSERT_EQUAL((std::string) "00:00:01,415", actual);
-#endif
-
+ gmtFormat.format(actual, ticks + 1423000, p);
+ CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:01,423"), actual);
}
void assertFormattedEquals(
@@ -189,6 +196,7 @@
baseFormat->format(expected, date, p);
cachedFormat.format(actual, date, p);
+
CPPUNIT_ASSERT_EQUAL(expected, actual);
}
@@ -199,7 +207,7 @@
std::locale localeEN(LOCALE_US);
DateFormatPtr baseFormat(
new SimpleDateFormat(LOG4CXX_STR("EEE, MMM dd, HH:mm:ss.SSS Z"), localeEN));
- CachedDateFormat cachedFormat(baseFormat);
+ CachedDateFormat cachedFormat(baseFormat, 1000000);
//
// use a date in 2000 to attempt to confuse the millisecond locator
apr_time_t ticks = MICROSECONDS_PER_DAY * 11141;
@@ -218,10 +226,10 @@
// subsequent calls within one minute
// are optimized to reuse previous formatted value
// make a couple of nearly spaced calls
- std::locale localeJP(LOCALE_JP);
- DateFormatPtr baseFormat(
- new SimpleDateFormat(LOG4CXX_STR("EEE, MMM dd, HH:mm:ss.SSS Z"), localeJP));
- CachedDateFormat cachedFormat(baseFormat);
+ LocaleChanger localeChange(LOCALE_JP);
+ 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;
@@ -246,46 +254,339 @@
CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("87"), numb);
}
- /**
- * Attempt to cache a RelativeTimeDateFormat which isn't compatible
- * with caching. Should just delegate to the RelativeTimeDateFormat.
- */
- void test7() {
- // subsequent calls within one minute
- // are optimized to reuse previous formatted value
- // make a couple of nearly spaced calls
- DateFormatPtr baseFormat(new RelativeTimeDateFormat());
- CachedDateFormat cachedFormat(baseFormat);
- //
- // 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);
- }
/**
* 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")));
- CachedDateFormat cachedFormat(baseFormat);
- cachedFormat.setTimeZone(TimeZone::getTimeZone(LOG4CXX_STR("GMT-6")));
+ 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);
+ CPPUNIT_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);
CPPUNIT_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;
+ CPPUNIT_ASSERT_EQUAL(statOK, stat);
+
+ Pool p;
+
+ LogString s;
+ cachedFormat->format(s, dec12, p);
+
+ CPPUNIT_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);
+ CPPUNIT_ASSERT_EQUAL(statOK, stat);
+
+ s.erase(s.begin(), s.end());
+ cachedFormat->format(s, jan1, p);
+
+ CPPUNIT_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() {
+ std::locale localeUS(LOCALE_US);
+ 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;
+ CPPUNIT_ASSERT_EQUAL(statOK, stat);
+
+ Pool p;
+
+ LogString s;
+ cachedFormat->format(s, oct5, p);
+
+ CPPUNIT_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);
+ CPPUNIT_ASSERT_EQUAL(statOK, stat);
+
+ s.erase(s.begin(), s.end());
+ cachedFormat->format(s, nov1, p);
+
+ CPPUNIT_ASSERT_EQUAL(
+ (LogString) LOG4CXX_STR("November 023 Monday"), s);
+
+ nov1 += 961000;
+ s.erase(s.begin(), s.end());
+ cachedFormat->format(s, nov1, p);
+
+ CPPUNIT_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);
+
+ CPPUNIT_ASSERT_EQUAL(
+ (LogString) LOG4CXX_STR("00,1200"), s);
+
+ jul2 = ticks + 87000;
+
+ s.erase(s.begin(), s.end());
+ gmtFormat->format(s, jul2, p);
+
+ CPPUNIT_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 millisecondStart = CachedDateFormat::findMillisecondStart(ticks,
+ formatted, df, p);
+ CPPUNIT_ASSERT_EQUAL(20, millisecondStart);
+}
+
+/**
+ * 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);
+ CPPUNIT_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);
+ CPPUNIT_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);
+ CPPUNIT_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);
+ CPPUNIT_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);
+
+ CPPUNIT_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);
+ CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,120 00:00:00,120"), s);
+
+ s.erase(s.begin(), s.end());
+ cachedFormat->format(s, jul2, p);
+
+ CPPUNIT_ASSERT_EQUAL((LogString) LOG4CXX_STR("00:00:00,120 00:00:00,120"), s) ;
+
+ int maxValid = CachedDateFormat::getMaximumCacheValidity(badPattern);
+ CPPUNIT_ASSERT_EQUAL(1000, maxValid);
+}
+
+/**
+ * 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"));
+ CPPUNIT_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"));
+ CPPUNIT_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"));
+ CPPUNIT_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"));
+ CPPUNIT_ASSERT_EQUAL(1000, maxValid);
+}
+
};
1.8 +2 -27 logging-log4cxx/tests/src/helpers/datetimedateformattestcase.cpp
Index: datetimedateformattestcase.cpp
===================================================================
RCS file: /home/cvs/logging-log4cxx/tests/src/helpers/datetimedateformattestcase.cpp,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- datetimedateformattestcase.cpp 15 Feb 2005 23:52:40 -0000 1.7
+++ datetimedateformattestcase.cpp 19 Feb 2005 01:59:37 -0000 1.8
@@ -21,6 +21,7 @@
#include "../insertwide.h"
#include <apr.h>
#include <apr_time.h>
+#include "localechanger.h"
using namespace log4cxx;
using namespace log4cxx::helpers;
@@ -39,36 +40,10 @@
#endif
-class LocaleChanger {
-public:
- LocaleChanger(const char* locale) {
- try {
- std::locale newLocale(locale);
- initial = std::locale::global(newLocale);
- effective = true;
- } catch(std::exception&) {
- }
- }
-
- ~LocaleChanger() {
- if (effective) {
- std::locale::global(initial);
- }
- }
- inline bool isEffective() { return effective; }
-
-private:
- LocaleChanger(LocaleChanger&);
- LocaleChanger& operator=(LocaleChanger&);
- std::locale initial;
- bool effective;
-};
-
-
/**
Unit test {@link DateTimeDateFormat}.
@author Curt Arnold
- @since 1.3.0
+ @since 0.9.8
*/
class DateTimeDateFormatTestCase : public CppUnit::TestFixture
{
1.1 logging-log4cxx/tests/src/helpers/localechanger.cpp
Index: localechanger.cpp
===================================================================
/*
* Copyright 2004-2005 The Apache Software Foundation.
*
* Licensed 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 "localechanger.h"
using namespace log4cxx::helpers;
/**
* Construction attemtps to change default locale.
* @param locale locale.
*/
LocaleChanger::LocaleChanger(const char* locale) {
try {
std::locale newLocale(locale);
initial = std::locale::global(newLocale);
effective = true;
} catch(std::exception&) {
}
}
/**
* Restores previous locale.
*/
LocaleChanger::~LocaleChanger() {
if (effective) {
std::locale::global(initial);
}
}
1.1 logging-log4cxx/tests/src/helpers/localechanger.h
Index: localechanger.h
===================================================================
/*
* Copyright 2004-2005 The Apache Software Foundation.
*
* Licensed 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.
*/
#ifndef _LOG4CXX_HELPERS_LOCALE_CHANGER_H
#define _LOG4CXX_HELPERS_LOCALE_CHANGER_H
#include <locale>
namespace log4cxx {
namespace helpers {
/**
* Utility class to change the locale for the duration of a test.
*
* @author Curt Arnold
* @since 0.9.8
*
*/
class LocaleChanger {
public:
/**
* Construction attemtps to change default locale.
* @param locale locale.
*/
LocaleChanger(const char* locale);
/**
* Restores previous locale.
*/
~LocaleChanger();
/**
* Determines whether locale change was effective.
* @return true if effective.
*/
inline bool isEffective() { return effective; }
private:
LocaleChanger(LocaleChanger&);
LocaleChanger& operator=(LocaleChanger&);
std::locale initial;
bool effective;
};
}
}
#endif