Skip to content

Commit

Permalink
filterx/object-primitive: fix double repr method to generate JSON lik…
Browse files Browse the repository at this point in the history
…e result

Our double repr was different to JSON a number of ways:
  * in JSON we need a ".0" even if we have an integer value to indicate that
    a member is floating point
  * we should not include trailing zeroes
  * we should use Infinite and NaN tokens to indicate these values

Signed-off-by: Balazs Scheidler <[email protected]>
  • Loading branch information
bazsi committed Feb 24, 2025
1 parent 0c505bb commit 3f37b9f
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 15 deletions.
43 changes: 37 additions & 6 deletions lib/filterx/object-primitive.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
#include "filterx/filterx-object-istype.h"
#include "str-utils.h"
#include "timeutils/misc.h"

#include "compat/json.h"
#include <math.h>

static gboolean
_truthy(FilterXObject *s)
Expand Down Expand Up @@ -139,12 +139,43 @@ _double_add(FilterXObject *s, FilterXObject *object)
}

gboolean
double_repr(double val, GString *repr)
double_repr(double dbl, GString *repr)
{
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));
if (isnan(dbl))
{
g_string_append_len(repr, "NaN", 3);
}
else if (isinf(dbl))
{
if (dbl < 0)
g_string_append_c(repr, '-');
g_string_append_len(repr, "Infinity", 8);
}
else
{
gchar buf[G_ASCII_DTOSTR_BUF_SIZE];

g_ascii_dtostr(buf, sizeof(buf), dbl);
gchar *dot = strchr(buf, '.');
if (!dot && strchr(buf, 'e') == NULL)
{
/* no fractions, not scientific notation */
strcat(buf, ".0");
}
else if (dot)
{
gchar *last_useful_digit = NULL;
for (gchar *c = dot+1; *c; c++)
{
if (*c != '0')
last_useful_digit = c;
}
/* truncate trailing zeroes */
if (last_useful_digit)
*(last_useful_digit+1) = 0;
}
g_string_append(repr, buf);
}
return TRUE;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/filterx/object-primitive.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ FilterXObject *filterx_typecast_integer(FilterXExpr *s, FilterXObject *args[], g
FilterXObject *filterx_typecast_double(FilterXExpr *s, FilterXObject *args[], gsize args_len);

gboolean bool_repr(gboolean bool_val, GString *repr);
gboolean double_repr(double val, GString *repr);
gboolean double_repr(gdouble val, GString *repr);
gboolean integer_repr(gint64 val, GString *repr);

/* NOTE: Consider using filterx_object_extract_integer() to also support message_value. */
Expand Down
8 changes: 4 additions & 4 deletions lib/filterx/tests/test_expr_comparison.c
Original file line number Diff line number Diff line change
Expand Up @@ -466,10 +466,10 @@ Test(expr_comparison, test_string_to_numeric_string_based_comparison)
_assert_comparison(filterx_string_new("3", 1), filterx_integer_new(3), FCMPX_GT | FCMPX_STRING_BASED, FALSE);
_assert_comparison(filterx_string_new("3", 1), filterx_integer_new(3), FCMPX_NE | FCMPX_STRING_BASED, FALSE);

_assert_comparison(filterx_string_new("3", 1), filterx_double_new(3.0), FCMPX_EQ | FCMPX_STRING_BASED, TRUE);
_assert_comparison(filterx_string_new("3", 1), filterx_double_new(3.0), FCMPX_LT | FCMPX_STRING_BASED, FALSE);
_assert_comparison(filterx_string_new("3", 1), filterx_double_new(3.0), FCMPX_GT | FCMPX_STRING_BASED, FALSE);
_assert_comparison(filterx_string_new("3", 1), filterx_double_new(3.0), FCMPX_NE | FCMPX_STRING_BASED, FALSE);
_assert_comparison(filterx_string_new("3.0", 3), filterx_double_new(3.0), FCMPX_EQ | FCMPX_STRING_BASED, TRUE);
_assert_comparison(filterx_string_new("3.0", 3), filterx_double_new(3.0), FCMPX_LT | FCMPX_STRING_BASED, FALSE);
_assert_comparison(filterx_string_new("3.0", 3), filterx_double_new(3.0), FCMPX_GT | FCMPX_STRING_BASED, FALSE);
_assert_comparison(filterx_string_new("3.0", 3), filterx_double_new(3.0), FCMPX_NE | FCMPX_STRING_BASED, FALSE);

_assert_comparison(filterx_string_new("3", 1), filterx_double_new(3.1), FCMPX_EQ | FCMPX_STRING_BASED, FALSE);
_assert_comparison(filterx_string_new("3", 1), filterx_double_new(3.1), FCMPX_LT | FCMPX_STRING_BASED,
Expand Down
4 changes: 2 additions & 2 deletions lib/filterx/tests/test_object_double.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ Test(filterx_double, test_filterx_double_repr)
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_str_eq(repr->str, "123.456");
cr_assert(filterx_object_repr_append(obj, repr));
cr_assert_str_eq("123.456123.456", repr->str);
cr_assert_str_eq(repr->str, "123.456123.456");
filterx_object_unref(obj);
}

Expand Down
31 changes: 29 additions & 2 deletions lib/filterx/tests/test_object_primitive.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,37 @@
#include "filterx/object-message-value.h"
#include "apphook.h"

Test(filterx_object, test_filterx_object_construction_and_free)
static void
_assert_repr_equals(FilterXObject *fobj, const gchar *expected)
{
GString *repr = g_string_sized_new(0);
filterx_object_repr(fobj, repr);
cr_assert_str_eq(repr->str, expected);
g_string_free(repr, TRUE);
}

Test(filterx_object, test_filterx_double_should_always_have_fraction_part)
{
FilterXObject *fobj = filterx_double_new(4.0);
_assert_repr_equals(fobj, "4.0");
filterx_object_unref(fobj);
}

Test(filterx_object, test_filterx_double_trailing_zeroes_are_removed)
{
FilterXObject *fobj = filterx_object_new(&FILTERX_TYPE_NAME(object));
/* we produce enough granularity when needed but do not produce trailing
* zeroes */

FilterXObject *fobj = filterx_double_new(4.1);
_assert_repr_equals(fobj, "4.0999999999999996");
filterx_object_unref(fobj);

fobj = filterx_double_new(4.2);
_assert_repr_equals(fobj, "4.2000000000000002");
filterx_object_unref(fobj);

fobj = filterx_double_new(4.5);
_assert_repr_equals(fobj, "4.5");
filterx_object_unref(fobj);
}

Expand Down

0 comments on commit 3f37b9f

Please sign in to comment.