freeswitch/libs/xmlrpc-c/src/test/value_datetime.c

425 lines
10 KiB
C

#define _XOPEN_SOURCE 600 /* Make sure strdup() is in <string.h> */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "casprintf.h"
#include "girstring.h"
#include "xmlrpc_config.h"
#include "xmlrpc-c/base.h"
#include "xmlrpc-c/string_int.h"
#include "testtool.h"
#include "value_datetime.h"
static const char *
truncateFracSec(const char * const datestring) {
/*----------------------------------------------------------------------------
Return 'datestring', but with any fractional seconds chopped off.
E.g. if 'datestring' is "20000301T00:00:00.654321",
we return "20000301T00:00:00".
-----------------------------------------------------------------------------*/
char * buffer;
unsigned int i;
buffer = strdup(datestring);
for (i = 0; i < strlen(buffer); ++i) {
if (buffer[i] == '.')
buffer[i] = '\0';
}
return buffer;
}
#if XMLRPC_HAVE_TIMEVAL
static struct timeval
makeTv(time_t const secs,
unsigned int const usecs) {
struct timeval retval;
retval.tv_sec = secs;
retval.tv_usec = usecs;
return retval;
}
static bool
tvIsEqual(struct timeval const comparand,
struct timeval const comparator) {
return
comparand.tv_sec == comparator.tv_sec &&
comparand.tv_usec == comparator.tv_usec;
}
#endif
#if XMLRPC_HAVE_TIMESPEC
static struct timespec
makeTs(time_t const secs,
unsigned int const usecs) {
struct timespec retval;
retval.tv_sec = secs;
retval.tv_nsec = usecs * 1000;
return retval;
}
static bool
tsIsEqual(struct timespec const comparand,
struct timespec const comparator) {
return
comparand.tv_sec == comparator.tv_sec &&
comparand.tv_nsec == comparator.tv_nsec;
}
#endif
static void
test_value_datetime_varytime(const char * const datestring,
time_t const datetime,
unsigned int const usec) {
xmlrpc_value * v;
xmlrpc_env env;
const char * readBackString;
time_t readBackDt;
unsigned int readBackUsec;
const char * datestringSec;
#if XMLRPC_HAVE_TIMEVAL
struct timeval const dtTimeval = makeTv(datetime, usec);
struct timeval readBackTv;
#endif
#if XMLRPC_HAVE_TIMESPEC
struct timespec const dtTimespec = makeTs(datetime, usec);
struct timespec readBackTs;
#endif
datestringSec = truncateFracSec(datestring);
xmlrpc_env_init(&env);
/* Test xmlrpc_datetime_new_str and time read functions*/
v = xmlrpc_datetime_new_str(&env, datestring);
TEST_NO_FAULT(&env);
TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v));
xmlrpc_read_datetime_sec(&env, v, &readBackDt);
TEST_NO_FAULT(&env);
TEST(readBackDt == datetime);
xmlrpc_read_datetime_usec(&env, v, &readBackDt, &readBackUsec);
TEST_NO_FAULT(&env);
TEST(readBackDt == datetime);
TEST(readBackUsec == usec);
#if XMLRPC_HAVE_TIMEVAL
xmlrpc_read_datetime_timeval(&env, v, &readBackTv);
TEST_NO_FAULT(&env);
TEST(tvIsEqual(dtTimeval, readBackTv));
#endif
#if XMLRPC_HAVE_TIMESPEC
xmlrpc_read_datetime_timespec(&env, v, &readBackTs);
TEST_NO_FAULT(&env);
TEST(tsIsEqual(dtTimespec, readBackTs));
#endif
xmlrpc_DECREF(v);
/* Test xmlrpc_datetime_new_sec */
v = xmlrpc_datetime_new_sec(&env, datetime);
TEST_NO_FAULT(&env);
TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v));
xmlrpc_read_datetime_str(&env, v, &readBackString);
TEST_NO_FAULT(&env);
TEST(streq(readBackString, datestringSec));
strfree(readBackString);
xmlrpc_DECREF(v);
/* Test xmlrpc_datetime_new_usec */
v = xmlrpc_datetime_new_usec(&env, datetime, usec);
TEST_NO_FAULT(&env);
TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v));
xmlrpc_read_datetime_str(&env, v, &readBackString);
TEST_NO_FAULT(&env);
TEST(streq(readBackString, datestring));
strfree(readBackString);
xmlrpc_DECREF(v);
#if XMLRPC_HAVE_TIMEVAL
/* Test xmlrpc_datetime_new_timeval */
v = xmlrpc_datetime_new_timeval(&env, dtTimeval);
TEST_NO_FAULT(&env);
TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v));
xmlrpc_read_datetime_str(&env, v, &readBackString);
TEST_NO_FAULT(&env);
TEST(streq(readBackString, datestring));
strfree(readBackString);
xmlrpc_DECREF(v);
#endif
#if XMLRPC_HAVE_TIMESPEC
/* Test xmlrpc_datetime_new_timespec */
v = xmlrpc_datetime_new_timespec(&env, dtTimespec);
TEST_NO_FAULT(&env);
TEST(XMLRPC_TYPE_DATETIME == xmlrpc_value_type(v));
xmlrpc_read_datetime_str(&env, v, &readBackString);
TEST_NO_FAULT(&env);
TEST(streq(readBackString, datestring));
strfree(readBackString);
xmlrpc_DECREF(v);
#endif
xmlrpc_env_clean(&env);
strfree(datestringSec);
}
static void
test_value_datetime_not_unix(const char * const datestring) {
xmlrpc_value * v;
xmlrpc_env env;
time_t dt;
xmlrpc_env_init(&env);
v = xmlrpc_datetime_new_str(&env, datestring);
TEST_NO_FAULT(&env);
xmlrpc_read_datetime_sec(&env, v, &dt);
TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR);
xmlrpc_DECREF(v);
xmlrpc_env_clean(&env);
}
static void
test_value_datetime_str_invalid1(const char * const datestring) {
/* Ideally, xmlrpc_datetime_new_str() would fail on these, but
the code doesn't implement that today. However,
xmlrpc_read_datetime_sec() does catch many cases, so we
use that.
Note that xmlrpc_read_datetime_sec() doesn't catch them all.
Sometimes it just returns garbage, e.g. returns July 1 for
June 31.
*/
xmlrpc_value * v;
xmlrpc_env env;
time_t dt;
xmlrpc_env_init(&env);
v = xmlrpc_datetime_new_str(&env, datestring);
TEST_NO_FAULT(&env);
xmlrpc_read_datetime_sec(&env, v, &dt);
TEST_FAULT(&env, XMLRPC_PARSE_ERROR);
xmlrpc_DECREF(v);
xmlrpc_env_clean(&env);
}
static void
test_value_datetime_str_invalid2(const char * const datestring) {
xmlrpc_value * v;
xmlrpc_env env;
xmlrpc_env_init(&env);
v = xmlrpc_datetime_new_str(&env, datestring);
TEST_FAULT(&env, XMLRPC_INTERNAL_ERROR);
xmlrpc_env_clean(&env);
}
static void
test_build_decomp_datetime(void) {
const char * datestring = "19980717T14:08:55";
time_t const datetime = 900684535;
xmlrpc_env env;
xmlrpc_value * v;
time_t dt;
const char * ds;
xmlrpc_env_init(&env);
v = xmlrpc_build_value(&env, "t", datetime);
TEST_NO_FAULT(&env);
TEST(v != NULL);
TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_DATETIME);
dt = 0;
xmlrpc_read_datetime_sec(&env, v, &dt);
TEST(dt == datetime);
dt = 0;
xmlrpc_decompose_value(&env, v, "t", &dt);
xmlrpc_DECREF(v);
TEST_NO_FAULT(&env);
TEST(dt == datetime);
v = xmlrpc_int_new(&env, 9);
TEST_NO_FAULT(&env);
xmlrpc_decompose_value(&env, v, "t", &dt);
TEST_FAULT(&env, XMLRPC_TYPE_ERROR);
xmlrpc_env_clean(&env);
xmlrpc_env_init(&env);
xmlrpc_decompose_value(&env, v, "8", &ds);
TEST_FAULT(&env, XMLRPC_TYPE_ERROR);
xmlrpc_env_clean(&env);
xmlrpc_env_init(&env);
xmlrpc_DECREF(v);
v = xmlrpc_build_value(&env, "8", datestring);
TEST_NO_FAULT(&env);
TEST(v != NULL);
TEST(xmlrpc_value_type(v) == XMLRPC_TYPE_DATETIME);
xmlrpc_decompose_value(&env, v, "8", &ds);
xmlrpc_DECREF(v);
TEST_NO_FAULT(&env);
TEST(streq(ds, datestring));
strfree(ds);
xmlrpc_env_clean(&env);
}
static void
test_value_datetime_basic(void) {
xmlrpc_value * v;
xmlrpc_env env;
xmlrpc_datetime dt;
xmlrpc_datetime readBackDt;
xmlrpc_env_init(&env);
dt.Y = 2001;
dt.M = 12;
dt.D = 25;
dt.h = 1;
dt.m = 2;
dt.s = 3;
dt.u = 4;
v = xmlrpc_datetime_new(&env, dt);
xmlrpc_read_datetime(&env, v, &readBackDt);
TEST_NO_FAULT(&env);
TEST(readBackDt.Y = dt.Y);
TEST(readBackDt.M = dt.M);
TEST(readBackDt.D = dt.D);
TEST(readBackDt.h = dt.h);
TEST(readBackDt.m = dt.m);
TEST(readBackDt.s = dt.s);
TEST(readBackDt.u = dt.u);
xmlrpc_env_clean(&env);
}
void
test_value_datetime(void) {
const char * datestring = "19980717T14:08:55";
time_t const datetime = 900684535;
xmlrpc_env env;
printf("\n Running datetime value tests");
xmlrpc_env_init(&env);
TEST(streq(xmlrpc_type_name(XMLRPC_TYPE_DATETIME), "DATETIME"));
test_value_datetime_basic();
/* Valid datetime, generated from XML-RPC string, time_t, and
time_t + microseconds
*/
test_value_datetime_varytime(datestring, datetime, 0);
/* test microseconds */
test_value_datetime_varytime("20000301T00:00:00.654321",
951868800, 654321);
test_value_datetime_varytime("20040229T23:59:59.123000",
1078099199, 123000);
test_value_datetime_varytime("20000229T23:59:59.000123",
951868799, 123);
/* Leap years */
test_value_datetime_varytime("20000229T23:59:59", 951868799, 0);
test_value_datetime_varytime("20000301T00:00:00", 951868800, 0);
test_value_datetime_varytime("20010228T23:59:59", 983404799, 0);
test_value_datetime_varytime("20010301T00:00:00", 983404800, 0);
test_value_datetime_varytime("20040229T23:59:59", 1078099199, 0);
test_value_datetime_varytime("20040301T00:00:00", 1078099200, 0);
/* Datetimes that can't be represented as time_t */
test_value_datetime_not_unix("19691231T23:59:59");
/* Invalid datetimes */
/* Note that the code today does a pretty weak job of validating datetimes,
so we test only the validation that we know is implemented.
*/
test_value_datetime_str_invalid1("19700101T25:00:00");
test_value_datetime_str_invalid1("19700101T10:61:01");
test_value_datetime_str_invalid1("19700101T10:59:61");
test_value_datetime_str_invalid1("19700001T10:00:00");
test_value_datetime_str_invalid1("19701301T10:00:00");
test_value_datetime_str_invalid1("19700132T10:00:00");
test_value_datetime_str_invalid2("19700132T10:00:00.");
test_value_datetime_str_invalid2("19700132T10:00:00,123");
test_build_decomp_datetime();
xmlrpc_env_clean(&env);
printf("\n");
printf(" datetime value tests done.\n");
}