From d0b5b711b6dae6e2c913f80bdabff02c80e4cab5 Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Thu, 16 May 2024 10:14:25 +0200 Subject: [PATCH 01/11] filterx: add filterx_function_args_get_named_literal_boolean() Signed-off-by: Attila Szakacs --- lib/filterx/expr-function.c | 35 +++++++++++++++++++++++++++++++++++ lib/filterx/expr-function.h | 2 ++ 2 files changed, 37 insertions(+) diff --git a/lib/filterx/expr-function.c b/lib/filterx/expr-function.c index b57ace2362..90579cf36e 100644 --- a/lib/filterx/expr-function.c +++ b/lib/filterx/expr-function.c @@ -28,6 +28,7 @@ #include "filterx/filterx-eval.h" #include "filterx/expr-literal.h" #include "filterx/object-string.h" +#include "filterx/object-primitive.h" #include "filterx/object-null.h" #include "plugin.h" #include "cfg.h" @@ -320,6 +321,40 @@ filterx_function_args_get_named_literal_string(FilterXFunctionArgs *self, const return str; } +gboolean +filterx_function_args_get_named_literal_boolean(FilterXFunctionArgs *self, const gchar *name, gboolean *exists, + gboolean *error) +{ + *error = FALSE; + + FilterXExpr *expr = filterx_function_args_get_named_expr(self, name); + *exists = !!expr; + if (!expr) + return FALSE; + + FilterXObject *obj = NULL; + gboolean value = FALSE; + + if (!filterx_expr_is_literal(expr)) + goto error; + + obj = filterx_expr_eval(expr); + if (!obj) + goto error; + + if (!filterx_boolean_unwrap(obj, &value)) + goto error; + + goto success; + +error: + *error = TRUE; +success: + filterx_object_unref(obj); + filterx_expr_unref(expr); + return value; +} + void filterx_function_args_free(FilterXFunctionArgs *self) { diff --git a/lib/filterx/expr-function.h b/lib/filterx/expr-function.h index 795a14bfbd..ff226da2ee 100644 --- a/lib/filterx/expr-function.h +++ b/lib/filterx/expr-function.h @@ -67,6 +67,8 @@ FilterXExpr *filterx_function_args_get_named_expr(FilterXFunctionArgs *self, con FilterXObject *filterx_function_args_get_named_object(FilterXFunctionArgs *self, const gchar *name, gboolean *exists); const gchar *filterx_function_args_get_named_literal_string(FilterXFunctionArgs *self, const gchar *name, gsize *len, gboolean *exists); +gboolean filterx_function_args_get_named_literal_boolean(FilterXFunctionArgs *self, const gchar *name, + gboolean *exists, gboolean *error); void filterx_function_args_free(FilterXFunctionArgs *self); FilterXExpr *filterx_function_lookup(GlobalConfig *cfg, const gchar *function_name, GList *args, GError **error); From a591633c5e20f6ac581e6150442b5a8d6ec0ce2e Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Thu, 16 May 2024 14:01:51 +0200 Subject: [PATCH 02/11] filterx: implement repr() for json Signed-off-by: Attila Szakacs --- lib/filterx/object-json-array.c | 12 ++++++++++++ lib/filterx/object-json-object.c | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/filterx/object-json-array.c b/lib/filterx/object-json-array.c index 064a403d18..ff40d48a69 100644 --- a/lib/filterx/object-json-array.c +++ b/lib/filterx/object-json-array.c @@ -78,6 +78,17 @@ _marshal(FilterXObject *s, GString *repr, LogMessageValueType *t) return TRUE; } +static gboolean +_repr(FilterXObject *s, GString *repr) +{ + FilterXJsonArray *self = (FilterXJsonArray *) s; + + const gchar *json_repr = json_object_to_json_string_ext(self->jso, JSON_C_TO_STRING_PLAIN); + g_string_append(repr, json_repr); + + return TRUE; +} + static gboolean _map_to_json(FilterXObject *s, struct json_object **jso, FilterXObject **assoc_object) { @@ -351,6 +362,7 @@ FILTERX_DEFINE_TYPE(json_array, FILTERX_TYPE_NAME(list), .truthy = _truthy, .free_fn = _free, .marshal = _marshal, + .repr = _repr, .map_to_json = _map_to_json, .clone = _clone, .list_factory = filterx_json_array_new_empty, diff --git a/lib/filterx/object-json-object.c b/lib/filterx/object-json-object.c index 32a2ca8cbe..0e10076018 100644 --- a/lib/filterx/object-json-object.c +++ b/lib/filterx/object-json-object.c @@ -53,6 +53,17 @@ _marshal(FilterXObject *s, GString *repr, LogMessageValueType *t) return TRUE; } +static gboolean +_repr(FilterXObject *s, GString *repr) +{ + FilterXJsonObject *self = (FilterXJsonObject *) s; + + const gchar *json_repr = json_object_to_json_string_ext(self->jso, JSON_C_TO_STRING_PLAIN); + g_string_append(repr, json_repr); + + return TRUE; +} + static gboolean _map_to_json(FilterXObject *s, struct json_object **jso, FilterXObject **assoc_object) { @@ -253,6 +264,7 @@ FILTERX_DEFINE_TYPE(json_object, FILTERX_TYPE_NAME(dict), .truthy = _truthy, .free_fn = _free, .marshal = _marshal, + .repr = _repr, .map_to_json = _map_to_json, .clone = _clone, .list_factory = filterx_json_array_new_empty, From 285de6769ebd6f9f5c37bf199c4fa5cde7fa8fd9 Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Thu, 16 May 2024 14:02:05 +0200 Subject: [PATCH 03/11] filterx: handle null properly for json Signed-off-by: Attila Szakacs --- lib/filterx/object-json-array.c | 6 +++++- lib/filterx/object-json.c | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/filterx/object-json-array.c b/lib/filterx/object-json-array.c index ff40d48a69..ebe7a101e5 100644 --- a/lib/filterx/object-json-array.c +++ b/lib/filterx/object-json-array.c @@ -117,7 +117,11 @@ _get_subscript(FilterXList *s, guint64 index) struct json_object *jso = json_object_array_get_idx(self->jso, index); if (!jso) - return NULL; + { + /* NULL is returned if the stored value is null. */ + if (json_object_array_length(self->jso) > index + 1) + return NULL; + } return filterx_json_convert_json_to_object_cached(&s->super, &self->root_container, jso); } diff --git a/lib/filterx/object-json.c b/lib/filterx/object-json.c index 3b47bfad53..cb31e49966 100644 --- a/lib/filterx/object-json.c +++ b/lib/filterx/object-json.c @@ -76,6 +76,8 @@ _convert_json_to_object(FilterXObject *self, FilterXWeakRef *root_container, str { switch (json_object_get_type(jso)) { + case json_type_null: + return filterx_null_new(); case json_type_double: return filterx_double_new(json_object_get_double(jso)); case json_type_boolean: @@ -132,6 +134,10 @@ filterx_json_convert_json_to_object_cached(FilterXObject *self, FilterXWeakRef * void filterx_json_associate_cached_object(struct json_object *jso, FilterXObject *filterx_obj) { + /* null JSON value turns into NULL pointer. */ + if (!jso) + return; + filterx_eval_store_weak_ref(filterx_obj); /* we are not storing a reference in userdata to avoid circular From 9803ba98c05d9f7f959bb5f459425ca751d9cc9f Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Fri, 17 May 2024 10:27:04 +0200 Subject: [PATCH 04/11] filterx: fix json double caching with < 0.14 https://github.com/json-c/json-c/issues/539 Signed-off-by: Attila Szakacs --- lib/filterx/object-json.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/filterx/object-json.c b/lib/filterx/object-json.c index cb31e49966..bb3edbb4fe 100644 --- a/lib/filterx/object-json.c +++ b/lib/filterx/object-json.c @@ -115,8 +115,15 @@ filterx_json_convert_json_to_object_cached(FilterXObject *self, FilterXWeakRef * * * Changing the value of the double to the same value, ditches this, * but only if necessary. + * + * This only works starting with 0.14, before that json_object_set_double() + * does not drop the string user data, so we cannot check if it is our + * filterx object or the string, which means we cannot cache doubles. */ + if (JSON_C_MAJOR_VERSION == 0 && JSON_C_MINOR_VERSION < 14) + return _convert_json_to_object(self, root_container, jso); + json_object_set_double(jso, json_object_get_double(jso)); } From ff0966bc6a67631f65bd1665ed037bc23c4c6ed7 Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Fri, 17 May 2024 12:59:11 +0200 Subject: [PATCH 05/11] filterx: make primitive repr() append Signed-off-by: Attila Szakacs --- lib/filterx/object-primitive.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/filterx/object-primitive.c b/lib/filterx/object-primitive.c index 17750f705d..9ddf272530 100644 --- a/lib/filterx/object-primitive.c +++ b/lib/filterx/object-primitive.c @@ -317,7 +317,7 @@ static gboolean _repr(FilterXObject *s, GString *repr) { LogMessageValueType t; - return filterx_object_marshal(s, repr, &t); + return filterx_object_marshal_append(s, repr, &t); } FILTERX_DEFINE_TYPE(integer, FILTERX_TYPE_NAME(object), From 8341d8d29798ae3ccb883926f0cee8b422298d0a Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Fri, 17 May 2024 12:59:46 +0200 Subject: [PATCH 06/11] filterx: optimize double repr This saves a copy. Signed-off-by: Attila Szakacs --- lib/filterx/object-primitive.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/filterx/object-primitive.c b/lib/filterx/object-primitive.c index 9ddf272530..92b9c71006 100644 --- a/lib/filterx/object-primitive.c +++ b/lib/filterx/object-primitive.c @@ -106,9 +106,10 @@ _double_map_to_json(FilterXObject *s, struct json_object **object, FilterXObject gboolean double_repr(double val, GString *repr) { - gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; - g_ascii_dtostr(buf, sizeof(buf), val); - g_string_append(repr, buf); + gsize init_len = repr->len; + g_string_set_size(repr, init_len + G_ASCII_DTOSTR_BUF_SIZE); + g_ascii_dtostr(repr->str + init_len, G_ASCII_DTOSTR_BUF_SIZE, val); + g_string_set_size(repr, init_len + strlen(repr->str + init_len)); return TRUE; } From adf2d1d9925a9d410f7ece1fdae0bef0f9096189 Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Fri, 17 May 2024 14:47:13 +0200 Subject: [PATCH 07/11] filterx: fix bytes repr format_hex_string_with_delimiter() needs enough space for the closing NUL. Fortunately it is allocated by g_string_set_size(), but we need to let format_hex_string_with_delimiter() know. Signed-off-by: Attila Szakacs --- lib/filterx/object-string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/filterx/object-string.c b/lib/filterx/object-string.c index 46c97fb188..a2791f2f55 100644 --- a/lib/filterx/object-string.c +++ b/lib/filterx/object-string.c @@ -186,7 +186,7 @@ _bytes_repr(FilterXObject *s, GString *repr) gsize target_len = self->str_len * 2; gsize repr_len = repr->len; g_string_set_size(repr, target_len + repr_len); - format_hex_string_with_delimiter(self->str, self->str_len, repr->str + repr_len, target_len, 0); + format_hex_string_with_delimiter(self->str, self->str_len, repr->str + repr_len, target_len + 1, 0); return TRUE; } From 83965025307bbfa7357c1ac830e5fa1932ab7de2 Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Fri, 17 May 2024 14:48:32 +0200 Subject: [PATCH 08/11] filterx: make it mandatory to set len of bytes and protobuf They are expected to have NULs in them. Signed-off-by: Attila Szakacs --- lib/filterx/object-string.c | 2 ++ lib/filterx/tests/test_object_bytes.c | 6 +++--- lib/filterx/tests/test_object_protobuf.c | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/filterx/object-string.c b/lib/filterx/object-string.c index a2791f2f55..b890cac5cb 100644 --- a/lib/filterx/object-string.c +++ b/lib/filterx/object-string.c @@ -193,6 +193,7 @@ _bytes_repr(FilterXObject *s, GString *repr) FilterXObject * filterx_bytes_new(const gchar *mem, gssize mem_len) { + g_assert(mem_len != -1); FilterXString *self = (FilterXString *) filterx_string_new(mem, mem_len); self->super.type = &FILTERX_TYPE_NAME(bytes); return &self->super; @@ -201,6 +202,7 @@ filterx_bytes_new(const gchar *mem, gssize mem_len) FilterXObject * filterx_protobuf_new(const gchar *mem, gssize mem_len) { + g_assert(mem_len != -1); FilterXString *self = (FilterXString *) filterx_bytes_new(mem, mem_len); self->super.type = &FILTERX_TYPE_NAME(protobuf); return &self->super; diff --git a/lib/filterx/tests/test_object_bytes.c b/lib/filterx/tests/test_object_bytes.c index 35fe6dacb2..b4c3d6d7fc 100644 --- a/lib/filterx/tests/test_object_bytes.c +++ b/lib/filterx/tests/test_object_bytes.c @@ -73,7 +73,7 @@ Test(filterx_bytes, test_filterx_bytes_typecast_null_object_arg) Test(filterx_bytes, test_filterx_bytes_typecast_from_bytes) { GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref); - FilterXObject *in = filterx_bytes_new("byte sequence", -1); + FilterXObject *in = filterx_bytes_new("byte \0sequence", 14); g_ptr_array_add(args, in); FilterXObject *obj = filterx_typecast_bytes(args); @@ -106,7 +106,7 @@ Test(filterx_bytes, test_filterx_bytes_typecast_from_string) Test(filterx_bytes, test_filterx_bytes_typecast_from_protobuf) { GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref); - FilterXObject *in = filterx_protobuf_new("not a valid protobuf!", -1); + FilterXObject *in = filterx_protobuf_new("not a valid \0protobuf!", 22); g_ptr_array_add(args, in); FilterXObject *obj = filterx_typecast_bytes(args); @@ -116,7 +116,7 @@ Test(filterx_bytes, test_filterx_bytes_typecast_from_protobuf) gsize size; const gchar *bytes = filterx_bytes_get_value(obj, &size); - cr_assert(memcmp("not a valid protobuf!", bytes, size) == 0); + cr_assert(memcmp("not a valid \0protobuf!", bytes, size) == 0); g_ptr_array_free(args, TRUE); filterx_object_unref(obj); diff --git a/lib/filterx/tests/test_object_protobuf.c b/lib/filterx/tests/test_object_protobuf.c index 940f62b7f4..9f64e7c79b 100644 --- a/lib/filterx/tests/test_object_protobuf.c +++ b/lib/filterx/tests/test_object_protobuf.c @@ -72,7 +72,7 @@ Test(filterx_protobuf, test_filterx_protobuf_typecast_null_object_arg) Test(filterx_protobuf, test_filterx_protobuf_typecast_from_bytes) { GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref); - FilterXObject *in = filterx_bytes_new("not valid protobuf!", -1); + FilterXObject *in = filterx_bytes_new("not valid \0protobuf!", 20); g_ptr_array_add(args, in); FilterXObject *obj = filterx_typecast_protobuf(args); @@ -82,7 +82,7 @@ Test(filterx_protobuf, test_filterx_protobuf_typecast_from_bytes) gsize size; const gchar *bytes = filterx_protobuf_get_value(obj, &size); - cr_assert(memcmp("not valid protobuf!", bytes, size) == 0); + cr_assert(memcmp("not valid \0protobuf!", bytes, size) == 0); g_ptr_array_free(args, TRUE); filterx_object_unref(obj); @@ -91,7 +91,7 @@ Test(filterx_protobuf, test_filterx_protobuf_typecast_from_bytes) Test(filterx_protobuf, test_filterx_protobuf_typecast_from_protobuf) { GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref); - FilterXObject *in = filterx_protobuf_new("not valid protobuf!", -1); + FilterXObject *in = filterx_protobuf_new("not valid \0protobuf!", 20); g_ptr_array_add(args, in); FilterXObject *obj = filterx_typecast_protobuf(args); From 73c219474a758207b3b682d4c87697b08cf5ff5c Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Fri, 17 May 2024 14:49:17 +0200 Subject: [PATCH 09/11] filterx: test casted datetime in UTs Signed-off-by: Attila Szakacs --- lib/filterx/tests/test_object_datetime.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/filterx/tests/test_object_datetime.c b/lib/filterx/tests/test_object_datetime.c index 609a17ee49..70fb2cf706 100644 --- a/lib/filterx/tests/test_object_datetime.c +++ b/lib/filterx/tests/test_object_datetime.c @@ -172,7 +172,7 @@ Test(filterx_datetime, test_filterx_datetime_typecast_from_datetime) Test(filterx_datetime, test_filterx_datetime_repr) { - const gchar *test_time_str = "2024-03-18T12:34:13+234"; + const gchar *test_time_str = "2024-03-18T12:34:13+0900"; 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); @@ -183,8 +183,8 @@ Test(filterx_datetime, test_filterx_datetime_repr) GString *repr = scratch_buffers_alloc(); - cr_assert(filterx_object_repr(in, repr)); - cr_assert_str_eq(test_time_str, repr->str); + cr_assert(filterx_object_repr(obj, repr)); + cr_assert_str_eq("2024-03-18T12:34:13.000+09:00", repr->str); g_ptr_array_free(args, TRUE); filterx_object_unref(obj); From 3199399e8d8c4c734828eda6137903ccb5db57e7 Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Fri, 17 May 2024 14:49:38 +0200 Subject: [PATCH 10/11] filterx: test repr_append() Signed-off-by: Attila Szakacs --- lib/filterx/tests/test_object_boolean.c | 3 ++ lib/filterx/tests/test_object_bytes.c | 12 ++++++ lib/filterx/tests/test_object_datetime.c | 7 ++-- lib/filterx/tests/test_object_double.c | 3 ++ lib/filterx/tests/test_object_integer.c | 3 ++ lib/filterx/tests/test_object_json.c | 25 ++++++++++++ lib/filterx/tests/test_object_message.c | 51 ++++++++++++++++-------- lib/filterx/tests/test_object_null.c | 4 ++ 8 files changed, 89 insertions(+), 19 deletions(-) diff --git a/lib/filterx/tests/test_object_boolean.c b/lib/filterx/tests/test_object_boolean.c index b2fd6eab62..d4c6e1634f 100644 --- a/lib/filterx/tests/test_object_boolean.c +++ b/lib/filterx/tests/test_object_boolean.c @@ -124,8 +124,11 @@ Test(filterx_boolean, test_filterx_boolean_repr) { FilterXObject *obj = filterx_boolean_new(TRUE); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(obj, repr)); cr_assert_str_eq("true", repr->str); + cr_assert(filterx_object_repr_append(obj, repr)); + cr_assert_str_eq("truetrue", repr->str); filterx_object_unref(obj); } diff --git a/lib/filterx/tests/test_object_bytes.c b/lib/filterx/tests/test_object_bytes.c index b4c3d6d7fc..040d0484e6 100644 --- a/lib/filterx/tests/test_object_bytes.c +++ b/lib/filterx/tests/test_object_bytes.c @@ -122,6 +122,18 @@ Test(filterx_bytes, test_filterx_bytes_typecast_from_protobuf) filterx_object_unref(obj); } +Test(filterx_bytes, filterx_bytes_repr) +{ + FilterXObject *obj = filterx_bytes_new("\0\1\2\3", 4); + GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); + cr_assert(filterx_object_repr(obj, repr)); + cr_assert_str_eq("00010203", repr->str); + cr_assert(filterx_object_repr_append(obj, repr)); + cr_assert_str_eq("0001020300010203", repr->str); + filterx_object_unref(obj); +} + static void setup(void) { diff --git a/lib/filterx/tests/test_object_datetime.c b/lib/filterx/tests/test_object_datetime.c index 70fb2cf706..c5f58fb62b 100644 --- a/lib/filterx/tests/test_object_datetime.c +++ b/lib/filterx/tests/test_object_datetime.c @@ -172,9 +172,8 @@ Test(filterx_datetime, test_filterx_datetime_typecast_from_datetime) Test(filterx_datetime, test_filterx_datetime_repr) { - const gchar *test_time_str = "2024-03-18T12:34:13+0900"; GPtrArray *args = g_ptr_array_new_with_free_func((GDestroyNotify) filterx_object_unref); - FilterXObject *in = filterx_string_new(test_time_str, -1); + FilterXObject *in = filterx_string_new("2024-03-18T12:34:13+0900", -1); g_ptr_array_add(args, in); FilterXObject *obj = filterx_typecast_datetime(args); @@ -182,9 +181,11 @@ Test(filterx_datetime, test_filterx_datetime_repr) cr_assert(filterx_object_is_type(obj, &FILTERX_TYPE_NAME(datetime))); GString *repr = scratch_buffers_alloc(); - + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(obj, repr)); cr_assert_str_eq("2024-03-18T12:34:13.000+09:00", repr->str); + cr_assert(filterx_object_repr_append(obj, repr)); + cr_assert_str_eq("2024-03-18T12:34:13.000+09:002024-03-18T12:34:13.000+09:00", repr->str); g_ptr_array_free(args, TRUE); filterx_object_unref(obj); diff --git a/lib/filterx/tests/test_object_double.c b/lib/filterx/tests/test_object_double.c index c71145bd33..8abdcdae37 100644 --- a/lib/filterx/tests/test_object_double.c +++ b/lib/filterx/tests/test_object_double.c @@ -152,8 +152,11 @@ Test(filterx_double, test_filterx_double_repr) { FilterXObject *obj = filterx_double_new(123.456); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(obj, repr)); cr_assert_str_eq("123.456", repr->str); + cr_assert(filterx_object_repr_append(obj, repr)); + cr_assert_str_eq("123.456123.456", repr->str); filterx_object_unref(obj); } diff --git a/lib/filterx/tests/test_object_integer.c b/lib/filterx/tests/test_object_integer.c index e3d803d527..67798ef5b9 100644 --- a/lib/filterx/tests/test_object_integer.c +++ b/lib/filterx/tests/test_object_integer.c @@ -206,8 +206,11 @@ Test(filterx_integer, test_filterx_integer_repr) { FilterXObject *obj = filterx_integer_new(65566); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(obj, repr)); cr_assert_str_eq("65566", repr->str); + cr_assert(filterx_object_repr_append(obj, repr)); + cr_assert_str_eq("6556665566", repr->str); filterx_object_unref(obj); } diff --git a/lib/filterx/tests/test_object_json.c b/lib/filterx/tests/test_object_json.c index 55810b3623..cbe76d7520 100644 --- a/lib/filterx/tests/test_object_json.c +++ b/lib/filterx/tests/test_object_json.c @@ -28,6 +28,7 @@ #include "filterx/object-message-value.h" #include "filterx/expr-function.h" #include "apphook.h" +#include "scratch-buffers.h" Test(filterx_json, test_filterx_object_json_from_repr) { @@ -164,6 +165,30 @@ Test(filterx_json, test_json_array_function) filterx_object_unref(fobj); } +Test(filterx_json, filterx_json_object_repr) +{ + FilterXObject *obj = filterx_json_object_new_from_repr("{\"foo\": \"foovalue\"}", -1); + GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); + cr_assert(filterx_object_repr(obj, repr)); + cr_assert_str_eq("{\"foo\":\"foovalue\"}", repr->str); + cr_assert(filterx_object_repr_append(obj, repr)); + cr_assert_str_eq("{\"foo\":\"foovalue\"}{\"foo\":\"foovalue\"}", repr->str); + filterx_object_unref(obj); +} + +Test(filterx_json, filterx_json_array_repr) +{ + FilterXObject *obj = filterx_json_array_new_from_repr("[\"foo\", \"bar\"]", -1); + GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); + cr_assert(filterx_object_repr(obj, repr)); + cr_assert_str_eq("[\"foo\",\"bar\"]", repr->str); + cr_assert(filterx_object_repr_append(obj, repr)); + cr_assert_str_eq("[\"foo\",\"bar\"][\"foo\",\"bar\"]", repr->str); + filterx_object_unref(obj); +} + static void setup(void) { diff --git a/lib/filterx/tests/test_object_message.c b/lib/filterx/tests/test_object_message.c index 946d600c39..9ffb61c826 100644 --- a/lib/filterx/tests/test_object_message.c +++ b/lib/filterx/tests/test_object_message.c @@ -77,52 +77,59 @@ Test(filterx_message, test_filterx_message_type_null_repr) { FilterXObject *fobj = filterx_message_value_new(NULL, 0, LM_VT_NULL); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(fobj, repr)); cr_assert_str_eq("null", repr->str); + cr_assert(filterx_object_repr_append(fobj, repr)); + cr_assert_str_eq("nullnull", repr->str); filterx_object_unref(fobj); } Test(filterx_message, test_filterx_message_type_string_repr) { - gchar *test_str = "any string"; - - FilterXObject *fobj = filterx_message_value_new(test_str, -1, LM_VT_STRING); + FilterXObject *fobj = filterx_message_value_new("any string", -1, LM_VT_STRING); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(fobj, repr)); - cr_assert_str_eq(test_str, repr->str); + cr_assert_str_eq("any string", repr->str); + cr_assert(filterx_object_repr_append(fobj, repr)); + cr_assert_str_eq("any stringany string", repr->str); filterx_object_unref(fobj); } Test(filterx_message, test_filterx_message_type_bytes_repr) { - gchar *test_str = "any bytes"; - - FilterXObject *fobj = filterx_message_value_new(test_str, -1, LM_VT_BYTES); + FilterXObject *fobj = filterx_message_value_new("any bytes", -1, LM_VT_BYTES); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(fobj, repr)); - cr_assert_str_eq(test_str, repr->str); + cr_assert_str_eq("any bytes", repr->str); + cr_assert(filterx_object_repr_append(fobj, repr)); + cr_assert_str_eq("any bytesany bytes", repr->str); filterx_object_unref(fobj); } Test(filterx_message, test_filterx_message_type_protobuf_repr) { - gchar *test_str = "not a valid protobuf!"; - - FilterXObject *fobj = filterx_message_value_new(test_str, -1, LM_VT_PROTOBUF); + FilterXObject *fobj = filterx_message_value_new("not a valid protobuf!", -1, LM_VT_PROTOBUF); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(fobj, repr)); - cr_assert_str_eq(test_str, repr->str); + cr_assert_str_eq("not a valid protobuf!", repr->str); + cr_assert(filterx_object_repr_append(fobj, repr)); + cr_assert_str_eq("not a valid protobuf!not a valid protobuf!", repr->str); filterx_object_unref(fobj); } Test(filterx_message, test_filterx_message_type_json_repr) { - gchar *test_str = "{\"test\":\"json\"}"; - - FilterXObject *fobj = filterx_message_value_new(test_str, -1, LM_VT_JSON); + FilterXObject *fobj = filterx_message_value_new("{\"test\": \"json\"}", -1, LM_VT_JSON); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(fobj, repr)); - cr_assert_str_eq(test_str, repr->str); + cr_assert_str_eq("{\"test\": \"json\"}", repr->str); + cr_assert(filterx_object_repr_append(fobj, repr)); + cr_assert_str_eq("{\"test\": \"json\"}{\"test\": \"json\"}", repr->str); filterx_object_unref(fobj); } @@ -131,8 +138,11 @@ Test(filterx_message, test_filterx_message_type_boolean_repr) gchar *val = "T"; FilterXObject *fobj = filterx_message_value_new(val, -1, LM_VT_BOOLEAN); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(fobj, repr)); cr_assert_str_eq("true", repr->str); + cr_assert(filterx_object_repr_append(fobj, repr)); + cr_assert_str_eq("truetrue", repr->str); filterx_object_unref(fobj); } @@ -141,8 +151,11 @@ Test(filterx_message, test_filterx_message_type_int_repr) gchar *val = "443"; FilterXObject *fobj = filterx_message_value_new(val, -1, LM_VT_INTEGER); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(fobj, repr)); cr_assert_str_eq("443", repr->str); + cr_assert(filterx_object_repr_append(fobj, repr)); + cr_assert_str_eq("443443", repr->str); filterx_object_unref(fobj); } @@ -151,8 +164,11 @@ Test(filterx_message, test_filterx_message_type_double_repr) gchar *val = "17.756"; FilterXObject *fobj = filterx_message_value_new(val, -1, LM_VT_DOUBLE); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(fobj, repr)); cr_assert_str_eq("17.756", repr->str); + cr_assert(filterx_object_repr_append(fobj, repr)); + cr_assert_str_eq("17.75617.756", repr->str); filterx_object_unref(fobj); } @@ -161,8 +177,11 @@ Test(filterx_message, test_filterx_message_type_datetime_repr) gchar *val = "1713520972.000000+02:00"; FilterXObject *fobj = filterx_message_value_new(val, -1, LM_VT_DATETIME); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(fobj, repr)); cr_assert_str_eq("2024-04-19T12:02:52.000+02:00", repr->str); + cr_assert(filterx_object_repr_append(fobj, repr)); + cr_assert_str_eq("2024-04-19T12:02:52.000+02:002024-04-19T12:02:52.000+02:00", repr->str); filterx_object_unref(fobj); } diff --git a/lib/filterx/tests/test_object_null.c b/lib/filterx/tests/test_object_null.c index 0f17d5b306..b17694d0c5 100644 --- a/lib/filterx/tests/test_object_null.c +++ b/lib/filterx/tests/test_object_null.c @@ -45,8 +45,12 @@ Test(filterx_null, test_filterx_object_null_repr) { FilterXObject *fobj = filterx_null_new(); GString *repr = scratch_buffers_alloc(); + g_string_assign(repr, "foo"); cr_assert(filterx_object_repr(fobj, repr)); cr_assert_str_eq("null", repr->str); + cr_assert(filterx_object_repr_append(fobj, repr)); + cr_assert_str_eq("nullnull", repr->str); + filterx_object_unref(fobj); } static void From 67696eb78c5766d79dc80a86ba37ca0c75ae98cc Mon Sep 17 00:00:00 2001 From: Attila Szakacs Date: Fri, 17 May 2024 15:08:06 +0200 Subject: [PATCH 11/11] filterx: fix type aware comparison Signed-off-by: Attila Szakacs --- lib/filterx/expr-comparison.c | 13 ++++----- lib/filterx/tests/test_expr_comparison.c | 34 ++++++++++++++---------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/lib/filterx/expr-comparison.c b/lib/filterx/expr-comparison.c index ad5ca47190..e6d996af8b 100644 --- a/lib/filterx/expr-comparison.c +++ b/lib/filterx/expr-comparison.c @@ -139,12 +139,13 @@ _evaluate_as_num(FilterXObject *lhs, FilterXObject *rhs, gint operator) static gboolean _evaluate_type_aware(FilterXObject *lhs, FilterXObject *rhs, gint operator) { - if (filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(string)) || - filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(bytes)) || - filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(protobuf)) || - filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(message_value)) || - filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(json_object)) || // TODO: we should have generic map and array cmp - filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(json_array))) + if (lhs->type == rhs->type && + (filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(string)) || + filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(bytes)) || + filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(protobuf)) || + filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(message_value)) || + filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(json_object)) || // TODO: we should have generic map and array cmp + filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(json_array)))) return _evaluate_as_string(lhs, rhs, operator); if (filterx_object_is_type(lhs, &FILTERX_TYPE_NAME(null)) || diff --git a/lib/filterx/tests/test_expr_comparison.c b/lib/filterx/tests/test_expr_comparison.c index 277e1f2a6c..07c69c0012 100644 --- a/lib/filterx/tests/test_expr_comparison.c +++ b/lib/filterx/tests/test_expr_comparison.c @@ -533,10 +533,17 @@ Test(expr_comparison, test_string_to_datetime_string_based_comparison) FCMPX_NE | FCMPX_STRING_BASED, TRUE); } -// FCMPX_TYPE_AWARE tests -// in case of LHS type is one of: [string, bytes, json, protobuf, message_value], uses FCMPX_STRING_BASED comparsion -// in case of any of LHS or RHS is filterx null, compares filterx types (null less than any) -// uses FCMPX_NUM_BASED in any other cases +/* + * Type aware tests. + * + * In case of both side's types are the same and they are one of: [string, bytes, json, protobuf, message_value], + * we do a string based comparison. + * + * If the one of the sides is null, and we check for eq or ne, they are equal if the other is null, + * and not equal if the other is not null. + * + * In any other scenario we do a number based comparison, which includes NaN logic. + */ Test(expr_comparison, test_null_cases_type_aware_comparison) { @@ -552,14 +559,13 @@ Test(expr_comparison, test_null_cases_type_aware_comparison) _assert_comparison(filterx_string_new("foobar", 6), filterx_null_new(), FCMPX_EQ | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_string_new("foobar", 6), filterx_null_new(), FCMPX_LT | FCMPX_TYPE_AWARE, FALSE); - _assert_comparison(filterx_string_new("foobar", 6), filterx_null_new(), FCMPX_GT | FCMPX_TYPE_AWARE, TRUE); + _assert_comparison(filterx_string_new("foobar", 6), filterx_null_new(), FCMPX_GT | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_string_new("foobar", 6), filterx_null_new(), FCMPX_NE | FCMPX_TYPE_AWARE, TRUE); } Test(expr_comparison, test_string_cases_type_aware_comparison) { - // TODO: fix float precision error in g_ascii_dtostr 3.14 -> "3.1400000000000000000000001" - // _assert_comparison(filterx_string_new("3.14", 4), filterx_double_new(3.14), FCMPX_EQ | FCMPX_TYPE_AWARE, TRUE); + _assert_comparison(filterx_string_new("3.14", 4), filterx_double_new(3.14), FCMPX_EQ | FCMPX_TYPE_AWARE, TRUE); // string - integer _assert_comparison(filterx_string_new("443", 3), filterx_integer_new(443), FCMPX_EQ | FCMPX_TYPE_AWARE, TRUE); @@ -570,29 +576,29 @@ Test(expr_comparison, test_string_cases_type_aware_comparison) // check if compared as string _assert_comparison(filterx_string_new("a443", 4), filterx_integer_new(443), FCMPX_EQ | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_string_new("a443", 4), filterx_integer_new(443), FCMPX_LT | FCMPX_TYPE_AWARE, FALSE); - _assert_comparison(filterx_string_new("a443", 4), filterx_integer_new(443), FCMPX_GT | FCMPX_TYPE_AWARE, TRUE); + _assert_comparison(filterx_string_new("a443", 4), filterx_integer_new(443), FCMPX_GT | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_string_new("a443", 4), filterx_integer_new(443), FCMPX_NE | FCMPX_TYPE_AWARE, TRUE); // bytes - boolean - _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(true), FCMPX_EQ | FCMPX_TYPE_AWARE, TRUE); + _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(true), FCMPX_EQ | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(true), FCMPX_LT | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(true), FCMPX_GT | FCMPX_TYPE_AWARE, FALSE); - _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(true), FCMPX_NE | FCMPX_TYPE_AWARE, FALSE); + _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(true), FCMPX_NE | FCMPX_TYPE_AWARE, TRUE); _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(false), FCMPX_EQ | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(false), FCMPX_LT | FCMPX_TYPE_AWARE, FALSE); - _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(false), FCMPX_GT | FCMPX_TYPE_AWARE, TRUE); + _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(false), FCMPX_GT | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_bytes_new("true", 4), filterx_boolean_new(false), FCMPX_NE | FCMPX_TYPE_AWARE, TRUE); // protobuf - double - _assert_comparison(filterx_protobuf_new("472", 3), filterx_double_new(472.0), FCMPX_EQ | FCMPX_TYPE_AWARE, TRUE); + _assert_comparison(filterx_protobuf_new("472", 3), filterx_double_new(472.0), FCMPX_EQ | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_protobuf_new("472", 3), filterx_double_new(472.0), FCMPX_LT | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_protobuf_new("472", 3), filterx_double_new(472.0), FCMPX_GT | FCMPX_TYPE_AWARE, FALSE); - _assert_comparison(filterx_protobuf_new("472", 3), filterx_double_new(472.0), FCMPX_NE | FCMPX_TYPE_AWARE, FALSE); + _assert_comparison(filterx_protobuf_new("472", 3), filterx_double_new(472.0), FCMPX_NE | FCMPX_TYPE_AWARE, TRUE); _assert_comparison(filterx_protobuf_new("a472", 4), filterx_double_new(472.0), FCMPX_EQ | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_protobuf_new("a472", 4), filterx_double_new(472.0), FCMPX_LT | FCMPX_TYPE_AWARE, FALSE); - _assert_comparison(filterx_protobuf_new("a472", 4), filterx_double_new(472.0), FCMPX_GT | FCMPX_TYPE_AWARE, TRUE); + _assert_comparison(filterx_protobuf_new("a472", 4), filterx_double_new(472.0), FCMPX_GT | FCMPX_TYPE_AWARE, FALSE); _assert_comparison(filterx_protobuf_new("a472", 4), filterx_double_new(472.0), FCMPX_NE | FCMPX_TYPE_AWARE, TRUE); }