libsoup r1117 - in trunk: . libsoup tests



Author: danw
Date: Sat Mar 29 19:43:18 2008
New Revision: 1117
URL: http://svn.gnome.org/viewvc/libsoup?rev=1117&view=rev

Log:
	* libsoup/soup-date.c (parse_day): fix the test for no-day-parsed
	(parse_year): likewise fix the test for no-year-parsed
	(parse_time): don't accept empty components here
	(parse_textual_date): don't accept a comma if it wasn't preceded
	by a weekday
	(soup_date_weekday): Fix leap year handling here; the code this
	was originally based on only had to work between 1970 and 2038, so
	it didn't worry about the mod 100 and mod 400 rules...

	* tests/date.c: Add date/string conversion tests (in particular,
	to make sure soup_date_weekday is working). Also add test cases
	with missing components and make sure they *don't* parse.


Modified:
   trunk/ChangeLog
   trunk/libsoup/soup-date.c
   trunk/tests/date.c

Modified: trunk/libsoup/soup-date.c
==============================================================================
--- trunk/libsoup/soup-date.c	(original)
+++ trunk/libsoup/soup-date.c	Sat Mar 29 19:43:18 2008
@@ -47,10 +47,47 @@
 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
 };
 
-static const int days_before[] = {
+static const int nonleap_days_in_month[] = {
+	0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static const int nonleap_days_before[] = {
 	0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
 };
 
+static inline gboolean
+is_leap_year (int year)
+{
+	return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
+}
+
+/* Computes the number of days since proleptic Gregorian 0000-12-31.
+ * (That is, 0001-01-01 is "1", and 1970-01-01 is 719163.
+ */
+static int
+rata_die_day (SoupDate *date)
+{
+	int day;
+
+	day = (date->year - 1) * 365 + ((date->year - 1) / 4) -
+		((date->year - 1) / 100) + ((date->year - 1) / 400);
+	day += nonleap_days_before[date->month] + date->day;
+	if (is_leap_year (date->year) && date->month > 2)
+		day++;
+	return day;
+}
+
+#define TIME_T_EPOCH_RATA_DIE_DAY 719163
+
+static inline int
+days_in_month (int month, int year)
+{
+	if (month == 2 && is_leap_year (year))
+		return 29;
+	else
+		return nonleap_days_in_month[month];
+}
+
 GType
 soup_date_get_type (void)
 {
@@ -181,7 +218,7 @@
 	char *end;
 
 	date->day = strtoul (*date_string, &end, 10);
-	if (end == (char *)date_string)
+	if (end == (char *)*date_string)
 		return FALSE;
 
 	while (*end == ' ' || *end == '-')
@@ -213,7 +250,7 @@
 	char *end;
 
 	date->year = strtoul (*date_string, &end, 10);
-	if (end == (char *)date_string)
+	if (end == (char *)*date_string)
 		return FALSE;
 
 	if (end == (char *)*date_string + 2) {
@@ -233,15 +270,20 @@
 static inline gboolean
 parse_time (SoupDate *date, const char **date_string)
 {
-	char *p;
+	char *p, *end;
 
-	date->hour = strtoul (*date_string, &p, 10);
-	if (*p++ != ':')
+	date->hour = strtoul (*date_string, &end, 10);
+	if (end == (char *)*date_string || *end++ != ':')
+		return FALSE;
+	p = end;
+	date->minute = strtoul (p, &end, 10);
+	if (end == p || *end++ != ':')
 		return FALSE;
-	date->minute = strtoul (p, &p, 10);
-	if (*p++ != ':')
+	p = end;
+	date->second = strtoul (p, &end, 10);
+	if (end == p)
 		return FALSE;
-	date->second = strtoul (p, &p, 10);
+	p = end;
 
 	while (*p == ' ')
 		p++;
@@ -289,12 +331,14 @@
 parse_textual_date (SoupDate *date, const char *date_string)
 {
 	/* If it starts with a word, it must be a weekday, which we skip */
-	while (g_ascii_isalpha (*date_string))
-		date_string++;
-	if (*date_string == ',')
-		date_string++;
-	while (g_ascii_isspace (*date_string))
-		date_string++;
+	if (g_ascii_isalpha (*date_string)) {
+		while (g_ascii_isalpha (*date_string))
+			date_string++;
+		if (*date_string == ',')
+			date_string++;
+		while (g_ascii_isspace (*date_string))
+			date_string++;
+	}
 
 	/* If there's now another word, this must be an asctime-date */
 	if (g_ascii_isalpha (*date_string)) {
@@ -325,13 +369,6 @@
 	return TRUE;
 }
 
-static int
-days_in_month (int month, int year)
-{
-	return days_before[month + 1] - days_before[month] +
-		(((year % 4 == 0) && month == 2) ? 1 : 0);
-}
-
 /**
  * SoupDateFormat:
  * @SOUP_DATE_HTTP: RFC 1123 format, used by the HTTP "Date" header. Eg
@@ -434,18 +471,10 @@
 static const char *
 soup_date_weekday (SoupDate *date)
 {
-	int day;
-
 	/* Proleptic Gregorian 0001-01-01 was a Monday, which
-	 * corresponds to 1 in the days[] array. So we take the
-	 * number of days since 0000-12-31, modulo 7.
+	 * corresponds to 1 in the days[] array.
 	 */
-	day = (date->year - 1) * 365 + ((date->year - 1) / 4);
-	day += days_before[date->month] + date->day;
-	if (date->year % 4 == 0 && date->month > 2)
-		day++;
-
-	return days[day % 7];
+	return days[rata_die_day (date) % 7];
 }
 
 /**
@@ -528,11 +557,7 @@
 	if (sizeof (time_t) == 4 && date->year > 2038)
 		return (time_t)0x7fffffff;
 
-	tt = (date->year - 1970) * 365;
-	tt += (date->year - 1968) / 4;
-	tt += days_before[date->month] + date->day - 1;
-	if (date->year % 4 == 0 && date->month <= 2)
-		tt--;
+	tt = rata_die_day (date) - TIME_T_EPOCH_RATA_DIE_DAY;
 	tt = ((((tt * 24) + date->hour) * 60) + date->minute) * 60 + date->second;
 
 	if (sizeof (time_t) == 4 && tt < 0)

Modified: trunk/tests/date.c
==============================================================================
--- trunk/tests/date.c	(original)
+++ trunk/tests/date.c	Sat Mar 29 19:43:18 2008
@@ -11,23 +11,41 @@
 
 #include "test-utils.h"
 
-const char *date_tests[] = {
+static const struct {
+	SoupDateFormat format;
+	const char *date;
+} good_dates[] = {
+	{ SOUP_DATE_HTTP,            "Sat, 06 Nov 2004 08:09:07 GMT" },
+	{ SOUP_DATE_COOKIE,          "Sat, 06-Nov-2004 08:09:07 GMT" },
+#ifdef NOT_YET
+	{ SOUP_DATE_RFC2822,         "Sat, 06 Nov 2004 08:09:07 +0000" },
+#endif
+	{ SOUP_DATE_ISO8601_COMPACT, "20041106T080907" },
+	{ SOUP_DATE_ISO8601_FULL,    "2004-11-06T08:09:07" },
+	{ SOUP_DATE_ISO8601_XMLRPC,  "20041106T08:09:07" }
+};
+
+static const char *ok_dates[] = {
 	/* rfc1123-date, and broken variants */
-	"Sun, 06 Nov 2004 08:09:07 GMT",
-	"Sun, 6 Nov 2004 08:09:07 GMT",
-	"Sun,  6 Nov 2004 08:09:07 GMT",
+	"Sat, 06 Nov 2004 08:09:07 GMT",
+	"Sat, 6 Nov 2004 08:09:07 GMT",
+	"Sat,  6 Nov 2004 08:09:07 GMT",
+	"Sat, 06 Nov 2004 08:09:07",
+	"06 Nov 2004 08:09:07 GMT",
 
 	/* rfc850-date, and broken variants */
-	"Sunday, 06-Nov-04 08:09:07 GMT",
-	"Sunday, 6-Nov-04 08:09:07 GMT",
-	"Sunday,  6-Nov-04 08:09:07 GMT",
-	"Sunday, 06-Nov-104 08:09:07 GMT",
+	"Saturday, 06-Nov-04 08:09:07 GMT",
+	"Saturday, 6-Nov-04 08:09:07 GMT",
+	"Saturday,  6-Nov-04 08:09:07 GMT",
+	"Saturday, 06-Nov-104 08:09:07 GMT",
+	"Saturday, 06-Nov-04 08:09:07",
+	"06-Nov-04 08:09:07 GMT",
 
 	/* asctime-date, and broken variants */
-	"Sun Nov  6 08:09:07 2004",
-	"Sun Nov 06 08:09:07 2004",
-	"Sun Nov 6 08:09:07 2004",
-	"Sun Nov  6 08:09:07 2004 GMT",
+	"Sat Nov  6 08:09:07 2004",
+	"Sat Nov 06 08:09:07 2004",
+	"Sat Nov 6 08:09:07 2004",
+	"Sat Nov  6 08:09:07 2004 GMT",
 
 	/* ISO 8601 */
 	"2004-11-06T08:09:07Z",
@@ -36,53 +54,130 @@
 	"20041106T080907+00:00",
 
 	/* Netscape cookie spec date, and broken variants */
-	"Sun, 06-Nov-2004 08:09:07 GMT",
-	"Sun, 6-Nov-2004 08:09:07 GMT",
-	"Sun,  6-Nov-2004 08:09:07 GMT",
+	"Sat, 06-Nov-2004 08:09:07 GMT",
+	"Sat, 6-Nov-2004 08:09:07 GMT",
+	"Sat,  6-Nov-2004 08:09:07 GMT",
+	"Sat, 06-Nov-2004 08:09:07",
 
 	/* Original version of Netscape cookie spec, and broken variants */
-	"Sun, 06-Nov-04 08:09:07 GMT",
-	"Sun, 6-Nov-04 08:09:07 GMT",
-	"Sun,  6-Nov-04 08:09:07 GMT",
-	"Sun, 06-Nov-104 08:09:07 GMT",
+	"Sat, 06-Nov-04 08:09:07 GMT",
+	"Sat, 6-Nov-04 08:09:07 GMT",
+	"Sat,  6-Nov-04 08:09:07 GMT",
+	"Sat, 06-Nov-104 08:09:07 GMT",
+	"Sat, 06-Nov-04 08:09:07",
 
 	/* Netscape cookie spec example syntax, and broken variants */
-	"Sunday, 06-Nov-04 08:09:07 GMT",
-	"Sunday, 6-Nov-04 08:09:07 GMT",
-	"Sunday,  6-Nov-04 08:09:07 GMT",
-	"Sunday, 06-Nov-104 08:09:07 GMT",
-	"Sunday, 06-Nov-2004 08:09:07 GMT",
-	"Sunday, 6-Nov-2004 08:09:07 GMT",
-	"Sunday,  6-Nov-2004 08:09:07 GMT",
+	"Saturday, 06-Nov-04 08:09:07 GMT",
+	"Saturday, 6-Nov-04 08:09:07 GMT",
+	"Saturday,  6-Nov-04 08:09:07 GMT",
+	"Saturday, 06-Nov-104 08:09:07 GMT",
+	"Saturday, 06-Nov-2004 08:09:07 GMT",
+	"Saturday, 6-Nov-2004 08:09:07 GMT",
+	"Saturday,  6-Nov-2004 08:09:07 GMT",
+	"Saturday, 06-Nov-04 08:09:07",
 
 	/* Miscellaneous broken formats seen on the web */
-	"Sun 06-Nov-2004  08:9:07",
-	"Sunday, 06-Nov-04 8:9:07 GMT",
-	"Sun, 06 Nov 2004 08:09:7 GMT",
-	"Sun, 06-Nov-2004 08:09:07"
+	"Sat 06-Nov-2004  08:9:07",
+	"Saturday, 06-Nov-04 8:9:07 GMT",
+	"Sat, 06 Nov 2004 08:09:7 GMT"
+};
+
+static const char *bad_dates[] = {
+	/* broken rfc1123-date */
+	", 06 Nov 2004 08:09:07 GMT",
+	"Sat, Nov 2004 08:09:07 GMT",
+	"Sat, 06 2004 08:09:07 GMT",
+	"Sat, 06 Nov 08:09:07 GMT",
+	"Sat, 06 Nov 2004 :09:07 GMT",
+	"Sat, 06 Nov 2004 09:07 GMT",
+	"Sat, 06 Nov 2004 08::07 GMT",
+	"Sat, 06 Nov 2004 08:09: GMT",
+
+	/* broken rfc850-date */
+	", 06-Nov-04 08:09:07 GMT",
+	"Saturday, -Nov-04 08:09:07 GMT",
+	"Saturday, Nov-04 08:09:07 GMT",
+	"Saturday, 06-04 08:09:07 GMT",
+	"Saturday, 06--04 08:09:07 GMT",
+	"Saturday, 06-Nov- 08:09:07 GMT",
+	"Saturday, 06-Nov 08:09:07 GMT",
+	"Saturday, 06-Nov-04 :09:07 GMT",
+	"Saturday, 06-Nov-04 09:07 GMT",
+	"Saturday, 06-Nov-04 08::07 GMT",
+	"Saturday, 06-Nov-04 08:09: GMT",
+
+	/* broken asctime-date */
+	"Nov  6 08:09:07 2004",
+	"Sat  6 08:09:07 2004",
+	"Sat Nov 08:09:07 2004",
+	"Sat Nov  6 :09:07 2004",
+	"Sat Nov  6 09:07 2004",
+	"Sat Nov  6 08::07 2004",
+	"Sat Nov  6 08:09: 2004",
+	"Sat Nov  6 08:09:07",
+	"Sat Nov  6 08:09:07 GMT 2004"
 };
 
 #define TIME_T 1099728547L
 #define TIME_T_STRING "1099728547"
 
-static void
-check (const char *strdate, SoupDate *date)
+static gboolean
+check_ok (const char *strdate, SoupDate *date)
 {
+	debug_printf (2, "%s\n", strdate);
+
 	if (date &&
 	    date->year == 2004 && date->month == 11 && date->day == 6 &&
 	    date->hour == 8 && date->minute == 9 && date->second == 7) {
 		soup_date_free (date);
-		return;
+		return TRUE;
 	}
 
-	fprintf (stderr, "date parsing failed for '%s'.\n", strdate);
+	debug_printf (1, "  date parsing failed for '%s'.\n", strdate);
 	if (date) {
-		fprintf (stderr, "  got: %d %d %d - %d %d %d\n\n",
-			 date->year, date->month, date->day,
-			 date->hour, date->minute, date->second);
+		debug_printf (1, "    got: %d %d %d - %d %d %d\n\n",
+			      date->year, date->month, date->day,
+			      date->hour, date->minute, date->second);
 		soup_date_free (date);
 	}
 	errors++;
+	return FALSE;
+}
+
+static void
+check_good (SoupDateFormat format, const char *strdate)
+{
+	SoupDate *date;
+	char *strdate2;
+
+	date = soup_date_new_from_string (strdate);
+	if (date)
+		strdate2 = soup_date_to_string (date, format);
+	if (!check_ok (strdate, date))
+		return;
+
+	if (strcmp (strdate, strdate2) != 0) {
+		debug_printf (1, "  restringification failed: '%s' -> '%s'\n",
+			      strdate, strdate2);
+		errors++;
+	}
+	g_free (strdate2);
+}
+
+static void
+check_bad (const char *strdate, SoupDate *date)
+{
+	debug_printf (2, "%s\n", strdate);
+
+	if (!date)
+		return;
+	errors++;
+
+	debug_printf (1, "  date parsing succeeded for '%s'!\n", strdate);
+	debug_printf (1, "    got: %d %d %d - %d %d %d\n\n",
+		      date->year, date->month, date->day,
+		      date->hour, date->minute, date->second);
+	soup_date_free (date);
 }
 
 int
@@ -92,10 +187,18 @@
 
 	test_init (argc, argv, NULL);
 
-	for (i = 0; i < G_N_ELEMENTS (date_tests); i++) {
-		check (date_tests[i], soup_date_new_from_string (date_tests[i]));
-	}
-	check (TIME_T_STRING, soup_date_new_from_time_t (TIME_T));
+	debug_printf (1, "Good dates:\n");
+	for (i = 0; i < G_N_ELEMENTS (good_dates); i++)
+		check_good (good_dates[i].format, good_dates[i].date);
+
+	debug_printf (1, "\nOK dates:\n");
+	for (i = 0; i < G_N_ELEMENTS (ok_dates); i++)
+		check_ok (ok_dates[i], soup_date_new_from_string (ok_dates[i]));
+	check_ok (TIME_T_STRING, soup_date_new_from_time_t (TIME_T));
+
+	debug_printf (1, "\nBad dates:\n");
+	for (i = 0; i < G_N_ELEMENTS (bad_dates); i++)
+		check_bad (bad_dates[i], soup_date_new_from_string (bad_dates[i]));
 
 	test_cleanup ();
 	return errors != 0;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]