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 9, 2024
1 parent b57541d commit dce3ae2
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 0 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
58 changes: 58 additions & 0 deletions lib/filterx/object-datetime.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,64 @@ _repr(FilterXObject *s, GString *repr)
return TRUE;
}

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);
if (!object || !filterx_object_is_type(object, &FILTERX_TYPE_NAME(string)))
{
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;
}
const gchar *timestr = filterx_string_get_value(object, 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_error("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: 152 additions & 0 deletions lib/filterx/tests/test_object_datetime.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,158 @@ Test(filterx_datetime, test_filterx_datetime_repr_isodate_Z)
#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)
{
#define 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);
#undef test_time_str
}

Test(filterx_datetime, test_filterx_datetime_strptime_non_matching_timefmt)
{
#define 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);
#undef test_time_str
}

Test(filterx_datetime, test_filterx_datetime_strptime_matching_timefmt)
{
#define 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);
#undef test_time_str
}

Test(filterx_datetime, test_filterx_datetime_strptime_matching_nth_timefmt)
{
#define 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);
#undef test_time_str
}

Test(filterx_datetime, test_filterx_datetime_strptime_non_matching_nth_timefmt)
{
#define 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);
#undef test_time_str
}

Test(filterx_datetime, test_filterx_datetime_strptime_invalid_arg_type)
{
#define 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);
#undef test_time_str
}

static void
setup(void)
{
Expand Down

0 comments on commit dce3ae2

Please sign in to comment.