From 7127defbaa3701fc3444feb3233401e2829fc1b6 Mon Sep 17 00:00:00 2001 From: "Rafael G. Martins" Date: Sat, 24 Oct 2015 18:47:41 -0200 Subject: datetime-parser: initial implementation. not used yet --- .gitignore | 1 + Makefile.am | 20 ++ src/datetime-parser.c | 375 +++++++++++++++++++++++++ src/datetime-parser.h | 17 ++ src/error.c | 3 + src/error.h | 1 + tests/check_datetime_parser.c | 631 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1048 insertions(+) create mode 100644 src/datetime-parser.c create mode 100644 src/datetime-parser.h create mode 100644 tests/check_datetime_parser.c diff --git a/.gitignore b/.gitignore index 69135d4..34052e4 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ blogc*.html # tests /tests/check_content_parser +/tests/check_datetime_parser /tests/check_error /tests/check_loader /tests/check_renderer diff --git a/Makefile.am b/Makefile.am index e64eea9..4a28b8b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,6 +25,7 @@ MAINTAINERCLEANFILES = \ noinst_HEADERS = \ src/content-parser.h \ + src/datetime-parser.h \ src/file.h \ src/error.h \ src/loader.h \ @@ -51,6 +52,7 @@ check_PROGRAMS = \ libblogc_la_SOURCES = \ src/content-parser.c \ + src/datetime-parser.c \ src/file.c \ src/error.c \ src/loader.c \ @@ -141,6 +143,7 @@ if USE_CMOCKA check_PROGRAMS += \ tests/check_content_parser \ + tests/check_datetime_parser \ tests/check_error \ tests/check_loader \ tests/check_renderer \ @@ -202,6 +205,23 @@ tests_check_content_parser_LDADD = \ libblogc.la \ $(NULL) +tests_check_datetime_parser_SOURCES = \ + tests/check_datetime_parser.c \ + $(NULL) + +tests_check_datetime_parser_CFLAGS = \ + $(CMOCKA_CFLAGS) \ + $(NULL) + +tests_check_datetime_parser_LDFLAGS = \ + -no-install \ + $(NULL) + +tests_check_datetime_parser_LDADD = \ + $(CMOCKA_LIBS) \ + libblogc.la \ + $(NULL) + tests_check_renderer_SOURCES = \ tests/check_renderer.c \ $(NULL) diff --git a/src/datetime-parser.c b/src/datetime-parser.c new file mode 100644 index 0000000..1d39490 --- /dev/null +++ b/src/datetime-parser.c @@ -0,0 +1,375 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015 Rafael G. Martins + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#ifdef HAVE_TIME_H +#include +#endif /* HAVE_TIME_H */ + +#include +#include + +#include "error.h" +#include "utils/utils.h" +#include "datetime-parser.h" + + +typedef enum { + DATETIME_FIRST_YEAR = 1, + DATETIME_SECOND_YEAR, + DATETIME_THIRD_YEAR, + DATETIME_FOURTH_YEAR, + DATETIME_FIRST_HYPHEN, + DATETIME_FIRST_MONTH, + DATETIME_SECOND_MONTH, + DATETIME_SECOND_HYPHEN, + DATETIME_FIRST_DAY, + DATETIME_SECOND_DAY, + DATETIME_SPACE, + DATETIME_FIRST_HOUR, + DATETIME_SECOND_HOUR, + DATETIME_FIRST_COLON, + DATETIME_FIRST_MINUTE, + DATETIME_SECOND_MINUTE, + DATETIME_SECOND_COLON, + DATETIME_FIRST_SECOND, + DATETIME_SECOND_SECOND, + DATETIME_DONE, +} blogc_datetime_state_t; + + +char* +blogc_convert_datetime(const char *orig, const char *format, + blogc_error_t **err) +{ + if (err == NULL || *err != NULL) + return NULL; + + struct tm t; + memset(&t, 0, sizeof(struct tm)); + t.tm_isdst = -1; + + blogc_datetime_state_t state = DATETIME_FIRST_YEAR; + int tmp = 0; + int diff = '0'; + + for (unsigned int i = 0; orig[i] != '\0'; i++) { + char c = orig[i]; + + switch (state) { + + case DATETIME_FIRST_YEAR: + if (c >= '0' && c <= '9') { + tmp += (c - diff) * 1000; + state = DATETIME_SECOND_YEAR; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid first digit of year. " + "Found '%c', must be integer >= 0 and <= 9.", c); + break; + + case DATETIME_SECOND_YEAR: + if (c >= '0' && c <= '9') { + tmp += (c - diff) * 100; + state = DATETIME_THIRD_YEAR; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid second digit of year. " + "Found '%c', must be integer >= 0 and <= 9.", c); + break; + + case DATETIME_THIRD_YEAR: + if (c >= '0' && c <= '9') { + tmp += (c - diff) * 10; + state = DATETIME_FOURTH_YEAR; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid third digit of year. " + "Found '%c', must be integer >= 0 and <= 9.", c); + break; + + case DATETIME_FOURTH_YEAR: + if (c >= '0' && c <= '9') { + tmp += c - diff - 1900; + if (tmp < 0) { + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid year. Found %d, must be >= 1900.", + tmp + 1900); + break; + } + t.tm_year = tmp; + state = DATETIME_FIRST_HYPHEN; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid fourth digit of year. " + "Found '%c', must be integer >= 0 and <= 9.", c); + break; + + case DATETIME_FIRST_HYPHEN: + if (c == '-') { + tmp = 0; + state = DATETIME_FIRST_MONTH; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid separator between year and month. " + "Found '%c', must be '-'.", c); + break; + + case DATETIME_FIRST_MONTH: + if (c >= '0' && c <= '1') { + tmp += (c - diff) * 10; + state = DATETIME_SECOND_MONTH; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid first digit of month. " + "Found '%c', must be integer >= 0 and <= 1.", c); + break; + + case DATETIME_SECOND_MONTH: + if (c >= '0' && c <= '9') { + tmp += c - diff - 1; + if (tmp < 0 || tmp > 11) { + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid month. Found %d, must be >= 1 and <= 12.", + tmp + 1); + break; + } + t.tm_mon = tmp; + state = DATETIME_SECOND_HYPHEN; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid second digit of month. " + "Found '%c', must be integer >= 0 and <= 9.", c); + break; + + case DATETIME_SECOND_HYPHEN: + if (c == '-') { + tmp = 0; + state = DATETIME_FIRST_DAY; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid separator between month and day. " + "Found '%c', must be '-'.", c); + break; + + case DATETIME_FIRST_DAY: + if (c >= '0' && c <= '3') { + tmp += (c - diff) * 10; + state = DATETIME_SECOND_DAY; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid first digit of day. " + "Found '%c', must be integer >= 0 and <= 3.", c); + break; + + case DATETIME_SECOND_DAY: + if (c >= '0' && c <= '9') { + tmp += c - diff; + if (tmp < 1 || tmp > 31) { + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid day. Found %d, must be >= 1 and <= 31.", + tmp); + break; + } + t.tm_mday = tmp; + state = DATETIME_SPACE; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid second digit of day. " + "Found '%c', must be integer >= 0 and <= 9.", c); + break; + + case DATETIME_SPACE: + if (c == ' ') { + tmp = 0; + state = DATETIME_FIRST_HOUR; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid separator between date and time. " + "Found '%c', must be ' ' (empty space).", c); + break; + + case DATETIME_FIRST_HOUR: + if (c >= '0' && c <= '2') { + tmp += (c - diff) * 10; + state = DATETIME_SECOND_HOUR; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid first digit of hours. " + "Found '%c', must be integer >= 0 and <= 2.", c); + break; + + case DATETIME_SECOND_HOUR: + if (c >= '0' && c <= '9') { + tmp += c - diff; + if (tmp < 0 || tmp > 23) { + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid hours. Found %d, must be >= 0 and <= 23.", + tmp); + break; + } + t.tm_hour = tmp; + state = DATETIME_FIRST_COLON; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid second digit of hours. " + "Found '%c', must be integer >= 0 and <= 9.", c); + break; + + case DATETIME_FIRST_COLON: + if (c == ':') { + tmp = 0; + state = DATETIME_FIRST_MINUTE; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid separator between hours and minutes. " + "Found '%c', must be ':'.", c); + break; + + case DATETIME_FIRST_MINUTE: + if (c >= '0' && c <= '5') { + tmp += (c - diff) * 10; + state = DATETIME_SECOND_MINUTE; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid first digit of minutes. " + "Found '%c', must be integer >= 0 and <= 5.", c); + break; + + case DATETIME_SECOND_MINUTE: + if (c >= '0' && c <= '9') { + tmp += c - diff; + if (tmp < 0 || tmp > 59) { + // this won't happen because we are restricting the digits + // to 00-59 already, but lets keep the code here for + // reference. + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid minutes. Found %d, must be >= 0 and <= 59.", + tmp); + break; + } + t.tm_min = tmp; + state = DATETIME_SECOND_COLON; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid second digit of minutes. " + "Found '%c', must be integer >= 0 and <= 9.", c); + break; + + case DATETIME_SECOND_COLON: + if (c == ':') { + tmp = 0; + state = DATETIME_FIRST_SECOND; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid separator between minutes and seconds. " + "Found '%c', must be ':'.", c); + break; + + case DATETIME_FIRST_SECOND: + if (c >= '0' && c <= '6') { + tmp += (c - diff) * 10; + state = DATETIME_SECOND_SECOND; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid first digit of seconds. " + "Found '%c', must be integer >= 0 and <= 6.", c); + break; + + case DATETIME_SECOND_SECOND: + if (c >= '0' && c <= '9') { + tmp += c - diff; + if (tmp < 0 || tmp > 60) { + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid seconds. Found %d, must be >= 0 and <= 60.", + tmp); + break; + } + t.tm_sec = tmp; + state = DATETIME_DONE; + break; + } + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid second digit of seconds. " + "Found '%c', must be integer >= 0 and <= 9.", c); + break; + + case DATETIME_DONE: + // well, its done ;) + break; + } + + if (*err != NULL) + return NULL; + } + + if (*err == NULL) { + switch (state) { + case DATETIME_FIRST_YEAR: + case DATETIME_SECOND_YEAR: + case DATETIME_THIRD_YEAR: + case DATETIME_FOURTH_YEAR: + case DATETIME_FIRST_HYPHEN: + case DATETIME_FIRST_MONTH: + case DATETIME_SECOND_MONTH: + case DATETIME_SECOND_HYPHEN: + case DATETIME_FIRST_DAY: + case DATETIME_SECOND_DAY: + case DATETIME_FIRST_HOUR: + case DATETIME_SECOND_HOUR: + case DATETIME_FIRST_MINUTE: + case DATETIME_SECOND_MINUTE: + case DATETIME_FIRST_SECOND: + case DATETIME_SECOND_SECOND: + *err = blogc_error_new_printf(BLOGC_ERROR_DATETIME_PARSER, + "Invalid datetime string. " + "Found '%s', formats allowed are: 'yyyy-mm-dd hh:mm:ss', " + "'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and 'yyyy-mm-dd'.", + orig); + return NULL; + + case DATETIME_SPACE: + case DATETIME_FIRST_COLON: + case DATETIME_SECOND_COLON: + case DATETIME_DONE: + break; // these states are ok + } + } + + mktime(&t); + + char buf[1024]; + if (0 == strftime(buf, sizeof(buf), format, &t)) { + fprintf(stderr, "blogc: warning: Failed to format DATE variable, " + "FORMAT is too long: %s\n", format); + return b_strdup(orig); + } + + return b_strdup(buf); +} diff --git a/src/datetime-parser.h b/src/datetime-parser.h new file mode 100644 index 0000000..7f94545 --- /dev/null +++ b/src/datetime-parser.h @@ -0,0 +1,17 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015 Rafael G. Martins + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifndef _DATETIME_H +#define _DATETIME_H + +#include "error.h" + +char* blogc_convert_datetime(const char *orig, const char *format, + blogc_error_t **err); + +#endif /* _DATETIME_H */ diff --git a/src/error.c b/src/error.c index d3d045d..0576d34 100644 --- a/src/error.c +++ b/src/error.c @@ -119,6 +119,9 @@ blogc_error_print(blogc_error_t *err) case BLOGC_ERROR_TEMPLATE_PARSER: fprintf(stderr, "Template parser error: %s\n", err->msg); break; + case BLOGC_ERROR_DATETIME_PARSER: + fprintf(stderr, "Datetime parser error: %s\n", err->msg); + break; case BLOGC_ERROR_LOADER: fprintf(stderr, "Loader error: %s\n", err->msg); break; diff --git a/src/error.h b/src/error.h index 8b5a2e5..d9b2862 100644 --- a/src/error.h +++ b/src/error.h @@ -15,6 +15,7 @@ typedef enum { BLOGC_ERROR_SOURCE_PARSER = 1, BLOGC_ERROR_TEMPLATE_PARSER, + BLOGC_ERROR_DATETIME_PARSER, BLOGC_ERROR_LOADER, } blogc_error_type_t; diff --git a/tests/check_datetime_parser.c b/tests/check_datetime_parser.c new file mode 100644 index 0000000..37deb02 --- /dev/null +++ b/tests/check_datetime_parser.c @@ -0,0 +1,631 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2015 Rafael G. Martins + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include "../src/error.h" +#include "../src/datetime-parser.h" + + +static void +test_convert_datetime(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(err); + assert_string_equal(dt, "Nov 30, 2010, 12:13:14 PM GMT"); + free(dt); +} + + +static void +test_convert_datetime_implicit_seconds(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 12:13", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(err); + assert_string_equal(dt, "Nov 30, 2010, 12:13:00 PM GMT"); + free(dt); +} + + +static void +test_convert_datetime_implicit_minutes(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 12", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(err); + assert_string_equal(dt, "Nov 30, 2010, 12:00:00 PM GMT"); + free(dt); +} + + +static void +test_convert_datetime_implicit_hours(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(err); + assert_string_equal(dt, "Nov 30, 2010, 12:00:00 AM GMT"); + free(dt); +} + + +static void +test_convert_datetime_invalid_formats(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("20", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '20', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("201", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '201', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2010", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2010', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2010-", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2010-', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2010-1", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2010-1', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2010-11", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2010-11', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2010-11-", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2010-11-', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2010-11-3", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2010-11-3', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2010-11-30 ", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2010-11-30 ', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2010-11-30 1", "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2010-11-30 1', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2010-11-30 12:1", "%b %d, %Y, %I:%M:%S %p GMT", + &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2010-11-30 12:1', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); + + err = NULL; + dt = blogc_convert_datetime("2010-11-30 12:13:1", "%b %d, %Y, %I:%M:%S %p GMT", + &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid datetime string. Found '2010-11-30 12:13:1', formats allowed are: " + "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and " + "'yyyy-mm-dd'."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_1st_year(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("a010-11-30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid first digit of year. Found 'a', must be integer >= 0 and <= 9."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_2nd_year(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2a10-11-30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid second digit of year. Found 'a', must be integer >= 0 and <= 9."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_3rd_year(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("20a0-11-30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid third digit of year. Found 'a', must be integer >= 0 and <= 9."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_4th_year(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("201a-11-30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid fourth digit of year. Found 'a', must be integer >= 0 and <= 9."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_year(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("1899-11-30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid year. Found 1899, must be >= 1900."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_1st_hyphen(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010 11-30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid separator between year and month. Found ' ', must be '-'."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_1st_month(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-a1-30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid first digit of month. Found 'a', must be integer >= 0 and <= 1."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_2nd_month(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-1a-30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid second digit of month. Found 'a', must be integer >= 0 and <= 9."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_month(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-13-30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid month. Found 13, must be >= 1 and <= 12."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_2nd_hyphen(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11 30 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid separator between month and day. Found ' ', must be '-'."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_1st_day(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-a0 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid first digit of day. Found 'a', must be integer >= 0 and <= 3."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_2nd_day(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-3a 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid second digit of day. Found 'a', must be integer >= 0 and <= 9."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_day(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-12-32 12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid day. Found 32, must be >= 1 and <= 31."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_space(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30-12:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid separator between date and time. Found '-', must be ' ' " + "(empty space)."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_1st_hours(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 a2:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid first digit of hours. Found 'a', must be integer >= 0 and <= 2."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_2nd_hours(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 1a:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid second digit of hours. Found 'a', must be integer >= 0 and <= 9."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_hours(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-12-30 24:13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid hours. Found 24, must be >= 0 and <= 23."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_1st_colon(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 12 13:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid separator between hours and minutes. Found ' ', must be ':'."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_1st_minutes(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 12:a3:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid first digit of minutes. Found 'a', must be integer >= 0 and <= 5."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_2nd_minutes(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 12:1a:14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid second digit of minutes. Found 'a', must be integer >= 0 and <= 9."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_2nd_colon(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 12:13 14", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid separator between minutes and seconds. Found ' ', must be ':'."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_1st_seconds(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 12:13:a4", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid first digit of seconds. Found 'a', must be integer >= 0 and <= 6."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_2nd_seconds(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-11-30 12:13:1a", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid second digit of seconds. Found 'a', must be integer >= 0 and <= 9."); + blogc_error_free(err); +} + + +static void +test_convert_datetime_invalid_seconds(void **state) +{ + blogc_error_t *err = NULL; + char *dt = blogc_convert_datetime("2010-12-30 12:13:69", + "%b %d, %Y, %I:%M:%S %p GMT", &err); + assert_null(dt); + assert_non_null(err); + assert_int_equal(err->type, BLOGC_ERROR_DATETIME_PARSER); + assert_string_equal(err->msg, + "Invalid seconds. Found 69, must be >= 0 and <= 60."); + blogc_error_free(err); +} + + +int +main(void) +{ + setlocale(LC_ALL, "C"); + const UnitTest tests[] = { + unit_test(test_convert_datetime), + unit_test(test_convert_datetime_implicit_seconds), + unit_test(test_convert_datetime_implicit_minutes), + unit_test(test_convert_datetime_implicit_hours), + unit_test(test_convert_datetime_invalid_formats), + unit_test(test_convert_datetime_invalid_1st_year), + unit_test(test_convert_datetime_invalid_2nd_year), + unit_test(test_convert_datetime_invalid_3rd_year), + unit_test(test_convert_datetime_invalid_4th_year), + unit_test(test_convert_datetime_invalid_year), + unit_test(test_convert_datetime_invalid_1st_hyphen), + unit_test(test_convert_datetime_invalid_1st_month), + unit_test(test_convert_datetime_invalid_2nd_month), + unit_test(test_convert_datetime_invalid_month), + unit_test(test_convert_datetime_invalid_2nd_hyphen), + unit_test(test_convert_datetime_invalid_1st_day), + unit_test(test_convert_datetime_invalid_2nd_day), + unit_test(test_convert_datetime_invalid_day), + unit_test(test_convert_datetime_invalid_space), + unit_test(test_convert_datetime_invalid_1st_hours), + unit_test(test_convert_datetime_invalid_2nd_hours), + unit_test(test_convert_datetime_invalid_hours), + unit_test(test_convert_datetime_invalid_1st_colon), + unit_test(test_convert_datetime_invalid_1st_minutes), + unit_test(test_convert_datetime_invalid_2nd_minutes), + //unit_test(test_convert_datetime_invalid_minutes), // not possible + unit_test(test_convert_datetime_invalid_2nd_colon), + unit_test(test_convert_datetime_invalid_1st_seconds), + unit_test(test_convert_datetime_invalid_2nd_seconds), + unit_test(test_convert_datetime_invalid_seconds), + }; + return run_tests(tests); +} -- cgit v1.2.3-18-g5258