Skip to content

Commit

Permalink
filterx: strptime builtin function implementation
Browse files Browse the repository at this point in the history
Signed-off-by: shifter <[email protected]>
  • Loading branch information
bshifter committed Apr 10, 2024
1 parent fd4a3e9 commit c59c937
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 4 deletions.
1 change: 1 addition & 0 deletions lib/filterx/filterx-globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ filterx_builtin_functions_init(void)
g_assert(filterx_builtin_function_register("bool", filterx_typecast_boolean));
g_assert(filterx_builtin_function_register("int", filterx_typecast_integer));
g_assert(filterx_builtin_function_register("double", filterx_typecast_double));
g_assert(filterx_builtin_function_register("strptime", filterx_datetime_strptime));
}

void
Expand Down
78 changes: 78 additions & 0 deletions lib/filterx/object-datetime.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "timeutils/format.h"
#include "filterx/object-string.h"
#include "filterx/object-primitive.h"
#include "filterx/object-message-value.h"
#include "generic-number.h"
#include "filterx-globals.h"
#include "compat/json.h"
Expand Down Expand Up @@ -200,6 +201,83 @@ _repr(FilterXObject *s, GString *repr)
return TRUE;
}

const gchar *
_strptime_get_time_str_from_object(FilterXObject *obj)
{
if (!obj)
return NULL;

if (filterx_object_is_type(obj, &FILTERX_TYPE_NAME(string)))
return filterx_string_get_value(obj, NULL);

if (filterx_object_is_type(obj, &FILTERX_TYPE_NAME(message_value)))
{
gsize len;
if (filterx_message_value_get_type(obj) == LM_VT_STRING)
return filterx_message_value_get_value(obj, &len);
}

return NULL;
}

FilterXObject *
filterx_datetime_strptime(GPtrArray *args)
{
if (args == NULL || args->len < 2)
{
msg_error("FilterX: Failed to create datetime object: invalid number of arguments. "
"Usage: strptime(time_str, format_str0, ..., format_strN)");
return NULL;
}

FilterXObject *object = g_ptr_array_index(args, 0);
const gchar *timestr = _strptime_get_time_str_from_object(object);
if (!timestr)
{
msg_error("FilterX: Failed to create datetime object: bad argument. "
"Usage: strptime(time_str, format_str0, ..., format_strN)",
evt_tag_int("arg_pos", 0));
return NULL;
}

FilterXObject *result = NULL;

WallClockTime wct = WALL_CLOCK_TIME_INIT;
UnixTime ut = UNIX_TIME_INIT;
gchar *end = NULL;

for (int i = 1; i < args->len; i++)
{
FilterXObject *time_fmt_obj = g_ptr_array_index(args, i);
if (!time_fmt_obj || !filterx_object_is_type(time_fmt_obj, &FILTERX_TYPE_NAME(string)))
{
msg_debug("FilterX: Failed to create datetime object: bad argument. "
"Usage: strptime(time_str, format_str0, ..., format_strN)",
evt_tag_int("arg_pos", i));
return NULL;
}

const gchar *time_fmt = filterx_string_get_value(time_fmt_obj, NULL);
end = wall_clock_time_strptime(&wct, time_fmt, timestr);
if (!end)
{
msg_error("filterx: unable to parse time",
evt_tag_str("time_string", timestr),
evt_tag_str("format", time_fmt));
}
else
break;
}

if (end)
{
convert_wall_clock_time_to_unix_time(&wct, &ut);
result = filterx_datetime_new(&ut);
}

return result;
}

FILTERX_DEFINE_TYPE(datetime, FILTERX_TYPE_NAME(object),
.truthy = _truthy,
.map_to_json = _map_to_json,
Expand Down
1 change: 1 addition & 0 deletions lib/filterx/object-datetime.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ FilterXObject *filterx_datetime_new(const UnixTime *ut);
UnixTime filterx_datetime_get_value(FilterXObject *s);
FilterXObject *filterx_typecast_datetime(GPtrArray *args);
FilterXObject *filterx_typecast_datetime_isodate(GPtrArray *args);
FilterXObject *filterx_datetime_strptime(GPtrArray *args);

#endif
152 changes: 148 additions & 4 deletions lib/filterx/tests/test_object_datetime.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ Test(filterx_datetime, test_filterx_datetime_typecast_from_datetime)

Test(filterx_datetime, test_filterx_datetime_repr)
{
#define test_time_str "2024-03-18T12:34:13+234"
const gchar *test_time_str = "2024-03-18T12:34:13+234";
GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref);
FilterXObject *in = filterx_string_new(test_time_str, -1);
g_ptr_array_add(args, in);
Expand All @@ -193,12 +193,11 @@ Test(filterx_datetime, test_filterx_datetime_repr)

g_ptr_array_free(args, TRUE);
filterx_object_unref(obj);
#undef test_time_str
}

Test(filterx_datetime, test_filterx_datetime_repr_isodate_Z)
{
#define test_time_str "2024-03-18T12:34:00Z"
const gchar *test_time_str = "2024-03-18T12:34:00Z";
GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref);
FilterXObject *in = filterx_string_new(test_time_str, -1);
g_ptr_array_add(args, in);
Expand All @@ -214,7 +213,152 @@ Test(filterx_datetime, test_filterx_datetime_repr_isodate_Z)

g_ptr_array_free(args, TRUE);
filterx_object_unref(obj);
#undef test_time_str
}

Test(filterx_datetime, test_filterx_datetime_strptime_with_null_args)
{
FilterXObject *obj = filterx_datetime_strptime(NULL);
cr_assert_null(obj);

filterx_object_unref(obj);
}

Test(filterx_datetime, test_filterx_datetime_strptime_without_args)
{
GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref);

FilterXObject *obj = filterx_datetime_strptime(args);
cr_assert_null(obj);

g_ptr_array_free(args, TRUE);
filterx_object_unref(obj);
}


Test(filterx_datetime, test_filterx_datetime_strptime_without_timefmt)
{
const gchar *test_time_str = "2024-04-08T10:11:12Z";
GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref);
FilterXObject *in = filterx_string_new(test_time_str, -1);
g_ptr_array_add(args, in);

FilterXObject *obj = filterx_datetime_strptime(args);
cr_assert_null(obj);

g_ptr_array_free(args, TRUE);
filterx_object_unref(obj);
}

Test(filterx_datetime, test_filterx_datetime_strptime_non_matching_timefmt)
{
const gchar *test_time_str = "2024-04-08T10:11:12Z";
GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref);
FilterXObject *in = filterx_string_new(test_time_str, -1);
g_ptr_array_add(args, in);

FilterXObject *time_fmt = filterx_string_new("non matching timefmt", -1);
g_ptr_array_add(args, time_fmt);

FilterXObject *obj = filterx_datetime_strptime(args);
cr_assert_null(obj);

g_ptr_array_free(args, TRUE);
filterx_object_unref(obj);
}

Test(filterx_datetime, test_filterx_datetime_strptime_matching_timefmt)
{
const gchar *test_time_str = "2024-04-08T10:11:12Z";
GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref);
FilterXObject *in = filterx_string_new(test_time_str, -1);
g_ptr_array_add(args, in);

FilterXObject *time_fmt = filterx_string_new(datefmt_isodate, -1);
g_ptr_array_add(args, time_fmt);

FilterXObject *obj = filterx_datetime_strptime(args);
cr_assert_not_null(obj);
cr_assert(filterx_object_is_type(obj, &FILTERX_TYPE_NAME(datetime)));

GString *repr = scratch_buffers_alloc();

cr_assert(filterx_object_repr(in, repr));
cr_assert_str_eq(test_time_str, repr->str);

g_ptr_array_free(args, TRUE);
filterx_object_unref(obj);
}

Test(filterx_datetime, test_filterx_datetime_strptime_matching_nth_timefmt)
{
const gchar *test_time_str = "2024-04-08T10:11:12+01:00";
GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref);
FilterXObject *in = filterx_string_new(test_time_str, -1);
g_ptr_array_add(args, in);

FilterXObject *bad_fmt1 = filterx_string_new("bad format 1", -1);
g_ptr_array_add(args, bad_fmt1);

FilterXObject *bad_fmt2 = filterx_string_new("bad format 2", -1);
g_ptr_array_add(args, bad_fmt2);

FilterXObject *time_fmt = filterx_string_new(datefmt_isodate, -1);
g_ptr_array_add(args, time_fmt);

FilterXObject *obj = filterx_datetime_strptime(args);
cr_assert_not_null(obj);
cr_assert(filterx_object_is_type(obj, &FILTERX_TYPE_NAME(datetime)));

GString *repr = scratch_buffers_alloc();

cr_assert(filterx_object_repr(in, repr));
cr_assert_str_eq(test_time_str, repr->str);

g_ptr_array_free(args, TRUE);
filterx_object_unref(obj);
}

Test(filterx_datetime, test_filterx_datetime_strptime_non_matching_nth_timefmt)
{
const gchar *test_time_str = "2024-04-08T10:11:12Z";
GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref);
FilterXObject *in = filterx_string_new(test_time_str, -1);
g_ptr_array_add(args, in);

FilterXObject *bad_fmt1 = filterx_string_new("bad format 1", -1);
g_ptr_array_add(args, bad_fmt1);

FilterXObject *bad_fmt2 = filterx_string_new("bad format 2", -1);
g_ptr_array_add(args, bad_fmt2);

FilterXObject *time_fmt = filterx_string_new("non matching fmt", -1);
g_ptr_array_add(args, time_fmt);

FilterXObject *obj = filterx_datetime_strptime(args);
cr_assert_null(obj);

g_ptr_array_free(args, TRUE);
filterx_object_unref(obj);
}

Test(filterx_datetime, test_filterx_datetime_strptime_invalid_arg_type)
{
const gchar *test_time_str = "2024-04-08T10:11:12Z";
GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref);
FilterXObject *in = filterx_string_new(test_time_str, -1);
g_ptr_array_add(args, in);

FilterXObject *bad_fmt1 = filterx_integer_new(1337);
g_ptr_array_add(args, bad_fmt1);

FilterXObject *time_fmt = filterx_string_new(datefmt_isodate, -1);
g_ptr_array_add(args, time_fmt);

FilterXObject *obj = filterx_datetime_strptime(args);
cr_assert_null(obj);

g_ptr_array_free(args, TRUE);
filterx_object_unref(obj);
}

static void
Expand Down

0 comments on commit c59c937

Please sign in to comment.