The manual says halt_error prints its input with no decoration, not
even a newline, but non-string values such as {"a":"xyz"} were printed
with a trailing newline.
Dump non-string values to JSON and print them the same way as strings,
so {"a":"xyz"} | halt_error(1) now writes exactly {"a":"xyz"} to stderr.
1109 lines
35 KiB
Bash
Executable File
1109 lines
35 KiB
Bash
Executable File
#!/bin/sh -x
|
|
|
|
. "${0%/*}/setup" "$@"
|
|
|
|
msys=false
|
|
mingw=false
|
|
sunos=false
|
|
netbsd=false
|
|
case "$(uname -s)" in
|
|
MSYS*) msys=true;;
|
|
MINGW*) mingw=true;;
|
|
SunOS*) sunos=true;;
|
|
NetBSD*) netbsd=true;;
|
|
esac
|
|
|
|
JQ_NO_B=$JQ
|
|
JQ="$JQ -b"
|
|
|
|
# On Solaris, GNU tools are available in /usr/gnu. This script should prefer
|
|
# them over the native tools, because the native versions may lack some
|
|
# command-line options the script relies on.
|
|
$sunos && PATH="/usr/gnu/bin:$PATH"
|
|
|
|
PATH=$JQBASEDIR:$PATH $JQBASEDIR/tests/jq-f-test.sh > /dev/null
|
|
|
|
SHELL=/bin/sh
|
|
export SHELL
|
|
|
|
unset JQ_COLORS
|
|
unset NO_COLOR
|
|
|
|
if [ -f "$JQBASEDIR/.libs/libinject_errors.so" ]; then
|
|
# Do some simple error injection tests to check that we're handling
|
|
# I/O errors correctly.
|
|
(
|
|
libinject=$JQBASEDIR/.libs/libinject_errors.so
|
|
cd $d
|
|
LD_PRELOAD=$libinject $JQ . /dev/null
|
|
touch fail_read
|
|
LD_PRELOAD=$libinject $JQ . fail_read && exit 2
|
|
touch fail_close
|
|
LD_PRELOAD=$libinject $JQ . fail_close && exit 2
|
|
true
|
|
)
|
|
fi
|
|
|
|
printf 'a\0b\nc\0d\ne' > $d/input
|
|
$VALGRIND $Q $JQ -Rse '. == "a\u0000b\nc\u0000d\ne"' $d/input
|
|
$VALGRIND $Q $JQ -Rne '[inputs] == ["a\u0000b", "c\u0000d", "e"]' $d/input
|
|
|
|
## Test constant folding
|
|
nref=$($VALGRIND $Q $JQ -n --debug-dump-disasm '"foo"' | wc -l)
|
|
for exp in '1+1' '1-1' '2*3' '9/3' '9%3' '9==3' '9!=3' \
|
|
'9<3' '9>3' '9<=3' '9>=3' '1+2*3-4/5%6' '"foo" + "bar"'; do
|
|
n=$($VALGRIND $Q $JQ -n --debug-dump-disasm "$exp" | wc -l)
|
|
if [ $n -ne $nref ]; then
|
|
echo "Constant expression folding didn't work: $exp"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
## Test UTF-8 BOM is stripped at the start of each input file
|
|
printf '\357\273\277[{"foo": 1}\n,{"foo": 2}\n]\n' > $d/bom1.json
|
|
printf '\357\273\277[{"foo": 3}\n,{"foo": 4}\n]\n' > $d/bom2.json
|
|
$VALGRIND $Q $JQ -e '.[0].foo == 1' $d/bom1.json
|
|
$VALGRIND $Q $JQ -se '. == [[{"foo":1},{"foo":2}],[{"foo":3},{"foo":4}]]' $d/bom1.json $d/bom2.json
|
|
$VALGRIND $Q $JQ -ne '[inputs] == [[{"foo":1},{"foo":2}],[{"foo":3},{"foo":4}]]' $d/bom1.json $d/bom2.json
|
|
$VALGRIND $Q $JQ -ne '[inputs] == [[{"foo":1},{"foo":2}],[{"foo":3},{"foo":4}]]' $d/bom1.json - < $d/bom2.json
|
|
$VALGRIND $Q $JQ -Rne '[inputs] == ["[{\"foo\": 1}", ",{\"foo\": 2}", "]", "[{\"foo\": 3}", ",{\"foo\": 4}", "]"]' $d/bom1.json $d/bom2.json
|
|
$VALGRIND $Q $JQ -ne --slurpfile x $d/bom1.json '$x == [[{"foo":1},{"foo":2}]]'
|
|
$VALGRIND $Q $JQ -ne --rawfile x $d/bom1.json '$x == "[{\"foo\": 1}\n,{\"foo\": 2}\n]\n"'
|
|
|
|
## Test that --run-tests reports failures (#2765)
|
|
cat > $d/passing.test <<'EOF'
|
|
.
|
|
1
|
|
1
|
|
EOF
|
|
cat > $d/passing.expected <<'EOF'
|
|
Test #1: '.' at line number 1
|
|
1 of 1 tests passed (0 malformed, 0 skipped)
|
|
EOF
|
|
$VALGRIND $Q $JQ --run-tests $d/passing.test > $d/out 2>&1
|
|
head -n 2 $d/out | cmp $d/passing.expected -
|
|
|
|
cat > $d/erroneous-result.test <<'EOF'
|
|
.
|
|
1
|
|
2
|
|
EOF
|
|
cat > $d/erroneous-result.expected <<'EOF'
|
|
Test #1: '.' at line number 1
|
|
*** Expected 2, but got 1 for test at line number 3: .
|
|
0 of 1 tests passed (0 malformed, 0 skipped)
|
|
EOF
|
|
|
|
cat > $d/insufficient-results.test <<'EOF'
|
|
empty
|
|
null
|
|
{"expected":true}
|
|
EOF
|
|
cat > $d/insufficient-results.expected <<'EOF'
|
|
Test #1: 'empty' at line number 1
|
|
*** Insufficient results for test at line number 3: empty
|
|
0 of 1 tests passed (0 malformed, 0 skipped)
|
|
EOF
|
|
|
|
cat > $d/superfluous-result.test <<'EOF'
|
|
., .
|
|
1
|
|
1
|
|
EOF
|
|
cat > $d/superfluous-result.expected <<'EOF'
|
|
Test #1: '., .' at line number 1
|
|
*** Superfluous result: 1 for test at line number 3, ., .
|
|
0 of 1 tests passed (1 malformed, 0 skipped)
|
|
EOF
|
|
|
|
for test in erroneous-result insufficient-results superfluous-result; do
|
|
ret=0
|
|
# Keep memory errors distinct from the expected test failure status.
|
|
if [ -n "$VALGRIND" ]; then
|
|
$VALGRIND $Q --error-exitcode=99 $JQ --run-tests $d/$test.test > $d/out 2>&1 || ret=$?
|
|
else
|
|
$JQ --run-tests $d/$test.test > $d/out 2>&1 || ret=$?
|
|
fi
|
|
if [ "$ret" -ne 1 ]; then
|
|
cat $d/out
|
|
echo "Expected --run-tests to report $test with status 1, got $ret" >&2
|
|
exit 1
|
|
fi
|
|
cmp $d/out $d/$test.expected
|
|
done
|
|
|
|
## Test JSON sequence support
|
|
cat > $d/expected <<EOF
|
|
jq: ignoring parse error: Truncated value at line 2, column 5
|
|
jq: ignoring parse error: Truncated value at line 2, column 25
|
|
jq: ignoring parse error: Truncated value at line 2, column 41
|
|
EOF
|
|
printf '1\0362 3\n[0,1\036[4,5]true"ab"{"c":4\036{}{"d":5,"e":6"\036false\n'|$VALGRIND $Q $JQ -ces --seq '. == [2,3,[4,5],true,"ab",{},false]' > /dev/null 2> $d/out
|
|
cmp $d/out $d/expected
|
|
|
|
cat > $d/expected <<EOF
|
|
jq: ignoring parse error: Truncated value at line 2, column 5
|
|
jq: ignoring parse error: Truncated value at line 2, column 25
|
|
jq: ignoring parse error: Truncated value at line 3, column 1
|
|
EOF
|
|
printf '1\0362 3\n[0,1\036[4,5]true"ab"{"c":4\036{}{"d":5,"e":6"false\n\036null'|$VALGRIND $Q $JQ -ces --seq '. == [2,3,[4,5],true,"ab",{},null]' > /dev/null 2> $d/out
|
|
cmp $d/out $d/expected
|
|
|
|
# A syntax error skips the rest of the text, up to the next RS
|
|
cat > $d/expected <<EOF
|
|
jq: ignoring parse error: Invalid numeric literal at line 1, column 8 (need RS to resync)
|
|
jq: ignoring parse error: Unmatched '}' at line 2, column 5 (need RS to resync)
|
|
EOF
|
|
printf '\036{"a":x,"b":7}\n\036[1,}2\n\0363\n' | $VALGRIND $Q $JQ -ces --seq '. == [3]' > /dev/null 2> $d/out
|
|
cmp $d/out $d/expected
|
|
|
|
# Note that here jq sees no inputs at all but it still succeeds because
|
|
# --seq ignores parse errors
|
|
cat > $d/expected <<EOF
|
|
jq: ignoring parse error: Unfinished abandoned text at EOF at line 1, column 4
|
|
EOF
|
|
printf '"foo' | $JQ -c --seq . > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
|
|
# with -e option should give 4 here as there's no valid output after
|
|
# ignoring parse errors with --seq.
|
|
printf '"foo' | $JQ -ce --seq . > $d/out 2>&1 || ret=$?
|
|
[ $ret -eq 4 ]
|
|
cmp $d/out $d/expected
|
|
|
|
# Numeric values truncated by EOF are ignored
|
|
cat > $d/expected <<EOF
|
|
jq: ignoring parse error: Unfinished abandoned text at EOF at line 1, column 1
|
|
EOF
|
|
printf '1' | $JQ -c --seq . > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
|
|
cat > $d/expected <<EOF
|
|
jq: error (at <stdin>:1): Unfinished abandoned text at EOF at line 2, column 0
|
|
EOF
|
|
if printf '1\n' | $JQ -cen --seq '[inputs] == []' >/dev/null 2> $d/out; then
|
|
printf 'Error expected but jq exited successfully\n' 1>&2
|
|
exit 2
|
|
fi
|
|
cmp $d/out $d/expected
|
|
|
|
# Test control characters for #2909
|
|
cat > $d/expected <<EOF
|
|
jq: parse error: Invalid string: control characters from U+0000 through U+001F must be escaped at line 1, column 3
|
|
EOF
|
|
for i in 1 2 30 31; do
|
|
if printf "\"$(printf '\\%03o' $i)\"" | $JQ '.' > $d/out 2>&1; then
|
|
printf 'Error expected but jq exited successfully\n' 1>&2
|
|
exit 2
|
|
fi
|
|
cmp $d/out $d/expected
|
|
done
|
|
printf '" ~\\u007f"\n' > $d/expected
|
|
printf "\"$(printf '\\%03o' 32 126 127)\"" | $JQ '.' > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
|
|
# Regression test for #3110: a raw NUL byte outside of a string must be a clean
|
|
# parse error, not silently truncate the surrounding token. Previously
|
|
# `printf '12\0003'` printed 12 and dropped the trailing 3.
|
|
cat > $d/expected <<EOF
|
|
jq: parse error: Invalid character at line 1, column 3
|
|
EOF
|
|
if printf '12\0003' | $JQ '.' > $d/out 2>&1; then
|
|
printf 'Error expected but jq exited successfully\n' 1>&2
|
|
exit 2
|
|
fi
|
|
cmp $d/out $d/expected
|
|
# A NUL at the very start of the input is rejected too.
|
|
cat > $d/expected <<EOF
|
|
jq: parse error: Invalid character at line 1, column 1
|
|
EOF
|
|
if printf '\000' | $JQ '.' > $d/out 2>&1; then
|
|
printf 'Error expected but jq exited successfully\n' 1>&2
|
|
exit 2
|
|
fi
|
|
cmp $d/out $d/expected
|
|
|
|
## Test --exit-status
|
|
data='{"i": 1}\n{"i": 2}\n{"i": 3}\n'
|
|
printf "$data" | $JQ --exit-status 'select(.i==1)' > /dev/null 2>&1
|
|
printf "$data" | $JQ --exit-status 'select(.i==2)' > /dev/null 2>&1
|
|
printf "$data" | $JQ --exit-status 'select(.i==3)' > /dev/null 2>&1
|
|
ret=0
|
|
printf "$data" | $JQ --exit-status 'select(.i==4)' > /dev/null 2>&1 || ret=$?
|
|
[ $ret -eq 4 ]
|
|
ret=0
|
|
printf "$data" | $JQ --exit-status 'select(.i==2) | false' > /dev/null 2>&1 || ret=$?
|
|
[ $ret -eq 1 ]
|
|
printf "$data" | $JQ --exit-status 'select(.i==2) | true' > /dev/null 2>&1
|
|
|
|
|
|
# Regression test for #951
|
|
printf '"a\n' > $d/input
|
|
if $VALGRIND $Q $JQ -e . $d/input; then
|
|
printf 'Issue #951 is back?\n' 1>&2
|
|
exit 2
|
|
fi
|
|
|
|
# Regression test for #2146
|
|
if echo "foobar" | $JQ .; then
|
|
printf 'Issue #2146 is back?\n' 1>&2
|
|
exit 1
|
|
elif [ $? -ne 5 ]; then
|
|
echo "Invalid input had wrong error code" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# Regression test for #2367; make sure to call jq twice
|
|
if ! echo '{"a": 1E9999999999}' | $JQ . | $JQ -e .a; then
|
|
printf 'Issue #2367 is back?\n' 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# Regression test for #1534
|
|
echo "[1,2,3,4]" > $d/expected
|
|
printf "[1,2][3,4]" | $JQ -cs add > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
printf "[1,2][3,4]\n" | $JQ -cs add > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
|
|
# Regression test for #3273
|
|
echo "[[[0],1],[[0]],[[0],2],[[0]]]" > $d/expected
|
|
printf "[1][2]" | $JQ -c -s --stream . > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
printf "[1][2]\n" | $JQ -c -s --stream . > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
|
|
# Regression test for --raw-output0
|
|
printf "a\0b\0" > $d/expected
|
|
printf '["a", "b"]' | $VALGRIND $Q $JQ --raw-output0 '.[]' > $d/out
|
|
cmp $d/out $d/expected
|
|
printf "a\0" > $d/expected
|
|
if printf '["a", "c\\u0000d", "b"]' | $VALGRIND $Q $JQ --raw-output0 '.[]' > $d/out; then
|
|
echo "Should exit error on string containing NUL with --raw-output0" 1>&2
|
|
exit 1
|
|
elif [ $? -ne 5 ]; then
|
|
echo "Invalid error code" 1>&2
|
|
exit 1
|
|
else
|
|
cmp $d/out $d/expected
|
|
fi
|
|
|
|
# Regression tests for #3194
|
|
echo 42 > $d/expected
|
|
$JQ -nn 42 > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
|
|
$JQ -nL. 42 > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
$JQ -nL . 42 > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
|
|
$JQ -h > $d/expected 2>&1
|
|
$JQ -hV > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
$JQ -h -V > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
|
|
$JQ -V > $d/expected 2>&1
|
|
$JQ -Vh > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
$JQ -V -h > $d/out 2>&1
|
|
cmp $d/out $d/expected
|
|
|
|
# CRLF line break support #1219
|
|
if ! x=$($JQ -n "$(printf '1\r\n+\r\n2')") || [ "$x" != '3' ]; then
|
|
echo 'CRLF line break support failed?' 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
## Test streaming parser
|
|
|
|
## If we add an option to stream to the `import ... as $symbol;` directive
|
|
## then we can move these tests into tests/all.test.
|
|
$VALGRIND $Q $JQ -c '. as $d|path(..) as $p|$d|getpath($p)|select((type|. != "array" and . != "object") or length==0)|[$p,.]' < "$JQTESTDIR/torture/input0.json" > $d/out0
|
|
$VALGRIND $Q $JQ --stream -c '.|select(length==2)' < "$JQTESTDIR/torture/input0.json" > $d/out1
|
|
diff $d/out0 $d/out1
|
|
|
|
printf '["Unfinished JSON term at EOF at line 1, column 1",[0]]\n' > $d/expected
|
|
printf '[' | $VALGRIND $Q $JQ --stream-errors -c . > $d/out 2>&1
|
|
diff $d/out $d/expected
|
|
|
|
|
|
## XXX This test can be moved to tests/all.test _now_
|
|
clean=false
|
|
if which seq > /dev/null 2>&1; then
|
|
# XXX We should try every prefix of input0.json, but that makes this
|
|
# test very, very slow when run with valgrind, and the whole point
|
|
# is to run it with valgrind.
|
|
#
|
|
#len=$(wc -c < "$JQTESTDIR/torture/input0.json")
|
|
if [ -z "$VALGRIND" ]; then
|
|
start=1
|
|
end=$(wc -c < "$JQTESTDIR/torture/input0.json")
|
|
else
|
|
start=120
|
|
end=151
|
|
fi
|
|
for i in $(seq $start $end); do
|
|
dd "if=tests/torture/input0.json" bs=$i count=1 2>/dev/null |
|
|
$VALGRIND $JQ -c . > $d/out0 2>$d/err || true
|
|
if [ -n "$VALGRIND" ]; then
|
|
grep '^==[0-9][0-9]*== ERROR SUMMARY: 0 errors' $d/err > /dev/null
|
|
else
|
|
tail -n1 -- "$d/err" | grep -Ei 'assert|abort|core' && false
|
|
fi
|
|
|
|
dd "if=tests/torture/input0.json" bs=$i count=1 2>/dev/null |
|
|
$VALGRIND $JQ -cn --stream 'fromstream(inputs)' > $d/out1 2>$d/err || true
|
|
if [ -n "$VALGRIND" ]; then
|
|
grep '^==[0-9][0-9]*== ERROR SUMMARY: 0 errors' $d/err > /dev/null
|
|
else
|
|
tail -n1 -- "$d/err" | grep -Ei 'assert|abort|core' && false
|
|
fi
|
|
|
|
diff $d/out0 $d/out1
|
|
done
|
|
else
|
|
echo "Not doing torture tests"
|
|
fi
|
|
|
|
## Regression test for issue #2378 assert when stream parse broken object pair
|
|
echo '{"a":1,"b",' | $JQ --stream > /dev/null 2> $d/err || true
|
|
grep 'Objects must consist of key:value pairs' $d/err > /dev/null
|
|
|
|
## Regression tests for issue #2463 assert when stream parse non-scalar object key
|
|
echo '{{"a":"b"}}' | $JQ --stream > /dev/null 2> $d/err || true
|
|
grep "Expected string key after '{', not '{'" $d/err > /dev/null
|
|
echo '{"x":"y",{"a":"b"}}' | $JQ --stream > /dev/null 2> $d/err || true
|
|
grep "Expected string key after ',' in object, not '{'" $d/err > /dev/null
|
|
echo '{["a","b"]}' | $JQ --stream > /dev/null 2> $d/err || true
|
|
grep "Expected string key after '{', not '\\['" $d/err > /dev/null
|
|
echo '{"x":"y",["a","b"]}' | $JQ --stream > /dev/null 2> $d/err || true
|
|
grep "Expected string key after ',' in object, not '\\['" $d/err > /dev/null
|
|
|
|
# debug, stderr
|
|
$VALGRIND $Q $JQ -n '"test", {} | debug, stderr' >/dev/null
|
|
$JQ -n -c -j '"hello\nworld", null, [false, 0], {"foo":["bar"]}, "\n" | stderr' >$d/out 2>$d/err
|
|
cat > $d/expected <<'EOF'
|
|
hello
|
|
worldnull[false,0]{"foo":["bar"]}
|
|
EOF
|
|
cmp $d/out $d/expected
|
|
cmp $d/err $d/expected
|
|
|
|
# --arg, --argjson, $ARGS.named
|
|
$VALGRIND $JQ -n -c --arg foo 1 --argjson bar 2 '{$foo, $bar} | ., . == $ARGS.named' > $d/out
|
|
printf '{"foo":"1","bar":2}\ntrue\n' > $d/expected
|
|
cmp $d/out $d/expected
|
|
|
|
# --slurpfile, --rawfile
|
|
$VALGRIND $JQ -n --slurpfile foo $JQBASEDIR/tests/modules/data.json \
|
|
--rawfile bar $JQBASEDIR/tests/modules/data.json '{$foo, $bar}' > $d/out
|
|
cat > $d/expected <<'EOF'
|
|
{
|
|
"foo": [
|
|
{
|
|
"this": "is a test",
|
|
"that": "is too"
|
|
}
|
|
],
|
|
"bar": "{\n \"this\": \"is a test\",\n \"that\": \"is too\"\n}\n"
|
|
}
|
|
EOF
|
|
cmp $d/out $d/expected
|
|
|
|
# --args, --jsonargs, $ARGS.positional
|
|
$VALGRIND $JQ -n -c --args '$ARGS.positional' foo bar baz > $d/out
|
|
printf '["foo","bar","baz"]\n' > $d/expected
|
|
cmp $d/out $d/expected
|
|
$VALGRIND $JQ -n -c --jsonargs '$ARGS.positional' null true '[]' '{}' > $d/out
|
|
printf '[null,true,[],{}]\n' > $d/expected
|
|
cmp $d/out $d/expected
|
|
$VALGRIND $JQ -n -c '$ARGS.positional' --args foo 1 --jsonargs 2 '{}' --args 3 4 > $d/out
|
|
printf '["foo","1",2,{},"3","4"]\n' > $d/expected
|
|
cmp $d/out $d/expected
|
|
$VALGRIND $JQ -n -c '$ARGS.positional' --args --jsonargs > $d/out
|
|
printf '[]\n' > $d/expected
|
|
cmp $d/out $d/expected
|
|
|
|
## Regression test for issue #2572 assert when using --jsonargs and invalid JSON
|
|
$VALGRIND $JQ -n --jsonargs null invalid && EC=$? || EC=$?
|
|
if [ "$EC" -ne 2 ]; then
|
|
echo "--jsonargs exited with wrong exit code, expected 2 got $EC" 1>&2
|
|
exit 1
|
|
fi
|
|
# this tests the args_done code path "--"
|
|
$VALGRIND $JQ -n --jsonargs null -- invalid && EC=$? || EC=$?
|
|
if [ "$EC" -ne 2 ]; then
|
|
echo "--jsonargs exited with wrong exit code, expected 2 got $EC" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
## Fuzz parser
|
|
|
|
## XXX With a $(urandom) builtin we could move this test into tests/all.test
|
|
clean=false
|
|
if dd if=/dev/urandom bs=16 count=1024 > $d/rand 2>/dev/null; then
|
|
# Have a /dev/urandom, good
|
|
$VALGRIND $Q $JQ --seq . $d/rand >/dev/null 2>&1
|
|
$VALGRIND $Q $JQ --seq --stream . $d/rand >/dev/null 2>&1
|
|
dd if=/dev/urandom bs=16 count=1024 > $d/rand 2>/dev/null
|
|
$VALGRIND $Q $JQ --seq . $d/rand >/dev/null 2>&1
|
|
$VALGRIND $Q $JQ --seq --stream . $d/rand >/dev/null 2>&1
|
|
dd if=/dev/urandom bs=16 count=1024 > $d/rand 2>/dev/null
|
|
$VALGRIND $Q $JQ --seq . $d/rand >/dev/null 2>&1
|
|
$VALGRIND $Q $JQ --seq --stream . $d/rand >/dev/null 2>&1
|
|
fi
|
|
clean=true
|
|
|
|
## Test library/module system
|
|
|
|
# Check handling of ~/.jq; these can't move into jq_test.c yet because
|
|
# they depend on $HOME
|
|
if [ "$(HOME="$mods/home1" $VALGRIND $Q $JQ -nr fg)" != foobar ]; then
|
|
echo "Bug #479 appears to be back" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if $msys || $mingw; then
|
|
HOME_BAK=$HOME
|
|
unset HOME
|
|
if [ "$(USERPROFILE="$mods/home1" $VALGRIND $Q $JQ -nr foo)" != baz ]; then
|
|
echo "Bug #3104 regressed (sourcing %USERPROFILE%/.jq on Windows)" 1>&2
|
|
exit 1
|
|
fi
|
|
export HOME=$HOME_BAK
|
|
unset HOME_BAK
|
|
fi
|
|
|
|
if [ $(HOME="$mods/home1" $VALGRIND $Q $JQ --debug-dump-disasm -n fg | grep '^[a-z]' | wc -l) -ne 3 ]; then
|
|
echo "Binding too many defs into program" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! HOME="$mods/home2" $VALGRIND $Q $JQ -n 'include "g"; empty'; then
|
|
echo "Mishandling directory ~/.jq" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
(
|
|
cd "$JQBASEDIR" # so that relative library paths are guaranteed correct
|
|
if ! $VALGRIND $Q $JQ -L ./tests/modules -ne 'import "test_bind_order" as check; check::check==true'; then
|
|
echo "Issue #817 regression?" 1>&2
|
|
exit 1
|
|
fi
|
|
)
|
|
|
|
(
|
|
cd "$JQBASEDIR"
|
|
if ! $VALGRIND $Q $JQ -L tests/modules -ne 'import "test_bind_order" as check; check::check==true'; then
|
|
echo "Issue #817 regression?" 1>&2
|
|
exit 1
|
|
fi
|
|
)
|
|
|
|
# CVE-2026-44777: Circular imports should be detected
|
|
if $VALGRIND $JQ -L "$mods" -ne 'import "cycle_a" as a; null' 2> $d/out; then
|
|
echo "Mutual import should be rejected" 1>&2
|
|
exit 1
|
|
fi
|
|
if ! grep -q "circular import" $d/out; then
|
|
echo "Expected circular import error" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
if $VALGRIND $JQ -L "$mods" -ne 'import "cycle_self" as s; null' 2> $d/out; then
|
|
echo "Self import should be rejected" 1>&2
|
|
exit 1
|
|
fi
|
|
if ! grep -q "circular import" $d/out; then
|
|
echo "Expected circular import error" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
## Halt
|
|
|
|
if ! $VALGRIND $Q $JQ -n halt; then
|
|
echo "jq halt didn't work as expected" 1>&2
|
|
exit 1
|
|
fi
|
|
if $VALGRIND $Q $VG_EXIT0 $JQ -n 'halt_error(1)'; then
|
|
echo "jq halt_error(1) didn't work as expected" 1>&2
|
|
exit 1
|
|
elif [ $? -ne 1 ]; then
|
|
echo "jq halt_error(1) had wrong error code" 1>&2
|
|
exit 1
|
|
fi
|
|
if $VALGRIND $Q $VG_EXIT0 $JQ -n 'halt_error(11)'; then
|
|
echo "jq halt_error(11) didn't work as expected" 1>&2
|
|
exit 1
|
|
elif [ $? -ne 11 ]; then
|
|
echo "jq halt_error(11) had wrong error code" 1>&2
|
|
exit 1
|
|
fi
|
|
for opt in '' -e; do
|
|
if $VALGRIND $Q $VG_EXIT0 $JQ $opt -n 'halt_error(-1)'; then
|
|
echo "jq $opt halt_error(-1) didn't work as expected" 1>&2
|
|
exit 1
|
|
elif [ $? -ne 255 ]; then
|
|
echo "jq $opt halt_error(-1) had wrong error code" 1>&2
|
|
exit 1
|
|
fi
|
|
done
|
|
if [ -n "$($VALGRIND $Q $JQ -n 'halt_error(1)' 2>&1)" ]; then
|
|
echo "jq halt_error(1) had unexpected output" 1>&2
|
|
exit 1
|
|
fi
|
|
if [ -n "$($VALGRIND $Q $JQ -n '"xyz\n" | halt_error(1)' 2>/dev/null)" ]; then
|
|
echo "jq halt_error(1) had unexpected output on stdout" 1>&2
|
|
exit 1
|
|
fi
|
|
if [ "$($VALGRIND $Q $JQ -n '"xy" | halt_error(1)' 2>&1 || echo "z")" != "xyz" ]; then
|
|
echo "jq halt_error(1) had unexpected output" 1>&2
|
|
exit 1
|
|
fi
|
|
if [ "$($VALGRIND $Q $JQ -n '"x\u0000y\u0000z" | halt_error(1)' 2>&1 | tr '\0' '.')" != "x.y.z" ]; then
|
|
echo "jq halt_error(1) had unexpected output" 1>&2
|
|
exit 1
|
|
fi
|
|
if [ "$($VALGRIND $Q $JQ -n '{"a":"xyz"} | halt_error(1)' 2>&1 || echo "z")" != '{"a":"xyz"}z' ]; then
|
|
echo "jq halt_error(1) had unexpected output" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# Check $JQ_COLORS
|
|
|
|
## Default colors, null input
|
|
$JQ -Ccn . > $d/color
|
|
printf '\033[0;90mnull\033[0m\n' > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
## Set non-default color, null input
|
|
JQ_COLORS='4;31' $JQ -Ccn . > $d/color
|
|
printf '\033[4;31mnull\033[0m\n' > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
## Set implicit empty color, null input
|
|
$JQ -Ccn . > $d/color
|
|
printf '\033[0;90mnull\033[0m\n' > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
## Set explicit empty color, null input
|
|
JQ_COLORS=':' $JQ -Ccn . > $d/color
|
|
printf '\033[mnull\033[0m\n' > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
## Extra colors, null input
|
|
JQ_COLORS='::::::::' $JQ -Ccn . > $d/color
|
|
printf '\033[mnull\033[0m\n' > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
## Default colors, complex input
|
|
$JQ -Ccn '[{"a":true,"b":false},"abc",123,null]' > $d/color
|
|
{
|
|
printf '\033[1;39m[\033[0m'
|
|
printf '\033[1;39m{\033[0m'
|
|
printf '\033[1;34m"a"\033[0m'
|
|
printf '\033[1;39m:\033[0m'
|
|
printf '\033[0;39mtrue\033[0m'
|
|
printf '\033[1;39m,\033[0m'
|
|
printf '\033[1;34m"b"\033[0m'
|
|
printf '\033[1;39m:\033[0m'
|
|
printf '\033[0;39mfalse\033[0m'
|
|
printf '\033[1;39m}\033[0m'
|
|
printf '\033[1;39m,\033[0m'
|
|
printf '\033[0;32m"abc"\033[0m'
|
|
printf '\033[1;39m,\033[0m'
|
|
printf '\033[0;39m123\033[0m'
|
|
printf '\033[1;39m,\033[0m'
|
|
printf '\033[0;90mnull\033[0m'
|
|
printf '\033[1;39m]\033[0m\n'
|
|
} > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
## Set non-default colors, complex input
|
|
JQ_COLORS='0;30:0;31:0;32:0;33:0;34:1;35:1;36:1;37' \
|
|
$JQ -Ccn '[{"a":true,"b":false},"abc",123,null]' > $d/color
|
|
{
|
|
printf '\033[1;35m[\033[0m'
|
|
printf '\033[1;36m{\033[0m'
|
|
printf '\033[1;37m"a"\033[0m'
|
|
printf '\033[1;36m:\033[0m'
|
|
printf '\033[0;32mtrue\033[0m'
|
|
printf '\033[1;36m,\033[0m'
|
|
printf '\033[1;37m"b"\033[0m'
|
|
printf '\033[1;36m:\033[0m'
|
|
printf '\033[0;31mfalse\033[0m'
|
|
printf '\033[1;36m}\033[0m'
|
|
printf '\033[1;35m,\033[0m'
|
|
printf '\033[0;34m"abc"\033[0m'
|
|
printf '\033[1;35m,\033[0m'
|
|
printf '\033[0;33m123\033[0m'
|
|
printf '\033[1;35m,\033[0m'
|
|
printf '\033[0;30mnull\033[0m'
|
|
printf '\033[1;35m]\033[0m\n'
|
|
} > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
## Set non-default colors only for literals, complex input
|
|
JQ_COLORS='0;37:0;31:0;35:0;34:0;36' \
|
|
$JQ -Ccn '[{"a":true,"b":false},"abc",123,null]' > $d/color
|
|
{
|
|
printf '\033[1;39m[\033[0m'
|
|
printf '\033[1;39m{\033[0m'
|
|
printf '\033[1;34m"a"\033[0m'
|
|
printf '\033[1;39m:\033[0m'
|
|
printf '\033[0;35mtrue\033[0m'
|
|
printf '\033[1;39m,\033[0m'
|
|
printf '\033[1;34m"b"\033[0m'
|
|
printf '\033[1;39m:\033[0m'
|
|
printf '\033[0;31mfalse\033[0m'
|
|
printf '\033[1;39m}\033[0m'
|
|
printf '\033[1;39m,\033[0m'
|
|
printf '\033[0;36m"abc"\033[0m'
|
|
printf '\033[1;39m,\033[0m'
|
|
printf '\033[0;34m123\033[0m'
|
|
printf '\033[1;39m,\033[0m'
|
|
printf '\033[0;37mnull\033[0m'
|
|
printf '\033[1;39m]\033[0m\n'
|
|
} > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
## Default colors, complex input, indented
|
|
$JQ -Cn '[{"a":true,"b":false},"abc",123,null]' > $d/color
|
|
{
|
|
printf '\033[1;39m[\033[0m\n'
|
|
printf ' \033[1;39m{\033[0m\n'
|
|
printf ' \033[1;34m"a"\033[0m'
|
|
printf '\033[1;39m:\033[0m '
|
|
printf '\033[0;39mtrue\033[0m'
|
|
printf '\033[1;39m,\033[0m\n'
|
|
printf ' \033[1;34m"b"\033[0m'
|
|
printf '\033[1;39m:\033[0m '
|
|
printf '\033[0;39mfalse\033[0m\n'
|
|
printf ' \033[1;39m}\033[0m'
|
|
printf '\033[1;39m,\033[0m\n'
|
|
printf ' \033[0;32m"abc"\033[0m'
|
|
printf '\033[1;39m,\033[0m\n'
|
|
printf ' \033[0;39m123\033[0m'
|
|
printf '\033[1;39m,\033[0m\n'
|
|
printf ' \033[0;90mnull\033[0m\n'
|
|
printf '\033[1;39m]\033[0m\n'
|
|
} > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
## Set non-default colors, complex input, indented
|
|
JQ_COLORS='0;30:0;31:0;32:0;33:0;34:1;35:1;36:1;37' \
|
|
$JQ -Cn '[{"a":true,"b":false},"abc",123,null]' > $d/color
|
|
{
|
|
printf '\033[1;35m[\033[0m\n'
|
|
printf ' \033[1;36m{\033[0m\n'
|
|
printf ' \033[1;37m"a"\033[0m'
|
|
printf '\033[1;36m:\033[0m '
|
|
printf '\033[0;32mtrue\033[0m'
|
|
printf '\033[1;36m,\033[0m\n'
|
|
printf ' \033[1;37m"b"\033[0m'
|
|
printf '\033[1;36m:\033[0m '
|
|
printf '\033[0;31mfalse\033[0m\n'
|
|
printf ' \033[1;36m}\033[0m'
|
|
printf '\033[1;35m,\033[0m\n'
|
|
printf ' \033[0;34m"abc"\033[0m'
|
|
printf '\033[1;35m,\033[0m\n'
|
|
printf ' \033[0;33m123\033[0m'
|
|
printf '\033[1;35m,\033[0m\n'
|
|
printf ' \033[0;30mnull\033[0m\n'
|
|
printf '\033[1;35m]\033[0m\n'
|
|
} > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
## Set truecolor, complex input, indented
|
|
JQ_COLORS=$(printf '38;2;%s:' \
|
|
'255;173;173' '255;214;165' '253;255;182' '202;255;191' \
|
|
'155;246;255' '160;196;255' '189;178;255' '255;198;255') \
|
|
$JQ -Cn '[{"a":true,"b":false},"abc",123,null]' > $d/color
|
|
{
|
|
printf '\033[38;2;160;196;255m[\033[0m\n'
|
|
printf ' \033[38;2;189;178;255m{\033[0m\n'
|
|
printf ' \033[38;2;255;198;255m"a"\033[0m'
|
|
printf '\033[38;2;189;178;255m:\033[0m '
|
|
printf '\033[38;2;253;255;182mtrue\033[0m'
|
|
printf '\033[38;2;189;178;255m,\033[0m\n'
|
|
printf ' \033[38;2;255;198;255m"b"\033[0m'
|
|
printf '\033[38;2;189;178;255m:\033[0m '
|
|
printf '\033[38;2;255;214;165mfalse\033[0m\n'
|
|
printf ' \033[38;2;189;178;255m}\033[0m'
|
|
printf '\033[38;2;160;196;255m,\033[0m\n'
|
|
printf ' \033[38;2;155;246;255m"abc"\033[0m'
|
|
printf '\033[38;2;160;196;255m,\033[0m\n'
|
|
printf ' \033[38;2;202;255;191m123\033[0m'
|
|
printf '\033[38;2;160;196;255m,\033[0m\n'
|
|
printf ' \033[38;2;255;173;173mnull\033[0m\n'
|
|
printf '\033[38;2;160;196;255m]\033[0m\n'
|
|
} > $d/expect
|
|
cmp $d/color $d/expect
|
|
|
|
# Check invalid JQ_COLORS
|
|
echo 'Failed to set $JQ_COLORS' > $d/expect_warning
|
|
$JQ -Ccn '[{"a":true,"b":false},"abc",123,null]' > $d/expect
|
|
for colors in '/' '[30' '30m' '30:31m:32' '30:*:31' 'invalid'; do
|
|
export JQ_COLORS=$colors
|
|
$JQ -Ccn '[{"a":true,"b":false},"abc",123,null]' > $d/color 2>$d/warning
|
|
cmp $d/color $d/expect
|
|
cmp $d/warning $d/expect_warning
|
|
done
|
|
unset JQ_COLORS
|
|
|
|
# Check $NO_COLOR and $TERM
|
|
test_no_color=true
|
|
$msys && test_no_color=false
|
|
$mingw && test_no_color=false
|
|
$sunos && test_no_color=false
|
|
# NetBSD's script(1) intermittently loses the whole session output (the
|
|
# output file comes back empty for fast commands about half the time), so
|
|
# the pty checks cannot run reliably there.
|
|
$netbsd && test_no_color=false
|
|
if $test_no_color && command -v script >/dev/null 2>&1; then
|
|
if script -qc echo /dev/null >/dev/null 2>&1; then
|
|
faketty() { script -qec "$*" /dev/null; }
|
|
else # macOS
|
|
faketty() { script -q /dev/null "$@" /dev/null |
|
|
sed 's/^\x5E\x44\x08\x08//'; }
|
|
fi
|
|
|
|
faketty env TERM=xterm-256color $JQ_NO_B -n . > $d/color
|
|
printf '\033[0;90mnull\033[0m\r\n' > $d/expect
|
|
od -tc $d/expect
|
|
od -tc $d/color
|
|
cmp $d/color $d/expect
|
|
faketty env TERM=xterm-256color NO_COLOR= $JQ_NO_B -n . > $d/color
|
|
printf '\033[0;90mnull\033[0m\r\n' > $d/expect
|
|
od -tc $d/expect
|
|
od -tc $d/color
|
|
cmp $d/color $d/expect
|
|
faketty env TERM=xterm-256color NO_COLOR=1 $JQ_NO_B -n . > $d/color
|
|
printf 'null\r\n' > $d/expect
|
|
od -tc $d/expect
|
|
od -tc $d/color
|
|
cmp $d/color $d/expect
|
|
faketty env TERM=xterm-256color NO_COLOR=1 $JQ_NO_B -Cn . > $d/color
|
|
printf '\033[0;90mnull\033[0m\r\n' > $d/expect
|
|
od -tc $d/expect
|
|
od -tc $d/color
|
|
cmp $d/color $d/expect
|
|
faketty env TERM=dumb $JQ_NO_B -n . > $d/color
|
|
printf 'null\r\n' > $d/expect
|
|
od -tc $d/expect
|
|
od -tc $d/color
|
|
cmp $d/color $d/expect
|
|
faketty env TERM=dumb $JQ_NO_B -Cn . > $d/color
|
|
printf '\033[0;90mnull\033[0m\r\n' > $d/expect
|
|
od -tc $d/expect
|
|
od -tc $d/color
|
|
cmp $d/color $d/expect
|
|
faketty env TERM= $JQ_NO_B -n . > $d/color
|
|
printf 'null\r\n' > $d/expect
|
|
od -tc $d/expect
|
|
od -tc $d/color
|
|
cmp $d/color $d/expect
|
|
faketty env TERM= $JQ_NO_B -Cn . > $d/color
|
|
printf '\033[0;90mnull\033[0m\r\n' > $d/expect
|
|
od -tc $d/expect
|
|
od -tc $d/color
|
|
cmp $d/color $d/expect
|
|
(unset TERM; faketty $JQ_NO_B -n . > $d/color)
|
|
printf 'null\r\n' > $d/expect
|
|
od -tc $d/expect
|
|
od -tc $d/color
|
|
cmp $d/color $d/expect
|
|
(unset TERM; faketty $JQ_NO_B -Cn . > $d/color)
|
|
printf '\033[0;90mnull\033[0m\r\n' > $d/expect
|
|
od -tc $d/expect
|
|
od -tc $d/color
|
|
cmp $d/color $d/expect
|
|
fi
|
|
|
|
# #2785
|
|
if $VALGRIND $Q $JQ -n -f "$JQTESTDIR/no-main-program.jq" > $d/out 2>&1; then
|
|
echo "jq -f $JQTESTDIR/no-main-program.jq succeeded"
|
|
exit 1
|
|
else
|
|
EC=$?
|
|
if [ $EC -eq 1 ]; then
|
|
echo "jq -f $JQTESTDIR/no-main-program.jq failed with memory errors"
|
|
exit 1
|
|
fi
|
|
if [ $EC -ne 3 ]; then
|
|
echo "jq -f $JQTESTDIR/no-main-program.jq failed with wrong exit code ($EC)"
|
|
exit 1
|
|
fi
|
|
fi
|
|
cat > $d/expected <<EOF
|
|
jq: error: Top-level program not given (try ".")
|
|
jq: 1 compile error
|
|
EOF
|
|
if ! diff $d/expected $d/out; then
|
|
echo "jq -f $JQTESTDIR/no-main-program.jq failed but its error message is not the expected one"
|
|
exit 1
|
|
fi
|
|
|
|
if ! $VALGRIND $Q $JQ -n -f "$JQTESTDIR/yes-main-program.jq" > $d/out 2>&1; then
|
|
echo "jq -f $JQTESTDIR/yes-main-program.jq failed"
|
|
exit 1
|
|
fi
|
|
|
|
if ! $msys && ! $mingw && locales=$(locale -a); then
|
|
{ l=$(grep -Ev '^(C|LANG|POSIX|en)' | grep -Ei '\.utf-?8$' | head -n1) ;} \
|
|
<<EOF
|
|
$locales
|
|
EOF
|
|
if [ -z "$l" ]; then
|
|
echo "WARNING: Not testing localization"
|
|
elif [ "$(LC_ALL=C date +%a%b)" = "$(LC_ALL=$l date +%a%b)" ]; then
|
|
echo "WARNING: Date does not produce locale-dependent output for $l, skipping localization test"
|
|
else
|
|
dt1=$(LC_ALL=$l date +'%a %d %b %Y at %H:%M:%S')
|
|
dt2=$(LC_ALL=$l $JQ -nr 'now | strflocaltime("%a %d %b %Y at %H:%M:%S")')
|
|
dt3=$(LC_ALL=$l date +'%a %d %b %Y at %H:%M:%S')
|
|
if [ "$dt1" != "$dt2" ] && [ "$dt2" != "$dt3" ]; then
|
|
echo "jq does not honor LC_ALL environment variable ($dt1, $dt2, $dt3)"
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# strflocaltime/1 allows a format that expands to an empty string
|
|
l=fr_FR.UTF-8
|
|
if ! $msys && ! $mingw && [ -z "$(LC_ALL=$l date +%p 2>/dev/null)" ]; then
|
|
if ! out=$(LC_ALL=$l $VALGRIND $Q $JQ -n '0 | strflocaltime("%p")' 2>&1) || [ "$out" != '""' ]; then
|
|
echo "strflocaltime(\"%p\") in $l should output an empty string but got: $out"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Test syntax error messages of multiline filter (we can't test in jq.test)
|
|
if $VALGRIND $Q $JQ -n '[
|
|
try if .
|
|
then 1
|
|
else 2
|
|
catch ]' > $d/out 2>&1; then
|
|
echo 'syntax error not detected'
|
|
exit 1
|
|
fi
|
|
cat > $d/expected <<EOF
|
|
jq: error: syntax error, unexpected catch, expecting end or '|' or ',' at <top-level>, line 5, column 3:
|
|
catch ]
|
|
^^^^^
|
|
jq: error: Possibly unterminated 'if' statement at <top-level>, line 2, column 7:
|
|
try if .
|
|
^^^^
|
|
jq: error: Possibly unterminated 'try' statement at <top-level>, line 2, column 3:
|
|
try if .
|
|
^^^^^^^^
|
|
jq: 3 compile errors
|
|
EOF
|
|
diff $d/out $d/expected
|
|
|
|
# Test syntax error messages when error happens at the end.
|
|
if $VALGRIND $Q $JQ -n 'if
|
|
' > $d/out 2>&1; then
|
|
echo 'syntax error not detected'
|
|
exit 1
|
|
fi
|
|
cat > $d/expected <<EOF
|
|
jq: error: syntax error, unexpected end of file at <top-level>, line 1, column 3:
|
|
if
|
|
^
|
|
jq: 1 compile error
|
|
EOF
|
|
diff $d/out $d/expected
|
|
|
|
# Comments!
|
|
if ! x=$($JQ -n '123 # comment') || [ "$x" != 123 ]; then
|
|
echo 'comment did not work'
|
|
exit 1
|
|
fi
|
|
|
|
cr=$(printf \\r)
|
|
if ! x=$($JQ -n "1 # foo$cr + 2") || [ "$x" != 1 ]; then
|
|
echo 'regression: carriage return terminates comment'
|
|
exit 1
|
|
fi
|
|
|
|
if ! x=$($JQ -cn '[
|
|
1,
|
|
# foo \
|
|
2,
|
|
# bar \\
|
|
3,
|
|
4, # baz \\\
|
|
5, \
|
|
6,
|
|
7
|
|
# comment \
|
|
comment \
|
|
comment
|
|
]') || [ "$x" != '[1,3,4,7]' ]; then
|
|
echo 'multiline comment was not handled correctly'
|
|
exit 1
|
|
fi
|
|
|
|
if ! x=$($JQ -cn "$(printf '[\r\n1,# comment\r\n2,# comment\\\r\ncomment\r\n3\r\n]')") \
|
|
|| [ "$x" != '[1,2,3]' ]; then
|
|
echo 'multiline comment with CRLF line breaks was not handled correctly'
|
|
exit 1
|
|
fi
|
|
|
|
# Allow passing the inline jq script before -- #2919
|
|
if ! r=$($JQ --args -rn -- '$ARGS.positional[0]' bar) || [ "$r" != bar ]; then
|
|
echo "passing the inline script after -- didn't work"
|
|
exit 1
|
|
fi
|
|
if ! r=$($JQ --args -rn 1 -- '$ARGS.positional[0]' bar) || [ "$r" != 1 ]; then
|
|
echo "passing the inline script before -- didn't work"
|
|
exit 1
|
|
fi
|
|
|
|
# CVE-2023-50246: No heap overflow for '-10E-1000000001'
|
|
$VALGRIND $Q $JQ . <<\NUM
|
|
-10E-1000000001
|
|
NUM
|
|
|
|
# test for --indent and --compact-output -- #1465
|
|
printf '[1,2]\n' > $d/expected
|
|
$JQ --compact-output -n "[1,2]" > $d/out
|
|
cmp $d/out $d/expected
|
|
|
|
printf '[\n1,\n2\n]\n' > $d/expected
|
|
$JQ --indent 0 -n "[1,2]" > $d/out
|
|
cmp $d/out $d/expected
|
|
|
|
printf '[\n 1,\n 2\n]\n' > $d/expected
|
|
$JQ --indent 1 -n "[1,2]" > $d/out
|
|
cmp $d/out $d/expected
|
|
|
|
printf '[\n 1,\n 2\n]\n' > $d/expected
|
|
$JQ --indent 5 -n "[1,2]" > $d/out
|
|
cmp $d/out $d/expected
|
|
|
|
printf '[\n{\n"a": 1\n}\n]\n' > $d/expected
|
|
$JQ --indent 0 -n "[{a:1}]" > $d/out
|
|
cmp $d/out $d/expected
|
|
|
|
printf '[\n {\n "a": 1\n }\n]\n' > $d/expected
|
|
$JQ --indent 1 -n "[{a:1}]" > $d/out
|
|
cmp $d/out $d/expected
|
|
|
|
printf '[\n {\n "a": 1\n }\n]\n' > $d/expected
|
|
$JQ --indent 6 -n "[{a:1}]" > $d/out
|
|
cmp $d/out $d/expected
|
|
|
|
if ! $msys && ! $mingw; then
|
|
# Test handling of timezones -- #2429, #2475
|
|
if ! r=$(TZ=Asia/Tokyo $JQ -rn '1731627341 | strflocaltime("%F %T %z %Z")') \
|
|
|| [ "$r" != "2024-11-15 08:35:41 +0900 JST" ]; then
|
|
echo "Incorrectly formatted local time"
|
|
exit 1
|
|
fi
|
|
|
|
if ! r=$(TZ=Europe/Paris $JQ -rn '1731627341 | strflocaltime("%F %T %z %Z")') \
|
|
|| [ "$r" != "2024-11-15 00:35:41 +0100 CET" ]; then
|
|
echo "Incorrectly formatted local time"
|
|
exit 1
|
|
fi
|
|
|
|
# Test when DST is in effect: #1912
|
|
if ! r=$(TZ=Europe/Paris $JQ -rn '1750500000 | strflocaltime("%F %T %z %Z")') \
|
|
|| [ "$r" != "2025-06-21 12:00:00 +0200 CEST" ]; then
|
|
echo "Incorrectly formatted local time"
|
|
exit 1
|
|
fi
|
|
|
|
if ! r=$(TZ=Europe/Paris $JQ -rn '1731627341 | strftime("%F %T %z %Z")') \
|
|
|| ( [ "$r" != "2024-11-14 23:35:41 +0000 UTC" ] \
|
|
&& [ "$r" != "2024-11-14 23:35:41 +0000 GMT" ] ); then
|
|
echo "Incorrectly formatted universal time"
|
|
exit 1
|
|
fi
|
|
|
|
if ! r=$(TZ=Etc/GMT+7 $JQ -nc '1731627341 | .,. | [strftime("%FT%T"),strflocaltime("%FT%T%z")]'
|
|
) \
|
|
|| [ "$r" != '["2024-11-14T23:35:41","2024-11-14T16:35:41-0700"]
|
|
["2024-11-14T23:35:41","2024-11-14T16:35:41-0700"]' ]; then
|
|
echo "strftime or strftimelocal are not pure functions"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Test ARG_NEWCLOSURE overflow protection (issue #3458)
|
|
# Test 1: Too many function parameters (4097 params triggers the limit)
|
|
echo "Testing function parameter limit..."
|
|
cat > $d/expected <<EOF
|
|
jq: error: too many function parameters or local function definitions (max 4095)
|
|
jq: 1 compile error
|
|
EOF
|
|
$JQ -rn '"def f(\([range(4097) | "a\(.)"] | join(";"))): .; f(\([range(4097)] | join(";")))"' > $d/prog.jq
|
|
$JQ -nf $d/prog.jq 2> $d/out && {
|
|
echo "Expected compile error for too many parameters"
|
|
exit 1
|
|
}
|
|
diff $d/out $d/expected
|
|
|
|
# Test 2: Too many local functions (4097 functions triggers the limit)
|
|
echo "Testing local function limit..."
|
|
cat > $d/expected <<EOF
|
|
jq: error: too many function parameters or local function definitions (max 4095)
|
|
jq: 1 compile error
|
|
EOF
|
|
$JQ -rn '"\([range(4097) | "def f\(.): \(.)"] | join("; ")); \([range(4097) | "f\(.)"] | join(" + "))"' > $d/prog.jq
|
|
$JQ -nf $d/prog.jq 2> $d/out && {
|
|
echo "Expected compile error for too many local functions"
|
|
exit 1
|
|
}
|
|
diff $d/out $d/expected
|
|
|
|
# Test 3: Too many function parameters in a nested function (issue #3661)
|
|
echo "Testing function parameter limit in a nested function..."
|
|
cat > $d/expected <<EOF
|
|
jq: error: function has too many parameters (max 4095)
|
|
jq: error: too many function parameters or local function definitions (max 4095)
|
|
jq: 2 compile errors
|
|
EOF
|
|
$JQ -rn '"def g(\([range(4097) | "a\(.)"] | join(";"))): .; def f: g(\([range(4097)] | join(";"))); f"' > $d/prog.jq
|
|
$JQ -nf $d/prog.jq 2> $d/out && {
|
|
echo "Expected compile error for too many parameters in a nested function"
|
|
exit 1
|
|
}
|
|
diff $d/out $d/expected
|
|
|
|
# CVE-2026-33948: No NUL truncation in the JSON parser
|
|
if printf '{}\x00{}' | $JQ >/dev/null 2> /dev/null; then
|
|
printf 'Error expected but jq exited successfully\n' 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# CVE-2026-41256: No NUL truncation in program files loaded with -f
|
|
printf '.\x00invalid' > "$d/nul_prog.jq"
|
|
if echo '42' | $JQ -f "$d/nul_prog.jq" >/dev/null 2>/dev/null; then
|
|
printf 'Error expected for program file with NUL bytes\n' 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# CVE-2026-43895: No NUL bytes in module/data import paths
|
|
printf 'import "a\\u0000b" as $x; .' > "$d/nul_import.jq"
|
|
if $JQ -nf "$d/nul_import.jq" >/dev/null 2>/dev/null; then
|
|
printf 'Error expected for import path with NUL bytes\n' 1>&2
|
|
exit 1
|
|
fi
|
|
printf 'include "a\\u0000b"; .' > "$d/nul_include.jq"
|
|
if $JQ -nf "$d/nul_include.jq" >/dev/null 2>/dev/null; then
|
|
printf 'Error expected for include path with NUL bytes\n' 1>&2
|
|
exit 1
|
|
fi
|
|
printf '"a\\u0000b" | modulemeta' > "$d/nul_modulemeta.jq"
|
|
if $JQ -nf "$d/nul_modulemeta.jq" >/dev/null 2>/dev/null; then
|
|
printf 'Error expected for modulemeta with NUL bytes\n' 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
exit 0
|