Skip to content

Commit

Permalink
Make tests pass when --disable-decnum
Browse files Browse the repository at this point in the history
  • Loading branch information
nicowilliams committed May 15, 2024
1 parent c127616 commit 6d02d53
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 37 deletions.
1 change: 1 addition & 0 deletions .github/workflows/decnum.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
--disable-maintainer-mode \
--disable-decnum
make -j"$(nproc)"
make check
file ./jq
- name: Test
run: |
Expand Down
49 changes: 36 additions & 13 deletions docs/content/manual/manual.yml
Original file line number Diff line number Diff line change
Expand Up @@ -357,20 +357,24 @@ sections:
The way in which jq handles numbers has changed over time
and further changes are likely within the parameters set by
the relevant JSON standards. The following remarks are
therefore offered with the understanding that they are
intended to be descriptive of the current version of jq and
should not be interpreted as being prescriptive:
the relevant JSON standards. Moreover, build configuration
options can alter how jq processes numbers.
The following remarks are therefore offered with the
understanding that they are intended to be descriptive of the
current version of jq and should not be interpreted as being
prescriptive:
(1) Any arithmetic operation on a number that has not
already been converted to an IEEE754 double precision
representation will trigger a conversion to the IEEE754
representation.
(2) jq will attempt to maintain the original decimal
precision of number literals, but in expressions such
`1E1234567890`, precision will be lost if the exponent is
too large.
precision of number literals (if the `--disable-decnum`
build configuration option was not used), but in expressions
such `1E1234567890`, precision will be lost if the exponent
is too large.
(3) In jq programs, a leading minus sign will trigger the
conversion of the number to an IEEE754 representation.
Expand All @@ -379,6 +383,12 @@ sections:
big decimal representation of numbers if available, as
illustrated in one of the following examples.
The examples below use the builtin function `have_decnum` in
order to demonstrate the expected effects of using / not
using the `--disable-decnum` build configuration option, and
also to allow automated tests derived from these examples to
pass regardless of whether that option is used.
examples:
- program: '.'
input: '"Hello, world!"'
Expand All @@ -388,21 +398,21 @@ sections:
input: '0.12345678901234567890123456789'
output: ['0.12345678901234567890123456789']

- program: '[., tojson]'
- program: '[., tojson] | . == if have_decnum then [12345678909876543212345,"12345678909876543212345"] else [12345678909876543000000,"12345678909876543000000"] end'
input: '12345678909876543212345'
output: ['[12345678909876543212345,"12345678909876543212345"]']
output: ['true']

- program: '. < 0.12345678901234567890123456788'
input: '0.12345678901234567890123456789'
output: ['false']

- program: 'map([., . == 1]) | tojson'
- program: 'map([., . == 1]) | tojson | . == if have_decnum then "[[1,true],[1.000,true],[1.0,true],[1.00,true]]" else "[[1,true],[1,true],[1,true],[1,true]]" end'
input: '[1, 1.000, 1.0, 100e-2]'
output: ['"[[1,true],[1.000,true],[1.0,true],[1.00,true]]"']
output: ['true']

- program: '. as $big | [$big, $big + 1] | map(. > 10000000000000000000000000000000)'
- program: '. as $big | [$big, $big + 1] | map(. > 10000000000000000000000000000000) | . == if have_decnum then [true, false] else [false, false] end'
input: '10000000000000000000000000000001'
output: ['[true, false]']
output: ['true']

- title: "Object Identifier-Index: `.foo`, `.foo.bar`"
body: |
Expand Down Expand Up @@ -1992,6 +2002,19 @@ sections:
output:
- '[{"a":{"b":2}}]'

- title: "`have_literal_numbers`"
body: |
This builtin returns true if jq's build configuration
includes support for preservation of input number literals.
- title: "`have_decnum`"
body: |
This builtin returns true if jq was built with "decnum",
which is the current literal number preserving numeric
backend implementation for jq.
- title: "`$JQ_BUILD_CONFIGURATION`"
body: |
Expand Down
30 changes: 21 additions & 9 deletions jq.1.prebuilt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions src/builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -1741,6 +1741,15 @@ static jv f_current_line(jq_state *jq, jv a) {
return jq_util_input_get_current_line(jq);
}

static jv f_have_decnum(jq_state *jq, jv a) {
jv_free(a);
#ifdef USE_DECNUM
return jv_true();
#else
return jv_false();
#endif
}

#define LIBM_DD(name) \
{f_ ## name, #name, 1},
#define LIBM_DD_NO(name) LIBM_DD(name)
Expand Down Expand Up @@ -1818,6 +1827,8 @@ BINOPS
{f_now, "now", 1},
{f_current_filename, "input_filename", 1},
{f_current_line, "input_line_number", 1},
{f_have_decnum, "have_decnum", 1},
{f_have_decnum, "have_literal_numbers", 1},
};
#undef LIBM_DDDD_NO
#undef LIBM_DDD_NO
Expand Down
2 changes: 2 additions & 0 deletions src/jq_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,11 +208,13 @@ static void run_jq_tests(jv lib_dirs, int verbose, FILE *testdata, int skip, int
printf(" for test at line number %u: %s\n", lineno, prog);
pass = 0;
}
#ifdef USE_DECNUM
jv as_string = jv_dump_string(jv_copy(expected), rand() & ~(JV_PRINT_COLOR|JV_PRINT_REFCOUNT));
jv reparsed = jv_parse_sized(jv_string_value(as_string), jv_string_length_bytes(jv_copy(as_string)));
assert(jv_equal(jv_copy(expected), jv_copy(reparsed)));
jv_free(as_string);
jv_free(reparsed);
#endif
jv_free(expected);
jv_free(actual);
}
Expand Down
14 changes: 7 additions & 7 deletions tests/jq.test
Original file line number Diff line number Diff line change
Expand Up @@ -1874,17 +1874,17 @@ map(. == 1)

# When no arithmetic is involved jq should preserve the literal value

.[0] | tostring
.[0] | tostring | . == if have_decnum then "13911860366432393" else "13911860366432392" end
[13911860366432393]
"13911860366432393"
true

.x | tojson
.x | tojson | . == if have_decnum then "13911860366432393" else "13911860366432392" end
{"x":13911860366432393}
"13911860366432393"
true

13911860366432393 == 13911860366432392
(13911860366432393 == 13911860366432392) | . == if have_decnum then false else true end
null
false
true


# Applying arithmetic to the value will truncate the result to double
Expand Down Expand Up @@ -1977,7 +1977,7 @@ tojson | fromjson
{"a":null}

# also "nan with payload" #2985
fromjson | isnan
if have_decnum then fromjson else nan end | isnan
"nan1234"
true

Expand Down
12 changes: 6 additions & 6 deletions tests/man.test

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions tests/shtest
Original file line number Diff line number Diff line change
Expand Up @@ -668,9 +668,11 @@ if ! x=$($JQ -cn '[
fi

# CVE-2023-50268: No stack overflow comparing a nan with a large payload
$VALGRIND $Q $JQ '1 != .' <<\EOF >/dev/null
Nan4000
if $JQ -ne 'have_decnum'; then
$VALGRIND $Q $JQ '1 != .' <<\EOF >/dev/null
Nan4000
EOF
fi

# Allow passing the inline jq script before -- #2919
if ! r=$($JQ --args -rn -- '$ARGS.positional[0]' bar) || [ "$r" != bar ]; then
Expand Down

0 comments on commit 6d02d53

Please sign in to comment.